Category Api lari tayyor

This commit is contained in:
2025-11-24 15:57:46 +05:00
parent b0ad0ea173
commit 37a16900f7
17 changed files with 199 additions and 14 deletions

View File

@@ -19,8 +19,8 @@ def home(request):
urlpatterns = [ urlpatterns = [
path("health/", home), path("health/", home),
path("", include("core.apps.accounts.urls")), path("", include("core.apps.accounts.urls")),
path("api/", include("core.apps.shared.urls")), path("api/v1/", include("core.apps.shared.urls")),
path("api/", include("core.apps.api.urls")), path("api/v1/", include("core.apps.api.urls")),
] ]
urlpatterns += [ urlpatterns += [
path("admin/", admin.site.urls), path("admin/", admin.site.urls),

View File

@@ -0,0 +1 @@
from .category import * # noqa

View File

@@ -0,0 +1 @@
from .category import * # noqa

View File

@@ -0,0 +1,12 @@
from django.contrib import admin
from unfold.admin import ModelAdmin
from core.apps.api.models import Category
@admin.register(Category)
class CategoryAdmin(ModelAdmin):
list_display = (
"id",
"__str__",
)

View File

@@ -0,0 +1 @@
from .category import * # noqa

View File

@@ -0,0 +1,14 @@
from django_filters import rest_framework as filters
from core.apps.api.models import Category
class CategoryFilter(filters.FilterSet):
# name = filters.CharFilter(field_name="name", lookup_expr="icontains")
class Meta:
model = Category
fields = [
"show_home",
"id",
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.2.7 on 2025-11-24 10:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0002_adtopplan_color_tags_admodel_adimage_adoption_adsize_and_more'),
]
operations = [
migrations.AddField(
model_name='category',
name='image',
field=models.ImageField(blank=True, null=True, upload_to='', verbose_name='Image'),
),
]

View File

@@ -8,6 +8,14 @@ class Category(AbstractBaseModel):
parent = models.ForeignKey('self', null=True, blank=True, related_name='children', on_delete=models.CASCADE) parent = models.ForeignKey('self', null=True, blank=True, related_name='children', on_delete=models.CASCADE)
show_home = models.BooleanField(default=False, verbose_name=_('Show Home')) show_home = models.BooleanField(default=False, verbose_name=_('Show Home'))
level = models.IntegerField(default=0, verbose_name=_('Level')) level = models.IntegerField(default=0, verbose_name=_('Level'))
image = models.ImageField(verbose_name=_('Image'), null=True, blank=True)
def save(self, *args, **kwargs):
if self.parent:
self.level = self.parent.level + 1
else:
self.level = 0
super().save(*args, **kwargs)
def __str__(self): def __str__(self):
return str(self.pk) return str(self.pk)

View File

@@ -0,0 +1 @@
from .category import * # noqa

View File

@@ -0,0 +1 @@
from .category import * # noqa

View File

@@ -0,0 +1,44 @@
from rest_framework import serializers
from core.apps.api.models import Category
class BaseCategorySerializer(serializers.ModelSerializer):
children = serializers.SerializerMethodField()
class Meta:
model = Category
fields = [
"id",
"name",
"show_home",
"level",
"children",
]
def get_children(self, obj):
qs = obj.children.all()
return BaseCategorySerializer(qs, many=True, context=self.context).data
class ListCategorySerializer(BaseCategorySerializer):
class Meta(BaseCategorySerializer.Meta): ...
class ListCategoryNoChildSerializer(BaseCategorySerializer):
class Meta(BaseCategorySerializer.Meta):
fields = [
"id",
"name",
"show_home",
"level",
"image",
]
class RetrieveCategorySerializer(BaseCategorySerializer):
class Meta(BaseCategorySerializer.Meta): ...
class CreateCategorySerializer(BaseCategorySerializer):
class Meta(BaseCategorySerializer.Meta): ...

View File

@@ -1,9 +1,8 @@
from django.urls import path, include from django.urls import include, path
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
from core.apps.api.views import CategoryViewSet
router = DefaultRouter() router = DefaultRouter()
router.register("category", CategoryViewSet, basename="category")
urlpatterns = [path("", include(router.urls))]
urlpatterns = [
path("", include(router.urls)),
]

View File

@@ -0,0 +1 @@
from .category import * # noqa

View File

@@ -0,0 +1 @@
from .category import * # noqa

View File

@@ -0,0 +1,45 @@
from rest_framework.permissions import AllowAny
from rest_framework.viewsets import ReadOnlyModelViewSet
from django_core.mixins.base import BaseViewSetMixin
from drf_spectacular.utils import extend_schema
from core.apps.api.models import Category
from django_filters.rest_framework import DjangoFilterBackend
from core.apps.api.filters.category import CategoryFilter
from core.apps.api.serializers.category import (
ListCategorySerializer,
RetrieveCategorySerializer,
CreateCategorySerializer,
ListCategoryNoChildSerializer,
)
@extend_schema(tags=["Category"])
class CategoryViewSet(BaseViewSetMixin, ReadOnlyModelViewSet):
permission_classes = [AllowAny]
serializer_class = ListCategorySerializer
pagination_class = None
filter_backends = [DjangoFilterBackend]
filterset_class = CategoryFilter
action_permission_classes = {}
action_serializer_class = {
"list": ListCategorySerializer,
"retrieve": RetrieveCategorySerializer,
"create": CreateCategorySerializer,
}
def get_queryset(self):
qs = Category.objects.all()
if not self.request.query_params:
qs = qs.filter(level=0)
return qs
def get_serializer_class(self):
if "show_home" in self.request.query_params:
return ListCategoryNoChildSerializer
if hasattr(self, 'action_serializer_class'):
return self.action_serializer_class.get(self.action, self.serializer_class)
return super().get_serializer_class()

View File

@@ -1,11 +1,8 @@
from django.urls import path, include from django.urls import include, path
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
from .views import SettingsView from .views import SettingsView
router = DefaultRouter() router = DefaultRouter()
router.register("settings", SettingsView, basename="settings") router.register("settings", SettingsView, basename="settings")
urlpatterns = [path("", include(router.urls))]
urlpatterns = [
path("", include(router.urls)),
]

41
test.py Normal file
View File

@@ -0,0 +1,41 @@
import random
from core.apps.api.models import Category
def generate_categories(total=150):
Category.objects.all().delete()
created = []
queue = []
# 1) Root level: 35 ta
root_count = random.randint(3, 5)
for i in range(root_count):
cat = Category.objects.create(name=f"Category {len(created) + 1}")
created.append(cat)
queue.append(cat)
# 2) Qolganlarini yaratamiz
while len(created) < total:
if not queue:
break
parent = queue.pop(0)
# Har bir parentga 13 ta bola
children_count = random.randint(1, 3)
for _ in range(children_count):
if len(created) >= total:
break
child = Category.objects.create(
name=f"Category {len(created) + 1}",
parent=parent,
)
created.append(child)
# bola yana parent bo'lishi mumkin — shuning uchun queue ga qoshamiz
queue.append(child)
return f"{len(created)} ta category yaratildi!"