【问题标题】:Enumerating model choices in a Django Rest Framework serializer在 Django Rest Framework 序列化程序中枚举模型选择
【发布时间】:2015-05-28 14:04:19
【问题描述】:

我有一个使用 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 Web 应用程序。在我的 Angular Web 应用程序中,我想要一个包含所有这些选项的组合框小部件。不是整数,而是文本选择,例如“模糊”、“标准问题”等。

现在,我可以将组合框手动编码到 Angular 应用程序中,但是本着 DRY 的精神,是否可以编写一个仅返回这些选项(即 QUESTION_TYPES 对象)的 DRF 序列化程序,以便我可以填充组合带有 ReST 查询的框?

“可能”,我想我的意思是“简单而优雅”。也许我也指“ReSTful”。 (这样做是不是 ReSTful?)

只是想知道。 . .

谢谢

约翰

【问题讨论】:

  • 通过 URL 公开该模型。在您的 AngularJS 控制器中执行 $http.get() 以检索所有值。将这些值粘贴到 $scope 变量上(称为 foo)。然后将 foo 引用为 ng-options 元素的 ng-options 属性。
  • 按照我阅读您的建议的方式,这只是一个常规的 API 调用,它会返回表中的所有行,不是吗?我不想要返回表格行的 API——我已经有了。我想要一个简单地返回 QUESTION_TYPES - 11 行数据的 API,即使模型的表本身是空的。我无法从表行可靠地重建 QUESTION_TYPES,因为可能没有任何给定类型的表行。
  • 啊。然后您可以创建一个模型,该模型确实具有该类型的所有值。

标签: django angularjs rest django-rest-framework


【解决方案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 in DRF3,它应该支持 @ 987654324@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

演示:

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}

【讨论】:

  • 有人对此进行了测试并使其正常工作吗? DRF 不喜欢source=QUESTION_NAMES 位;错误地说它无法拆分元组。
  • 我采用了另一种方法。我真的希望ListField 能成为此类问题的答案,但我错了。阅读ListField 上的源代码,我不确定在哪里使用它。
【解决方案2】:

我通过为仅使用 GET 动词的选择创建一个 API 端点来实现这一点。

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

【讨论】:

    【解决方案3】:

    如果您将ModelViewSetModelSerializer 结合使用,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
                    },
                    //...
            }
        }
    }
    

    您可以遍历qtype 上的choices 属性以获取所有可用选项。

    要更加熟悉这个主题,您可以阅读:Metadata

    【讨论】:

      猜你喜欢
      • 2013-11-27
      • 1970-01-01
      • 1970-01-01
      • 2015-10-02
      • 2019-01-16
      • 2019-05-25
      • 1970-01-01
      • 1970-01-01
      • 2016-11-14
      相关资源
      最近更新 更多