Search code examples
pythondjangodjango-rest-frameworkmany-to-manyserialization

how to display my M2M model in Django Rest Framework


I'm trying to display a 'nested' model in my API response and having trouble shaping the data.

I have the model the API is called from:

something like

class Rules(Model):
    conditions = models.ManyToManyField(RulesPoliciesConditions)
    ...
    ...

class RulesPoliciesConditions(Model):
    rules = models.ForeignKey(Rules, ...) 
    policies = models.ForeignKey(Policy, ...)

Rules and Policies are their own models with a few TextFields (name, nickname, timestamp, etc)

My problem is that when I use the Rules model to call a field called conditions, only the rules and policies PK display. I want to reach the other attributes like name, timestamp, nickname, etc.

I tried making my fields (in my Serializer) try to call specifically like "conditions__rules__name" but it's invalid, I also tried "conditions.rules.name" which is also invalid. Maybe I'm using the wrong field in my serializer, I'm trying out conditions = serializers.SlugRelatedField(many=True, queryset=q, slug_field="id")

My intention is to display something like:

conditions: [
    {
     rules: {id: rulesId, name: rulesName, ...},
     policies: {id: policiesId, name: policiesName, ...}
    }, ...
]

or just even: conditions: [ { rules: rulesName, policies: policiesName }, ... ]

since right now it just returns the rulesId and policiesId and it doesn't "know" about the other fields

EDIT: I found a relevant question on SO but couldn't get a relevant answer Django REST Framework: Add field from related object to ModelSerializer


Solution

  • This can be achieved by using nested serializers. The level of nesting can be controlled/customized by various methods

    class RulesPoliciesConditionsSerializer(serializers.ModelSerializer):
        class Meta:
            fields = '__all__'
            model = RulesPoliciesConditions
            depth = 1
    
    
    class RulesSerializer(serializers.ModelSerializer):
        conditions = RulesPoliciesConditionsSerializer(many=True)
    
        class Meta:
            fields = '__all__'
            model = Rules

    Pass your Rules queryset to the RulesSerializer serializer to get the desired output

    Example

    
    rules_qs = Rules.objects.all()
    rules_serializer = RulesSerializer(rules_qs, many=True)
    data = rules_serializer.data
    


    References
    1. serializer depth
    2. Nested serializer