Search code examples
pythondjango-rest-frameworkdjango-serializer

Add expandable field to Serializer on Self Related Model


I have got a model of User Details which is Self Related to create the relationship between two users.

Model

class AdvDetails(models.Model):
    user_id = models.UUIDField(primary_key=True,default=uuid.uuid4,editable=False)
    title = models.CharField(max_length=5, choices=[('Mr', 'Mr'), ('Ms', 'Ms'), ('Mrs', 'Mrs'), ('Dr', 'Dr'), ('NA', '')], default='NA')
    first_name = models.CharField(max_length=255)
    last_name = models.CharField(max_length=255)
    email_id = models.EmailField(null=True, blank=True, default=None)
    parent_profile = models.ForeignKey("self", null=True, blank=True)

View Set

class AdvDetailsViewSet(viewsets.ModelViewSet):
    serializer_class = AdvDetailsSerializer
    filter_backends = (filters.SearchFilter,DjangoFilterBackend, filters.OrderingFilter)
    filter_fields = ('email_id,'parent_profile')
    search_fields = (  '^first_name',)

    def get_queryset(self):
        return AdvDetails.objects.all()

Serializer

class AdvDetailsSerializer(serializers.ModelSerializer):

    class Meta:
        model = AdvDetails
        fields = '__all__'

This structure facilitates me to help get the data in the below format

{
  "user_id": "055cbde6-10ea-4558-86fc-1b42624ce760",
  "title": "Mr",
  "first_name": "foo",
  "last_name": "bar",
  "email_id" : "foo@bar.com"
  "parent_profile":"6c429d4c-9fb4-42e5-9d7d-9fc782f81fb0"
}

I would like to modify the serializer in such a way that I would get the data of the parent profile's email_id as below

{
  "user_id": "055cbde6-10ea-4558-86fc-1b42624ce760",
  "title": "Mr",
  "first_name": "foo",
  "last_name": "bar",
  "email_id" : "foo@bar.com",
  "parent_profile":"6c429d4c-9fb4-42e5-9d7d-9fc782f81fb0",
  "parent_email_id" : "parent@email.com"
}

Any help is highly appreciated. I've tried PrimaryKeyRelatedField but it was not solving my problem.


Solution

  • I made a package that allows expanding fields dynamically, on-demand per request: https://github.com/rsinger86/drf-flex-fields

    For your case:

    class AdvDetailsSerializer(FlexFieldsModelSerializer):
        class Meta:
            model = AdvDetails
            fields = ('user_id', 'title', 'first_name', 'last_name', 'email_id', 'parent_profile', 'parent_email_id' )
            expandable_fields = {'parent_profile': '<app_name>.AdvDetailsSerializer'}
    

    Replace <app_name> with the name of the Django app that defines the serializer, so it can be loaded lazily.

    If instead you would like to statically expand a field, you can define that field as a nested serializer:

    class AdvDetailsSerializer(serializers.ModelSerializer):
        parent_profile = ProfileProfileSerializer()
    
        class Meta:
            model = AdvDetails
            fields = (
               'user_id', 
               'title',
               'first_name',
               'last_name', 
               'email_id',
               'parent_profile',
               'parent_email_id'
            )