Получение данных из другого внешнего ключа - DRF

Отношения таблиц показаны на рисунке. У меня есть основная таблица с именем Product. Две таблицы ProductImage, OrderedProduct имеют установленный для них внешний ключ. Теперь я хочу получить изображение из OrderedProduct. Как я должен написать код для сериализации для этого? Спасибо

Модели.py Визуализация

Это мой model.py файл:

class Product(models.Model):
    name = models.CharField(max_length=50)
    description = models.TextField()
    def __str__(self) -> str:
        return self.name


class ProductImage(models.Model):
    product = models.ForeignKey(
        Product, on_delete=models.CASCADE, related_name='product_images')
    image = models.ImageField(upload_to="images/", null=True, blank=True)

class OrderedProduct(models.Model):
    product = models.ForeignKey(
        Product, on_delete=models.CASCADE, related_name='ordered_products')
    quantity = models.IntegerField()

Serializers.py

class OrderedProductSerializer(serializers.ModelSerializer):
    product_name = serializers.CharField(source='product.name')
    product_price = serializers.FloatField(source='product.price')
    # product_img = >>> what should I do here? <<<

    class Meta:
        model = OrderedProduct
        fields = ('user', 'product', 'quantity',
                  'delivered', 'product_name', 'product_price', 'product_img')

Я читал документацию, спрашивал в некоторых группах по программированию, но не смог найти никакого хорошего решения. Я ожидаю, что кто-нибудь даст ссылку, которая приведет к решению.

Я предлагаю вам переместить изображение продукта в модель продукта. Подумайте об этом, изображение товара - это атрибут товара. Это решит вашу проблему и очистит ваш код.

class Product(models.Model):
    name = models.CharField(max_length=50)
    description = models.TextField()
    image = models.ImageField(upload_to="images/", null=True, blank=True) # new
    def __str__(self) -> str:
        return self.name

class OrderedProduct(models.Model):
    product = models.ForeignKey(
        Product, on_delete=models.CASCADE, related_name='ordered_products')
    quantity = models.IntegerField()

Теперь вы можете получить доступ к нему, используя source='product.image

Еще одно замечание: Я заметил, что вы добавили некоторые поля в вашей серийной OrderedProductSerializer модели, но их нет в вашей OrderedProduct модели. Это может привести к ошибке.

Поэтому я рекомендую вам потратить еще немного времени на полировку ваших моделей.

Решение 1

Вы можете использовать SerializerMethodField вот так:

class OrderedProductSerializer(serializers.ModelSerializer):
    product_name = serializers.CharField(source='product.name')
    product_price = serializers.FloatField(source='product.price')
    product_imgs = serializers.SerializerMethodField()

    class Meta:
        model = OrderedProduct
        fields = ('product', 'quantity',
                  'product_name', 'product_price', 'product_imgs')

    def get_product_imgs(self, order):
        return list(order.product.product_images.all().values_list('image', flat=True))

вывод:

[
    {
        "product": 1,
        "quantity": 100,
        "product_name": "ProductX",
        "product_price": 123,
        "product_imgs": ["url1", "url2"]
    }
]

Решение 2

Если у вас нет ограничений по структуре, я предлагаю вам изменить эту структуру и создать сериализатор для каждой модели, а при получении заказа отправлять объект продукта следующим образом:

class ProductImagesSerializer(serializers.ModelSerializer):
    class Meta:
        model = ProductImage
        fields = ('image',)


class ProductSerializer(serializers.ModelSerializer):
    product_images = ProductImagesSerializer()
    
    class Meta:
        model = Product
        fields = ('name', 'price', 'product_images')


class OrderedProductSerializer(serializers.ModelSerializer):
    product = ProductSerializer()

    class Meta:
        model = OrderedProduct
        fields = ('product', 'quantity')

вывод:

[
    {
        "product": {
            "name": "productX",
            "price": 100,
            "product_images": [
                {
                    "image": "some_url"
                },
                {
                    "image": "some_url2"
                }
            ]
        },
        "quantity": 123
    }
]
Вернуться на верх