Search code examples
djangodjango-modelsdjango-serializer

How to access field from ManyToMany relation on top of Foreign key relation in a django serializer?


I have the following structure:

class Model_1():
    model_2_ref = models.ForeignKey(to="Model_2", null=True, on_delete=models.SET_NULL)
    model_1_field_1 = models.CharField(max_length=120)
    ...

class Model_2():
    model_2_field_1 = models.CharField(max_length=120)
    model_2_field_2 = models.CharField(max_length=120)
    ....

class Model_3():
    model_2_ref = models.ManyToManyField(to="Model_2", related_name="model_2_rel_name")
    model_3_field_1 = models.CharField(max_length=120)
    user_id = models.Integer()
    ....

Each record of Model_1 is related to only one record of Model_2. Also each record of the Model_2 is related to only one record of Model_3 for the current user. The serializer will be used by a viewset that filters the matches from model_3 by user_id, transforming this into a One-to-one relation of sorts.

I have a serializer for Model_1, where I would like to include it's related fields from Model_2 and Model_3.

In theory, this is what I would like to achieve:

class Model_1_Serializer():
    model_1_field_1 = serializers.CharField()
    model_2_field_1 = serializers.CharField(source='model_2_ref.model_2_field_1')
    model_2_field_2 = serializers.CharField(source='model_2_ref.model_2_field_1')
    model_3_field_1 = serializers.CharField(source='model_2_ref.model_3_ref.model_3_field_1')

For model_3_field_1 this syntax does not work, but for the fields of model 2 it does. How can I access the related fields of Model_3 from the serializer of Model_1?


Solution

  • Maybe something like (untested)?

    models.py

    class Model2(...):
        
        # this method returns the first model_3 instance or None:
        @property
        def model_3_single_ref(self): return self.model_3_ref.first() 
    
    
    class Model3(...):
        
        model_3_field_1 = models.CharField(...)
        model_2_ref = models.ForeignKey(..., related_name = 'model_3_ref')
    

    serializers.py

    class Model_1_Serializer(...):
    
        # list of model_3_field_1s
        model_3_field_1s = serializers.SlugRelatedField(
            many = True,
            read_only = True,
            slug_field = 'model_3_field_1',
            source = 'model_2_ref.model_3_ref'
        )
        
        # model_3_field_1 as just a string:
        model_3_field_1 = serializers.SlugRelatedField(
            read_only = True,
            slug_field = 'model_3_field_1',
            source = 'model_2_ref.model_3_single_ref'            
        )