Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I serialize a queryset from an unrelated model as a nested serializer?

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?

like image 217
Henry Goddard Avatar asked Mar 14 '17 00:03

Henry Goddard


People also ask

What is the difference between serializer and model serializer?

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.

How do you make a serializer?

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.

Which class allows you to automatically create a serializer?

The ModelSerializer class provides a shortcut that lets you automatically create a Serializer class with fields that correspond to the Model fields.

What is serializing in Django?

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).

Can I use nested serializers in the rest framework?

Here I’m going to use nested serializers. The serializers in the REST framework work very similarly to Django’s Form and ModelForm classes.

How to serialize a queryset or list of objects?

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.

How to serialize multiple objects at once?

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.

How do I pass a none value to a nested 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.


1 Answers

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
like image 121
ChidG Avatar answered Oct 06 '22 19:10

ChidG