Enumerating model choices in a Django Rest Framework serializer Enumerating model choices in a Django Rest Framework serializer angularjs angularjs

Enumerating model choices in a Django Rest Framework serializer


I would probably try something like the following:

# models.pyclass Question(models.Model):    QUESTION_NAMES = (        'Blurb',        'Group Header',        'Group Footer',        'Sub-Group Header',        'Sub-Group Footer',        'Save Button',        'Standard Question',        'Text-Area Question',        'Multiple-Choice Question',        'Standard Sub-Question',        'Multiple-Choice Sub-Question')    QUESTION_VALS = (10, 20, 21, 30,                     31, 50, 100, 105, 110,                     120, 130)    QUESTION_TYPES = tuple(zip(QUESTION_VALS, QUESTION_NAMES))    # Personal choice here: I never name attribs after Python built-ins:    qtype = models.IntegerField(default=100,choices=QUESTION_TYPES)

The following doesn't work as I thought it should

(Following was my original intuition on serializing a list of objects, but it did not work. I'm leaving it in here anyway, because it seems like it should work.)

Okay, so we have a way to access the strings on their own, now we just need to serialize them, and for that, I'd probably try to use the ListField in DRF3, which should support the source kwarg, I would think?

# serializers.pyfrom .models import Questionclass YourSerializer(ModelSerializer):    names = serializers.ListField(       child=serializers.CharField(max_length=40),       source=Question.QUESTION_NAMES    )    class Meta:        model = Question        fields = ('names', etc.)

The following does return a list of results

Fallback: use a SerializerMethodField:

from .models import Questionclass YourSerializer(serializers.ModelSerializer):    ...    names = serializers.SerializerMethodField()    def get_names(self, obj):        return Question.QUESTION_NAMES    class Meta:        model = Question

Demo:

In [1]: q = Question.objects.create()Out[1]: <Question: Question object>  In [2]: ser = YourSerializer(q)In [3]: ser.dataOut[3]: {'id': 1, 'names': ['Blurb', 'Group Header', 'Group Footer', 'Sub-Group Header', 'Sub-Group Footer', 'Save Button', 'Standard Question', 'Text-Area Question', 'Multiple-Choice Question', 'Standard Sub-Question', 'Multiple-Choice Sub-Question'], 'qtype': 100}


if you use a ModelViewSet in combination with a ModelSerializer, the OPTIONS request will return metadata that you can use to get the choice options.

from models import Questionfrom rest_framework import serializersclass QuestionSerializer(serializers.ModelSerializer):    class Meta:        model = Questionfrom rest_framework.viewsets import ModelViewSetclass QuestionChoicesViewSet(ModelViewSet):    queryset = Question.objects.all()    serializer_class = QuestionSerializer

This will give you a response that includes the actions attribute, that might look something like this:

"actions": {    "POST": {        "id": {            "type": "integer",            "required": false,            "read_only": true,            "label": "ID"        },        "qtype": {            "type": "choice",            "required": false,            "read_only": false,            "label": "Qtype",            "choices": [                {                    "display_name": "Blurb",                    "value": 10                },                {                    "display_name": "Group Header",                    "value": 20                },                {                    "display_name": "Group Footer",                    "value": 21                },                {                    "display_name": "Sub-Group Header",                    "value": 30                },                //...        }    }}

You can iterate over the choices attribute on qtype to get all of the available choices.

To get more familiar with this topic you can read: Metadata


I accomplished this by making an API endpoint for the choices which only use the GET verb.

models.py

QUESTION_TYPES = (    (10,'Blurb'),    (20,'Group Header'),    (21,'Group Footer'),    (30,'Sub-Group Header'),    (31,'Sub-Group Footer'),    (50,'Save Button'),    (100,'Standard Question'),    (105,'Text-Area Question'),    (110,'Multiple-Choice Question'),    (120,'Standard Sub-Question'),    (130,'Multiple-Choice Sub-Question'))class Question(models.Model):    type = models.IntegerField(default=100,choices=QUESTION_TYPES)

viewsets.py

from models import QUESTION_NAMES, Questionfrom rest_framework import serializersclass QuestionSerializer(serializers.ModelSerializer):    type = serializers.ChoiceField(choices=QUESTION_NAMES, default=100)    class Meta:        model = Questionfrom rest_framework.response import Responsefrom rest_framework.views import APIViewclass QuestionChoicesViewSet(APIView):    def get(self, request):        return Response(QUESTION_NAMES)from rest_framework import viewsetsclass QuestionViewSet(viewsets.ModelViewSet):    queryset = Question.objects.all()    serializer_class = QuestionSerializer