Add Serializer on Reverse Relationship - Django Rest Framework

17,507

Solution 1

Ahmed Hosny was correct in his answer. It required the many parameter to be set to True to work.

So final version of the CartSerializer looked like this:

class CartSerializer(serializers.ModelSerializer):
    cartitem_set = CartItemSerializer(read_only=True, many=True) # many=True is required
    class Meta:
        model = Cart
        depth = 1
        fields = (
            'id', 
            'date_created', 
            'voucher', 
            'carrier', 
            'currency', 
            'cartitem_set', 
        )

Solution 2

It's important to define a related name in your models, and to use that related name in the serializer relationship:

class Cart(models.Model):
   name = models.CharField(max_length=500)

class CartItem(models.Model):
   cart = models.ForeignKey(Cart, related_name='cart_items')
   items = models.IntegerField()

Then in your serializer definition you use those exact names:

class CartSerializer(serializers.ModelSerializer):
    cart_items = CartItemSerializer(read_only=True)
    class Meta:
       model = Cart
       fields = ('name', 'cart_items',)
Share:
17,507

Related videos on Youtube

Marcus Lind
Author by

Marcus Lind

Originally from Sweden, I lived in Bangkok, Thailand for 8 years and I'm currently living in London, United Kingdom where I work as a Lead AI Software Engineer and lead machine learning and data science teams working on projects for Fortune 500 companies. I have an entrepreneurial background, I founded Tourn -- a marketing platform for social media influencers -- which was acquired in 2014, and since then I've been involved in multiple e-commerce and mobile gaming startups. I am currently working with AI and Analytics cases with BCG GAMMA (Boston Consulting Group) in London. My background has given me experience working with technologies such as Django, Python, Angular, Javascript, Spark, Hadoop, Docker, Ansible and more.

Updated on September 16, 2022

Comments

  • Marcus Lind
    Marcus Lind over 1 year

    I have a Cart model and a CartItem model. The CartItem model has a ForeignKey to the Cart model.

    Using Django Rest Framework I have a view where the API user can display the Cart, and obviously then I want to include the CartItem in the respone.

    I set up my Serializer like this:

    class CartSerializer(serializers.ModelSerializer):
        user = UserSerializer(read_only=True)
        cartitem_set = CartItemSerializer(read_only=True)
        class Meta:
            model = Cart
            depth = 1
            fields = (
                'id', 
                'user', 
                'date_created', 
                'voucher', 
                'carrier', 
                'currency', 
                'cartitem_set', 
            )
    

    My problem is the second line, cartitem_set = CartItemSerializer(read_only=True).

    I get AttributeErrors saying 'RelatedManager' object has no attribute 'product'. ('product' is a field in the CartItem model. If I exclude product from the CartItemSerializer I just get a new AttributeError with the next field and so on. No matter if I only leave 1 or all fields in the Serializer, I will get a error.

    My guess is that for some reason Django REST Framework does not support adding Serializers to reverse relationships like this. Am I wrong? How should I do this?

    PS

    The reason why I want to use the CartItemSerializer() is because I want to have control of what is displayed in the response.

    • Ahmed Hosny
      Ahmed Hosny about 8 years
      try cartitem_set = CartItemSerializer(read_only=True, many=True)
  • Ranvijay Sachan
    Ranvijay Sachan almost 8 years
    can we change name cartitem_set to items ?
  • Aaron C. de Bruyn
    Aaron C. de Bruyn almost 7 years
    You can change the name by doing something like: items = CartItemSerializer(read_only=True, many=True, source='cartitem_set')
  • Gonzalo
    Gonzalo over 6 years
    You can change cartitem_set name, from related_name. In class CartItem : cart = models.ForeignKey(Cart, related_name='items') , then in "fields" inside serializer, you must use name items
  • Shahabaz
    Shahabaz about 5 years
    I have an issue here. I am not getting any column as cartitem_set in the JSON response any idea? (Data is present). Response returns without cartitem_set key pair .
  • Helen
    Helen about 5 years
    Is it possible to use this solution then filter the items returned in the set?
  • Marcus Lind
    Marcus Lind about 5 years
    @Helen you can pass in a source kwarg to the field and set a custom source if you want.
  • Helen
    Helen about 5 years
    What would the syntax of that look like? I've currently got source set to source='cartitem_set' to change the name, but since it's a string, how would I pass a filter or a queryset into it? Appreciate your help Marcus.
  • adrian oviedo
    adrian oviedo almost 4 years
    In the original question he keeps the implicit related name: cartitem_set
  • Joel G Mathew
    Joel G Mathew over 2 years
    Yes, this is very important for reverse relationship to work
  • Thorvald
    Thorvald about 2 years
    This solution is incredibly slow for bigger queries, any way to increase the performance here?
  • Thorvald
    Thorvald about 2 years
    Had to use a prefetch_related on the query of course: prefetch_related('cartitem_set')