Getting data from another Foreign key - DRF

The relations of tables are shown in the picture. I have a main Table named Product. Two tables ProductImage , OrderedProduct have a Foreign key set to it. Now, I want to retrieve the image from OrderedProduct. How should I write the code for Serialization for it? Thanks

Models.py Visualization

This is my model.py file:

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')

I've read the documentation, asked in some programming groups but couldn't find any good solution. I am expecting someone to give a reference that leads to the solution.

I suggest you move the product's image to the product model. Think about it, the image of a product is a product's attribute. This will fix your problem and clean up your code.

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()

So now you can access it using source='product.image

On another note: I noticed you added some fields in your serial OrderedProductSerializer but they are not in your OrderedProduct model. That is likely to give you an error.

So I recommend you spend some more time polishing up your models.

Solution 1

You can use the SerializerMethodField like that:

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))

output:

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

Solution 2

If you dont have a structure contraint i propose you to change this structure and create a serializer for each model and on order retrieve you send product object like that:

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')

output:

[
    {
        "product": {
            "name": "productX",
            "price": 100,
            "product_images": [
                {
                    "image": "some_url"
                },
                {
                    "image": "some_url2"
                }
            ]
        },
        "quantity": 123
    }
]
Back to Top