feat(category): add brands relationship and resolve method
enable brands association with categories and allow querying of active brands within a category. Updated GraphQL schema, models, and serializers to include this relationship while deprecating redundant category-to-brand ManyToManyField.
This commit is contained in:
parent
10f5c798d4
commit
87ed875fe6
4 changed files with 19 additions and 6 deletions
|
|
@ -421,10 +421,7 @@ class BrandAdmin(
|
||||||
"priority",
|
"priority",
|
||||||
"is_active",
|
"is_active",
|
||||||
)
|
)
|
||||||
list_filter = (
|
list_filter = ("is_active",)
|
||||||
"categories",
|
|
||||||
"is_active",
|
|
||||||
)
|
|
||||||
search_fields = (
|
search_fields = (
|
||||||
"uuid",
|
"uuid",
|
||||||
"name",
|
"name",
|
||||||
|
|
|
||||||
|
|
@ -230,6 +230,7 @@ class CategoryType(DjangoObjectType):
|
||||||
"minimum and maximum prices for products in this category, if available."
|
"minimum and maximum prices for products in this category, if available."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
brands = List(lambda: BrandType, description=_("brands in this category"))
|
||||||
tags = DjangoFilterConnectionField(
|
tags = DjangoFilterConnectionField(
|
||||||
lambda: CategoryTagType, description=_("tags for this category")
|
lambda: CategoryTagType, description=_("tags for this category")
|
||||||
)
|
)
|
||||||
|
|
@ -249,6 +250,7 @@ class CategoryType(DjangoObjectType):
|
||||||
"slug",
|
"slug",
|
||||||
"description",
|
"description",
|
||||||
"image",
|
"image",
|
||||||
|
"brands",
|
||||||
"min_max_prices",
|
"min_max_prices",
|
||||||
)
|
)
|
||||||
filter_fields = ["uuid"]
|
filter_fields = ["uuid"]
|
||||||
|
|
@ -294,6 +296,9 @@ class CategoryType(DjangoObjectType):
|
||||||
"max_price": min_max_prices["max_price"],
|
"max_price": min_max_prices["max_price"],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def resolve_brands(self: Category, info) -> QuerySet[Brand]:
|
||||||
|
return self.brands
|
||||||
|
|
||||||
def resolve_seo_meta(self: Category, info):
|
def resolve_seo_meta(self: Category, info):
|
||||||
lang = graphene_current_lang()
|
lang = graphene_current_lang()
|
||||||
base = f"https://{settings.BASE_DOMAIN}"
|
base = f"https://{settings.BASE_DOMAIN}"
|
||||||
|
|
|
||||||
|
|
@ -443,6 +443,14 @@ class Category(ExportModelOperationsMixin("category"), NiceModel, MPTTModel):
|
||||||
# Fallback to favicon.png from static files
|
# Fallback to favicon.png from static files
|
||||||
return static("favicon.png")
|
return static("favicon.png")
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def brands(self) -> QuerySet["Brand"]:
|
||||||
|
return Brand.objects.filter(
|
||||||
|
products__category=self,
|
||||||
|
products__is_active=True,
|
||||||
|
is_active=True,
|
||||||
|
).distinct()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("category")
|
verbose_name = _("category")
|
||||||
verbose_name_plural = _("categories")
|
verbose_name_plural = _("categories")
|
||||||
|
|
@ -490,8 +498,8 @@ class Brand(ExportModelOperationsMixin("brand"), NiceModel):
|
||||||
categories = ManyToManyField(
|
categories = ManyToManyField(
|
||||||
"core.Category",
|
"core.Category",
|
||||||
blank=True,
|
blank=True,
|
||||||
help_text=_("optional categories that this brand is associated with"),
|
help_text=_("DEPRECATED"),
|
||||||
verbose_name=_("associated categories"),
|
verbose_name=_("DEPRECATED"),
|
||||||
)
|
)
|
||||||
slug = AutoSlugField(
|
slug = AutoSlugField(
|
||||||
populate_from=("name",),
|
populate_from=("name",),
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ from engine.core.models import (
|
||||||
Wishlist,
|
Wishlist,
|
||||||
)
|
)
|
||||||
from engine.core.serializers.simple import (
|
from engine.core.serializers.simple import (
|
||||||
|
BrandSimpleSerializer,
|
||||||
CategorySimpleSerializer,
|
CategorySimpleSerializer,
|
||||||
ProductSimpleSerializer,
|
ProductSimpleSerializer,
|
||||||
)
|
)
|
||||||
|
|
@ -60,6 +61,7 @@ class CategoryDetailListSerializer(ListSerializer):
|
||||||
class CategoryDetailSerializer(ModelSerializer):
|
class CategoryDetailSerializer(ModelSerializer):
|
||||||
children = SerializerMethodField()
|
children = SerializerMethodField()
|
||||||
filterable_attributes = SerializerMethodField()
|
filterable_attributes = SerializerMethodField()
|
||||||
|
brands = BrandSimpleSerializer(many=True, read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Category
|
model = Category
|
||||||
|
|
@ -71,6 +73,7 @@ class CategoryDetailSerializer(ModelSerializer):
|
||||||
"image",
|
"image",
|
||||||
"markup_percent",
|
"markup_percent",
|
||||||
"filterable_attributes",
|
"filterable_attributes",
|
||||||
|
"brands",
|
||||||
"children",
|
"children",
|
||||||
"slug",
|
"slug",
|
||||||
"created",
|
"created",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue