674 lines
21 KiB
Python
674 lines
21 KiB
Python
from django.contrib import admin, messages
|
|
from django import forms
|
|
import logging
|
|
from django.contrib.postgres.aggregates import StringAgg
|
|
from django.db.models import Value
|
|
from django.db.models.functions import Coalesce
|
|
logger = logging.getLogger(__name__)
|
|
# 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 django.utils.html import format_html
|
|
from .permissions import ProductDetailCategoryPermission, ProductAdminPermission, ProductVariantAdminPermission, ProductVariantInlineAdminPermission, InPackItemsAdminPermission, AttributeTypeAdminPermission, AttributeValueAdminPermission
|
|
from django import forms
|
|
from django.core.cache import cache
|
|
|
|
# Cache key for home page
|
|
HOME_CACHE_KEY = 'home_view_data_anonymous'
|
|
|
|
@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
|
|
|
|
def get_readonly_fields(self, request, obj = ...):
|
|
if request.user.is_superuser:
|
|
return []
|
|
else:
|
|
return ['user', 'shop_name', 'commission_percent']
|
|
|
|
def has_change_permission(self, request, obj=None):
|
|
return True
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
def has_add_permission(self, request, obj = ...):
|
|
return True
|
|
|
|
def has_change_permission(self, request, obj = ...):
|
|
return True
|
|
|
|
def has_view_permission(self, request, obj = ...):
|
|
return True
|
|
|
|
def has_delete_permission(self, request, obj = ...):
|
|
return True
|
|
|
|
|
|
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
|
|
|
|
def get_queryset(self, request):
|
|
|
|
if request.user.is_superuser:
|
|
logger.info('Returning all ProductDetailModels for superuser')
|
|
return ProductDetailModel.objects.all()
|
|
|
|
if not hasattr(request.user, 'shop'):
|
|
logger.info('User has no shop, returning empty queryset')
|
|
return ProductDetailModel.objects.none()
|
|
logger.info('Filtering ProductDetailModels by shop')
|
|
queryset = ProductDetailModel.objects.filter(product__product__shop__id=request.user.shop.id)
|
|
return queryset
|
|
|
|
def has_change_permission(self, request, obj = ...):
|
|
return True
|
|
|
|
|
|
def has_delete_permission(self, request, obj = ...):
|
|
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', 'in_stock', 'price', 'currency', 'profit', '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']
|
|
|
|
def save_formset(self, request, form, formset, change):
|
|
super().save_formset(request, form, formset, change)
|
|
cache.delete(HOME_CACHE_KEY)
|
|
|
|
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]
|
|
|
|
def save_model(self, request, obj, form, change):
|
|
super().save_model(request, obj, form, change)
|
|
cache.delete(HOME_CACHE_KEY)
|
|
|
|
|
|
from unfold.sections import TableSection
|
|
|
|
class VariantsTableSection(TableSection):
|
|
verbose_name = 'تنوع های محصولی'
|
|
related_name = "variants"
|
|
height = 380
|
|
fields = [
|
|
'get_name',
|
|
"price",
|
|
'in_stock',
|
|
'sell',
|
|
]
|
|
|
|
# @display(description='برگذار شده', label=True)
|
|
# def get_done(self, obj):
|
|
# from django.utils import timezone
|
|
# now = timezone.localtime()
|
|
# today = now.date()
|
|
# time = now.time()
|
|
# return obj.date > today or (obj.date == today and obj.time > time)
|
|
|
|
@display(description='نام تنوع')
|
|
def get_name(self, obj):
|
|
attrs = getattr(obj, "attrs", "")
|
|
return f"{obj.product.name} - {attrs}"
|
|
|
|
|
|
|
|
|
|
|
|
def get_queryset(self, request):
|
|
qs = super().get_queryset(request)
|
|
|
|
qs = qs.select_related("product").annotate(
|
|
attrs=Coalesce(
|
|
StringAgg("product_attributes__value", delimiter=", "),
|
|
Value("")
|
|
)
|
|
)
|
|
|
|
return qs.only(
|
|
"id",
|
|
"product__name",
|
|
"price",
|
|
"in_stock",
|
|
"sell",
|
|
)
|
|
|
|
|
|
|
|
@admin.register(ProductModel)
|
|
class ProductModelAdmin(ProductAdminPermission, ModelAdmin, ImportExportModelAdmin):
|
|
list_sections = [VariantsTableSection]
|
|
import_form_class = ImportForm
|
|
export_form_class = ExportForm
|
|
inlines = [ProductVariantInLine]
|
|
readonly_fields = ('slug', 'created_at')
|
|
search_fields = ['name', 'description', ]
|
|
|
|
list_per_page = 10
|
|
list_filter = [('category', RelatedDropdownFilter), 'show_in_bot', ('category__parent', RelatedDropdownFilter)]
|
|
list_filter_submit = True
|
|
autocomplete_fields = ['related_products', 'shop', 'category']
|
|
# 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', 'view', 'rating', 'category', 'created_at' ,'show_in_website', ]
|
|
fieldsets = (
|
|
('فیلد های اصلی', {'fields': ('name', 'description', 'category', 'image', 'related_products','show_in_trends', 'show_in_most_viewed', 'show_in_lot_of_discount', 'show_in_top_seller', '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_in_top_seller','show_in_trends', 'show_in_most_viewed', 'show_in_lot_of_discount','meta_description', 'meta_keywords', 'meta_rating', 'rating', 'view', 'slug']
|
|
|
|
def save_model(self, request, obj, form, change):
|
|
super().save_model(request, obj, form, change)
|
|
cache.delete(HOME_CACHE_KEY)
|
|
|
|
def get_queryset(self, request):
|
|
qs = super().get_queryset(request)
|
|
|
|
qs = qs.select_related(
|
|
"shop",
|
|
"category",
|
|
"category__parent",
|
|
).only(
|
|
"id",
|
|
"name",
|
|
"description",
|
|
"image",
|
|
"view",
|
|
"rating",
|
|
"created_at",
|
|
"show_in_bot",
|
|
"category",
|
|
"shop",
|
|
)
|
|
|
|
return qs
|
|
|
|
|
|
def show_in_website(self, obj):
|
|
url = f"https://heymlz.com/product/{obj.slug}"
|
|
return format_html('<a href="{}" target="_blank" class="button">نمایش</a>', url)
|
|
show_in_website.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']
|
|
|
|
|
|
|
|
|
|
@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,
|
|
}
|
|
}
|
|
|
|
def save_model(self, request, obj, form, change):
|
|
super().save_model(request, obj, form, change)
|
|
cache.delete(HOME_CACHE_KEY)
|
|
cache.delete('all_categories_v2')
|
|
|
|
@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,
|
|
}
|
|
}
|
|
|
|
def has_view_permission(self, request, obj = ...):
|
|
return True
|
|
|
|
def has_add_permission(self, request):
|
|
return True
|
|
|
|
def has_change_permission(self, request, obj=None):
|
|
return True
|
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
return False
|
|
|
|
def save_model(self, request, obj, form, change):
|
|
super().save_model(request, obj, form, change)
|
|
cache.delete(HOME_CACHE_KEY)
|
|
cache.delete('all_categories_v2')
|
|
|
|
@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 = 'محتوای کامنت'
|
|
|
|
def has_view_permission(self, request, obj = ...):
|
|
return request.user.is_superuser
|
|
|
|
def has_add_permission(self, request):
|
|
return request.user.is_superuser
|
|
|
|
def has_change_permission(self, request, obj=None):
|
|
return request.user.is_superuser
|
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
return request.user.is_superuser
|
|
|
|
|
|
|
|
@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',)
|
|
|
|
@admin.register(ProductRating)
|
|
class ProductRatingAdmin(ModelAdmin):
|
|
list_display = ('product', 'user', 'rating', 'created_at')
|
|
list_filter = ('rating', 'created_at')
|
|
search_fields = ('product__name', 'user__phone', 'user__first_name', 'user__last_name')
|
|
readonly_fields = ('product', 'user', 'created_at', 'updated_at')
|
|
date_hierarchy = 'created_at'
|
|
ordering = ('-created_at',)
|
|
compressed_fields = True
|
|
warn_unsaved_form = True
|
|
|
|
def has_view_permission(self, request, obj = ...):
|
|
return request.user.is_superuser
|
|
|
|
def has_add_permission(self, request):
|
|
return request.user.is_superuser
|
|
|
|
def has_change_permission(self, request, obj=None):
|
|
return request.user.is_superuser
|
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
return request.user.is_superuser |