【问题标题】:Django Rest Framework - OPTIONS request - Get foreign key choicesDjango Rest Framework - OPTIONS 请求 - 获取外键选择
【发布时间】:2018-03-17 09:51:02
【问题描述】:

假设我在 Django 中有两个模型,并且我使用标准视图集和序列化器来公开端点。

ModelA 有一个指向 ModelB 的 ForeignKey 字段。当我向 ModelA 端点发出 OPTIONS 请求时,它只是将其列为一个字段,如下所示:

"actions": {
    "POST": {
        "pk": {
            "type": "integer",
            "required": false,
            "read_only": true,
            "label": "ID"
        },
        "created": {
            "type": "datetime",
            "required": false,
            "read_only": true,
            "label": "Created"
        },

        "foreign_key_field": {
            "type": "field",
            "required": true,
            "read_only": false,
            "label": "Wcp"
        },
    }
}

我希望它有一个“选择”属性,可以下拉模型 B 的每个实例。这样,在我的 Angular 前端,我可以创建所有选择的下拉列表。

我想我需要创建一个新的 MetaData 类或其他东西。但我找不到任何可靠的方法来做到这一点。我还认为此功能在 DRF 3.X 中发生了变化,因此互联网上的旧答案不再有用。

干杯, 院长

【问题讨论】:

    标签: python django django-rest-framework


    【解决方案1】:

    我也没有一个完美的答案,但我实现这一点的方法是将 json 项目映射到它们的 id 并存储这样的集合(角度):

    $scope.nodes = response.data; //original data retrieved from django
    $scope.nodesIds = response.data.map(function (v) { return v.id; }); //particular ids
    

    这样做,您可以通过以下方式在 ng-options 中使用该映射:

    <select ng-model="node_start" ng-options="node for node in nodesIds" />
    

    有更好的想法吗?

    //经过深思熟虑(原来这是‘手动’的做法)

    from rest_framework.metadata import SimpleMetadata
    class MyMetadata(SimpleMetadata):
        def get_serializer_info(self, serializer):
            orderedDict = super().get_serializer_info(serializer)
            orderedDict['foreign_key_field']['choices'] = [x.id for x in Node.objects.all()]
            return orderedDict
    
    class ViewSet(ModelViewSet):
        metadata_class = MyMetadata
    

    如果它适合你,请告诉我:)

    //最后(更改默认 DRF 代码的智能方法)

    如果你想要它完全自动,你所要做的就是在 metadata.py 中添加三行代码:

    在顶部:

    from rest_framework.relations import PrimaryKeyRelatedField
    

    在 get_field_info 方法中:

    if type(field) is PrimaryKeyRelatedField:
        field_info['choices'] = [x.id for x in field.queryset.all()]
    

    【讨论】:

    • 嗯,我正计划解决 Django 方面的问题。我知道我需要对 DRF 进行一些更改 - 可能是处理选项请求的元数据类
    • 不简单的 ng-options="node.id as node.id for node in nodes" 满足您的需求吗?也许有些事情我不清楚,但我不明白为什么不按他们的 id 存储外键?
    • 我使用的是 Angular 4,而且这与 DRF 如何处理选项无关。
    • 好的。我想到的是创建你自己的类,从默认的 SimpleMetadata 派生——在这个类中,你需要重写确定元数据方法并在那里添加选择属性。为我工作。我应该在另一个答案中发布 sn-p 吗?
    • 请。那很好啊! ?
    【解决方案2】:

    感谢@detoix 提示,我解决了这个问题:

    from rest_framework.relations import ManyRelatedField
    from rest_framework.metadata import SimpleMetadata
    
    
    class MyMetaData(SimpleMetadata):
    
        def get_field_info(self, field):
            field_info = super(MyMetaData, self).get_field_info(field)
            if isinstance(field, ManyRelatedField):
                field_info['choices'] = field.get_choices()
            return field_info
    

    在views.py中:

    class ViewSet(ModelViewSet):
        metadata_class = MyMetadata
    

    【讨论】:

      【解决方案3】:

      对@ralfzen 他的回答进行了一些改进以改进序列化。 还需要使用 RelatedField 而不是 ManyRelatedField

      from django.utils.encoding import force_text
      from rest_framework.views import APIView
      from rest_framework.metadata import SimpleMetadata
      from rest_framework.relations import ManyRelatedField, RelatedField
      
      
      class MyMetaData(SimpleMetadata):
      
          def get_field_info(self, field):
              field_info = super(MyMetaData, self).get_field_info(field)
              if isinstance(field, (RelatedField, ManyRelatedField)):
                  field_info['choices'] = [
                      {
                          'value': choice_value,
                          'display_name': force_text(choice_name, strings_only=True)
                      }
                      for choice_value, choice_name in field.get_choices().items()
                  ]
              return field_info
      
      
      class MyView(APIView):
          metadata_class = MyMetaData
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-10-13
        • 1970-01-01
        • 1970-01-01
        • 2018-05-30
        • 1970-01-01
        • 2017-09-12
        • 2014-10-03
        • 1970-01-01
        相关资源
        最近更新 更多