Features: 1) Add is_digital field to ProductAdmin for filtering and display; 2) Extend admin search fields to include slug for products; 3) Introduce slug field in readonly and form layout sections for products.

Fixes: 1) Add `# type: ignore` comments for ForeignKey fields to resolve type-checking warnings in models.

Extra: 1) Refactor admin field formatting for better readability; 2) Add `# noinspection PyProtectedMember` annotation in `rebuild_slugs` management command; 3) Clean up spacing and alignment in various files.
This commit is contained in:
Egor Pavlovich Gorbunov 2025-06-18 23:41:28 +03:00
parent 30144c5b6a
commit b15df3b72a
4 changed files with 44 additions and 13 deletions

View file

@ -169,10 +169,20 @@ class StockInline(TabularInline):
@admin.register(Product)
class ProductAdmin(BasicModelAdmin, TabbedTranslationAdmin):
list_display = ("name", "partnumber", "is_active", "category", "brand", "price", "rating", "modified")
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",
@ -185,9 +195,10 @@ class ProductAdmin(BasicModelAdmin, TabbedTranslationAdmin):
"brand__name",
"category__name",
"uuid",
"slug",
)
readonly_fields = ("created", "modified", "uuid", "rating", "price")
readonly_fields = ("created", "modified", "uuid", "rating", "price", "slug")
autocomplete_fields = ("category", "brand", "tags")
def price(self, obj):
@ -206,8 +217,10 @@ class ProductAdmin(BasicModelAdmin, TabbedTranslationAdmin):
{
"fields": (
"uuid",
"slug",
"partnumber",
"is_active",
"is_digital",
"name",
"category",
"brand",
@ -270,7 +283,15 @@ class OrderProductInline(admin.TabularInline):
@admin.register(Order)
class OrderAdmin(BasicModelAdmin):
list_display = ("human_readable_id", "user", "is_business", "status", "total_price", "buy_time", "modified")
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")
inlines = [OrderProductInline]
@ -374,7 +395,14 @@ class ProductImageAdmin(BasicModelAdmin):
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")
search_fields = (
"raw_data",
"street",
"city",
"postal_code",
"user__email",
"address_line",
)
gis_widget_kwargs = {
"attrs": {
@ -394,7 +422,9 @@ class ConstanceAdmin(BaseConstanceAdmin):
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"),
path(
"", self.admin_site.admin_view(self.changelist_view), name=f"{info}_add"
),
]

View file

@ -78,7 +78,7 @@ def process_query(query: str = "", request: Request | None = None):
obj_name = (
getattr(hit, "name", None) or getattr(hit, "title", None) or "N/A"
)
obj_slug = ""
raw_slug = getattr(hit, "slug", None)
if raw_slug:
obj_slug = raw_slug

View file

@ -5,6 +5,7 @@ from django.utils.crypto import get_random_string
from core.models import Brand, Category, Product
# noinspection PyProtectedMember
class Command(BaseCommand):
help = "Rebuild slug field for all slugified instances"

View file

@ -300,14 +300,14 @@ class Brand(ExportModelOperationsMixin("brand"), NiceModel):
class Product(ExportModelOperationsMixin("product"), NiceModel):
is_publicly_visible = True
category: Category = ForeignKey(
category: Category = ForeignKey( # type: ignore
"core.Category",
on_delete=CASCADE,
help_text=_("category this product belongs to"),
verbose_name=_("category"),
related_name="products",
)
brand: Brand = ForeignKey(
brand: Brand = ForeignKey( # type: ignore
"core.Brand",
on_delete=CASCADE,
blank=True,
@ -454,14 +454,14 @@ class Attribute(ExportModelOperationsMixin("attribute"), NiceModel):
class AttributeValue(ExportModelOperationsMixin("attribute_value"), NiceModel):
is_publicly_visible = True
attribute: Attribute = ForeignKey(
attribute: Attribute = ForeignKey( # type: ignore
"core.Attribute",
on_delete=CASCADE,
related_name="values",
help_text=_("attribute of this value"),
verbose_name=_("attribute"),
)
product: Product = ForeignKey(
product: Product = ForeignKey( # type: ignore
"core.Product",
on_delete=CASCADE,
blank=False,
@ -852,7 +852,7 @@ class PromoCode(ExportModelOperationsMixin("promocode"), NiceModel):
class Order(ExportModelOperationsMixin("order"), NiceModel):
is_publicly_visible = False
billing_address: Address = ForeignKey(
billing_address: Address = ForeignKey( # type: ignore
"core.Address",
on_delete=CASCADE,
blank=True,
@ -861,7 +861,7 @@ class Order(ExportModelOperationsMixin("order"), NiceModel):
help_text=_("the billing address used for this order"),
verbose_name=_("billing address"),
)
promo_code: PromoCode = ForeignKey(
promo_code: PromoCode = ForeignKey( # type: ignore
"core.PromoCode",
on_delete=PROTECT,
blank=True,
@ -869,7 +869,7 @@ class Order(ExportModelOperationsMixin("order"), NiceModel):
help_text=_("optional promo code applied to this order"),
verbose_name=_("applied promo code"),
)
shipping_address: Address = ForeignKey(
shipping_address: Address = ForeignKey( # type: ignore
"core.Address",
on_delete=CASCADE,
blank=True,