我正在使用这种结构创建一个 django rest 框架应用程序(假设导入是正确的,所以我在下面的代码中省略了它们。
models.py:
class Door(models.Model):
type = models.CharField(max_length=40)
color = models.CharField(max_length=40)
serializers.py:
class DoorSerializer(serializers.ModelSerializer):
class Meta:
model = Door
fields = ['type', 'color']
views.py:
class DoorViewSet(viewsets.ModelViewSet):
serializer_class = DoorSerializer
queryset = Door.objects.all()
def get_queryset(self, *args, **kwargs):
queryset = Door.objects.all()
parameter = self.request.query_params.get('type', '')
if parameter:
return queryset.filter(type=parameter)
else:
return queryset
到目前为止,它的行为符合预期,当我对 localhost/Doors
进行 api 调用时,它会列出所有的门。当我对 localhost/Doors/?type=big
进行 api 调用时,它会列出所有在其“类型”字段中具有“大”值的门。
我想添加的是另一个参数检查,它将返回数据库中存在的所有唯一门类型的列表。这可以在 manage.py shell 中使用:Door.objects.all().values('type').distinct()
我的尝试是对 views.py 进行以下修改:
...
parameter = self.request.query.params.get('type', '')
unique = self.request.query.params.get('unique', '')
if parameter:
...
elif unique:
return Door.objects.all().values('type').distinct()
...
我的假设是,当我调用 Door.objects.all().values('type').distinct()
时,这将返回与 localhost/Doors/?unique=whatever
相同的值
但是我收到错误消息:“尝试获取序列化程序 color
上的字段 DoorSerializer
的值时出现 KeyError。\n序列化程序字段可能命名不正确,并且与上的任何属性或键不匹配dict
实例。\n原始异常文本是:'color'。"
我假设这意味着序列化器需要一个对象或一个包含相应模型的所有字段的对象列表。
有什么办法可以通过修复视图来规避这个问题,还是应该创建一个不同的序列化程序?在任何一种情况下,由于我对 DRF / django 差异感到非常困惑,而且我可能无法遵循抽象说明,您能否提供解决该问题的代码解决方案?另外,在很可能我的假设完全不成立的情况下,您能否解释一下导致问题的原因?感谢您的时间!
编辑以阐明所需的结果:
假设我的数据库有 4 个门,它们是:
{
"id": 1,
"type": "big",
"color": "blue"
},
{
"id": 2,
"type": "big",
"color": "yellow"
},
{
"id": 3,
"type": "small",
"color": "green"
},
{
"id": 4,
"type": "big",
"color": "red"
},
我想向某个网址发出 get
请求,例如 localhost/Doors/?unique=Yes
并让 api 返回给我列表 {"big", "small}
答案 0 :(得分:1)
from rest_framework.decorators import api_view
from rest_framework.response import Response
@api_view()
def Unique_door_types(request):
types = Door.objects.values_list('type', flat=True).distinct()
return Response({"types": list(types)})
不需要额外的视图或序列化程序。覆盖 list
方法。请注意,这更像是一种技巧,而不是一种好的编程方式。
from rest_framework.response import Response
class DoorViewSet(viewsets.ModelViewSet):
serializer_class = DoorSerializer
def get_queryset(self, *args, **kwargs):
queryset = Door.objects.all()
parameter = self.request.query_params.get('type', '')
if parameter:
return queryset.filter(type=parameter)
else:
return queryset
def list(self, request):
unique = self.request.query_params.get('unique', '')
if unique:
types = Door.objects.values_list('type', flat=True).distinct()
return Response({"types": list(types)})
return super().list()
答案 1 :(得分:1)
我的建议是创建一个单独的路由,如 /doors/types/
。您可以通过向带有 DoorViewSet
装饰器的 @action
类添加方法来实现此目的。有关如何执行此操作的更多详细信息,请参阅 https://www.django-rest-framework.org/api-guide/viewsets/#marking-extra-actions-for-routing。