21

I'm trying to add a nested serializer to an existing serializer based on some criteria of the parent model, not a foreign key. The use case is to return a 'Research' object with an array of 'ResearchTemplate' objects that are identified by filtering on a Postgres ArrayField.

Models

class Research(TimeStampedModel):
 category = models.CharField(max_length=100, choices=RESEARCH_TEMPLATE_CATEGORIES, default='quote')
 body = models.CharField(max_length=1000, blank=True, default='') #The body of text comprising the nugget
 additionaldata = JSONField(null=True) # all the varying values to be merged into a wrapper
 def __str__(self):
 return self.body
 class Meta:
 ordering = ('created',)
class ResearchTemplate(TimeStampedModel):
 template = models.TextField(blank=True, default='')
 category = models.CharField(max_length=100, choices=RESEARCH_TEMPLATE_CATEGORIES, default='quote')
 mergefields = ArrayField(models.CharField(max_length=200), blank=True)
 def save(self, *args, **kwargs):
 merges = re.findall("{{(.*?)}}", self.template) #get all the template names from within the mustaches
 self.mergefields = list(set(merges)) #TODO: Make Unique
 super(TimeStampedModel, self).save(*args, **kwargs)
 def __str__(self):
 return self.wrapper
 class Meta:
 ordering = ('created',)

Serializers

class ResearchSerializer(serializers.ModelSerializer):
 templates = ResearchTemplateSerializer(many=True)
 class Meta:
 model = Research
 fields = ('id', 'created', 'speaker', 'body', 'templates')
class ResearchTemplateSerializer(serializers.RelatedField):
 def get_queryset(self, values):
 return ResearchTemplate.objects.filter(mergefields__contained_by=['django']) #This must an array of keys from the Research object's JSON field
 class Meta:
 model = ResearchTemplate
 fields = ('id', 'template')

I've been able to nest serializers when there is a foreign key mapping them, however I am unable to do so with a custom queryset. Perhaps I'm not thinking about this properly, and I require some form of 'relationship' field on the Research model.

How can I nest a serialized list of all rows that are returned from a filter with values specified from the parent model?

Peter Mortensen
31.4k22 gold badges110 silver badges134 bronze badges
asked Mar 14, 2017 at 0:23

1 Answer 1

45

You can use DRF's SerializerMethodField.

Define your ResearchTemplateSerializer as a normal ModelSerializer, not as a RelatedField.

Then replace your ResearchSerializer with this:

class ResearchSerializer(serializers.ModelSerializer):
 templates = serializers.SerializerMethodField()
 class Meta:
 model = Research
 fields = ('id', 'created', 'speaker', 'body', 'templates')
 def get_templates(self, obj):
 values = obj.get_values() # whatever your filter values are. obj is the Research instance
 templates = ResearchTemplate.objects.filter(mergefields__contained_by=values) # Or whatever queryset filter
 return ResearchTemplateSerializer(templates, many=True).data
funnydman
11.8k4 gold badges51 silver badges67 bronze badges
answered Mar 14, 2017 at 2:25
Sign up to request clarification or add additional context in comments.

3 Comments

I was not aware of SerializerMethodField() thanks for this! The answer to a lot of my issues.
I searched for a quite a while to find this, thank you.
Thank you! Just to add, I did not know that the many=True was important for this to work. Initially, the values were still null. Only when I added the many=True did it work! In hindsight, yes the query might return several values, but my use case only returned 1. If you are only returning 1 value, use .first(): templates = ResearchTemplate.objects.filter(mergefields__contained_by=values).first() then you can return without the many=True: return ResearchTemplateSerializer(templates).data

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.