假设我在 Django 中有两个模型,我正在使用标准视图集和序列化程序来公开端点。
模型 A 有一个指向模型 B 的"外键"字段。当我对 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 前端中,我可以创建所有选择的下拉列表。
我想我需要创建一个新的元数据类或其他东西。但我找不到任何可靠的方法来做到这一点。我也认为此功能在 DRF 的 3.X 中发生了变化,因此互联网上的旧答案不再有帮助。
干杯Dean
对@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
我也没有一个完美的答案,但我实现这一目标的方法是将 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()]
由于这样的提示@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