from django.contrib import admin, messages from django import forms # from product.tasks import update_prices from .models import * from unfold.admin import TabularInline, StackedInline from home.models import LearnVideoModel from import_export.admin import ImportExportModelAdmin from unfold.contrib.import_export.forms import ExportForm, ImportForm, SelectableFieldsExportForm from unfold.contrib.forms.widgets import ArrayWidget, WysiwygWidget from django.contrib.postgres.fields import ArrayField from unfold.widgets import UnfoldAdminColorInputWidget from unfold.decorators import action, display from utils.admin import ModelAdmin from django.shortcuts import redirect, render from .permissions import ProductDetailCategoryPermission, ProductAdminPermission, ProductVariantAdminPermission, ProductVariantInlineAdminPermission, InPackItemsAdminPermission, AttributeTypeAdminPermission, AttributeValueAdminPermission from django import forms @admin.register(ProductDetailCategory) class ProductDetailCategoryAdmin(ProductDetailCategoryPermission, ModelAdmin, ImportExportModelAdmin): import_form_class = ImportForm export_form_class = ExportForm search_fields = ['title'] compressed_fields = True warn_unsaved_form = True formfield_overrides = { ArrayField: { "widget": ArrayWidget, } } @admin.register(UnitCategoryModel) class UnitCategoryAdmin(ModelAdmin): pass @admin.register(InPackItems) class InPackItemsAdmin(InPackItemsAdminPermission, ModelAdmin, ImportExportModelAdmin): import_form_class = ImportForm export_form_class = ExportForm search_fields = ['item_title'] compressed_fields = True warn_unsaved_form = True formfield_overrides = { ArrayField: { "widget": ArrayWidget, } } from account.models import ShopModel @admin.register(ShopModel) class ShopModelAdmin(ModelAdmin, ImportExportModelAdmin): search_fields = ['name'] compressed_fields = True warn_unsaved_form = True formfield_overrides = { ArrayField: { "widget": ArrayWidget, } } def get_queryset(self, request): if request.user.is_superuser: return ShopModel.objects.all() if not hasattr(request.user, 'shop'): return ShopModel.objects.none() queryset = ShopModel.objects.filter(id=request.user.shop.id) return queryset def has_view_permission(self, request, obj=None): if request.user.is_superuser or obj == None: return True if not hasattr(request.user, 'shop'): return False return request.user.shop == obj class AttributeValueInLine(StackedInline): model = AttributeValue extra = 0 show_change_link = True min_num = 1 # autocomplete_fields = ['product_attributes', 'in_pack_items', 'images'] # search_fields = [''] def has_view_permission(self, request, obj = ...): return True def has_add_permission(self, request, obj): return True def has_change_permission(self, request, obj = ...): return False def has_delete_permission(self, request, obj = ...): return False @admin.register(AttributeType) class AttributeTypeAdmin(AttributeTypeAdminPermission, ModelAdmin, ImportExportModelAdmin): import_form_class = ImportForm export_form_class = ExportForm search_fields = ['name'] compressed_fields = True warn_unsaved_form = True inlines = [AttributeValueInLine] formfield_overrides = { ArrayField: { "widget": ArrayWidget, } } @admin.register(AttributeValue) class AttributeValueAdmin(AttributeValueAdminPermission, ModelAdmin, ImportExportModelAdmin): import_form_class = ImportForm export_form_class = ExportForm search_fields = ['value', 'attribute_type__name'] compressed_fields = True warn_unsaved_form = True formfield_overrides = { ArrayField: { "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 @admin.register(ProductImageModel) class ProductImagesAdmin(ModelAdmin): import_form_class = ImportForm export_form_class = ExportForm search_fields = ['name'] compressed_fields = True warn_unsaved_form = True list_display = ['display_image', 'name',] formfield_overrides = { ArrayField: { "widget": ArrayWidget, } } def has_view_permission(self, request, obj=None): return True def has_add_permission(self, request, obj=None): return True @display(description='محصول', header=True) def display_image(self, instance): if instance and instance.image: image = instance.image.url else: image = None return [ instance.name, None, None, { "path": image, "height": 30, "width": 30, "borderless": True, # "squared": True, }, ] @admin.register(DetailModel) class DetailModelAdmin(ModelAdmin, ImportExportModelAdmin): import_form_class = ImportForm export_form_class = ExportForm search_fields = ['title'] compressed_fields = True warn_unsaved_form = True formfield_overrides = { ArrayField: { "widget": ArrayWidget, } } class DetailInLine(StackedInline): model = DetailModel extra = 0 show_change_link = True min_num = 1 max_num = 4 from unfold.widgets import UnfoldAdminTextInputWidget # --- ProductVariantAdminForm for price formatting --- class ProductVariantAdminForm(forms.ModelForm): class Meta: model = ProductVariant fields = "__all__" widgets = { "input_price": UnfoldAdminTextInputWidget(attrs={"class": "price-input"}), "min_price": UnfoldAdminTextInputWidget(attrs={"class": "price-input"}), "profit": UnfoldAdminTextInputWidget(attrs={"class": "price-input"}), } @admin.register(ProductDetailModel) class ProductDetailModel1Admin(ModelAdmin, ImportExportModelAdmin): import_form_class = ImportForm export_form_class = ExportForm search_fields = ['detail_category__title', 'name'] compressed_fields = True warn_unsaved_form = True autocomplete_fields = ['detail_category',] inlines = [DetailInLine] formfield_overrides = { ArrayField: { "widget": ArrayWidget, } } def has_view_permission(self, request, obj=None): return True def has_add_permission(self, request, obj=None): return True class ProductVariantInLine(ProductVariantInlineAdminPermission, StackedInline): model = ProductVariant form = ProductVariantAdminForm extra = 0 show_change_link = True tab = True min_num = 1 readonly_fields = ['price', 'sell', 'price_in_dollor'] # inlines = [DetailModelInLine] autocomplete_fields = ['product_attributes', 'in_pack_items', 'images', 'details'] fields = ['input_price', 'min_price', 'currency', 'price', 'profit', 'in_stock', 'discount', 'special_discount_percent', 'images', 'video', 'color', 'product_attributes', 'in_pack_items', 'details', 'sell', 'slider_category'] # search_fields = [''] 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) def get_readonly_fields(self, request, obj = ...): if request.user.is_superuser: return ['price', 'sell', 'price_in_dollor'] else: return ['price', 'sell', 'price_in_dollor', 'slider_category'] from unfold.contrib.filters.admin import RelatedDropdownFilter class BulkSubCategoryForm(forms.Form): """فرم برای انتخاب زیر دسته‌بندی برای محصولات""" subcategory = forms.ModelChoiceField( queryset=SubCategoryModel.objects.all(), required=True, label='زیر دسته‌بندی', help_text='زیر دسته‌بندی جدید را برای محصولات انتخاب شده انتخاب کنید' ) @admin.register(ProductVariant) class ProductVariantAdmin(ProductVariantAdminPermission, ModelAdmin, ImportExportModelAdmin): form = ProductVariantAdminForm class Media: js = ("price-format.js",) import_form_class = ImportForm export_form_class = ExportForm autocomplete_fields = ['product_attributes', 'images', 'in_pack_items', 'details'] warn_unsaved_form = True readonly_fields = ['price', 'created_at'] list_filter = [('product__category', RelatedDropdownFilter), ('product__category__parent', RelatedDropdownFilter), ('product', RelatedDropdownFilter)] list_filter_submit = True list_display = ('product', 'created_at') # inlines = [DetailModelInLine] @admin.register(ProductModel) class ProductModelAdmin(ProductAdminPermission, ModelAdmin, ImportExportModelAdmin): import_form_class = ImportForm export_form_class = ExportForm inlines = [ProductVariantInLine] readonly_fields = ('slug', 'created_at') search_fields = ['name', 'description', ] list_filter = ['show', ('category', RelatedDropdownFilter), 'show_in_bot', ('category__parent', RelatedDropdownFilter)] list_filter_submit = True autocomplete_fields = ['related_products', 'shop'] # compressed_fields = True warn_unsaved_form = True # list_per_page = 2 actions_list = ['redirect_to_learn', 'update_products_price'] list_display = ['display_image', 'shop__shop_name','display_price', 'view', 'show', 'rating', 'category', 'created_at'] fieldsets = ( ('فیلد های اصلی', {'fields': ('name', 'description', 'category', 'image', 'related_products', 'show', 'shop', 'show_in_bot', 'bot_banner'), "classes": ["tab"],}), ('فیلد های سيو', {'fields': ('meta_description', 'meta_keywords', 'meta_rating', 'slug'), "classes": ["tab"],}), ('فیلد های مربوط به کاربر', {'fields': ('rating', 'view',), "classes": ["tab"],}), # ('فیلد های ایتم های پک', {'fields': ('in_pack_items', ), "classes": ["tab"],}) ) formfield_overrides = { models.TextField: { "widget": WysiwygWidget, }, ArrayField: { "widget": ArrayWidget, } } def get_readonly_fields(self, request, obj=None): if request.user.is_superuser: return ['slug', 'created_at'] else: return ['show_in_bot', 'bot_banner', 'created_at', 'show', 'meta_description', 'meta_keywords', 'meta_rating', 'rating', 'view', 'slug'] def display_price(self, obj): if obj.variants.all().first(): return obj.variants.all().first().price display_price.short_description = 'قیمت تومانی' @display(description='محصول', header=True) def display_image(self, instance): if instance and instance.variants.first() and instance.variants.first().images.first(): image = instance.variants.first().images.first().image.url if instance.variants.first().images.first().image else None else: image = None return [ instance.name, None, None, { "path": image, "height": 30, "width": 30, "borderless": True, # "squared": True, }, ] @action(description=f"اپدیت قیمت ها") def update_products_price(self, request): from product.tasks import update_prices update_prices() messages.success(request, f"قیمت {ProductVariant.objects.all().count()} تنوع محصول اپدیت شد") return redirect("admin:product_productmodel_changelist") def bulk_update_subcategory_action(self, request, queryset): """اکشن برای تغییر دسته‌بندی چند محصول همزمان""" # اگر فرم ارسال شده است if 'apply' in request.POST: form = BulkSubCategoryForm(request.POST) if form.is_valid(): subcategory = form.cleaned_data['subcategory'] count = queryset.count() # به‌روزرسانی تمام محصولات انتخاب شده queryset.update(category=subcategory) messages.success( request, f'دسته‌بندی {count} محصول به "{subcategory.name}" تغییر یافت.' ) return redirect('admin:product_productmodel_changelist') else: form = BulkSubCategoryForm() # نمایش صفحه تأیید context = { 'form': form, 'products': queryset, 'selected_ids': list(queryset.values_list('pk', flat=True)), 'action_name': 'bulk_update_subcategory_action', 'title': 'تغییر دسته‌بندی محصولات', } return render( request, 'admin/product/bulk_subcategory_form.html', context ) bulk_update_subcategory_action.short_description = "تغییر دسته‌بندی محصولات انتخاب شده" actions = ['bulk_update_subcategory_action'] # @display( # description=("نمایش در صفحه ی اصلی"), # label={ # True: "danger", # False: "success", # }, # ) # def display_show(self, instance): # return instance.show @admin.register(MainCategoryModel) class MainCategoryModelAdmin(ModelAdmin, ImportExportModelAdmin): import_form_class = ImportForm export_form_class = ExportForm list_display = ['name', ] readonly_fields = ('slug', ) search_fields = ['name', 'slug'] compressed_fields = True warn_unsaved_form = True formfield_overrides = { ArrayField: { "widget": ArrayWidget, } } @admin.register(SubCategoryModel) class SubCategoryModelAdmin(ModelAdmin, ImportExportModelAdmin): list_display = ['name', 'parent'] search_fields = ['name', 'slug'] list_filter = ['parent', ] import_form_class = ImportForm export_form_class = ExportForm readonly_fields = ('slug', ) compressed_fields = True warn_unsaved_form = True formfield_overrides = { ArrayField: { "widget": ArrayWidget, } } @admin.register(CommentModel) class CommentAdmin(ModelAdmin, ImportExportModelAdmin): import_form_class = ImportForm export_form_class = ExportForm list_display = ['user', 'product', 'display_content','review_status'] search_fields = ['content',] list_filter = ['review_status',] compressed_fields = True warn_unsaved_form = True formfield_overrides = { ArrayField: { "widget": ArrayWidget, } } radio_fields = {'review_status': admin.VERTICAL} def display_content(self, obj): return obj.content[0:35] + '...' display_content.short_description = 'محتوای کامنت' @admin.register(DollorModel) class DollorAdmin(ModelAdmin, ImportExportModelAdmin): import_form_class = ImportForm export_form_class = ExportForm exclude = ('unique_filed', ) compressed_fields = True warn_unsaved_form = True formfield_overrides = { ArrayField: { "widget": ArrayWidget, } } readonly_fields = ('price',)