diff --git a/config/conf/cors_headers.py b/config/conf/cors_headers.py index e9f731e..6306940 100644 --- a/config/conf/cors_headers.py +++ b/config/conf/cors_headers.py @@ -1,6 +1,7 @@ CORS_ALLOWED_ORIGINS = [ "http://localhost:8081", "http://127.0.0.1:8081", + 'https://uyqur.vercel.app' ] CSRF_TRUSTED_ORIGINS = [ diff --git a/core/apps/projects/migrations/0014_estimatework_total_price_alter_project_benifit_plan.py b/core/apps/projects/migrations/0014_estimatework_total_price_alter_project_benifit_plan.py new file mode 100644 index 0000000..415a1ea --- /dev/null +++ b/core/apps/projects/migrations/0014_estimatework_total_price_alter_project_benifit_plan.py @@ -0,0 +1,23 @@ +# Generated by Django 5.2.4 on 2025-08-09 15:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0013_projectestimate_estimateproduct_estimatework'), + ] + + operations = [ + migrations.AddField( + model_name='estimatework', + name='total_price', + field=models.PositiveBigIntegerField(default=0), + ), + migrations.AlterField( + model_name='project', + name='benifit_plan', + field=models.PositiveBigIntegerField(blank=True, null=True), + ), + ] diff --git a/core/apps/projects/migrations/0015_estimateproduct_estimate_work.py b/core/apps/projects/migrations/0015_estimateproduct_estimate_work.py new file mode 100644 index 0000000..8acdb61 --- /dev/null +++ b/core/apps/projects/migrations/0015_estimateproduct_estimate_work.py @@ -0,0 +1,19 @@ +# Generated by Django 5.2.4 on 2025-08-11 11:35 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0014_estimatework_total_price_alter_project_benifit_plan'), + ] + + operations = [ + migrations.AddField( + model_name='estimateproduct', + name='estimate_work', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='estimate_products', to='projects.estimatework'), + ), + ] diff --git a/core/apps/projects/models/project_estimate.py b/core/apps/projects/models/project_estimate.py index e6c13d9..e68f5e1 100644 --- a/core/apps/projects/models/project_estimate.py +++ b/core/apps/projects/models/project_estimate.py @@ -29,7 +29,8 @@ class EstimateWork(BaseModel): estimate = models.ForeignKey( ProjectEstimate, on_delete=models.CASCADE, related_name='estimate_works' ) - date = models.DateField(null=True, blank=True) + date = models.DateField(null=True, blank=True) + total_price = models.PositiveBigIntegerField(default=0) def __str__(self): return f"{self.number}.{self.name}" @@ -42,12 +43,12 @@ class EstimateWork(BaseModel): class EstimateProduct(BaseModel): product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='estimate_products') quantity = models.PositiveIntegerField(default=1) - price = models.PositiveBigIntegerField() unity = models.ForeignKey( Unity, on_delete=models.SET_NULL, null=True, related_name='estimate_products' ) price = models.PositiveBigIntegerField(null=True, blank=True) date = models.DateField(null=True, blank=True) + estimate_work = models.ForeignKey(EstimateWork, on_delete=models.CASCADE, related_name='estimate_products', null=True) def __str__(self): return f'{self.product} - {self.price}' diff --git a/core/apps/projects/serializers/estimate_product.py b/core/apps/projects/serializers/estimate_product.py new file mode 100644 index 0000000..5625e87 --- /dev/null +++ b/core/apps/projects/serializers/estimate_product.py @@ -0,0 +1,76 @@ +from django.db import transaction + +from rest_framework import serializers + +from core.apps.projects.models.project_estimate import EstimateProduct, EstimateWork +from core.apps.products.models import Product, Unity + + +class EstimateProductListSerializer(serializers.ModelSerializer): + product = serializers.SerializerMethodField(method_name='get_product') + + class Meta: + model = EstimateProduct + fields = [ + 'id', 'product', 'quantity', 'price', 'unity', 'price', 'date' + ] + + def get_product(self, obj): + return { + 'id': obj.product.id, + 'name': obj.product.name, + 'type': obj.product.type + } + + +class EstimateProductCreateSerializer(serializers.Serializer): + product_id = serializers.UUIDField() + quantity = serializers.IntegerField() + price = serializers.IntegerField() + unity_id = serializers.UUIDField(required=False) + date = serializers.DateField() + estimate_work_id = serializers.UUIDField() + + def validate(self, data): + product = Product.objects.filter(id=data['product_id']).first() + if not product: + raise serializers.ValidationError("Product not found") + estimate_work = EstimateWork.objects.filter(id=data['estimate_work_id']).first() + if not estimate_work: + raise serializers.ValidationError("EstimateWork not found") + if data.get('unity_id'): + unity = Unity.objects.filter(id=data['unity_id']).first() + if not unity: + raise serializers.ValidationError("Unity not found") + data['unity'] = unity + data['product'] = product + data['estimate_work'] = estimate_work + return data + + def create(self, validated_data): + with transaction.atomic(): + return EstimateProduct.objects.create( + product=validated_data.get('product'), + quantity=validated_data.get('quantity'), + price=validated_data.get('price'), + unity=validated_data.get('unity'), + date=validated_data.get('date'), + estimate_work=validated_data.get('estimate_work'), + ) + + +class EstimateProductUpdateSerializer(serializers.ModelSerializer): + class Meta: + model = EstimateProduct + fields = [ + 'product', 'quantity', 'price', 'unity', 'date' + ] + + def update(self, instance, validated_data): + instance.product = validated_data.get('product', instance.product) + instance.quantity = validated_data.get('quantity', instance.quantity) + instance.price = validated_data.get('price', instance.price) + instance.unity = validated_data.get('unity', instance.unity) + instance.date = validated_data.get('date', instance.date) + instance.save() + return instance \ No newline at end of file diff --git a/core/apps/projects/serializers/estimate_work.py b/core/apps/projects/serializers/estimate_work.py new file mode 100644 index 0000000..73ae6e3 --- /dev/null +++ b/core/apps/projects/serializers/estimate_work.py @@ -0,0 +1,81 @@ +from django.db import transaction + +from rest_framework import serializers + +from core.apps.projects.models.project_estimate import EstimateWork, ProjectEstimate +from core.apps.products.models.unity import Unity +from core.apps.projects.serializers.estimate_product import EstimateProductListSerializer + + +class EstimateWorkListSerializer(serializers.ModelSerializer): + unity = serializers.SerializerMethodField(method_name='get_unity') + estimate_products = EstimateProductListSerializer(many=True) + + class Meta: + model = EstimateWork + fields = [ + 'id', 'number', 'name', 'quantity', 'unity', 'price', 'date', 'total_price', 'estimate_products' + ] + + def get_unity(self, obj): + return { + "id": obj.unity.id, + 'value': obj.unity.value + } if obj.unity else None + + +class EstimateWorkCreateSerializer(serializers.Serializer): + number = serializers.IntegerField() + name = serializers.CharField() + quantity = serializers.IntegerField() + unity_id = serializers.UUIDField(required=False) + price = serializers.IntegerField(required=False) + date = serializers.DateField(required=False) + total_price = serializers.IntegerField(required=False) + estimate_id = serializers.UUIDField() + + def validate(self, data): + unity_id = data.get('unity_id') + if unity_id: + unity = Unity.objects.filter(id=unity_id).first() + if not unity: + raise serializers.ValidationError("Unity not found") + data['unity'] = unity + estimate = ProjectEstimate.objects.filter(id=data['estimate_id']).first() + if not estimate: + raise serializers.ValidationError("estimate not found") + data['estimate'] = estimate + return data + + def create(self, validated_data): + with transaction.atomic(): + estimate_work = EstimateWork.objects.create( + number=validated_data.get('number'), + name=validated_data.get('name'), + quantity=validated_data.get('quantity'), + unity=validated_data.get('unity'), + price=validated_data.get('price'), + date=validated_data.get('date'), + total_price=validated_data.get('total_price'), + estimate=validated_data.get('estimate') + ) + return estimate_work + + +class EstimateWorkUpdateSerializer(serializers.ModelSerializer): + class Meta: + model = EstimateWork + fields = [ + 'name', 'quantity', 'price', 'unity', 'date', 'total_price', + ] + + def update(self, instance, validated_data): + instance.name = validated_data.get('name', instance.name) + instance.quantity = validated_data.get('quantity', instance.quantity) + instance.price = validated_data.get('price', instance.price) + instance.unity = validated_data.get('unity', instance.unity) + instance.date = validated_data.get('date', instance.date) + instance.total_price = validated_data.get('total_price', instance.total_price) + instance.save() + return instance + diff --git a/core/apps/projects/serializers/project_estimate.py b/core/apps/projects/serializers/project_estimate.py index 3ad4003..65e5953 100644 --- a/core/apps/projects/serializers/project_estimate.py +++ b/core/apps/projects/serializers/project_estimate.py @@ -2,14 +2,17 @@ from django.db import transaction from rest_framework import serializers -from core.apps.projects.models.project_estimate import EstimateProduct, EstimateWork, ProjectEstimate +from core.apps.projects.models.project_estimate import ProjectEstimate +from core.apps.projects.serializers.estimate_work import EstimateWorkListSerializer class ProjectEstimateListSerializer(serializers.ModelSerializer): + estimate_works = EstimateWorkListSerializer(many=True) + class Meta: model = ProjectEstimate fields = [ - 'id', 'number', 'name' + 'id', 'number', 'name', 'estimate_works' ] diff --git a/core/apps/projects/urls.py b/core/apps/projects/urls.py index fd670a0..0f65e9d 100644 --- a/core/apps/projects/urls.py +++ b/core/apps/projects/urls.py @@ -3,6 +3,8 @@ from django.urls import path, include from core.apps.projects.views import project as project_views from core.apps.projects.views import builder as builder_views from core.apps.projects.views import project_estimate as estimate_views +from core.apps.projects.views import estimate_work as estimate_work_views +from core.apps.projects.views import estimate_product as estimate_product_views urlpatterns = [ path('project/', include( @@ -38,5 +40,19 @@ urlpatterns = [ path('/update/', estimate_views.ProjectEstimateUpdateApiView.as_view()), path('/delete/', estimate_views.ProjectEstimateDeleteApiView.as_view()), ] + )), + path('estimate_work/', include( + [ + path('create/', estimate_work_views.EstimateWorkCreateApiView.as_view()), + path('/update/', estimate_work_views.EstimateWorkUpdateApiView.as_view()), + path('/delete/', estimate_work_views.EstimateWorkDeleteApiView.as_view()), + ] + )), + path('estimate_product/', include( + [ + path('create/', estimate_product_views.EstimateProductCreateApiView.as_view()), + path('/update/', estimate_product_views.EstimateProductUpdateApiView.as_view()), + path('/delete/', estimate_product_views.EstimateProductDeleteApiView.as_view()), + ] )) ] \ No newline at end of file diff --git a/core/apps/projects/views/estimate_product.py b/core/apps/projects/views/estimate_product.py new file mode 100644 index 0000000..47b943e --- /dev/null +++ b/core/apps/projects/views/estimate_product.py @@ -0,0 +1,47 @@ +from django.shortcuts import get_object_or_404 + +from rest_framework import generics, views +from rest_framework.response import Response + +from core.apps.projects.serializers import estimate_product as serializers +from core.apps.projects.models.project_estimate import EstimateProduct +from core.apps.accounts.permissions.permissions import HasRolePermission + + +class EstimateProductCreateApiView(generics.GenericAPIView): + permission_classes = [HasRolePermission] + required_permissions = ['project'] + serializer_class = serializers.EstimateProductCreateSerializer + queryset = EstimateProduct.objects.all() + + def post(self, request): + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(): + serializer.save() + return Response({"success": True, 'message': 'created'}, status=201) + return Response({'success': False, 'message': serializer.errors}, status=400) + + +class EstimateProductUpdateApiView(generics.GenericAPIView): + serializer_class = serializers.EstimateProductUpdateSerializer + queryset = EstimateProduct.objects.all() + permission_classes = [HasRolePermission] + required_permissions = ['project'] + + def patch(self, request, id): + estimate_product = get_object_or_404(EstimateProduct, id=id) + serializer = self.serializer_class(data=request.data, instance=estimate_product, partial=True) + if serializer.is_valid(): + serializer.save() + return Response({"success": True, "message": 'updated'}, status=200) + return Response({"success": False, 'message': serializer.errors}, status=400) + + +class EstimateProductDeleteApiView(views.APIView): + permission_classes = [HasRolePermission] + required_permissions = ['project'] + + def delete(self, request, id): + estimate_product = get_object_or_404(EstimateProduct, id=id) + estimate_product.delete() + return Response({"success": True}, status=204) diff --git a/core/apps/projects/views/estimate_work.py b/core/apps/projects/views/estimate_work.py new file mode 100644 index 0000000..daf84f4 --- /dev/null +++ b/core/apps/projects/views/estimate_work.py @@ -0,0 +1,47 @@ +from django.shortcuts import get_object_or_404 + +from rest_framework import generics, views +from rest_framework.response import Response + +from core.apps.accounts.permissions.permissions import HasRolePermission +from core.apps.projects.models.project_estimate import EstimateWork +from core.apps.projects.serializers import estimate_work as serializers + + +class EstimateWorkCreateApiView(generics.GenericAPIView): + serializer_class = serializers.EstimateWorkCreateSerializer + queryset = EstimateWork.objects.all() + permission_classes = [HasRolePermission] + required_permissions = ['project', 'project_folder'] + + def post(self, request): + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(): + serializer.save() + return Response({'success': True, 'message': 'created!'}, status=201) + return Response({'success': False, 'message': serializer.errors}, status=400) + + +class EstimateWorkUpdateApiView(generics.GenericAPIView): + serializer_class = serializers.EstimateWorkUpdateSerializer + queryset = EstimateWork.objects.all() + permission_classes = [HasRolePermission] + required_permissions = ['project', 'project_folder'] + + def patch(self, request, id): + estimate_work = get_object_or_404(EstimateWork, id=id) + serializer = self.serializer_class(data=request.data, instance=estimate_work) + if serializer.is_valid(): + serializer.save() + return Response({"success": True, "message": "Updated"}, status=200) + return Response({'success': False, 'message': serializer.errors}, status=400) + + +class EstimateWorkDeleteApiView(views.APIView): + permission_classes = [HasRolePermission] + required_permissions = ['project'] + + def delete(self, request, id): + work = get_object_or_404(EstimateWork, id=id) + work.delete() + return Response({"success": True}, status=204) \ No newline at end of file diff --git a/core/apps/projects/views/project_estimate.py b/core/apps/projects/views/project_estimate.py index 6bf68a1..e117560 100644 --- a/core/apps/projects/views/project_estimate.py +++ b/core/apps/projects/views/project_estimate.py @@ -10,7 +10,7 @@ from core.apps.projects.serializers import project_estimate as serializers class ProjectEstimateListApiView(generics.ListAPIView): serializer_class = serializers.ProjectEstimateListSerializer - queryset = ProjectEstimate.objects.all() + queryset = ProjectEstimate.objects.prefetch_related('estimate_works') permission_classes = [HasRolePermission] required_permissions = ['project'] @@ -54,4 +54,3 @@ class ProjectEstimateDeleteApiView(generics.GenericAPIView): estimte = get_object_or_404(ProjectEstimate, id=id) estimte.delete() return Response({"success": True, "message": "deleted"}, status=204) - \ No newline at end of file diff --git a/resources/logs/django.log.2025-08-09 b/resources/logs/django.log.2025-08-09 new file mode 100644 index 0000000..1f37d02 --- /dev/null +++ b/resources/logs/django.log.2025-08-09 @@ -0,0 +1,272 @@ +WARNING 2025-08-09 11:54:16,155 log Forbidden: /api/v1/projects/project/list/ +WARNING 2025-08-09 11:54:24,194 log Not Found: / +WARNING 2025-08-09 11:54:24,296 log Not Found: /favicon.ico +ERROR 2025-08-09 12:13:13,318 log Internal Server Error: /api/v1/projects/project/8b40e979-0274-48d3-92f0-007bd2e11d71/ +Traceback (most recent call last): + File "/usr/local/lib/python3.12/site-packages/rest_framework/fields.py", line 437, in get_attribute + return get_attribute(instance, self.source_attrs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/fields.py", line 104, in get_attribute + instance = getattr(instance, attr) + ^^^^^^^^^^^^^^^^^^^^^^^ +AttributeError: 'ManyRelatedManager' object has no attribute 'address' + +During handling of the above exception, another exception occurred: + +Traceback (most recent call last): + File "/usr/local/lib/python3.12/site-packages/asgiref/sync.py", line 489, in thread_handler + raise exc_info[1] + File "/usr/local/lib/python3.12/site-packages/django/core/handlers/exception.py", line 42, in inner + response = await get_response(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/asgiref/sync.py", line 489, in thread_handler + raise exc_info[1] + File "/usr/local/lib/python3.12/site-packages/django/core/handlers/base.py", line 253, in _get_response_async + response = await wrapped_callback( + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/asgiref/sync.py", line 439, in __call__ + ret = await asyncio.shield(exec_coro) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/concurrent/futures/thread.py", line 59, in run + result = self.fn(*self.args, **self.kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/asgiref/sync.py", line 493, in thread_handler + return func(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/django/views/decorators/csrf.py", line 65, in _view_wrapper + return view_func(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/django/views/generic/base.py", line 105, in view + return self.dispatch(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/views.py", line 515, in dispatch + response = self.handle_exception(exc) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/views.py", line 475, in handle_exception + self.raise_uncaught_exception(exc) + File "/usr/local/lib/python3.12/site-packages/rest_framework/views.py", line 486, in raise_uncaught_exception + raise exc + File "/usr/local/lib/python3.12/site-packages/rest_framework/views.py", line 512, in dispatch + response = handler(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/generics.py", line 212, in get + return self.retrieve(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/mixins.py", line 56, in retrieve + return Response(serializer.data) + ^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/serializers.py", line 573, in data + ret = super().data + ^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/serializers.py", line 251, in data + self._data = self.to_representation(self.instance) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/serializers.py", line 540, in to_representation + ret[field.field_name] = field.to_representation(attribute) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/serializers.py", line 527, in to_representation + attribute = field.get_attribute(instance) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/fields.py", line 470, in get_attribute + raise type(exc)(msg) +AttributeError: Got AttributeError when attempting to get a value for field `address` on serializer `WhereHouseListSerializer`. +The serializer field might be named incorrectly and not match any attribute or key on the `ManyRelatedManager` instance. +Original exception text was: 'ManyRelatedManager' object has no attribute 'address'. +ERROR 2025-08-09 12:13:14,831 log Internal Server Error: /api/v1/projects/project/8b40e979-0274-48d3-92f0-007bd2e11d71/ +Traceback (most recent call last): + File "/usr/local/lib/python3.12/site-packages/rest_framework/fields.py", line 437, in get_attribute + return get_attribute(instance, self.source_attrs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/fields.py", line 104, in get_attribute + instance = getattr(instance, attr) + ^^^^^^^^^^^^^^^^^^^^^^^ +AttributeError: 'ManyRelatedManager' object has no attribute 'address' + +During handling of the above exception, another exception occurred: + +Traceback (most recent call last): + File "/usr/local/lib/python3.12/site-packages/asgiref/sync.py", line 489, in thread_handler + raise exc_info[1] + File "/usr/local/lib/python3.12/site-packages/django/core/handlers/exception.py", line 42, in inner + response = await get_response(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/asgiref/sync.py", line 489, in thread_handler + raise exc_info[1] + File "/usr/local/lib/python3.12/site-packages/django/core/handlers/base.py", line 253, in _get_response_async + response = await wrapped_callback( + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/asgiref/sync.py", line 439, in __call__ + ret = await asyncio.shield(exec_coro) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/concurrent/futures/thread.py", line 59, in run + result = self.fn(*self.args, **self.kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/asgiref/sync.py", line 493, in thread_handler + return func(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/django/views/decorators/csrf.py", line 65, in _view_wrapper + return view_func(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/django/views/generic/base.py", line 105, in view + return self.dispatch(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/views.py", line 515, in dispatch + response = self.handle_exception(exc) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/views.py", line 475, in handle_exception + self.raise_uncaught_exception(exc) + File "/usr/local/lib/python3.12/site-packages/rest_framework/views.py", line 486, in raise_uncaught_exception + raise exc + File "/usr/local/lib/python3.12/site-packages/rest_framework/views.py", line 512, in dispatch + response = handler(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/generics.py", line 212, in get + return self.retrieve(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/mixins.py", line 56, in retrieve + return Response(serializer.data) + ^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/serializers.py", line 573, in data + ret = super().data + ^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/serializers.py", line 251, in data + self._data = self.to_representation(self.instance) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/serializers.py", line 540, in to_representation + ret[field.field_name] = field.to_representation(attribute) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/serializers.py", line 527, in to_representation + attribute = field.get_attribute(instance) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/fields.py", line 470, in get_attribute + raise type(exc)(msg) +AttributeError: Got AttributeError when attempting to get a value for field `address` on serializer `WhereHouseListSerializer`. +The serializer field might be named incorrectly and not match any attribute or key on the `ManyRelatedManager` instance. +Original exception text was: 'ManyRelatedManager' object has no attribute 'address'. +ERROR 2025-08-09 15:14:16,166 log Internal Server Error: /swagger/ +Traceback (most recent call last): + File "/usr/local/lib/python3.12/site-packages/asgiref/sync.py", line 489, in thread_handler + raise exc_info[1] + File "/usr/local/lib/python3.12/site-packages/django/core/handlers/exception.py", line 42, in inner + response = await get_response(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/django/core/handlers/base.py", line 235, in _get_response_async + callback, callback_args, callback_kwargs = self.resolve_request(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/django/core/handlers/base.py", line 313, in resolve_request + resolver_match = resolver.resolve(request.path_info) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/django/urls/resolvers.py", line 666, in resolve + for pattern in self.url_patterns: + ^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/django/utils/functional.py", line 47, in __get__ + res = instance.__dict__[self.name] = self.func(instance) + ^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/django/urls/resolvers.py", line 718, in url_patterns + patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module) + ^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/django/utils/functional.py", line 47, in __get__ + res = instance.__dict__[self.name] = self.func(instance) + ^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/django/urls/resolvers.py", line 711, in urlconf_module + return import_module(self.urlconf_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/importlib/__init__.py", line 90, in import_module + return _bootstrap._gcd_import(name[level:], package, level) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "", line 1387, in _gcd_import + File "", line 1360, in _find_and_load + File "", line 1331, in _find_and_load_unlocked + File "", line 935, in _load_unlocked + File "", line 999, in exec_module + File "", line 488, in _call_with_frames_removed + File "/code/config/urls.py", line 33, in + path('projects/', include('core.apps.projects.urls')), + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/django/urls/conf.py", line 39, in include + urlconf_module = import_module(urlconf_module) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/importlib/__init__.py", line 90, in import_module + return _bootstrap._gcd_import(name[level:], package, level) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "", line 1387, in _gcd_import + File "", line 1360, in _find_and_load + File "", line 1331, in _find_and_load_unlocked + File "", line 935, in _load_unlocked + File "", line 995, in exec_module + File "", line 1133, in get_code + File "", line 1063, in source_to_code + File "", line 488, in _call_with_frames_removed + File "/code/core/apps/projects/urls.py", line 39 + path('/delete/', estimate_views.) + ^ +SyntaxError: invalid syntax +WARNING 2025-08-09 15:14:16,990 log Not Found: /favicon.ico +ERROR 2025-08-09 15:35:41,275 log Internal Server Error: /api/v1/projects/project_estimate/list/ +Traceback (most recent call last): + File "/usr/local/lib/python3.12/site-packages/asgiref/sync.py", line 489, in thread_handler + raise exc_info[1] + File "/usr/local/lib/python3.12/site-packages/django/core/handlers/exception.py", line 42, in inner + response = await get_response(request) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/asgiref/sync.py", line 489, in thread_handler + raise exc_info[1] + File "/usr/local/lib/python3.12/site-packages/django/core/handlers/base.py", line 253, in _get_response_async + response = await wrapped_callback( + ^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/asgiref/sync.py", line 439, in __call__ + ret = await asyncio.shield(exec_coro) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/concurrent/futures/thread.py", line 59, in run + result = self.fn(*self.args, **self.kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/asgiref/sync.py", line 493, in thread_handler + return func(*args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/django/views/decorators/csrf.py", line 65, in _view_wrapper + return view_func(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/django/views/generic/base.py", line 105, in view + return self.dispatch(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/views.py", line 515, in dispatch + response = self.handle_exception(exc) + ^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/views.py", line 475, in handle_exception + self.raise_uncaught_exception(exc) + File "/usr/local/lib/python3.12/site-packages/rest_framework/views.py", line 486, in raise_uncaught_exception + raise exc + File "/usr/local/lib/python3.12/site-packages/rest_framework/views.py", line 512, in dispatch + response = handler(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/generics.py", line 203, in get + return self.list(request, *args, **kwargs) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/mixins.py", line 43, in list + return self.get_paginated_response(serializer.data) + ^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/serializers.py", line 797, in data + ret = super().data + ^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/serializers.py", line 251, in data + self._data = self.to_representation(self.instance) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/serializers.py", line 716, in to_representation + self.child.to_representation(item) for item in iterable + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/serializers.py", line 540, in to_representation + ret[field.field_name] = field.to_representation(attribute) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/serializers.py", line 716, in to_representation + self.child.to_representation(item) for item in iterable + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/serializers.py", line 540, in to_representation + ret[field.field_name] = field.to_representation(attribute) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/local/lib/python3.12/site-packages/rest_framework/fields.py", line 1870, in to_representation + return method(value) + ^^^^^^^^^^^^^ + File "/code/core/apps/projects/serializers/project_estimate.py", line 20, in get_unity + 'name': obj.unity.name + ^^^^^^^^^^^^^^ +AttributeError: 'Unity' object has no attribute 'name'