DRF 查询集返回特定字段

时间:2021-04-08 13:25:26

标签: python django django-rest-framework

我正在使用这种结构创建一个 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}

2 个答案:

答案 0 :(得分:1)

  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)})
  1. 没有附加视图:

不需要额外的视图或序列化程序。覆盖 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

相关问题