From 53b0737ee52d9c69c05264920c4d2fbf7300e5b6 Mon Sep 17 00:00:00 2001 From: Husanjonazamov Date: Fri, 13 Feb 2026 18:33:56 +0500 Subject: [PATCH] QuickEvaluationModel modeli qoshildi shu tezkor baholash uchun ishatiladi --- core/apps/evaluation/admin/__init__.py | 1 + core/apps/evaluation/admin/quick.py | 12 +++ core/apps/evaluation/filters/__init__.py | 1 + core/apps/evaluation/filters/quick.py | 13 +++ core/apps/evaluation/forms/__init__.py | 1 + core/apps/evaluation/forms/quick.py | 10 ++ .../migrations/0007_quickevaluationmodel.py | 43 ++++++++ core/apps/evaluation/models/__init__.py | 3 +- core/apps/evaluation/models/quick.py | 78 ++++++++++++++ core/apps/evaluation/permissions/__init__.py | 1 + core/apps/evaluation/permissions/quick.py | 12 +++ core/apps/evaluation/serializers/__init__.py | 1 + .../serializers/quick/QuickEvaluation.py | 26 +++++ .../evaluation/serializers/quick/__init__.py | 1 + core/apps/evaluation/signals/__init__.py | 1 + core/apps/evaluation/signals/quick.py | 8 ++ core/apps/evaluation/tests/__init__.py | 1 + core/apps/evaluation/tests/quick/__init__.py | 1 + .../tests/quick/test_QuickEvaluation.py | 101 ++++++++++++++++++ core/apps/evaluation/translation/__init__.py | 1 + core/apps/evaluation/translation/quick.py | 8 ++ core/apps/evaluation/urls.py | 2 + core/apps/evaluation/validators/__init__.py | 1 + core/apps/evaluation/validators/quick.py | 8 ++ core/apps/evaluation/views/__init__.py | 1 + core/apps/evaluation/views/quick.py | 25 +++++ 26 files changed, 359 insertions(+), 2 deletions(-) create mode 100644 core/apps/evaluation/admin/quick.py create mode 100644 core/apps/evaluation/filters/quick.py create mode 100644 core/apps/evaluation/forms/quick.py create mode 100644 core/apps/evaluation/migrations/0007_quickevaluationmodel.py create mode 100644 core/apps/evaluation/models/quick.py create mode 100644 core/apps/evaluation/permissions/quick.py create mode 100644 core/apps/evaluation/serializers/quick/QuickEvaluation.py create mode 100644 core/apps/evaluation/serializers/quick/__init__.py create mode 100644 core/apps/evaluation/signals/quick.py create mode 100644 core/apps/evaluation/tests/quick/__init__.py create mode 100644 core/apps/evaluation/tests/quick/test_QuickEvaluation.py create mode 100644 core/apps/evaluation/translation/quick.py create mode 100644 core/apps/evaluation/validators/quick.py create mode 100644 core/apps/evaluation/views/quick.py diff --git a/core/apps/evaluation/admin/__init__.py b/core/apps/evaluation/admin/__init__.py index ce44113..ef86837 100644 --- a/core/apps/evaluation/admin/__init__.py +++ b/core/apps/evaluation/admin/__init__.py @@ -1,6 +1,7 @@ from .auto import * # noqa from .customer import * # noqa from .movable import * # noqa +from .quick import * # noqa from .real_estate import * # noqa from .valuation import * # noqa from .vehicle import * # noqa diff --git a/core/apps/evaluation/admin/quick.py b/core/apps/evaluation/admin/quick.py new file mode 100644 index 0000000..726438b --- /dev/null +++ b/core/apps/evaluation/admin/quick.py @@ -0,0 +1,12 @@ +from django.contrib import admin +from unfold.admin import ModelAdmin + +from core.apps.evaluation.models import QuickEvaluationModel + + +@admin.register(QuickEvaluationModel) +class QuickevaluationAdmin(ModelAdmin): + list_display = ( + "id", + "__str__", + ) diff --git a/core/apps/evaluation/filters/__init__.py b/core/apps/evaluation/filters/__init__.py index ce44113..ef86837 100644 --- a/core/apps/evaluation/filters/__init__.py +++ b/core/apps/evaluation/filters/__init__.py @@ -1,6 +1,7 @@ from .auto import * # noqa from .customer import * # noqa from .movable import * # noqa +from .quick import * # noqa from .real_estate import * # noqa from .valuation import * # noqa from .vehicle import * # noqa diff --git a/core/apps/evaluation/filters/quick.py b/core/apps/evaluation/filters/quick.py new file mode 100644 index 0000000..3685637 --- /dev/null +++ b/core/apps/evaluation/filters/quick.py @@ -0,0 +1,13 @@ +from django_filters import rest_framework as filters + +from core.apps.evaluation.models import QuickEvaluationModel + + +class QuickevaluationFilter(filters.FilterSet): + # name = filters.CharFilter(field_name="name", lookup_expr="icontains") + + class Meta: + model = QuickEvaluationModel + fields = [ + "name", + ] diff --git a/core/apps/evaluation/forms/__init__.py b/core/apps/evaluation/forms/__init__.py index ce44113..ef86837 100644 --- a/core/apps/evaluation/forms/__init__.py +++ b/core/apps/evaluation/forms/__init__.py @@ -1,6 +1,7 @@ from .auto import * # noqa from .customer import * # noqa from .movable import * # noqa +from .quick import * # noqa from .real_estate import * # noqa from .valuation import * # noqa from .vehicle import * # noqa diff --git a/core/apps/evaluation/forms/quick.py b/core/apps/evaluation/forms/quick.py new file mode 100644 index 0000000..3807a14 --- /dev/null +++ b/core/apps/evaluation/forms/quick.py @@ -0,0 +1,10 @@ +from django import forms + +from core.apps.evaluation.models import QuickEvaluationModel + + +class QuickevaluationForm(forms.ModelForm): + + class Meta: + model = QuickEvaluationModel + fields = "__all__" diff --git a/core/apps/evaluation/migrations/0007_quickevaluationmodel.py b/core/apps/evaluation/migrations/0007_quickevaluationmodel.py new file mode 100644 index 0000000..ebb9355 --- /dev/null +++ b/core/apps/evaluation/migrations/0007_quickevaluationmodel.py @@ -0,0 +1,43 @@ +# Generated by Django 5.2.7 on 2026-02-13 13:31 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('evaluation', '0006_movablepropertyevaluationmodel'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='QuickEvaluationModel', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('tech_passport_number', models.CharField(blank=True, max_length=50, null=True, verbose_name='tech passport number')), + ('license_plate', models.CharField(blank=True, max_length=20, null=True, verbose_name='license plate')), + ('model', models.CharField(blank=True, max_length=255, null=True, verbose_name='model')), + ('brand', models.CharField(blank=True, max_length=255, null=True, verbose_name='brand')), + ('manufacture_year', models.IntegerField(blank=True, null=True, verbose_name='manufacture year')), + ('mileage', models.IntegerField(blank=True, null=True, verbose_name='mileage')), + ('vin_number', models.CharField(blank=True, max_length=50, null=True, verbose_name='VIN number')), + ('engine_number', models.CharField(blank=True, max_length=50, null=True, verbose_name='engine number')), + ('color', models.CharField(blank=True, max_length=50, null=True, verbose_name='color')), + ('fuel_type', models.CharField(blank=True, choices=[('petrol', 'Petrol'), ('diesel', 'Diesel'), ('gas', 'Gas'), ('electric', 'Electric'), ('hybrid', 'Hybrid')], max_length=50, null=True, verbose_name='fuel type')), + ('body_type', models.CharField(blank=True, choices=[('hatchback', 'Hatchback'), ('sedan', 'Sedan'), ('universal', 'Universal'), ('coupe', 'Coupe'), ('cabriolet', 'Cabriolet'), ('liftback', 'Liftback'), ('minivan', 'Minivan'), ('crossover', 'Crossover')], max_length=50, null=True, verbose_name='body type')), + ('condition', models.CharField(blank=True, choices=[('excellent', 'Excellent'), ('good', 'Good'), ('average', 'Average'), ('needs_repair', 'Needs repair')], max_length=50, null=True, verbose_name='condition')), + ('estimated_price', models.DecimalField(blank=True, decimal_places=2, max_digits=15, null=True, verbose_name='estimated price')), + ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='quick_evaluations', to=settings.AUTH_USER_MODEL, verbose_name='created by')), + ], + options={ + 'verbose_name': 'Quick Evaluation', + 'verbose_name_plural': 'Quick Evaluations', + 'db_table': 'QuickEvaluation', + }, + ), + ] diff --git a/core/apps/evaluation/models/__init__.py b/core/apps/evaluation/models/__init__.py index 0f9a0ef..ef86837 100644 --- a/core/apps/evaluation/models/__init__.py +++ b/core/apps/evaluation/models/__init__.py @@ -1,8 +1,7 @@ from .auto import * # noqa from .customer import * # noqa from .movable import * # noqa +from .quick import * # noqa from .real_estate import * # noqa -from .movable import * # noqa - from .valuation import * # noqa from .vehicle import * # noqa diff --git a/core/apps/evaluation/models/quick.py b/core/apps/evaluation/models/quick.py new file mode 100644 index 0000000..60dc004 --- /dev/null +++ b/core/apps/evaluation/models/quick.py @@ -0,0 +1,78 @@ +from django.db import models +from django.utils.translation import gettext_lazy as _ +from django_core.models import AbstractBaseModel +from model_bakery import baker + + +from core.apps.evaluation.choices.vehicle import FuelType, BodyType, VehicleCondition + + +class QuickEvaluationModel(AbstractBaseModel): + created_by = models.ForeignKey( + "accounts.User", + on_delete=models.SET_NULL, + null=True, + blank=True, + related_name="quick_evaluations", + verbose_name=_("created by"), + ) + tech_passport_number = models.CharField( + verbose_name=_("tech passport number"), max_length=50, blank=True, null=True + ) + license_plate = models.CharField( + verbose_name=_("license plate"), max_length=20, blank=True, null=True + ) + model = models.CharField(verbose_name=_("model"), max_length=255, blank=True, null=True) + brand = models.CharField(verbose_name=_("brand"), max_length=255, blank=True, null=True) + manufacture_year = models.IntegerField( + verbose_name=_("manufacture year"), blank=True, null=True + ) + mileage = models.IntegerField(verbose_name=_("mileage"), blank=True, null=True) + vin_number = models.CharField( + verbose_name=_("VIN number"), max_length=50, blank=True, null=True + ) + engine_number = models.CharField( + verbose_name=_("engine number"), max_length=50, blank=True, null=True + ) + color = models.CharField(verbose_name=_("color"), max_length=50, blank=True, null=True) + fuel_type = models.CharField( + verbose_name=_("fuel type"), + max_length=50, + choices=FuelType.choices, + blank=True, + null=True, + ) + body_type = models.CharField( + verbose_name=_("body type"), + max_length=50, + choices=BodyType.choices, + blank=True, + null=True, + ) + condition = models.CharField( + verbose_name=_("condition"), + max_length=50, + choices=VehicleCondition.choices, + blank=True, + null=True, + ) + estimated_price = models.DecimalField( + verbose_name=_("estimated price"), + max_digits=15, + decimal_places=2, + blank=True, + null=True, + ) + + def __str__(self): + return f"Quick Evaluation {self.pk} by {self.created_by}" + + @classmethod + def _baker(cls): + return baker.make(cls) + + class Meta: + db_table = "QuickEvaluation" + verbose_name = _("Quick Evaluation") + verbose_name_plural = _("Quick Evaluations") + diff --git a/core/apps/evaluation/permissions/__init__.py b/core/apps/evaluation/permissions/__init__.py index ce44113..ef86837 100644 --- a/core/apps/evaluation/permissions/__init__.py +++ b/core/apps/evaluation/permissions/__init__.py @@ -1,6 +1,7 @@ from .auto import * # noqa from .customer import * # noqa from .movable import * # noqa +from .quick import * # noqa from .real_estate import * # noqa from .valuation import * # noqa from .vehicle import * # noqa diff --git a/core/apps/evaluation/permissions/quick.py b/core/apps/evaluation/permissions/quick.py new file mode 100644 index 0000000..79be75c --- /dev/null +++ b/core/apps/evaluation/permissions/quick.py @@ -0,0 +1,12 @@ +from rest_framework import permissions + + +class QuickevaluationPermission(permissions.BasePermission): + + def __init__(self) -> None: ... + + def __call__(self, *args, **kwargs): + return self + + def has_permission(self, request, view): + return True diff --git a/core/apps/evaluation/serializers/__init__.py b/core/apps/evaluation/serializers/__init__.py index ce44113..ef86837 100644 --- a/core/apps/evaluation/serializers/__init__.py +++ b/core/apps/evaluation/serializers/__init__.py @@ -1,6 +1,7 @@ from .auto import * # noqa from .customer import * # noqa from .movable import * # noqa +from .quick import * # noqa from .real_estate import * # noqa from .valuation import * # noqa from .vehicle import * # noqa diff --git a/core/apps/evaluation/serializers/quick/QuickEvaluation.py b/core/apps/evaluation/serializers/quick/QuickEvaluation.py new file mode 100644 index 0000000..44d3cb3 --- /dev/null +++ b/core/apps/evaluation/serializers/quick/QuickEvaluation.py @@ -0,0 +1,26 @@ +from rest_framework import serializers + +from core.apps.evaluation.models import QuickEvaluationModel + + +class BaseQuickevaluationSerializer(serializers.ModelSerializer): + class Meta: + model = QuickEvaluationModel + fields = [ + "id", + ] + + +class ListQuickevaluationSerializer(BaseQuickevaluationSerializer): + class Meta(BaseQuickevaluationSerializer.Meta): ... + + +class RetrieveQuickevaluationSerializer(BaseQuickevaluationSerializer): + class Meta(BaseQuickevaluationSerializer.Meta): ... + + +class CreateQuickevaluationSerializer(BaseQuickevaluationSerializer): + class Meta(BaseQuickevaluationSerializer.Meta): + fields = [ + "id", + ] diff --git a/core/apps/evaluation/serializers/quick/__init__.py b/core/apps/evaluation/serializers/quick/__init__.py new file mode 100644 index 0000000..7ec356a --- /dev/null +++ b/core/apps/evaluation/serializers/quick/__init__.py @@ -0,0 +1 @@ +from .QuickEvaluation import * # noqa diff --git a/core/apps/evaluation/signals/__init__.py b/core/apps/evaluation/signals/__init__.py index ce44113..ef86837 100644 --- a/core/apps/evaluation/signals/__init__.py +++ b/core/apps/evaluation/signals/__init__.py @@ -1,6 +1,7 @@ from .auto import * # noqa from .customer import * # noqa from .movable import * # noqa +from .quick import * # noqa from .real_estate import * # noqa from .valuation import * # noqa from .vehicle import * # noqa diff --git a/core/apps/evaluation/signals/quick.py b/core/apps/evaluation/signals/quick.py new file mode 100644 index 0000000..5cd3591 --- /dev/null +++ b/core/apps/evaluation/signals/quick.py @@ -0,0 +1,8 @@ +from django.db.models.signals import post_save +from django.dispatch import receiver + +from core.apps.evaluation.models import QuickEvaluationModel + + +@receiver(post_save, sender=QuickEvaluationModel) +def QuickevaluationSignal(sender, instance, created, **kwargs): ... diff --git a/core/apps/evaluation/tests/__init__.py b/core/apps/evaluation/tests/__init__.py index ce44113..ef86837 100644 --- a/core/apps/evaluation/tests/__init__.py +++ b/core/apps/evaluation/tests/__init__.py @@ -1,6 +1,7 @@ from .auto import * # noqa from .customer import * # noqa from .movable import * # noqa +from .quick import * # noqa from .real_estate import * # noqa from .valuation import * # noqa from .vehicle import * # noqa diff --git a/core/apps/evaluation/tests/quick/__init__.py b/core/apps/evaluation/tests/quick/__init__.py new file mode 100644 index 0000000..810feb1 --- /dev/null +++ b/core/apps/evaluation/tests/quick/__init__.py @@ -0,0 +1 @@ +from .test_QuickEvaluation import * # noqa diff --git a/core/apps/evaluation/tests/quick/test_QuickEvaluation.py b/core/apps/evaluation/tests/quick/test_QuickEvaluation.py new file mode 100644 index 0000000..c4d7bdb --- /dev/null +++ b/core/apps/evaluation/tests/quick/test_QuickEvaluation.py @@ -0,0 +1,101 @@ +import pytest +from django.urls import reverse +from rest_framework.test import APIClient + +from core.apps.evaluation.models import QuickEvaluationModel + + +@pytest.fixture +def instance(db): + return QuickEvaluationModel._baker() + + +@pytest.fixture +def api_client(instance): + client = APIClient() + ##client.force_authenticate(user=instance.user) + return client, instance + + +@pytest.fixture +def data(api_client): + client, instance = api_client + return ( + { + "list": reverse("quick-evaluation-list"), + "retrieve": reverse("quick-evaluation-detail", kwargs={"pk": instance.pk}), + "retrieve-not-found": reverse("quick-evaluation-detail", kwargs={"pk": 1000}), + }, + client, + instance, + ) + + +@pytest.mark.django_db +def test_list(data): + urls, client, _ = data + response = client.get(urls["list"]) + data_resp = response.json() + assert response.status_code == 200 + assert data_resp["status"] is True + + +@pytest.mark.django_db +def test_retrieve(data): + urls, client, _ = data + response = client.get(urls["retrieve"]) + data_resp = response.json() + assert response.status_code == 200 + assert data_resp["status"] is True + + +@pytest.mark.django_db +def test_retrieve_not_found(data): + urls, client, _ = data + response = client.get(urls["retrieve-not-found"]) + data_resp = response.json() + assert response.status_code == 404 + assert data_resp["status"] is False + + +# @pytest.mark.django_db +# def test_create(data): +# urls, client, _ = data +# response = client.post(urls["list"], data={"name": "test"}) +# assert response.json()["status"] is True +# assert response.status_code == 201 + + +# @pytest.mark.django_db +# def test_update(data): +# urls, client, _ = data +# response = client.patch(urls["retrieve"], data={"name": "updated"}) +# assert response.json()["status"] is True +# assert response.status_code == 200 +# +# # verify updated value +# response = client.get(urls["retrieve"]) +# assert response.json()["status"] is True +# assert response.status_code == 200 +# assert response.json()["data"]["name"] == "updated" + + +# @pytest.mark.django_db +# def test_partial_update(): +# urls, client, _ = data +# response = client.patch(urls["retrieve"], data={"name": "updated"}) +# assert response.json()["status"] is True +# assert response.status_code == 200 +# +# # verify updated value +# response = client.get(urls["retrieve"]) +# assert response.json()["status"] is True +# assert response.status_code == 200 +# assert response.json()["data"]["name"] == "updated" + + +# @pytest.mark.django_db +# def test_destroy(data): +# urls, client, _ = data +# response = client.delete(urls["retrieve"]) +# assert response.status_code == 204 diff --git a/core/apps/evaluation/translation/__init__.py b/core/apps/evaluation/translation/__init__.py index ce44113..ef86837 100644 --- a/core/apps/evaluation/translation/__init__.py +++ b/core/apps/evaluation/translation/__init__.py @@ -1,6 +1,7 @@ from .auto import * # noqa from .customer import * # noqa from .movable import * # noqa +from .quick import * # noqa from .real_estate import * # noqa from .valuation import * # noqa from .vehicle import * # noqa diff --git a/core/apps/evaluation/translation/quick.py b/core/apps/evaluation/translation/quick.py new file mode 100644 index 0000000..c8f0590 --- /dev/null +++ b/core/apps/evaluation/translation/quick.py @@ -0,0 +1,8 @@ +from modeltranslation.translator import TranslationOptions, register + +from core.apps.evaluation.models import QuickEvaluationModel + + +@register(QuickEvaluationModel) +class QuickevaluationTranslation(TranslationOptions): + fields = [] diff --git a/core/apps/evaluation/urls.py b/core/apps/evaluation/urls.py index 0934568..35b4b57 100644 --- a/core/apps/evaluation/urls.py +++ b/core/apps/evaluation/urls.py @@ -6,12 +6,14 @@ from .views import ( CustomerView, MovablePropertyEvaluationView, PropertyOwnerView, + QuickEvaluationView, RealEstateEvaluationView, ValuationView, VehicleView, ) router = DefaultRouter() +router.register("quick-evaluation", QuickEvaluationView, basename="quick-evaluation") router.register("movable-property-evaluation", MovablePropertyEvaluationView, basename="movable-property-evaluation") router.register("real-estate-evaluation", RealEstateEvaluationView, basename="real-estate-evaluation") router.register("auto-evaluation", AutoEvaluationView, basename="auto-evaluation") diff --git a/core/apps/evaluation/validators/__init__.py b/core/apps/evaluation/validators/__init__.py index ce44113..ef86837 100644 --- a/core/apps/evaluation/validators/__init__.py +++ b/core/apps/evaluation/validators/__init__.py @@ -1,6 +1,7 @@ from .auto import * # noqa from .customer import * # noqa from .movable import * # noqa +from .quick import * # noqa from .real_estate import * # noqa from .valuation import * # noqa from .vehicle import * # noqa diff --git a/core/apps/evaluation/validators/quick.py b/core/apps/evaluation/validators/quick.py new file mode 100644 index 0000000..03300a3 --- /dev/null +++ b/core/apps/evaluation/validators/quick.py @@ -0,0 +1,8 @@ +# from django.core.exceptions import ValidationError + + +class QuickevaluationValidator: + def __init__(self): ... + + def __call__(self): + return True diff --git a/core/apps/evaluation/views/__init__.py b/core/apps/evaluation/views/__init__.py index ce44113..ef86837 100644 --- a/core/apps/evaluation/views/__init__.py +++ b/core/apps/evaluation/views/__init__.py @@ -1,6 +1,7 @@ from .auto import * # noqa from .customer import * # noqa from .movable import * # noqa +from .quick import * # noqa from .real_estate import * # noqa from .valuation import * # noqa from .vehicle import * # noqa diff --git a/core/apps/evaluation/views/quick.py b/core/apps/evaluation/views/quick.py new file mode 100644 index 0000000..be837d1 --- /dev/null +++ b/core/apps/evaluation/views/quick.py @@ -0,0 +1,25 @@ +from django_core.mixins import BaseViewSetMixin +from drf_spectacular.utils import extend_schema +from rest_framework.permissions import AllowAny +from rest_framework.viewsets import ReadOnlyModelViewSet + +from core.apps.evaluation.models import QuickEvaluationModel +from core.apps.evaluation.serializers.quick import ( + CreateQuickevaluationSerializer, + ListQuickevaluationSerializer, + RetrieveQuickevaluationSerializer, +) + + +@extend_schema(tags=["QuickEvaluation"]) +class QuickEvaluationView(BaseViewSetMixin, ReadOnlyModelViewSet): + queryset = QuickEvaluationModel.objects.all() + serializer_class = ListQuickevaluationSerializer + permission_classes = [AllowAny] + + action_permission_classes = {} + action_serializer_class = { + "list": ListQuickevaluationSerializer, + "retrieve": RetrieveQuickevaluationSerializer, + "create": CreateQuickevaluationSerializer, + }