Karesh A
Karesh A

Reputation: 1751

Django model nested serializer

I have the model structure like below

class BaseProduct:
   id = models.CharField(max_length=15)
   name = models.CharField(max_length=20)

class Product
   base_product = ForeigKey(BaseProduct)
   name = models.CharField(max_length=20)

class Condition:
   category = models.ForeignKey(Product, related_name='allowed_product')
   check = models.IntegerField(default=0)
   allow = models.PositiveSmallIntegerField(default=1)

The query:

Product.objects.filter(condition__allow=1, condition__check=1)

I want format something like below Base Product and inside that list of products based on allow and check filter

[
    {
        "name": "BaseProduct 1",
        "products": [
            {

                "name": "TV",

            }, {}, ....

        ]
    },
........
]

Upvotes: 0

Views: 1208

Answers (2)

user8060120
user8060120

Reputation:

Try it, if you use django rest framework

from rest_framework import serializers
from rest_framework.fields import empty
from django.utils.functional import cached_property


class ProductSerializer(serializers.ModelSerializer):

    class Meta:
        model = Product
        fields = ('name')


class BaseProductSerializer(serializers.ModelSerializer):
        products = serializers.SerializerMethodField()

    class Meta:
        model = BaseProduct
        fields = ('name', 'products')

    def __init__(self, instance=None, data=empty, **kwargs):
        self._condition_allow = kwargs.pop('condition_allow', 1)
        super(BaseProductSerializer, self).__init__(instance=None, data=empty, **kwargs)

    @cached_property
    def _request_data(self):
        request = self.context.get('request')
        # if POST
        # return request.data if request else {}
        # if GET params
        return request.query_params if request else {}

    @cached_property
    def _condition(self):
         return self._request_data.get('CONDITION_PARAM_NAME')

    def get_products(self, obj):
        qs = obj.product_set.filter(condition__allow=self._condition_allow, condition__check=1)
        serializer = ProductSerializer(qs, many=True)
        #                             ^^^^^
        return serializer.data

in view

serialiser(qs, condition_allow=5)

Upvotes: 1

Kakar
Kakar

Reputation: 5599

Change your models to have related_name for the foreignkeys to have reverse relationship:

class BaseProduct:
   id = models.CharField(max_length=15)
   name = models.CharField(max_length=20)

class Product
   base_product = ForeigKey(BaseProduct, related_name='products')
   name = models.CharField(max_length=20)

class Condition:
   category = models.ForeignKey(Product, related_name='conditions')
   check = models.IntegerField(default=0)
   allow = models.PositiveSmallIntegerField(default=1)

So now you can use it in your serializers:

class BaseProductSerializer:
   class Meta:
    model = BaseProduct
    fields = ('name', 'products',)

class ProductSerializer:
   class Meta:
    model = Product
    fields = ('conditions',)

class ConditionSerializer:
   class Meta:
    model = Condition
    fields = '__all__'

Finally in your views, change this:

Product.objects.filter(condition__allow=1, condition__check=1)

into this:

BaseProduct.objects.filter(products__conditions__allow=1, products__conditions__allow=1)

And hopefully, this should generate JSON data in the format that you asked for.

Upvotes: 1

Related Questions