Features: 1) Add image_url property to Category and ProductImage models for constructing absolute image URLs; 2) Replace direct image.url references with image_url across serializers and GraphQL resolvers;

Fixes: None;

Extra: 1) Simplify serializer methods by removing redundant `suppress` blocks for `image.url`; 2) Minor adjustments to GraphQL resolver parameter names for consistency.
This commit is contained in:
Egor Pavlovich Gorbunov 2025-11-11 14:38:41 +03:00
parent 71b0cdd818
commit 01ba06d52c
4 changed files with 22 additions and 12 deletions

View file

@ -234,7 +234,7 @@ class CategoryType(DjangoObjectType): # type: ignore [misc]
return result return result
def resolve_image(self: Category, info) -> str: def resolve_image(self: Category, info) -> str:
return info.context.build_absolute_uri(self.image.url) if self.image else "" return self.image_url
def resolve_markup_percent(self: Category, info) -> float: def resolve_markup_percent(self: Category, info) -> float:
if info.context.user.has_perm("core.view_category"): if info.context.user.has_perm("core.view_category"):
@ -465,8 +465,8 @@ class ProductImageType(DjangoObjectType): # type: ignore [misc]
filter_fields = ["uuid"] filter_fields = ["uuid"]
description = _("product's images") description = _("product's images")
def resolve_image(self: ProductImage, info): def resolve_image(self: ProductImage, _info):
return info.context.build_absolute_uri(self.image.url) if self.image else "" return self.image_url
class ProductType(DjangoObjectType): # type: ignore [misc] class ProductType(DjangoObjectType): # type: ignore [misc]

View file

@ -420,6 +420,13 @@ class Category(ExportModelOperationsMixin("category"), NiceModel, MPTTModel): #
return list(by_attr.values()) # type: ignore [arg-type] return list(by_attr.values()) # type: ignore [arg-type]
@cached_property
def image_url(self) -> str:
with suppress(ValueError):
url = str(self.image.url)
url = url if "http" in url else f"https://api.{config.BASE_DOMAIN}{url}"
return ""
class Meta: class Meta:
verbose_name = _("category") verbose_name = _("category")
verbose_name_plural = _("categories") verbose_name_plural = _("categories")
@ -843,6 +850,13 @@ class ProductImage(ExportModelOperationsMixin("product_image"), NiceModel): # t
def __str__(self) -> str: def __str__(self) -> str:
return self.alt return self.alt
@cached_property
def image_url(self) -> str:
with suppress(ValueError):
url = str(self.image.url)
url = url if "http" in url else f"https://api.{config.BASE_DOMAIN}{url}"
return ""
class Meta: class Meta:
ordering = ("priority",) ordering = ("priority",)
verbose_name = _("product image") verbose_name = _("product image")

View file

@ -75,10 +75,8 @@ class CategoryDetailSerializer(ModelSerializer):
"modified", "modified",
] ]
def get_image(self, obj: Category) -> str | None: def get_image(self, obj: Category) -> str:
with suppress(ValueError): return obj.image_url
return obj.image.url
return None
def get_filterable_attributes(self, obj: Category) -> list[FilterableAttribute]: def get_filterable_attributes(self, obj: Category) -> list[FilterableAttribute]:
return obj.filterable_attributes return obj.filterable_attributes
@ -175,7 +173,7 @@ class ProductImageDetailSerializer(ModelSerializer):
] ]
def get_image(self, obj: ProductImage) -> str: def get_image(self, obj: ProductImage) -> str:
return obj.image.url or "" return obj.image_url
class AttributeDetailSerializer(ModelSerializer): class AttributeDetailSerializer(ModelSerializer):

View file

@ -54,10 +54,8 @@ class CategorySimpleSerializer(ModelSerializer): # type: ignore [type-arg]
"children", "children",
] ]
def get_image(self, obj: Category) -> str | None: def get_image(self, obj: Category) -> str:
with suppress(ValueError): return obj.image_url
return str(obj.image.url)
return None
def get_children(self, obj: Category) -> dict[str, Any]: def get_children(self, obj: Category) -> dict[str, Any]:
request = self.context.get("request") request = self.context.get("request")