paula.em.lafon
paula.em.lafon

Reputation: 591

Can't render nested relationship in Django Rest Framework

The problem is I have a 'details' field which should render into a nested relationship with it's parent serializer. I have tried a bunch of stuff and nothing seems to be working.

Here's my models:

class BusinessOrderModel(OrderToModel):
    reference = models.IntegerField()
    business_num = models.ForeignKey('BusinessModel', on_delete=models.CASCADE)
    def __str__(self):
        return str(self.reference)
    
class BusinessModel(models.Model):
    Business_num = models.IntegerField(primary_key=True)
    def __str__(self):
        return str(self.Business_num)

class DetailModel(models.Model):
    id = models.AutoField(primary_key=True)
    detail = models.TextField()
    order = models.ForeignKey('BusinessOrderModel', on_delete=models.CASCADE)

and here's my serializers which aren't working:

class DetailSerializer(serializers.ModelSerializer):
    class Meta:
        model = DetailModel
        fields = ('id', 'detail')

class BusinessOrderSerializer(serializers.ModelSerializer):
    details = DetailSerializer(many=True)
    class Meta:
        model = BusinessOrderModel
        fields = ('reference', 'business_num', 'details')

I've tried many different things but I get this error:

Got AttributeError when attempting to get a value for field details on serializer BusinessOrderSerializer. The serializer field might be named incorrectly and not match any attribute or key on the BusinessOrderModel instance. Original exception text was: 'BusinessOrderModel' object has no attribute 'details'.

Any help is much appreciated.

Thank you very much.

Upvotes: 0

Views: 306

Answers (1)

Navid Zarepak
Navid Zarepak

Reputation: 4208

Using details to lookup reverse relationships only works if you set it as the related_name. The default for BusinessOrderModel to DetailModel will be detailmodel_set.

To make it accessible by calling details you should make this change:

class DetailModel(models.Model):
    id = models.AutoField(primary_key=True)
    detail = models.TextField()
    order = models.ForeignKey('BusinessOrderModel', related_name="details", on_delete=models.CASCADE)

Now you can use DetailModel.objects.get(id=1).details.all()

You can also customize the query in your serializer:

class BusinessOrderSerializer(serializers.ModelSerializer):
    details = SerializerMethodField()
    class Meta:
        model = BusinessOrderModel
        fields = ('reference', 'business_num', 'details')

    def get_details(self, obj):
        return DetailSerializer(obj.details.filter(), many=True).data

Upvotes: 2

Related Questions