# noinspection PyUnresolvedReferences from constance.admin import Config 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.gis.admin import GISModelAdmin from django.db.models import Model from django.utils.translation import gettext_lazy as _ from modeltranslation.translator import translator from modeltranslation.utils import get_translation_fields from mptt.admin import DraggableMPTTAdmin from evibes.settings import CONSTANCE_CONFIG from .forms import OrderForm, OrderProductForm, VendorForm from .models import ( Address, Attribute, AttributeGroup, AttributeValue, Brand, Category, CategoryTag, Feedback, Order, OrderProduct, Product, ProductImage, ProductTag, PromoCode, Promotion, Stock, Vendor, Wishlist, ) class TranslationFieldsetMixin: model: Model def get_fieldsets(self, request, obj=None): fieldsets = super().get_fieldsets(request, obj) opts = translator.get_options_for_model(self.model) translation_fields = [] for orig in opts.local_fields: translation_fields += get_translation_fields(orig) if translation_fields: fieldsets = list(fieldsets) fieldsets.append( ( _("translations"), {"fields": translation_fields}, ) ) return fieldsets class BasicModelAdmin(ModelAdmin): @admin.action(description=str(_("activate selected %(verbose_name_plural)s"))) def activate_selected(self, _request, queryset) -> str: queryset.update(is_active=True) return str(_("%(verbose_name_plural)s activated successfully!")) @admin.action(description=str(_("deactivate selected %(verbose_name_plural)s"))) def deactivate_selected(self, _request, queryset) -> str: queryset.update(is_active=False) return str(_("%(verbose_name_plural)s deactivated successfully.")) def get_actions(self, request): actions = super().get_actions(request) actions["activate_selected"] = ( self.activate_selected, "activate_selected", str(_("activate selected %(verbose_name_plural)s")), ) actions["deactivate_selected"] = ( self.deactivate_selected, "deactivate_selected", str(_("deactivate selected %(verbose_name_plural)s")), ) return actions 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): 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" # 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) class ProductAdmin(TranslationFieldsetMixin, BasicModelAdmin): list_display = ( "name", "partnumber", "is_active", "category", "brand", "price", "rating", "modified", ) list_filter = ( "is_active", "is_digital", ("tags", admin.RelatedOnlyFieldListFilter), ("stocks__vendor", admin.RelatedOnlyFieldListFilter), "created", "modified", ) search_fields = ( "name", "partnumber", "brand__name", "category__name", "uuid", "slug", ) readonly_fields = ("created", "modified", "uuid", "rating", "price", "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 @admin.register(ProductTag) class ProductTagAdmin(TranslationFieldsetMixin, BasicModelAdmin): list_display = ("name",) search_fields = ("name",) @admin.register(CategoryTag) class CategoryTagAdmin(TranslationFieldsetMixin, BasicModelAdmin): list_display = ("name",) search_fields = ("name",) @admin.register(Vendor) class VendorAdmin(BasicModelAdmin): list_display = ("name", "markup_percent", "modified") list_filter = ("markup_percent", "is_active") search_fields = ("name",) form = VendorForm @admin.register(Feedback) class FeedbackAdmin(TranslationFieldsetMixin, BasicModelAdmin): list_display = ("order_product", "rating", "comment", "modified") list_filter = ("rating", "is_active") search_fields = ("order_product__product__name", "comment") @admin.register(Order) class OrderAdmin(BasicModelAdmin): list_display = ( "human_readable_id", "user", "is_business", "status", "total_price", "buy_time", "modified", ) 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") 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) @admin.register(OrderProduct) class OrderProductAdmin(BasicModelAdmin): 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) @admin.register(PromoCode) class PromoCodeAdmin(BasicModelAdmin): list_display = ( "code", "discount_percent", "discount_amount", "start_time", "end_time", "used_on", ) 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") @admin.register(Promotion) class PromotionAdmin(TranslationFieldsetMixin, BasicModelAdmin): 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") @admin.register(Stock) class StockAdmin(BasicModelAdmin): list_display = ("product", "vendor", "sku", "quantity", "price", "modified") list_filter = ("vendor", "quantity") search_fields = ("product__name", "vendor__name", "sku") autocomplete_fields = ("product", "vendor") @admin.register(Wishlist) class WishlistAdmin(BasicModelAdmin): list_display = ("user", "modified") search_fields = ("user__email",) @admin.register(ProductImage) class ProductImageAdmin(TranslationFieldsetMixin, BasicModelAdmin): list_display = ("alt", "product", "priority", "modified") list_filter = ("priority",) search_fields = ("alt", "product__name") autocomplete_fields = ("product",) @admin.register(Address) class AddressAdmin(GISModelAdmin): list_display = ("street", "city", "region", "country", "user") list_filter = ("country", "region") search_fields = ( "raw_data", "street", "city", "postal_code", "user__email", "address_line", ) gis_widget_kwargs = { "attrs": { "default_lon": 37.61556, "default_lat": 55.75222, "default_zoom": 6, } } # Constance config class ConstanceConfig: class Meta: app_label = "core" object_name = "Config" concrete_model = None model_name = module_name = "config" verbose_name_plural = _("config") abstract = False swapped = False is_composite_pk = False def get_change_permission(self): return f"change_{self.model_name}" @property def app_config(self): return apps.get_app_config(self.app_label) @property def label(self): return f"{self.app_label}.{self.object_name}" @property def label_lower(self): return f"{self.app_label}.{self.model_name}" def get_ordered_objects(self): return False _meta = Meta() admin.site.unregister([Config]) admin.site.register([ConstanceConfig], BaseConstanceAdmin) admin.site.site_title = f"{CONSTANCE_CONFIG.get('PROJECT_NAME')[0]}" admin.site.site_header = "eVibes" admin.site.index_title = f"{CONSTANCE_CONFIG.get('PROJECT_NAME')[0]}"