Home > Net >  Nested serializer representation for PrimaryKeyRelatedField
Nested serializer representation for PrimaryKeyRelatedField

Time:09-01

I want to add and remove products to an order by only using their ids, but I want the order representation to look like a nested serializer.

My Models:

class Product(models.Model):
    title = models.CharField(max_length=200)
    price = models.DecimalField(max_digits=1_000, decimal_places=2)

    def __str__(self):
        return self.title

class Order(models.Model):
    date = models.DateField()
    products = models.ManyToManyField(Product, blank=True, related_name='orders')

My Serializers:

class ProductSerializer(serializers.ModelSerializer):
    price = serializers.DecimalField(max_digits=1_000,
                                     decimal_places=2,
                                     coerce_to_string=False)

    class Meta:
        model = Product
        fields = ['id', 'title', 'price']


class OrderSerializer(serializers.ModelSerializer):
    products = serializers.PrimaryKeyRelatedField(queryset=Product.objects.all(), many=True)

    class Meta:
        model = Order
        fields = ['id', 'date', 'products']

I'm trying to get the below representation:

{
    "id": 1,
    "date": "2021-08-12",
    "products": [
        {
            "id": 1,
            "title": "Item 1",
            "price": 19.99
        },
        {
            "id": 3,
            "title": "Item 3",
            "price": 49.99
        }
    ]
}

However, if I want to create the above order the json should look like this:

{
    "date": "2021-08-12",
    "products":[1, 3]
}

And if I want to add a product with id==2 to the above order it should look like this:

{
    "id": 1,
    "date": "2021-08-12",
    "products":[1, 3, 2]
}

I've tried overriding the to_representation() method and adding a nested serializer there, but I have no idea how to go about it. Should it look something like this, or am I going in a completely wrong direction here?

def to_representation(self, instance):
    data = super().to_representation(instance)
    data['products'] = ProductSerializer(data=instance['products'])
    return data

CodePudding user response:

Ended up fixing it with the to_representation() method. I don't know if this is the best way to do it, but it works for now.

def to_representation(self, instance):
    data = super().to_representation(instance)
    products_list = []
    for product_id in data['products']:
        product = instance.products.get(pk=product_id)
        products_list.append(
            {
                'id': product.id,
                'title': product.title,
                'price': product.price
            }
        )
    data['products'] = products_list
    return data

CodePudding user response:

use Nested Serializer Relationships.
and your OrderSerializer serializer class will be like this:

class OrderSerializer(serializers.ModelSerializer):
    products = ProductSerializer(many=True)

    class Meta:
        model = Order
        fields = ['id', 'date', 'products']
  • Related