feat: add catalogue image management (#1)

- Add CatalogueImage model with FK to Product
- Add image resize service (strict/non-strict modes with configurable dimensions)
- Add CRUD API endpoints with admin-only write permissions
- Add catalogue_images field to product listing/detail endpoints
- Serve media files in development via static()
- 28 TDD tests covering model, API, permissions, resize, and product listing
This commit is contained in:
mono
2026-06-13 13:39:57 -05:00
parent 7160d64e86
commit 7112197ad2
14 changed files with 604 additions and 1 deletions

View File

@@ -1,3 +1,4 @@
from .catalogue_images import CatalogueImageSerializer
from .products import ProductSerializer, ListProductSerializer
from .customers import CustomerSerializer, ListCustomerSerializer
from .sales import (
@@ -17,6 +18,8 @@ from .payments import (
)
__all__ = [
# Catalogue Images
"CatalogueImageSerializer",
# Products
"ProductSerializer",
"ListProductSerializer",

View File

@@ -0,0 +1,20 @@
from django.conf import settings
from rest_framework import serializers
from ..models.catalogue_images import CatalogueImage
class CatalogueImageSerializer(serializers.ModelSerializer):
class Meta:
model = CatalogueImage
fields = ["id", "product", "image", "uploaded_at"]
read_only_fields = ["uploaded_at"]
def validate_image(self, value):
max_size = settings.CATALOGUE_MAX_UPLOAD_SIZE
if value.size > max_size:
raise serializers.ValidationError(
f"Image size exceeds the maximum allowed size of "
f"{max_size // (1024 * 1024)}MB."
)
return value

View File

@@ -4,6 +4,8 @@ from ..models.products import Product, ProductCategory
class ProductSerializer(serializers.ModelSerializer):
catalogue_images = serializers.SerializerMethodField()
class Meta:
model = Product
fields = [
@@ -14,10 +16,31 @@ class ProductSerializer(serializers.ModelSerializer):
"measuring_unit",
"categories",
"external_id",
"catalogue_images",
]
def get_catalogue_images(self, obj):
request = self.context.get("request")
if not request:
return [img.image.url for img in obj.catalogue_images.all()]
return [
request.build_absolute_uri(img.image.url)
for img in obj.catalogue_images.all()
]
class ListProductSerializer(serializers.ModelSerializer):
catalogue_images = serializers.SerializerMethodField()
class Meta:
model = Product
fields = ["id", "name"]
fields = ["id", "name", "catalogue_images"]
def get_catalogue_images(self, obj):
request = self.context.get("request")
if not request:
return [img.image.url for img in obj.catalogue_images.all()]
return [
request.build_absolute_uri(img.image.url)
for img in obj.catalogue_images.all()
]