Features: 1) Implement FieldsetsMixin to dynamically generate and manage admin fieldsets; 2) Refactor admin class definitions to leverage FieldsetsMixin for better consistency and extensibility.

Fixes: 1) Correct usage of `CONSTANCE_CONFIG` when setting `site_title` and `index_title` in `admin`.

Extra: Updated imports, removed redundant inline configs, cleaned up unused code, and improved readability in `admin.py`.
This commit is contained in:
Egor Pavlovich Gorbunov 2025-06-22 16:34:07 +03:00
parent d9c4717a8d
commit 092c7e908c

View file

@ -1,4 +1,3 @@
# noinspection PyUnresolvedReferences
from constance.admin import Config
from constance.admin import ConstanceAdmin as BaseConstanceAdmin
from django.apps import apps
@ -46,13 +45,32 @@ class TranslationFieldsetMixin:
for orig in opts.local_fields:
translation_fields += get_translation_fields(orig)
if translation_fields:
fieldsets = list(fieldsets)
fieldsets.append(
(
_("translations"),
{"fields": translation_fields},
)
)
fieldsets = list(fieldsets) + [
(_("Translations"), {"fields": translation_fields})
]
return fieldsets
class FieldsetsMixin:
general_fields = []
relation_fields = []
model: Model
def get_fieldsets(self, request, obj=None):
fieldsets = []
if self.general_fields:
fieldsets.append((_("General"), {"fields": self.general_fields}))
if self.relation_fields:
fieldsets.append((_("Relations"), {"fields": self.relation_fields}))
opts = self.model._meta
if any(f.name == "uuid" for f in opts.fields):
fieldsets.append((_("Metadata"), {"fields": ["uuid"]}))
ts = []
for name in ("created", "modified"):
if any(f.name == name for f in opts.fields):
ts.append(name)
if ts:
fieldsets.append((_("Timestamps"), {"fields": ts, "classes": ["collapse"]}))
return fieldsets
@ -85,29 +103,17 @@ class BasicModelAdmin(ModelAdmin):
class AttributeValueInline(TabularInline):
model = AttributeValue
extra = 0
is_navtab = True
verbose_name = _("attribute value")
verbose_name_plural = _("attribute values")
autocomplete_fields = ["attribute"]
icon = "fa-regular fa-circle-dot"
class ProductImageInline(TabularInline):
model = ProductImage
extra = 0
is_navtab = True
verbose_name = _("image")
verbose_name_plural = _("images")
icon = "fa-regular fa-images"
class StockInline(TabularInline):
model = Stock
extra = 0
is_navtab = True
verbose_name = _("stock")
verbose_name_plural = _("stocks")
icon = "fa-regular fa-boxes-stacked"
class OrderProductInline(TabularInline):
@ -115,10 +121,6 @@ class OrderProductInline(TabularInline):
extra = 0
readonly_fields = ("product", "quantity", "buy_price")
form = OrderProductForm
is_navtab = True
verbose_name = _("order product")
verbose_name_plural = _("order products")
icon = "fa-regular fa-circle-dot"
def get_queryset(self, request):
return (
@ -134,60 +136,72 @@ class CategoryChildrenInline(TabularInline):
fk_name = "parent"
extra = 0
fields = ("name", "description", "is_active", "image", "markup_percent")
icon = "fa-regular fa-circle-dot"
# Admin registrations
@admin.register(AttributeGroup)
class AttributeGroupAdmin(TranslationFieldsetMixin, BasicModelAdmin):
class AttributeGroupAdmin(FieldsetsMixin, TranslationFieldsetMixin, BasicModelAdmin):
model = AttributeGroup
list_display = ("name", "modified")
search_fields = ("uuid", "name")
general_fields = ["name", "parent"]
relation_fields = []
@admin.register(Attribute)
class AttributeAdmin(TranslationFieldsetMixin, BasicModelAdmin):
class AttributeAdmin(FieldsetsMixin, TranslationFieldsetMixin, BasicModelAdmin):
model = Attribute
list_display = ("name", "group", "value_type", "modified")
list_filter = ("value_type", "group", "is_active")
search_fields = ("uuid", "name", "group__name")
autocomplete_fields = ["categories", "group"]
general_fields = ["name", "value_type"]
relation_fields = ["group", "categories"]
@admin.register(AttributeValue)
class AttributeValueAdmin(TranslationFieldsetMixin, BasicModelAdmin):
class AttributeValueAdmin(FieldsetsMixin, TranslationFieldsetMixin, BasicModelAdmin):
model = AttributeValue
list_display = ("attribute", "value", "modified")
list_filter = ("attribute__group", "is_active")
search_fields = ("uuid", "value", "attribute__name")
autocomplete_fields = ["attribute"]
general_fields = ["value"]
relation_fields = ["attribute", "product"]
@admin.register(Category)
class CategoryAdmin(TranslationFieldsetMixin, DraggableMPTTAdmin, BasicModelAdmin):
mptt_indent_field = "name"
class CategoryAdmin(
FieldsetsMixin, TranslationFieldsetMixin, DraggableMPTTAdmin, BasicModelAdmin
):
model = Category
list_display = ("indented_title", "parent", "is_active", "modified")
list_filter = ("is_active", "level", "created", "modified")
list_display_links = ("indented_title",)
search_fields = ("uuid", "name")
inlines = [CategoryChildrenInline]
autocomplete_fields = ["parent", "tags"]
readonly_fields = ("uuid", "slug", "created", "modified")
readonly_fields = ("slug",)
def indented_title(self, instance):
return instance.name
indented_title.short_description = _("name")
indented_title.admin_order_field = "name"
general_fields = ["name", "description", "image", "markup_percent"]
relation_fields = ["parent", "tags"]
@admin.register(Brand)
class BrandAdmin(TranslationFieldsetMixin, BasicModelAdmin):
class BrandAdmin(FieldsetsMixin, TranslationFieldsetMixin, BasicModelAdmin):
model = Brand
list_display = ("name",)
list_filter = ("categories", "is_active")
search_fields = ("uuid", "name", "categories__name")
readonly_fields = ("uuid", "slug")
general_fields = ["name", "description"]
relation_fields = ["small_logo", "big_logo", "categories"]
@admin.register(Product)
class ProductAdmin(TranslationFieldsetMixin, BasicModelAdmin):
class ProductAdmin(FieldsetsMixin, TranslationFieldsetMixin, BasicModelAdmin):
model = Product
list_display = (
"name",
"partnumber",
@ -214,68 +228,63 @@ class ProductAdmin(TranslationFieldsetMixin, BasicModelAdmin):
"uuid",
"slug",
)
readonly_fields = ("created", "modified", "uuid", "rating", "price", "slug")
readonly_fields = ("slug",)
autocomplete_fields = ("category", "brand", "tags")
fieldsets = (
(
"general",
{"fields": ("name", "slug", "partnumber", "is_active", "is_digital")},
),
("relations", {"fields": ("category", "brand", "tags")}),
("metadata", {"fields": ("uuid",)}),
("timestamps", {"fields": ("created", "modified")}),
)
inlines = [AttributeValueInline, ProductImageInline, StockInline]
def price(self, obj):
return obj.price
price.short_description = _("price")
def rating(self, obj):
return obj.rating
rating.short_description = _("rating")
def get_changelist(self, request, **kwargs):
cl = super().get_changelist(request, **kwargs)
cl.filter_input_length = 64
return cl
general_fields = ["name", "partnumber", "is_active", "is_digital"]
relation_fields = ["category", "brand", "tags"]
@admin.register(ProductTag)
class ProductTagAdmin(TranslationFieldsetMixin, BasicModelAdmin):
list_display = ("name",)
search_fields = ("name",)
class ProductTagAdmin(FieldsetsMixin, TranslationFieldsetMixin, BasicModelAdmin):
model = ProductTag
list_display = ("tag_name",)
search_fields = ("tag_name",)
general_fields = ["tag_name", "name"]
relation_fields = []
@admin.register(CategoryTag)
class CategoryTagAdmin(TranslationFieldsetMixin, BasicModelAdmin):
list_display = ("name",)
search_fields = ("name",)
class CategoryTagAdmin(FieldsetsMixin, TranslationFieldsetMixin, BasicModelAdmin):
model = CategoryTag
list_display = ("tag_name",)
search_fields = ("tag_name",)
general_fields = ["tag_name", "name"]
relation_fields = []
@admin.register(Vendor)
class VendorAdmin(BasicModelAdmin):
class VendorAdmin(FieldsetsMixin, BasicModelAdmin):
model = Vendor
list_display = ("name", "markup_percent", "modified")
list_filter = ("markup_percent", "is_active")
search_fields = ("name",)
form = VendorForm
general_fields = ["name", "markup_percent", "authentication"]
relation_fields = []
@admin.register(Feedback)
class FeedbackAdmin(TranslationFieldsetMixin, BasicModelAdmin):
class FeedbackAdmin(FieldsetsMixin, TranslationFieldsetMixin, BasicModelAdmin):
model = Feedback
list_display = ("order_product", "rating", "comment", "modified")
list_filter = ("rating", "is_active")
search_fields = ("order_product__product__name", "comment")
general_fields = ["rating", "comment"]
relation_fields = ["order_product"]
@admin.register(Order)
class OrderAdmin(BasicModelAdmin):
class OrderAdmin(FieldsetsMixin, BasicModelAdmin):
model = Order
list_display = (
"human_readable_id",
"user",
"is_business",
"status",
"total_price",
"buy_time",
@ -283,56 +292,29 @@ class OrderAdmin(BasicModelAdmin):
)
list_filter = ("status", "buy_time", "modified", "created")
search_fields = ("user__email", "status", "uuid", "human_readable_id")
readonly_fields = ("total_price", "total_quantity", "buy_time", "human_readable_id")
readonly_fields = ("total_price", "total_quantity", "human_readable_id")
inlines = [OrderProductInline]
form = OrderForm
def is_business(self, obj):
return obj.is_business
is_business.short_description = _("is business")
def get_queryset(self, request):
return (
super()
.get_queryset(request)
.prefetch_related(
"user",
"shipping_address",
"billing_address",
"order_products",
"promo_code",
)
)
def save_model(self, request, obj, form, change):
if form.cleaned_data.get("attributes") is None:
obj.attributes = None
if form.cleaned_data.get("notifications") is None:
obj.notifications = None
super().save_model(request, obj, form, change)
general_fields = ["user", "status"]
relation_fields = ["promo_code", "billing_address", "shipping_address"]
@admin.register(OrderProduct)
class OrderProductAdmin(BasicModelAdmin):
class OrderProductAdmin(FieldsetsMixin, BasicModelAdmin):
model = OrderProduct
list_display = ("order", "product", "quantity", "buy_price", "status", "modified")
list_filter = ("status",)
search_fields = ("order__user__email", "product__name")
form = OrderProductForm
def get_queryset(self, request):
return super().get_queryset(request).prefetch_related("order", "product")
def save_model(self, request, obj, form, change):
if form.cleaned_data.get("attributes") is None:
obj.attributes = None
if form.cleaned_data.get("notifications") is None:
obj.notifications = None
super().save_model(request, obj, form, change)
general_fields = ["quantity", "buy_price", "status"]
relation_fields = ["order", "product"]
@admin.register(PromoCode)
class PromoCodeAdmin(BasicModelAdmin):
class PromoCodeAdmin(FieldsetsMixin, BasicModelAdmin):
model = PromoCode
list_display = (
"code",
"discount_percent",
@ -344,54 +326,61 @@ class PromoCodeAdmin(BasicModelAdmin):
list_filter = ("discount_percent", "discount_amount", "start_time", "end_time")
search_fields = ("code",)
def get_queryset(self, request):
return super().get_queryset(request).prefetch_related("user")
general_fields = ["code", "discount_amount", "discount_percent"]
relation_fields = ["user"]
@admin.register(Promotion)
class PromotionAdmin(TranslationFieldsetMixin, BasicModelAdmin):
class PromotionAdmin(FieldsetsMixin, TranslationFieldsetMixin, BasicModelAdmin):
model = Promotion
list_display = ("name", "discount_percent", "modified")
search_fields = ("name",)
autocomplete_fields = ("products",)
def get_queryset(self, request):
return super().get_queryset(request).prefetch_related("products")
general_fields = ["name", "discount_percent", "description"]
relation_fields = ["products"]
@admin.register(Stock)
class StockAdmin(BasicModelAdmin):
class StockAdmin(FieldsetsMixin, BasicModelAdmin):
model = Stock
list_display = ("product", "vendor", "sku", "quantity", "price", "modified")
list_filter = ("vendor", "quantity")
search_fields = ("product__name", "vendor__name", "sku")
autocomplete_fields = ("product", "vendor")
general_fields = ["sku", "quantity", "price", "purchase_price", "digital_asset"]
relation_fields = ["product", "vendor"]
@admin.register(Wishlist)
class WishlistAdmin(BasicModelAdmin):
class WishlistAdmin(FieldsetsMixin, BasicModelAdmin):
model = Wishlist
list_display = ("user", "modified")
search_fields = ("user__email",)
general_fields = ["user"]
relation_fields = ["products"]
@admin.register(ProductImage)
class ProductImageAdmin(TranslationFieldsetMixin, BasicModelAdmin):
class ProductImageAdmin(FieldsetsMixin, TranslationFieldsetMixin, BasicModelAdmin):
model = ProductImage
list_display = ("alt", "product", "priority", "modified")
list_filter = ("priority",)
search_fields = ("alt", "product__name")
autocomplete_fields = ("product",)
general_fields = ["alt", "priority", "image"]
relation_fields = ["product"]
@admin.register(Address)
class AddressAdmin(GISModelAdmin):
class AddressAdmin(FieldsetsMixin, GISModelAdmin):
model = Address
list_display = ("street", "city", "region", "country", "user")
list_filter = ("country", "region")
search_fields = (
"raw_data",
"street",
"city",
"postal_code",
"user__email",
"address_line",
)
search_fields = ("street", "city", "postal_code", "user__email")
gis_widget_kwargs = {
"attrs": {
"default_lon": 37.61556,
@ -400,15 +389,27 @@ class AddressAdmin(GISModelAdmin):
}
}
general_fields = [
"address_line",
"street",
"district",
"city",
"region",
"postal_code",
"country",
"raw_data",
]
relation_fields = ["user", "api_response"]
# Constance config
# Constance configuration
class ConstanceConfig:
class Meta:
app_label = "core"
object_name = "Config"
concrete_model = None
model_name = module_name = "config"
verbose_name_plural = _("config")
verbose_name_plural = _("Config")
abstract = False
swapped = False
is_composite_pk = False
@ -436,6 +437,6 @@ class ConstanceConfig:
admin.site.unregister([Config])
admin.site.register([ConstanceConfig], BaseConstanceAdmin)
admin.site.site_title = f"{CONSTANCE_CONFIG.get('PROJECT_NAME')[0]}"
admin.site.site_title = CONSTANCE_CONFIG["PROJECT_NAME"][0]
admin.site.site_header = "eVibes"
admin.site.index_title = f"{CONSTANCE_CONFIG.get('PROJECT_NAME')[0]}"
admin.site.index_title = CONSTANCE_CONFIG["PROJECT_NAME"][0]