Features: 1) Replace I18NTabTranslationAdmin with I18NFieldsetMixin for admin classes; 2) Introduce _TranslationInline for managing translation fields dynamically; 3) Add created and modified fields to readonly_fields in Category admin class;

Fixes: 1) Resolve unnecessary imports from `modeltranslation.admin` and streamline admin imports;

Extra: 1) Refactor translation logic into `get_inline_instances` for improved modularity and clarity.
This commit is contained in:
Egor Pavlovich Gorbunov 2025-06-22 01:55:46 +03:00
parent 0d37b5b23b
commit 76c3cd17e3

View file

@ -4,13 +4,12 @@ from constance.admin import ConstanceAdmin as BaseConstanceAdmin
from django.apps import apps
from django.contrib import admin
from django.contrib.admin import ModelAdmin, TabularInline
from django.contrib.admin.options import InlineModelAdmin
from django.contrib.gis.admin import GISModelAdmin
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 modeltranslation.admin import (
TabbedExternalJqueryTranslationAdmin,
)
from modeltranslation.translator import translator
from modeltranslation.utils import get_translation_fields
from mptt.admin import DraggableMPTTAdmin
@ -48,41 +47,50 @@ SECTION_RELATIONS = _("relations")
class I18NFieldsetMixin:
model: type[Model]
"""
Pulls all <field>_<lang> translation columns out of the regular
fieldsets and tucks them into one extra fieldset/tab called "I18N".
"""
def get_fieldsets(self, request, obj=None):
base_fieldsets = super().get_fieldsets(request, obj)
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 = []
for orig in trans_opts.local_fields:
translation_fields.extend(get_translation_fields(orig))
translation_fields += get_translation_fields(orig)
cleaned = []
for title, opts in base_fieldsets:
original = list(opts.get("fields", []))
filtered = [f for f in original if f not in translation_fields]
opts = opts.copy()
opts["fields"] = filtered
cleaned.append((title, opts))
cleaned.append(
(
SECTION_I18N,
{
"classes": ("suit-tab-i18n",),
"fields": tuple(translation_fields),
},
class _TranslationInline(InlineModelAdmin[self.model, self.model]):
model = self.model
form = modelform_factory(
self.model,
fields=translation_fields,
formfield_callback=lambda f, **kw: super(
I18NFieldsetMixin, self
).formfield_for_dbfield(f, request, **kw),
)
)
return cleaned
template = "admin/edit_inline/tabular.html"
is_navtab = True
verbose_name = _("translations")
verbose_name_plural = _("translations")
extra = 0
def get_queryset(self, request):
return (
self.model.objects.filter(pk=obj.pk)
if obj
else self.model.objects.none()
)
class I18NTabTranslationAdmin(I18NFieldsetMixin, TabbedExternalJqueryTranslationAdmin):
pass
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):
@ -121,7 +129,7 @@ class AttributeValueInline(TabularInline):
@admin.register(AttributeGroup)
class AttributeGroupAdmin(BasicModelAdmin, I18NTabTranslationAdmin):
class AttributeGroupAdmin(BasicModelAdmin, I18NFieldsetMixin):
list_display = ("name", "modified")
search_fields = (
"uuid",
@ -144,7 +152,7 @@ class AttributeGroupAdmin(BasicModelAdmin, I18NTabTranslationAdmin):
@admin.register(Attribute)
class AttributeAdmin(BasicModelAdmin, I18NTabTranslationAdmin):
class AttributeAdmin(BasicModelAdmin, I18NFieldsetMixin):
list_display = ("name", "group", "value_type", "modified")
list_filter = ("value_type", "group", "is_active")
search_fields = ("uuid", "name", "group__name")
@ -152,7 +160,7 @@ class AttributeAdmin(BasicModelAdmin, I18NTabTranslationAdmin):
@admin.register(AttributeValue)
class AttributeValueAdmin(BasicModelAdmin, I18NTabTranslationAdmin):
class AttributeValueAdmin(BasicModelAdmin, I18NFieldsetMixin):
list_display = ("attribute", "value", "modified")
list_filter = ("attribute__group", "is_active")
search_fields = ("uuid", "value", "attribute__name")
@ -168,7 +176,7 @@ class CategoryChildrenInline(admin.TabularInline):
@admin.register(Category)
class CategoryAdmin(DraggableMPTTAdmin, BasicModelAdmin, I18NTabTranslationAdmin):
class CategoryAdmin(DraggableMPTTAdmin, BasicModelAdmin, I18NFieldsetMixin):
mptt_indent_field = "name"
list_display = ("indented_title", "parent", "is_active", "modified")
# noinspection PyUnresolvedReferences
@ -214,6 +222,8 @@ class CategoryAdmin(DraggableMPTTAdmin, BasicModelAdmin, I18NTabTranslationAdmin
readonly_fields = (
"uuid",
"slug",
"created",
"modified",
)
def indented_title(self, instance):
@ -224,7 +234,7 @@ class CategoryAdmin(DraggableMPTTAdmin, BasicModelAdmin, I18NTabTranslationAdmin
@admin.register(Brand)
class BrandAdmin(BasicModelAdmin, I18NTabTranslationAdmin):
class BrandAdmin(BasicModelAdmin, I18NFieldsetMixin):
list_display = ("name",)
list_filter = ("categories", "is_active")
search_fields = (
@ -255,7 +265,7 @@ class StockInline(TabularInline):
@admin.register(Product)
class ProductAdmin(BasicModelAdmin, I18NTabTranslationAdmin):
class ProductAdmin(BasicModelAdmin, I18NFieldsetMixin):
list_display = (
"name",
"partnumber",
@ -340,13 +350,13 @@ class ProductAdmin(BasicModelAdmin, I18NTabTranslationAdmin):
@admin.register(ProductTag)
class ProductTagAdmin(BasicModelAdmin, I18NTabTranslationAdmin):
class ProductTagAdmin(BasicModelAdmin, I18NFieldsetMixin):
list_display = ("name",)
search_fields = ("name",)
@admin.register(CategoryTag)
class CategoryTagAdmin(BasicModelAdmin, I18NTabTranslationAdmin):
class CategoryTagAdmin(BasicModelAdmin, I18NFieldsetMixin):
list_display = ("name",)
search_fields = ("name",)
@ -458,7 +468,7 @@ class PromoCodeAdmin(BasicModelAdmin):
@admin.register(Promotion)
class PromotionAdmin(BasicModelAdmin, I18NTabTranslationAdmin):
class PromotionAdmin(BasicModelAdmin, I18NFieldsetMixin):
list_display = ("name", "discount_percent", "modified")
search_fields = ("name",)
autocomplete_fields = ("products",)