Features: 1) Replace I18NFieldsetMixin with TranslationFieldsetMixin across all applicable admin classes; 2) Add new inlines for managing related objects such as OrderProduct and CategoryChildren; 3) Introduce support for dynamic translation fields in admin fieldsets.
Fixes: 1) Correct `notifications` field handling in `OrderAdmin` and `OrderItemAdmin` save logic; 2) Fix admin `get_queryset` prefetching logic for various models. Extra: Remove outdated labels and sections in fieldsets; clean up unused imports and commented code for readability.
This commit is contained in:
parent
5425225e31
commit
c682137fc5
2 changed files with 139 additions and 285 deletions
|
|
@ -15,7 +15,6 @@ class NiceModel(Model):
|
||||||
default=uuid.uuid4,
|
default=uuid.uuid4,
|
||||||
editable=False,
|
editable=False,
|
||||||
)
|
)
|
||||||
uuid.id_for_label = "uuid"
|
|
||||||
is_active: bool = BooleanField( # type: ignore
|
is_active: bool = BooleanField( # type: ignore
|
||||||
default=True,
|
default=True,
|
||||||
verbose_name=_("is active"),
|
verbose_name=_("is active"),
|
||||||
|
|
@ -23,15 +22,12 @@ class NiceModel(Model):
|
||||||
"if set to false, this object can't be seen by users without needed permission"
|
"if set to false, this object can't be seen by users without needed permission"
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
is_active.id_for_label = "is_active"
|
|
||||||
created: datetime = CreationDateTimeField( # type: ignore
|
created: datetime = CreationDateTimeField( # type: ignore
|
||||||
_("created"), help_text=_("when the object first appeared on the database")
|
_("created"), help_text=_("when the object first appeared on the database")
|
||||||
)
|
)
|
||||||
created.id_for_label = "created"
|
|
||||||
modified: datetime = ModificationDateTimeField( # type: ignore
|
modified: datetime = ModificationDateTimeField( # type: ignore
|
||||||
_("modified"), help_text=_("when the object was last modified")
|
_("modified"), help_text=_("when the object was last modified")
|
||||||
)
|
)
|
||||||
modified.id_for_label = "modified"
|
|
||||||
|
|
||||||
def save(self, **kwargs):
|
def save(self, **kwargs):
|
||||||
self.update_modified = kwargs.pop(
|
self.update_modified = kwargs.pop(
|
||||||
|
|
|
||||||
408
core/admin.py
408
core/admin.py
|
|
@ -4,11 +4,8 @@ from constance.admin import ConstanceAdmin as BaseConstanceAdmin
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.admin import ModelAdmin, TabularInline
|
from django.contrib.admin import ModelAdmin, TabularInline
|
||||||
from django.contrib.admin.options import InlineModelAdmin
|
|
||||||
from django.contrib.gis.admin import GISModelAdmin
|
from django.contrib.gis.admin import GISModelAdmin
|
||||||
from django.db.models import Model
|
from django.db.models import Model
|
||||||
from django.forms import modelform_factory
|
|
||||||
from django.urls import path
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from modeltranslation.translator import translator
|
from modeltranslation.translator import translator
|
||||||
from modeltranslation.utils import get_translation_fields
|
from modeltranslation.utils import get_translation_fields
|
||||||
|
|
@ -38,72 +35,37 @@ from .models import (
|
||||||
Wishlist,
|
Wishlist,
|
||||||
)
|
)
|
||||||
|
|
||||||
SECTION_GENERAL = _("general")
|
|
||||||
SECTION_I18N = _("I18N")
|
|
||||||
SECTION_META = _("metadata")
|
|
||||||
SECTION_DATES = _("timestamps")
|
|
||||||
SECTION_RELATIONS = _("relations")
|
|
||||||
|
|
||||||
|
class TranslationFieldsetMixin:
|
||||||
|
model: Model
|
||||||
|
|
||||||
class I18NFieldsetMixin:
|
def get_fieldsets(self, request, obj=None):
|
||||||
model: type[Model]
|
fieldsets = super().get_fieldsets(request, obj)
|
||||||
|
opts = translator.get_options_for_model(self.model)
|
||||||
def get_inline_instances(self, request, obj=None):
|
|
||||||
inlines = super().get_inline_instances(request, obj)
|
|
||||||
trans_opts = translator.get_options_for_model(self.model)
|
|
||||||
translation_fields = []
|
translation_fields = []
|
||||||
for orig in trans_opts.local_fields:
|
for orig in opts.local_fields:
|
||||||
translation_fields += get_translation_fields(orig)
|
translation_fields += get_translation_fields(orig)
|
||||||
|
if translation_fields:
|
||||||
class _TranslationInline(InlineModelAdmin[self.model, self.model]):
|
fieldsets = list(fieldsets)
|
||||||
model = self.model
|
fieldsets.append(
|
||||||
form = modelform_factory(
|
(
|
||||||
self.model,
|
_("translations"),
|
||||||
fields=translation_fields,
|
{"fields": translation_fields},
|
||||||
formfield_callback=lambda f, **kw: super(
|
|
||||||
I18NFieldsetMixin, self
|
|
||||||
).formfield_for_dbfield(f, request, **kw),
|
|
||||||
)
|
)
|
||||||
template = "admin/edit_inline/tabular.html"
|
|
||||||
is_navtab = True
|
|
||||||
verbose_name = _("translations")
|
|
||||||
verbose_name_plural = _("translations")
|
|
||||||
extra = 0
|
|
||||||
icon = "fa-solid fa-language"
|
|
||||||
|
|
||||||
def get_queryset(self, request):
|
|
||||||
return (
|
|
||||||
self.model.objects.filter(pk=obj.pk)
|
|
||||||
if obj
|
|
||||||
else self.model.objects.none()
|
|
||||||
)
|
)
|
||||||
|
return fieldsets
|
||||||
def get_formset(self, request, obj=None, **kw):
|
|
||||||
return super().get_formset(
|
|
||||||
request,
|
|
||||||
obj,
|
|
||||||
**{
|
|
||||||
**kw,
|
|
||||||
"form": self.form,
|
|
||||||
"fields": translation_fields,
|
|
||||||
"exclude": [],
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
inlines.append(_TranslationInline(self.model, self.admin_site))
|
|
||||||
return inlines
|
|
||||||
|
|
||||||
|
|
||||||
class BasicModelAdmin(ModelAdmin):
|
class BasicModelAdmin(ModelAdmin):
|
||||||
@admin.action(description=str(_("activate selected %(verbose_name_plural)s")))
|
@admin.action(description=str(_("activate selected %(verbose_name_plural)s")))
|
||||||
def activate_selected(self, _request, queryset) -> str:
|
def activate_selected(self, _request, queryset) -> str:
|
||||||
queryset.update(is_active=True)
|
queryset.update(is_active=True)
|
||||||
return ""
|
return str(_("%(verbose_name_plural)s activated successfully!"))
|
||||||
|
|
||||||
@admin.action(description=str(_("deactivate selected %(verbose_name_plural)s")))
|
@admin.action(description=str(_("deactivate selected %(verbose_name_plural)s")))
|
||||||
def deactivate_selected(self, _request, queryset) -> str:
|
def deactivate_selected(self, _request, queryset) -> str:
|
||||||
queryset.update(is_active=False)
|
queryset.update(is_active=False)
|
||||||
return ""
|
return str(_("%(verbose_name_plural)s deactivated successfully."))
|
||||||
|
|
||||||
def get_actions(self, request):
|
def get_actions(self, request):
|
||||||
actions = super().get_actions(request)
|
actions = super().get_actions(request)
|
||||||
|
|
@ -130,134 +92,13 @@ class AttributeValueInline(TabularInline):
|
||||||
icon = "fa-regular fa-circle-dot"
|
icon = "fa-regular fa-circle-dot"
|
||||||
|
|
||||||
|
|
||||||
@admin.register(AttributeGroup)
|
|
||||||
class AttributeGroupAdmin(BasicModelAdmin, I18NFieldsetMixin):
|
|
||||||
list_display = ("name", "modified")
|
|
||||||
search_fields = (
|
|
||||||
"uuid",
|
|
||||||
"name",
|
|
||||||
)
|
|
||||||
fieldsets = (
|
|
||||||
(
|
|
||||||
SECTION_GENERAL,
|
|
||||||
{
|
|
||||||
"fields": ("name", "parent", "is_active"),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
SECTION_META,
|
|
||||||
{
|
|
||||||
"fields": ("uuid",),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Attribute)
|
|
||||||
class AttributeAdmin(BasicModelAdmin, I18NFieldsetMixin):
|
|
||||||
list_display = ("name", "group", "value_type", "modified")
|
|
||||||
list_filter = ("value_type", "group", "is_active")
|
|
||||||
search_fields = ("uuid", "name", "group__name")
|
|
||||||
autocomplete_fields = ["categories", "group"]
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(AttributeValue)
|
|
||||||
class AttributeValueAdmin(BasicModelAdmin, I18NFieldsetMixin):
|
|
||||||
list_display = ("attribute", "value", "modified")
|
|
||||||
list_filter = ("attribute__group", "is_active")
|
|
||||||
search_fields = ("uuid", "value", "attribute__name")
|
|
||||||
|
|
||||||
autocomplete_fields = ["attribute"]
|
|
||||||
|
|
||||||
|
|
||||||
class CategoryChildrenInline(admin.TabularInline):
|
|
||||||
model = Category
|
|
||||||
fk_name = "parent"
|
|
||||||
extra = 0
|
|
||||||
fields = ("name", "description", "is_active", "image", "markup_percent")
|
|
||||||
icon = "fa-regular fa-circle-dot"
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Category)
|
|
||||||
class CategoryAdmin(DraggableMPTTAdmin, BasicModelAdmin, I18NFieldsetMixin):
|
|
||||||
mptt_indent_field = "name"
|
|
||||||
list_display = ("indented_title", "parent", "is_active", "modified")
|
|
||||||
# noinspection PyUnresolvedReferences
|
|
||||||
list_filter = ("is_active", "level", "created", "modified")
|
|
||||||
list_display_links = ("indented_title",)
|
|
||||||
search_fields = (
|
|
||||||
"uuid",
|
|
||||||
"name",
|
|
||||||
)
|
|
||||||
inlines = [CategoryChildrenInline]
|
|
||||||
fieldsets = (
|
|
||||||
(
|
|
||||||
SECTION_GENERAL,
|
|
||||||
{
|
|
||||||
"fields": (
|
|
||||||
"name",
|
|
||||||
"slug",
|
|
||||||
"parent",
|
|
||||||
"is_active",
|
|
||||||
),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
SECTION_RELATIONS,
|
|
||||||
{
|
|
||||||
"fields": ("tags",),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
SECTION_META,
|
|
||||||
{
|
|
||||||
"fields": ("uuid",),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
SECTION_DATES,
|
|
||||||
{
|
|
||||||
"fields": ("created", "modified"),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
autocomplete_fields = ["parent", "tags"]
|
|
||||||
readonly_fields = (
|
|
||||||
"uuid",
|
|
||||||
"slug",
|
|
||||||
"created",
|
|
||||||
"modified",
|
|
||||||
)
|
|
||||||
|
|
||||||
def indented_title(self, instance):
|
|
||||||
return instance.name
|
|
||||||
|
|
||||||
indented_title.short_description = _("name") # type: ignore
|
|
||||||
indented_title.admin_order_field = "name" # type: ignore
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Brand)
|
|
||||||
class BrandAdmin(BasicModelAdmin, I18NFieldsetMixin):
|
|
||||||
list_display = ("name",)
|
|
||||||
list_filter = ("categories", "is_active")
|
|
||||||
search_fields = (
|
|
||||||
"uuid",
|
|
||||||
"name",
|
|
||||||
"categories__name",
|
|
||||||
)
|
|
||||||
readonly_fields = (
|
|
||||||
"uuid",
|
|
||||||
"slug",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class ProductImageInline(TabularInline):
|
class ProductImageInline(TabularInline):
|
||||||
model = ProductImage
|
model = ProductImage
|
||||||
extra = 0
|
extra = 0
|
||||||
is_navtab = True
|
is_navtab = True
|
||||||
verbose_name = _("image")
|
verbose_name = _("image")
|
||||||
verbose_name_plural = _("images")
|
verbose_name_plural = _("images")
|
||||||
icon = "fa-regular fa-circle-dot"
|
icon = "fa-regular fa-images"
|
||||||
|
|
||||||
|
|
||||||
class StockInline(TabularInline):
|
class StockInline(TabularInline):
|
||||||
|
|
@ -266,11 +107,87 @@ class StockInline(TabularInline):
|
||||||
is_navtab = True
|
is_navtab = True
|
||||||
verbose_name = _("stock")
|
verbose_name = _("stock")
|
||||||
verbose_name_plural = _("stocks")
|
verbose_name_plural = _("stocks")
|
||||||
|
icon = "fa-regular fa-boxes-stacked"
|
||||||
|
|
||||||
|
|
||||||
|
class OrderProductInline(TabularInline):
|
||||||
|
model = OrderProduct
|
||||||
|
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 (
|
||||||
|
super()
|
||||||
|
.get_queryset(request)
|
||||||
|
.select_related("product")
|
||||||
|
.only("product__name")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CategoryChildrenInline(TabularInline):
|
||||||
|
model = Category
|
||||||
|
fk_name = "parent"
|
||||||
|
extra = 0
|
||||||
|
fields = ("name", "description", "is_active", "image", "markup_percent")
|
||||||
icon = "fa-regular fa-circle-dot"
|
icon = "fa-regular fa-circle-dot"
|
||||||
|
|
||||||
|
|
||||||
|
# Admin registrations
|
||||||
|
@admin.register(AttributeGroup)
|
||||||
|
class AttributeGroupAdmin(TranslationFieldsetMixin, BasicModelAdmin):
|
||||||
|
list_display = ("name", "modified")
|
||||||
|
search_fields = ("uuid", "name")
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Attribute)
|
||||||
|
class AttributeAdmin(TranslationFieldsetMixin, BasicModelAdmin):
|
||||||
|
list_display = ("name", "group", "value_type", "modified")
|
||||||
|
list_filter = ("value_type", "group", "is_active")
|
||||||
|
search_fields = ("uuid", "name", "group__name")
|
||||||
|
autocomplete_fields = ["categories", "group"]
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(AttributeValue)
|
||||||
|
class AttributeValueAdmin(TranslationFieldsetMixin, BasicModelAdmin):
|
||||||
|
list_display = ("attribute", "value", "modified")
|
||||||
|
list_filter = ("attribute__group", "is_active")
|
||||||
|
search_fields = ("uuid", "value", "attribute__name")
|
||||||
|
autocomplete_fields = ["attribute"]
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Category)
|
||||||
|
class CategoryAdmin(TranslationFieldsetMixin, DraggableMPTTAdmin, BasicModelAdmin):
|
||||||
|
mptt_indent_field = "name"
|
||||||
|
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")
|
||||||
|
|
||||||
|
def indented_title(self, instance):
|
||||||
|
return instance.name
|
||||||
|
|
||||||
|
indented_title.short_description = _("name")
|
||||||
|
indented_title.admin_order_field = "name"
|
||||||
|
|
||||||
|
|
||||||
|
@admin.register(Brand)
|
||||||
|
class BrandAdmin(TranslationFieldsetMixin, BasicModelAdmin):
|
||||||
|
list_display = ("name",)
|
||||||
|
list_filter = ("categories", "is_active")
|
||||||
|
search_fields = ("uuid", "name", "categories__name")
|
||||||
|
readonly_fields = ("uuid", "slug")
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Product)
|
@admin.register(Product)
|
||||||
class ProductAdmin(BasicModelAdmin, I18NFieldsetMixin):
|
class ProductAdmin(TranslationFieldsetMixin, BasicModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
"name",
|
"name",
|
||||||
"partnumber",
|
"partnumber",
|
||||||
|
|
@ -281,7 +198,6 @@ class ProductAdmin(BasicModelAdmin, I18NFieldsetMixin):
|
||||||
"rating",
|
"rating",
|
||||||
"modified",
|
"modified",
|
||||||
)
|
)
|
||||||
|
|
||||||
list_filter = (
|
list_filter = (
|
||||||
"is_active",
|
"is_active",
|
||||||
"is_digital",
|
"is_digital",
|
||||||
|
|
@ -290,7 +206,6 @@ class ProductAdmin(BasicModelAdmin, I18NFieldsetMixin):
|
||||||
"created",
|
"created",
|
||||||
"modified",
|
"modified",
|
||||||
)
|
)
|
||||||
|
|
||||||
search_fields = (
|
search_fields = (
|
||||||
"name",
|
"name",
|
||||||
"partnumber",
|
"partnumber",
|
||||||
|
|
@ -299,69 +214,43 @@ class ProductAdmin(BasicModelAdmin, I18NFieldsetMixin):
|
||||||
"uuid",
|
"uuid",
|
||||||
"slug",
|
"slug",
|
||||||
)
|
)
|
||||||
|
|
||||||
readonly_fields = ("created", "modified", "uuid", "rating", "price", "slug")
|
readonly_fields = ("created", "modified", "uuid", "rating", "price", "slug")
|
||||||
autocomplete_fields = ("category", "brand", "tags")
|
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):
|
def price(self, obj):
|
||||||
return obj.price
|
return obj.price
|
||||||
|
|
||||||
price.short_description = _("price") # type: ignore
|
price.short_description = _("price")
|
||||||
|
|
||||||
def rating(self, obj):
|
def rating(self, obj):
|
||||||
return obj.rating
|
return obj.rating
|
||||||
|
|
||||||
rating.short_description = _("rating") # type: ignore
|
rating.short_description = _("rating")
|
||||||
|
|
||||||
fieldsets = (
|
|
||||||
(
|
|
||||||
SECTION_GENERAL,
|
|
||||||
{
|
|
||||||
"fields": (
|
|
||||||
"name",
|
|
||||||
"slug",
|
|
||||||
"partnumber",
|
|
||||||
"is_active",
|
|
||||||
"is_digital",
|
|
||||||
),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
SECTION_RELATIONS,
|
|
||||||
{
|
|
||||||
"fields": ("category", "brand", "tags"),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
SECTION_META,
|
|
||||||
{
|
|
||||||
"fields": ("uuid",),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
(
|
|
||||||
SECTION_DATES,
|
|
||||||
{
|
|
||||||
"fields": ("created", "modified"),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
inlines = [AttributeValueInline, ProductImageInline, StockInline]
|
|
||||||
|
|
||||||
def get_changelist(self, request, **kwargs):
|
def get_changelist(self, request, **kwargs):
|
||||||
changelist = super().get_changelist(request, **kwargs)
|
cl = super().get_changelist(request, **kwargs)
|
||||||
changelist.filter_input_length = 64
|
cl.filter_input_length = 64
|
||||||
return changelist
|
return cl
|
||||||
|
|
||||||
|
|
||||||
@admin.register(ProductTag)
|
@admin.register(ProductTag)
|
||||||
class ProductTagAdmin(BasicModelAdmin, I18NFieldsetMixin):
|
class ProductTagAdmin(TranslationFieldsetMixin, BasicModelAdmin):
|
||||||
list_display = ("name",)
|
list_display = ("name",)
|
||||||
search_fields = ("name",)
|
search_fields = ("name",)
|
||||||
|
|
||||||
|
|
||||||
@admin.register(CategoryTag)
|
@admin.register(CategoryTag)
|
||||||
class CategoryTagAdmin(BasicModelAdmin, I18NFieldsetMixin):
|
class CategoryTagAdmin(TranslationFieldsetMixin, BasicModelAdmin):
|
||||||
list_display = ("name",)
|
list_display = ("name",)
|
||||||
search_fields = ("name",)
|
search_fields = ("name",)
|
||||||
|
|
||||||
|
|
@ -375,27 +264,12 @@ class VendorAdmin(BasicModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Feedback)
|
@admin.register(Feedback)
|
||||||
class FeedbackAdmin(BasicModelAdmin):
|
class FeedbackAdmin(TranslationFieldsetMixin, BasicModelAdmin):
|
||||||
list_display = ("order_product", "rating", "comment", "modified")
|
list_display = ("order_product", "rating", "comment", "modified")
|
||||||
list_filter = ("rating", "is_active")
|
list_filter = ("rating", "is_active")
|
||||||
search_fields = ("order_product__product__name", "comment")
|
search_fields = ("order_product__product__name", "comment")
|
||||||
|
|
||||||
|
|
||||||
class OrderProductInline(admin.TabularInline):
|
|
||||||
model = OrderProduct
|
|
||||||
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):
|
|
||||||
qs = super().get_queryset(request)
|
|
||||||
return qs.select_related("product").only("product__name")
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Order)
|
@admin.register(Order)
|
||||||
class OrderAdmin(BasicModelAdmin):
|
class OrderAdmin(BasicModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
|
|
@ -409,30 +283,33 @@ class OrderAdmin(BasicModelAdmin):
|
||||||
)
|
)
|
||||||
list_filter = ("status", "buy_time", "modified", "created")
|
list_filter = ("status", "buy_time", "modified", "created")
|
||||||
search_fields = ("user__email", "status", "uuid", "human_readable_id")
|
search_fields = ("user__email", "status", "uuid", "human_readable_id")
|
||||||
|
readonly_fields = ("total_price", "total_quantity", "buy_time", "human_readable_id")
|
||||||
inlines = [OrderProductInline]
|
inlines = [OrderProductInline]
|
||||||
form = OrderForm
|
form = OrderForm
|
||||||
readonly_fields = ("total_price", "total_quantity", "buy_time", "human_readable_id")
|
|
||||||
|
|
||||||
def is_business(self, obj):
|
def is_business(self, obj):
|
||||||
return obj.is_business
|
return obj.is_business
|
||||||
|
|
||||||
is_business.short_description = _("is business") # type: ignore
|
is_business.short_description = _("is business")
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
qs = super().get_queryset(request)
|
return (
|
||||||
return qs.prefetch_related(
|
super()
|
||||||
|
.get_queryset(request)
|
||||||
|
.prefetch_related(
|
||||||
"user",
|
"user",
|
||||||
"shipping_address",
|
"shipping_address",
|
||||||
"billing_address",
|
"billing_address",
|
||||||
"order_products",
|
"order_products",
|
||||||
"promo_code",
|
"promo_code",
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def save_model(self, request, obj, form, change):
|
def save_model(self, request, obj, form, change):
|
||||||
if form.cleaned_data.get("attributes") is None:
|
if form.cleaned_data.get("attributes") is None:
|
||||||
obj.attributes = None
|
obj.attributes = None
|
||||||
if form.cleaned_data.get("notifications") is None:
|
if form.cleaned_data.get("notifications") is None:
|
||||||
obj.attributes = None
|
obj.notifications = None
|
||||||
super().save_model(request, obj, form, change)
|
super().save_model(request, obj, form, change)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -444,14 +321,13 @@ class OrderProductAdmin(BasicModelAdmin):
|
||||||
form = OrderProductForm
|
form = OrderProductForm
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
qs = super().get_queryset(request)
|
return super().get_queryset(request).prefetch_related("order", "product")
|
||||||
return qs.prefetch_related("order", "product")
|
|
||||||
|
|
||||||
def save_model(self, request, obj, form, change):
|
def save_model(self, request, obj, form, change):
|
||||||
if form.cleaned_data.get("attributes") is None:
|
if form.cleaned_data.get("attributes") is None:
|
||||||
obj.attributes = None
|
obj.attributes = None
|
||||||
if form.cleaned_data.get("notifications") is None:
|
if form.cleaned_data.get("notifications") is None:
|
||||||
obj.attributes = None
|
obj.notifications = None
|
||||||
super().save_model(request, obj, form, change)
|
super().save_model(request, obj, form, change)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -469,19 +345,17 @@ class PromoCodeAdmin(BasicModelAdmin):
|
||||||
search_fields = ("code",)
|
search_fields = ("code",)
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
qs = super().get_queryset(request)
|
return super().get_queryset(request).prefetch_related("user")
|
||||||
return qs.prefetch_related("user")
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Promotion)
|
@admin.register(Promotion)
|
||||||
class PromotionAdmin(BasicModelAdmin, I18NFieldsetMixin):
|
class PromotionAdmin(TranslationFieldsetMixin, BasicModelAdmin):
|
||||||
list_display = ("name", "discount_percent", "modified")
|
list_display = ("name", "discount_percent", "modified")
|
||||||
search_fields = ("name",)
|
search_fields = ("name",)
|
||||||
autocomplete_fields = ("products",)
|
autocomplete_fields = ("products",)
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
qs = super().get_queryset(request)
|
return super().get_queryset(request).prefetch_related("products")
|
||||||
return qs.prefetch_related("products")
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Stock)
|
@admin.register(Stock)
|
||||||
|
|
@ -499,7 +373,7 @@ class WishlistAdmin(BasicModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
@admin.register(ProductImage)
|
@admin.register(ProductImage)
|
||||||
class ProductImageAdmin(BasicModelAdmin):
|
class ProductImageAdmin(TranslationFieldsetMixin, BasicModelAdmin):
|
||||||
list_display = ("alt", "product", "priority", "modified")
|
list_display = ("alt", "product", "priority", "modified")
|
||||||
list_filter = ("priority",)
|
list_filter = ("priority",)
|
||||||
search_fields = ("alt", "product__name")
|
search_fields = ("alt", "product__name")
|
||||||
|
|
@ -518,7 +392,6 @@ class AddressAdmin(GISModelAdmin):
|
||||||
"user__email",
|
"user__email",
|
||||||
"address_line",
|
"address_line",
|
||||||
)
|
)
|
||||||
|
|
||||||
gis_widget_kwargs = {
|
gis_widget_kwargs = {
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"default_lon": 37.61556,
|
"default_lon": 37.61556,
|
||||||
|
|
@ -528,21 +401,7 @@ class AddressAdmin(GISModelAdmin):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ConstanceAdmin(BaseConstanceAdmin):
|
# Constance config
|
||||||
def get_urls(self):
|
|
||||||
info = f"{self.model._meta.app_label}_{self.model._meta.model_name}"
|
|
||||||
return [
|
|
||||||
path(
|
|
||||||
"",
|
|
||||||
self.admin_site.admin_view(self.changelist_view),
|
|
||||||
name=f"{info}_changelist",
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
"", self.admin_site.admin_view(self.changelist_view), name=f"{info}_add"
|
|
||||||
),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class ConstanceConfig:
|
class ConstanceConfig:
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = "core"
|
app_label = "core"
|
||||||
|
|
@ -554,9 +413,6 @@ class ConstanceConfig:
|
||||||
swapped = False
|
swapped = False
|
||||||
is_composite_pk = False
|
is_composite_pk = False
|
||||||
|
|
||||||
def get_ordered_objects(self):
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_change_permission(self):
|
def get_change_permission(self):
|
||||||
return f"change_{self.model_name}"
|
return f"change_{self.model_name}"
|
||||||
|
|
||||||
|
|
@ -572,12 +428,14 @@ class ConstanceConfig:
|
||||||
def label_lower(self):
|
def label_lower(self):
|
||||||
return f"{self.app_label}.{self.model_name}"
|
return f"{self.app_label}.{self.model_name}"
|
||||||
|
|
||||||
|
def get_ordered_objects(self):
|
||||||
|
return False
|
||||||
|
|
||||||
_meta = Meta()
|
_meta = Meta()
|
||||||
|
|
||||||
|
|
||||||
admin.site.unregister([Config]) # type: ignore
|
admin.site.unregister([Config])
|
||||||
admin.site.register([ConstanceConfig], ConstanceAdmin) # type: ignore
|
admin.site.register([ConstanceConfig], BaseConstanceAdmin)
|
||||||
|
admin.site.site_title = f"{CONSTANCE_CONFIG.get('PROJECT_NAME')[0]}"
|
||||||
admin.site.site_title = f"{CONSTANCE_CONFIG.get('PROJECT_NAME')[0]}" # type: ignore
|
|
||||||
admin.site.site_header = "eVibes"
|
admin.site.site_header = "eVibes"
|
||||||
admin.site.index_title = f"{CONSTANCE_CONFIG.get('PROJECT_NAME')[0]}" # type: ignore
|
admin.site.index_title = f"{CONSTANCE_CONFIG.get('PROJECT_NAME')[0]}"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue