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?
The model serializer is just the same as the above serializer in the sense that it does the same job, only that it builds the serializer based on the model, making the creation of the serializer easier than building it normally. So in other words, explicitly defining CRUD methods (get, post,...) is not required.
Creating a basic Serializer To create a basic serializer one needs to import serializers class from rest_framework and define fields for a serializer just like creating a form or model in Django.
The ModelSerializer class provides a shortcut that lets you automatically create a Serializer class with fields that correspond to the Model fields.
Django's serialization framework provides a mechanism for “translating” Django models into other formats. Usually these other formats will be text-based and used for sending Django data over a wire, but it's possible for a serializer to handle any format (text-based or not).
Here I’m going to use nested serializers. The serializers in the REST framework work very similarly to Django’s Form and ModelForm classes.
To serialize a queryset or list of objects instead of a single object instance, you should pass the many=True flag when instantiating the serializer. You can then pass a queryset or list of objects to be serialized.
The ListSerializer class provides the behavior for serializing and validating multiple objects at once. You won't typically need to use ListSerializer directly, but should instead simply pass many=True when instantiating a serializer.
If a nested representation may optionally accept the None value you should pass the required=False flag to the nested serializer. Similarly if a nested representation should be a list of items, you should pass the many=True flag to the nested serializer.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With