This commit is contained in:
Mamalizz
2025-02-11 23:27:25 +03:30
12 changed files with 250 additions and 44 deletions
+3 -3
View File
@@ -27,14 +27,14 @@ class UserAdmin(BaseUserAdmin, ModelAdmin, ImportExportModelAdmin):
inlines = [UserAddressInLine]
list_filter = ['is_superuser']
search_fields = ['phone', 'first_name', 'last_name', 'email']
list_display = ['full_name_display', 'phone', 'email', 'is_superuser', ]
list_display = ['full_name_display', 'phone', 'email', 'is_superuser', 'gender', 'birth_date']
# readonly_fields = ['phone', 'email', 'otp_expiry', 'otp_hash', 'date_joined', 'profile_photo']
exclude = ('otp_hash', 'otp_expiry', 'is_active', 'is_staff', 'password', 'last_login')
exclude = ('otp_hash', 'otp_expiry', 'is_active', 'is_staff', 'password', 'last_login',)
import_form_class = ImportForm
export_form_class = ExportForm
fieldsets = (
('اطلاعات شخصی', {'fields': ('first_name', 'last_name', 'profile_photo', 'password'),}),
('اطلاعات شخصی', {'fields': ('first_name', 'last_name', 'profile_photo', 'password', 'gender', 'birth_date'),}),
('اطلاعات ارتباطی', {'fields': ('phone', 'email'),}),
)
empty_value_display = 'ثبت نشده'
@@ -0,0 +1,25 @@
# Generated by Django 5.1.2 on 2025-02-11 17:14
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('account', '0005_alter_useraddressmodel_options_alter_user_is_active_and_more'),
]
operations = [
migrations.AddField(
model_name='user',
name='brith_day',
field=models.DateField(default='2024-10-09'),
preserve_default=False,
),
migrations.AddField(
model_name='user',
name='gender',
field=models.CharField(choices=[('male', 'مرد'), ('female', 'زن')], default='male', max_length=20, verbose_name='جنسیت'),
preserve_default=False,
),
]
@@ -0,0 +1,18 @@
# Generated by Django 5.1.2 on 2025-02-11 18:10
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('account', '0006_user_brith_day_user_gender'),
]
operations = [
migrations.RenameField(
model_name='user',
old_name='brith_day',
new_name='birth_day',
),
]
@@ -0,0 +1,18 @@
# Generated by Django 5.1.2 on 2025-02-11 18:21
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('account', '0007_rename_brith_day_user_birth_day'),
]
operations = [
migrations.RenameField(
model_name='user',
old_name='birth_day',
new_name='birth_date',
),
]
@@ -0,0 +1,18 @@
# Generated by Django 5.1.2 on 2025-02-11 18:42
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('account', '0008_rename_birth_day_user_birth_date'),
]
operations = [
migrations.AlterField(
model_name='user',
name='gender',
field=models.CharField(choices=[('مرد', 'مرد'), ('زن', 'زن')], max_length=20, verbose_name='جنسیت'),
),
]
+6
View File
@@ -41,6 +41,12 @@ class User(AbstractBaseUser, PermissionsMixin):
profile_photo = models.ImageField(upload_to='profile_photos/', null=True, blank=True, verbose_name='عکس پروفایل')
is_active = models.BooleanField(default=True, verbose_name='فعال بودن کاربر')
is_staff = models.BooleanField(default=False, verbose_name='کارمند')
gender_option = (
('مرد', 'مرد'),
('زن', 'زن')
)
gender = models.CharField(choices=gender_option, max_length=20, verbose_name='جنسیت')
birth_date = models.DateField()
date_joined = models.DateTimeField(auto_now_add=True, verbose_name='تاریخ ثبتنام')
otp_hash = models.CharField(max_length=64, null=True, blank=True, verbose_name='کد یک بار مصرف')
otp_expiry = models.DateTimeField(null=True, blank=True, verbose_name='تاریخ تمام شدن کد یک بار مصرف')
+1 -1
View File
@@ -10,7 +10,7 @@ class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['first_name', 'last_name', 'email', 'profile_photo', 'phone']
fields = ['first_name', 'last_name', 'email', 'profile_photo', 'phone', 'gender', 'birth_date']
read_only_fields = ("phone",)
+43 -30
View File
@@ -77,11 +77,24 @@ class AttributeValueAdmin(ModelAdmin, ImportExportModelAdmin):
"widget": ArrayWidget,
}
}
def get_form(self, request, obj=None, change=False, **kwargs):
form = super().get_form(request, obj, change, **kwargs)
form.base_fields["color"].widget = UnfoldAdminColorInputWidget()
return form
# def get_form(self, request, obj=None, change=False, **kwargs):
# form = super().get_form(request, obj, change, **kwargs)
# form.base_fields["color"].widget = UnfoldAdminColorInputWidget()
# return form
@admin.register(ProductImageModel)
class ProductImagesAdmin(ModelAdmin):
import_form_class = ImportForm
export_form_class = ExportForm
search_fields = ['name']
compressed_fields = True
warn_unsaved_form = True
formfield_overrides = {
ArrayField: {
"widget": ArrayWidget,
}
}
@@ -92,14 +105,14 @@ class ProductVariantInLine(StackedInline):
show_change_link = True
tab = True
min_num = 1
autocomplete_fields = ['attributes']
autocomplete_fields = ['attributes', 'in_pack_items', 'images']
# search_fields = ['']
def get_form(self, request, obj=None, change=False, **kwargs):
form = super().get_form(request, obj, change, **kwargs)
form.base_fields["color"].widget = UnfoldAdminColorInputWidget()
return form
def formfield_for_dbfield(self, db_field, request, **kwargs):
if db_field.name == 'color':
kwargs['widget'] = UnfoldAdminColorInputWidget()
return super().formfield_for_dbfield(db_field, request, **kwargs)
@@ -138,15 +151,15 @@ class ProductModelAdmin(ModelAdmin, ImportExportModelAdmin):
readonly_fields = ('slug', )
search_fields = ['name', 'description', ]
list_filter = ['show', 'category']
autocomplete_fields = ['related_products', 'in_pack_items',]
autocomplete_fields = ['related_products', ]
# compressed_fields = True
warn_unsaved_form = True
list_display = ['display_image', 'display_price', 'view', 'show', 'rating', 'category', ]
list_display = ['display_price', 'view', 'show', 'rating', 'category', ]
fieldsets = (
('فیلد های اصلی', {'fields': ('name', 'description', 'category', 'related_products', 'show',), "classes": ["tab"],}),
('فیلد های سيو', {'fields': ('meta_description', 'meta_keywords', 'meta_rating', 'slug'), "classes": ["tab"],}),
('فیلد های مربوط به کاربر', {'fields': ('rating', 'view',), "classes": ["tab"],}),
('فیلد های ایتم های پک', {'fields': ('in_pack_items', ), "classes": ["tab"],})
# ('فیلد های ایتم های پک', {'fields': ('in_pack_items', ), "classes": ["tab"],})
)
formfield_overrides = {
@@ -163,24 +176,24 @@ class ProductModelAdmin(ModelAdmin, ImportExportModelAdmin):
return obj.get_toman_price()
display_price.short_description = 'قیمت تومانی'
@display(description='محصول', header=True)
def display_image(self, instance):
if instance and instance.variants.first() and instance.variants.first().attributes.first():
image = instance.variants.first().attributes.first().image.url if instance.variants.first().attributes.first().image else None
else:
image = None
return [
instance.name,
None,
None,
{
"path": image,
"height": 30,
"width": 30,
"borderless": True,
# "squared": True,
},
]
# @display(description='محصول', header=True)
# def display_image(self, instance):
# if instance and instance.variants.first() and instance.variants.first().attributes.first():
# image = instance.variants.first().attributes.first().image.url if instance.variants.first().attributes.first().image else None
# else:
# image = None
# return [
# instance.name,
# None,
# None,
# {
# "path": image,
# "height": 30,
# "width": 30,
# "borderless": True,
# # "squared": True,
# },
# ]
# @display(
# description=("نمایش در صفحه ی اصلی"),
# label={
@@ -0,0 +1,22 @@
# Generated by Django 5.1.2 on 2025-02-11 17:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('product', '0020_productvariant_max_price_and_more'),
]
operations = [
migrations.RemoveField(
model_name='productmodel',
name='in_pack_items',
),
migrations.AddField(
model_name='productvariant',
name='in_pack_items',
field=models.ManyToManyField(blank=True, to='product.inpackitems', verbose_name='ایتم های داخل پک'),
),
]
@@ -0,0 +1,48 @@
# Generated by Django 5.1.2 on 2025-02-11 19:19
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('product', '0021_remove_productmodel_in_pack_items_and_more'),
]
operations = [
migrations.CreateModel(
name='ProductImageModel',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=30, verbose_name='نام عکس')),
('image', models.ImageField(upload_to='product_images/')),
],
),
migrations.RemoveField(
model_name='attributevalue',
name='color',
),
migrations.RemoveField(
model_name='attributevalue',
name='image',
),
migrations.RemoveField(
model_name='attributevalue',
name='video',
),
migrations.AddField(
model_name='productvariant',
name='color',
field=models.CharField(blank=True, max_length=7, null=True, verbose_name='رنک'),
),
migrations.AddField(
model_name='productvariant',
name='video',
field=models.FileField(blank=True, null=True, upload_to='product_videos/', verbose_name='ویدیو'),
),
migrations.AddField(
model_name='productvariant',
name='images',
field=models.ManyToManyField(to='product.productimagemodel', verbose_name='عکس ها'),
),
]
+22 -7
View File
@@ -111,7 +111,6 @@ class ProductModel(models.Model):
created_at = models.DateTimeField(auto_now_add=True, verbose_name='زمان ثبت محصول')
category = models.ForeignKey(SubCategoryModel, null=True, on_delete=models.SET_NULL, related_name='products', verbose_name='دسته بندی محصول')
related_products = models.ManyToManyField('self', blank=True, verbose_name='محصولات مرتبط')
in_pack_items = models.ManyToManyField(InPackItems, blank=True, verbose_name='ایتم های داخل پک')
@@ -132,9 +131,9 @@ class ProductModel(models.Model):
class DetailModel(models.Model):
title = models.CharField(max_length=50, verbose_name='عنوان')
detail_text1 = models.CharField(max_length=150 , verbose_name='متن جزیات ۱')
detail_text2 = models.CharField(max_length=150 , verbose_name='متن جزیات ۲')
detail_text3 = models.CharField(max_length=150 , verbose_name='متن جزیات ۳')
detail_text4 = models.CharField(max_length=150 , verbose_name='متن جزیات ۴')
detail_text2 = models.CharField(max_length=150 , verbose_name='متن جزیات ۲', blank=True, null=True)
detail_text3 = models.CharField(max_length=150 , verbose_name='متن جزیات ۳', blank=True, null=True)
detail_text4 = models.CharField(max_length=150 , verbose_name='متن جزیات ۴', blank=True, null=True)
def __str__(self):
return self.title
@@ -198,15 +197,27 @@ class AttributeType(models.Model):
class AttributeValue(models.Model):
attribute_type = models.ForeignKey(AttributeType, on_delete=models.CASCADE, blank=True, null=True)
value = models.CharField(verbose_name='مقدار نوع اتربیوت', max_length=100, blank=True, null=True)
color = models.CharField(verbose_name='رنک', max_length=7, blank=True, null=True)
image = models.ImageField(upload_to='product_images/')
video = models.FileField(upload_to='product_videos/', blank=True, null=True, verbose_name='ویدیو')
class Meta:
unique_together = ('attribute_type', 'value')
def __str__(self):
return f"{self.attribute_type.name}: {self.value}"
class ProductImageModel(models.Model):
name = models.CharField(max_length=30, verbose_name='نام عکس')
image = models.ImageField(upload_to='product_images/')
def __str__(self):
return self.name
class Meta:
verbose_name = 'عکس محصولات'
verbose_name_plural = 'عکس های محصولات'
class ProductVariant(models.Model):
product = models.ForeignKey(ProductModel, on_delete=models.CASCADE, related_name='variants', verbose_name='محصول')
attributes = models.ManyToManyField(AttributeValue, verbose_name='ویژگی‌ها', related_name='variant')
@@ -219,9 +230,13 @@ class ProductVariant(models.Model):
('toman', 'تومان'),
('derham', 'درهم')
)
in_pack_items = models.ManyToManyField(InPackItems, blank=True, verbose_name='ایتم های داخل پک')
sell = models.IntegerField(default=0, verbose_name='فروش')
currency = models.CharField(verbose_name='نوع ارز', max_length=20, choices=currency_type)
discount = models.SmallIntegerField(default=0, verbose_name='تخفیف')
color = models.CharField(verbose_name='رنک', max_length=7, blank=True, null=True)
images = models.ManyToManyField(ProductImageModel, verbose_name='عکس ها')
video = models.FileField(upload_to='product_videos/', blank=True, null=True, verbose_name='ویدیو')
class Meta:
verbose_name = 'تنوع محصول'
verbose_name_plural = 'تنوع‌های محصول'
+26 -3
View File
@@ -30,18 +30,38 @@ class AttributeValueSerialzier(serializers.ModelSerializer):
model = AttributeValue
fields = "__all__"
class InPackItemsSerialzier(serializers.ModelSerializer):
class Meta:
model = InPackItems
fields = '__all__'
class ProductImageSerailizer(serializers.ModelSerializer):
class Meta:
model = ProductImageModel
fields = '__all__'
class ProductVariantSerialzier(serializers.ModelSerializer):
attributes = AttributeValueSerialzier(many=True)
price = serializers.SerializerMethodField()
in_pack_items = InPackItemsSerialzier(many=True)
images = ProductImageSerailizer(many=True)
class Meta:
model = ProductVariant
exclude = ('min_price', 'sell', 'currency', 'product')
exclude = ('min_price', 'max_price','sell', 'currency', 'product')
def get_price(self, obj):
dollor_price = self.context.get('dollor_price')
toman_price = obj.get_toman_price(dollor_price=dollor_price)
return "{:,.0f} تومان".format(toman_price)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
view_type = self.context.get('view_type', None)
if view_type == 'list':
self.fields.pop('in_pack_items', None)
@@ -49,11 +69,12 @@ class ProductVariantSerialzier(serializers.ModelSerializer):
class DynamicProductSerializer(serializers.ModelSerializer):
variants = ProductVariantSerialzier(many=True)
variants = serializers.SerializerMethodField()
# variants_colors = serializers.SerializerMethodField()
is_new = serializers.SerializerMethodField()
related_products = serializers.SerializerMethodField()
details = ProductDetailSerializer(many=True, read_only=True)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
view_type = self.context.get('view_type', 'all')
@@ -74,7 +95,9 @@ class DynamicProductSerializer(serializers.ModelSerializer):
'instance': ['name', 'description', 'rating', 'slug', 'meta_description', 'meta_keywords', 'meta_rating', 'category', 'related_products', 'details', 'in_pack_items', 'variants'],
'chat': ['name', 'description', 'variants']
}
def get_variants(self, obj):
return ProductVariantSerialzier(instance=obj.variants.all(), many=True, context=self.context).data
# def get_variants_colors(self, obj):
# varients = obj.variants.all()