Перечисление выбора модели в сериализаторе Django Rest Framework
У меня есть модель, которая использует поле выбора Django, например:
class Question(models.Model):
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')
)
type = models.IntegerField(default=100,choices=QUESTION_TYPES)
Я использую Django Rest Framework, чтобы представить эту модель как API для веб-приложения Angular. В моем веб-приложении Angular мне нужен виджет со списком со всеми этими вариантами. Не целые числа, а текстовые варианты, такие как "реклама", "стандартный вопрос" и т.д.
Теперь я могу скомпоновать поле со списком в приложение Angular, но в духе DRY, возможно ли написать сериализатор DRF, который просто возвращает эти варианты (то есть объект QUESTION_TYPES), поэтому я могу заполнить в поле со списком с запросом ReST?
И под "возможным", я думаю, я имею в виду "простой и элегантный". И, может быть, я также имею в виду "ReSTful". (Это ReSTful, чтобы сделать это таким образом?)
Просто интересно.,.
Спасибо
Джон
Ответы
Ответ 1
Вероятно, я бы попытался сделать что-то вроде следующего:
# models.py
class 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)
Следующее не работает, поскольку я думал, что он должен
(Следующей была моя первоначальная интуиция по сериализации списка объектов, но это не сработало. Я все равно оставляю ее здесь, потому что похоже, что она должна работать.)
Итак, у нас есть способ получить доступ к строкам самостоятельно, теперь нам просто нужно их сериализовать, и для этого я, вероятно, попытаюсь использовать ListField
в DRF3, который должен поддерживать source
kwarg, я бы подумал?
# serializers.py
from .models import Question
class YourSerializer(ModelSerializer):
names = serializers.ListField(
child=serializers.CharField(max_length=40),
source=Question.QUESTION_NAMES
)
class Meta:
model = Question
fields = ('names', etc.)
Ниже приведен список результатов
Возврат: используйте SerializerMethodField
:
from .models import Question
class 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.data
Out[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}
Ответ 2
если вы используете ModelViewSet
в сочетании с ModelSerializer
, запрос OPTIONS
возвращает метаданные, которые вы можете использовать для получения параметров выбора.
from models import Question
from rest_framework import serializers
class QuestionSerializer(serializers.ModelSerializer):
class Meta:
model = Question
from rest_framework.viewsets import ModelViewSet
class QuestionChoicesViewSet(ModelViewSet):
queryset = Question.objects.all()
serializer_class = QuestionSerializer
Это даст вам ответ, который включает атрибут actions
, который может выглядеть примерно так:
"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
},
//...
}
}
}
Вы можете выполнить итерацию по атрибуту choices
на qtype
, чтобы получить все доступные варианты.
Чтобы больше узнать об этом, прочитайте: Metadata
Ответ 3
Я достиг этого, создав конечную точку API для выбора, в котором используется только GET-глагол.
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, Question
from rest_framework import serializers
class QuestionSerializer(serializers.ModelSerializer):
type = serializers.ChoiceField(choices=QUESTION_NAMES, default=100)
class Meta:
model = Question
from rest_framework.response import Response
from rest_framework.views import APIView
class QuestionChoicesViewSet(APIView):
def get(self, request):
return Response(QUESTION_NAMES)
from rest_framework import viewsets
class QuestionViewSet(viewsets.ModelViewSet):
queryset = Question.objects.all()
serializer_class = QuestionSerializer