Merge pull request 'feat: add search, filter, sort and pagination to QuickEvaluation list API' (#22) from feat/quick-evaluation-list-api into main
All checks were successful
Deploy to Production / build-and-deploy (push) Successful in 1m50s

Reviewed-on: #22
This commit is contained in:
2026-03-09 08:30:49 +00:00
13 changed files with 168 additions and 21 deletions

View File

@@ -15,12 +15,18 @@ class QuickEvaluationAdmin(ModelAdmin):
"manufacture_year",
"condition",
"estimated_price",
"status",
"car_type",
"state_car",
"created_at",
)
list_filter = (
"fuel_type",
"body_type",
"condition",
"status",
"car_type",
"state_car",
)
search_fields = (
"brand",
@@ -50,10 +56,11 @@ class QuickEvaluationAdmin(ModelAdmin):
"fields": (
("fuel_type", "body_type"),
"condition",
("car_type", "state_car"),
),
}),
("Natija", {
"fields": ("estimated_price",),
"fields": ("estimated_price", "status"),
}),
("Tizim", {
"classes": ("collapse",),

View File

@@ -0,0 +1,23 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
class QuickEvaluationStatus(models.TextChoices):
CREATED = "created", _("Created")
EVALUATOR_ASSIGNED = "evaluator_assigned", _("Evaluator assigned")
EVALUATED = "evaluated", _("Evaluated")
REJECTED = "rejected", _("Rejected")
APPROVED = "approved", _("Approved")
class CarType(models.TextChoices):
LIGHTWEIGHT = "lightweight", _("Lightweight")
TRUCK = "truck", _("Truck")
BUS = "bus", _("Bus")
MOTO = "moto", _("Moto")
class CarState(models.TextChoices):
GOOD = "good", _("Good")
SATISFACTORY = "satisfactory", _("Satisfactory")
BAD = "bad", _("Bad")

View File

@@ -8,6 +8,4 @@ class ValuationdocumentFilter(filters.FilterSet):
class Meta:
model = ValuationDocumentModel
fields = [
"name",
]
fields = []

View File

@@ -4,10 +4,28 @@ from core.apps.evaluation.models import QuickEvaluationModel
class QuickevaluationFilter(filters.FilterSet):
# name = filters.CharFilter(field_name="name", lookup_expr="icontains")
status = filters.CharFilter(method="filter_status")
car_type = filters.CharFilter(field_name="car_type", lookup_expr="exact")
state_car = filters.CharFilter(field_name="state_car", lookup_expr="exact")
created_from = filters.DateFilter(field_name="created_at", lookup_expr="gte")
created_to = filters.DateFilter(field_name="created_at", lookup_expr="lte")
year_from = filters.NumberFilter(field_name="manufacture_year", lookup_expr="gte")
year_to = filters.NumberFilter(field_name="manufacture_year", lookup_expr="lte")
def filter_status(self, queryset, name, value):
if value:
statuses = [s.strip() for s in value.split(",") if s.strip()]
return queryset.filter(status__in=statuses)
return queryset
class Meta:
model = QuickEvaluationModel
fields = [
"name",
"status",
"car_type",
"state_car",
"created_from",
"created_to",
"year_from",
"year_to",
]

View File

@@ -8,6 +8,4 @@ class RealestateevaluationFilter(filters.FilterSet):
class Meta:
model = RealEstateEvaluationModel
fields = [
"name",
]
fields = []

View File

@@ -8,6 +8,4 @@ class EvaluationreportFilter(filters.FilterSet):
class Meta:
model = EvaluationReportModel
fields = [
"name",
]
fields = []

View File

@@ -8,6 +8,4 @@ class ValuationFilter(filters.FilterSet):
class Meta:
model = ValuationModel
fields = [
"name",
]
fields = []

View File

@@ -8,6 +8,4 @@ class VehicleFilter(filters.FilterSet):
class Meta:
model = VehicleModel
fields = [
"name",
]
fields = []

View File

@@ -0,0 +1,28 @@
# Generated by Django 5.2.7 on 2026-03-09 07:59
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('evaluation', '0009_valuationdocumentmodel'),
]
operations = [
migrations.AddField(
model_name='quickevaluationmodel',
name='car_type',
field=models.CharField(blank=True, choices=[('lightweight', 'Yengil avtomobil'), ('yuk', 'Yuk mashinasi'), ('bus', 'Avtobus'), ('moto', 'Mototsikl')], max_length=50, null=True, verbose_name='car type'),
),
migrations.AddField(
model_name='quickevaluationmodel',
name='state_car',
field=models.CharField(blank=True, choices=[('yaxshi', 'Yaxshi'), ('qoniqarli', 'Qoniqarli'), ('yomon', 'Yomon')], max_length=50, null=True, verbose_name='car state'),
),
migrations.AddField(
model_name='quickevaluationmodel',
name='status',
field=models.CharField(choices=[('yaratildi', 'Yaratildi'), ('baxolovchi_biriktirildi', 'Baxolovchi biriktirildi'), ('baxolandi', 'Baxolandi'), ('rad_etildi', 'Rad etildi'), ('tasdiqlandi', 'Tasdiqlandi')], default='yaratildi', max_length=50, verbose_name='status'),
),
]

View File

@@ -0,0 +1,28 @@
# Generated by Django 5.2.7 on 2026-03-09 08:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('evaluation', '0010_add_status_car_type_state_car_to_quick_evaluation'),
]
operations = [
migrations.AlterField(
model_name='quickevaluationmodel',
name='car_type',
field=models.CharField(blank=True, choices=[('lightweight', 'Lightweight'), ('truck', 'Truck'), ('bus', 'Bus'), ('moto', 'Moto')], max_length=50, null=True, verbose_name='car type'),
),
migrations.AlterField(
model_name='quickevaluationmodel',
name='state_car',
field=models.CharField(blank=True, choices=[('good', 'Good'), ('satisfactory', 'Satisfactory'), ('bad', 'Bad')], max_length=50, null=True, verbose_name='car state'),
),
migrations.AlterField(
model_name='quickevaluationmodel',
name='status',
field=models.CharField(choices=[('created', 'Created'), ('evaluator_assigned', 'Evaluator assigned'), ('evaluated', 'Evaluated'), ('rejected', 'Rejected'), ('approved', 'Approved')], default='created', max_length=50, verbose_name='status'),
),
]

View File

@@ -3,8 +3,8 @@ 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
from core.apps.evaluation.choices.quick import CarState, CarType, QuickEvaluationStatus
from core.apps.evaluation.choices.vehicle import BodyType, FuelType, VehicleCondition
class QuickEvaluationModel(AbstractBaseModel):
@@ -63,6 +63,26 @@ class QuickEvaluationModel(AbstractBaseModel):
blank=True,
null=True,
)
status = models.CharField(
verbose_name=_("status"),
max_length=50,
choices=QuickEvaluationStatus.choices,
default=QuickEvaluationStatus.CREATED,
)
car_type = models.CharField(
verbose_name=_("car type"),
max_length=50,
choices=CarType.choices,
blank=True,
null=True,
)
state_car = models.CharField(
verbose_name=_("car state"),
max_length=50,
choices=CarState.choices,
blank=True,
null=True,
)
def __str__(self):
return f"Quick Evaluation {self.pk} by {self.created_by}"

View File

@@ -6,6 +6,9 @@ class BaseQuickevaluationSerializer(serializers.ModelSerializer):
body_type_display = serializers.CharField(source="get_body_type_display", read_only=True)
condition_display = serializers.CharField(source="get_condition_display", read_only=True)
created_by_name = serializers.CharField(source="created_by.get_full_name", read_only=True)
status_display = serializers.CharField(source="get_status_display", read_only=True)
car_type_display = serializers.CharField(source="get_car_type_display", read_only=True)
state_car_display = serializers.CharField(source="get_state_car_display", read_only=True)
class Meta:
model = QuickEvaluationModel
@@ -18,6 +21,12 @@ class BaseQuickevaluationSerializer(serializers.ModelSerializer):
"license_plate",
"manufacture_year",
"estimated_price",
"status",
"status_display",
"car_type",
"car_type_display",
"state_car",
"state_car_display",
"created_at",
]
@@ -57,4 +66,6 @@ class CreateQuickevaluationSerializer(BaseQuickevaluationSerializer):
"fuel_type",
"body_type",
"condition",
"car_type",
"state_car",
]

View File

@@ -1,8 +1,11 @@
from django_core.mixins import BaseViewSetMixin
from django_filters.rest_framework import DjangoFilterBackend
from drf_spectacular.utils import extend_schema
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.permissions import AllowAny
from rest_framework.viewsets import ReadOnlyModelViewSet
from core.apps.evaluation.filters.quick import QuickevaluationFilter
from core.apps.evaluation.models import QuickEvaluationModel
from core.apps.evaluation.serializers.quick import (
CreateQuickevaluationSerializer,
@@ -13,10 +16,29 @@ from core.apps.evaluation.serializers.quick import (
@extend_schema(tags=["QuickEvaluation"])
class QuickEvaluationView(BaseViewSetMixin, ReadOnlyModelViewSet):
queryset = QuickEvaluationModel.objects.all()
queryset = QuickEvaluationModel.objects.select_related("created_by").all()
serializer_class = ListQuickevaluationSerializer
permission_classes = [AllowAny]
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
filterset_class = QuickevaluationFilter
search_fields = ["license_plate", "model", "brand"]
ordering_fields = [
"created_at",
"updated_at",
"license_plate",
"brand",
"model",
"car_type",
"manufacture_year",
"color",
"fuel_type",
"state_car",
"status",
"mileage",
]
ordering = ["-created_at"]
action_permission_classes = {}
action_serializer_class = {
"list": ListQuickevaluationSerializer,