unit category added
This commit is contained in:
@@ -182,6 +182,12 @@ UNFOLD = {
|
||||
"collapsible": True,
|
||||
"items": [
|
||||
|
||||
{
|
||||
"title": _("دسته بندی واحد"),
|
||||
"icon": "category",
|
||||
"link": reverse_lazy("admin:product_unitcategorymodel_changelist"),
|
||||
"permission": lambda request: request.user.is_superuser,
|
||||
},
|
||||
{
|
||||
"title": _("دسته بندی"),
|
||||
"icon": "category",
|
||||
|
||||
@@ -30,6 +30,12 @@ class ProductDetailCategoryAdmin(ModelAdmin, ImportExportModelAdmin):
|
||||
return request.user.is_superuser
|
||||
|
||||
|
||||
@admin.register(UnitCategoryModel)
|
||||
class UnitCategoryAdmin(ModelAdmin):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@admin.register(InPackItems)
|
||||
class InPackItemsAdmin(ModelAdmin, ImportExportModelAdmin):
|
||||
import_form_class = ImportForm
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# Generated by Django 5.1.2 on 2025-12-04 09:48
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('product', '0057_productvariant_profit_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='UnitCategoryModel',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=50, verbose_name='نام دسته بندی')),
|
||||
('slug', models.SlugField(help_text='اسم دسته را برای مسیر به انگلیسی و بدون فاصله وارد کنید', unique=True)),
|
||||
('icon', models.ImageField(blank=True, null=True, upload_to='category_model/', verbose_name='آیکون')),
|
||||
('image', models.ImageField(blank=True, null=True, upload_to='category_model/', verbose_name='عکس')),
|
||||
('meta_title', models.CharField(blank=True, help_text='عنوان متا برای SEO', max_length=60, null=True, verbose_name='عنوان متا')),
|
||||
('meta_description', models.TextField(blank=True, help_text='توضیحات متا برای SEO', max_length=160, null=True, verbose_name='توضیحات متا')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'دسته\u200cبندی اصلی',
|
||||
'verbose_name_plural': 'دسته\u200cبندی\u200cهااصلی',
|
||||
},
|
||||
),
|
||||
migrations.RenameIndex(
|
||||
model_name='maincategorymodel',
|
||||
new_name='unit_category_slug_idx',
|
||||
old_name='main_category_slug_idx',
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='unitcategorymodel',
|
||||
index=models.Index(fields=['slug'], name='main_category_slug_idx'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='maincategorymodel',
|
||||
name='parent',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='unitcategorys', to='product.unitcategorymodel', verbose_name='دسته\u200cبندی والد'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 5.1.2 on 2025-12-04 09:56
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('product', '0058_unitcategorymodel_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='maincategorymodel',
|
||||
name='parent',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='maincategorys', to='product.unitcategorymodel', verbose_name='دسته\u200cبندی والد'),
|
||||
),
|
||||
]
|
||||
@@ -8,6 +8,38 @@ from django.core.exceptions import ValidationError
|
||||
from home.models import ShowCaseSlider
|
||||
|
||||
|
||||
|
||||
class UnitCategoryModel(models.Model):
|
||||
name = models.CharField(max_length=50, verbose_name='نام دسته بندی')
|
||||
slug = models.SlugField(max_length=50, unique=True,
|
||||
help_text="اسم دسته را برای مسیر به انگلیسی و بدون فاصله وارد کنید")
|
||||
icon = models.ImageField(upload_to='category_model/',
|
||||
verbose_name='آیکون', blank=True, null=True)
|
||||
image = models.ImageField(
|
||||
upload_to='category_model/', verbose_name='عکس', blank=True, null=True)
|
||||
meta_title = models.CharField(
|
||||
max_length=60, verbose_name="عنوان متا", help_text="عنوان متا برای SEO", blank=True, null=True)
|
||||
meta_description = models.TextField(
|
||||
max_length=160, verbose_name="توضیحات متا", help_text="توضیحات متا برای SEO", blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "دستهبندی اصلی"
|
||||
verbose_name_plural = "دستهبندیهااصلی"
|
||||
indexes = [
|
||||
models.Index(fields=['slug'], name='main_category_slug_idx'),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.slug:
|
||||
self.slug = 'unit-category-' + slugify(self.name, allow_unicode=True)
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
|
||||
|
||||
|
||||
class MainCategoryModel(models.Model):
|
||||
name = models.CharField(max_length=50, verbose_name='نام دسته بندی')
|
||||
slug = models.SlugField(max_length=50, unique=True,
|
||||
@@ -22,12 +54,13 @@ class MainCategoryModel(models.Model):
|
||||
max_length=160, verbose_name="توضیحات متا", help_text="توضیحات متا برای SEO", blank=True, null=True)
|
||||
video = models.FileField(upload_to='category_videos/',
|
||||
blank=True, null=True, verbose_name='ویدیو')
|
||||
|
||||
parent = models.ForeignKey(UnitCategoryModel, on_delete=models.CASCADE,
|
||||
related_name='maincategorys', verbose_name='دستهبندی والد', null=True)
|
||||
class Meta:
|
||||
verbose_name = "دستهبندی اصلی"
|
||||
verbose_name_plural = "دستهبندیهااصلی"
|
||||
indexes = [
|
||||
models.Index(fields=['slug'], name='main_category_slug_idx'),
|
||||
models.Index(fields=['slug'], name='unit_category_slug_idx'),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
|
||||
@@ -110,6 +110,13 @@ class SubCategorySerializer(serializers.ModelSerializer):
|
||||
return obj.parent.name
|
||||
|
||||
|
||||
class UnitCategorySerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = UnitCategoryModel
|
||||
fields = ['id', 'name', 'slug', 'icon', 'meta_title',
|
||||
'meta_description', 'image']
|
||||
|
||||
|
||||
class MainCategorySerializer(serializers.ModelSerializer):
|
||||
subcategorys = SubCategorySerializer(many=True)
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
from django.urls import path, re_path
|
||||
from .views import AllCategories, ProductView, AllProductsView, CommentView, ShowCaseProductsView, ShowCaseCategoryListView, BotProductsView,BotProductDetailView,BotCategoryView
|
||||
from .views import AllCategories, ProductView, AllProductsView, CommentView, ShowCaseProductsView, ShowCaseCategoryListView, BotProductsView,BotProductDetailView,BotCategoryView ,AllCategoriesV2
|
||||
|
||||
urlpatterns = [
|
||||
path('slider_category', ShowCaseProductsView.as_view(), name='category-products'),
|
||||
path('bot', BotProductsView.as_view(), name='bot-products'),
|
||||
path('bot/<int:pk>/', BotProductDetailView.as_view(), name='bot-product-detail'),
|
||||
path('categories', AllCategories.as_view(), name='all-categories'),
|
||||
path('categories/v2', AllCategoriesV2.as_view(), name='all-categories'),
|
||||
path('categories/bot', BotCategoryView.as_view(), name='bot-categories'),
|
||||
path('slider_categories', ShowCaseCategoryListView.as_view(), name='all-categories'),
|
||||
re_path(r'^comments/(?P<slug>[\w\u0600-\u06FF\-]+)$', CommentView.as_view(), name='comment-views'),
|
||||
|
||||
@@ -65,6 +65,48 @@ class AllCategories(APIView):
|
||||
categories_ser = self.serializer_class(
|
||||
instance=categories, many=True, context={'request': request})
|
||||
return Response(categories_ser.data, status=status.HTTP_200_OK)
|
||||
class UnitCategorySerializerV2(serializers.ModelSerializer):
|
||||
maincategorys = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = UnitCategoryModel
|
||||
fields = ['id', 'name', 'slug', 'icon', 'meta_title',
|
||||
'meta_description', 'image', 'maincategorys']
|
||||
|
||||
def get_maincategorys(self, obj):
|
||||
main_categories = obj.maincategorys.all()
|
||||
return MainCategorySerializer(main_categories, many=True, context=self.context).data
|
||||
|
||||
|
||||
class AllCategoriesV2(APIView):
|
||||
serializer_class = UnitCategorySerializerV2
|
||||
authentication_classes = []
|
||||
|
||||
@extend_schema(
|
||||
responses={
|
||||
200: UnitCategorySerializerV2(many=True),
|
||||
404: OpenApiTypes.OBJECT,
|
||||
},
|
||||
)
|
||||
def get(self, request):
|
||||
# Optimize query with prefetch_related to avoid N+1 queries
|
||||
unit_categories = UnitCategoryModel.objects.prefetch_related(
|
||||
Prefetch(
|
||||
'maincategorys',
|
||||
queryset=MainCategoryModel.objects.prefetch_related(
|
||||
Prefetch(
|
||||
'subcategorys',
|
||||
queryset=SubCategoryModel.objects.annotate(
|
||||
product_count=Count('products')
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
).all()
|
||||
|
||||
categories_ser = self.serializer_class(
|
||||
instance=unit_categories, many=True, context={'request': request})
|
||||
return Response(categories_ser.data, status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
class ProductView(APIView):
|
||||
|
||||
Reference in New Issue
Block a user