如何更改 Django Rest Framework 中的视图集检索响应?

How to change viewset retrieve response in Django Rest Framework?

我目前正在开发一个使用 API 作为大学项目后端的 Web 应用程序。

而且我读到 DRF 是开发和部署 API 的最快和最简单的方法,我已经遵循了他们的整个官方

文档,我似乎不明白如何在他们的 ViewSet 和 Serializer 中执行以下操作。

这是我的 API 的一个端点,称为机场。

美国可用的所有机场

Returns json/csv link 美国可用机场列表。

显示机场信息

Returns 所有 link 到在特定机场运营的航空公司, link 到特定月份的相关统计数据和年份还有一条link到机场的路线。如果未指定年份或月份,则默认为最近的日期。

/airports/:id

GET

{
    "airport": {
      "code": "PHL",
      "name": "Philadelphia, PA: Philadelphia International",
      "id": 123,
      "url": "/airports/123"
    },
    "routes_link": "/airports/123/routes",
    "carriers": [
        {
          "id": 124,
          "url": "/carriers/124?airport_id=123",
          "statistics_url":"/airports/1carrier=124&statistics='flights'"
        },
        .
        .
        .
      ]
}

我能够执行 /airports 正确列出数据库中的所有可用机场,但是在使用 ViewSet 时,我不知道如何 "customize" 在尝试仅检索有关一个机场的信息时做出响应由 id 指定,在应用程序中,路由将动态生成,我打算添加到响应主体而不是模型中的另一个字段。

型号:

class Carrier(models.Model):
    code = models.CharField(max_length=10)
    name = models.TextField()
    #airports = models.ManyToManyField(Airport) 

    def __str__(self):
        return self.name

class Airport(models.Model):
    code = models.CharField(max_length=10)
    name = models.TextField()
    carriers = models.ManyToManyField(Carrier, related_name='airports')

    def __str__(self):
        return self.name

序列化程序:

class AirportSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = models.Airport
        fields = ('id', 'name', 'code', 'url')

class CarrierSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = models.Carrier
        fields = ('id', 'name', 'code', 'url')

查看:

class AirportList(viewsets.ModelViewSet):
    queryset = models.Airport.objects.all()
    serializer_class = AirportSerializer
    # @Override something here?

有人告诉我如何使用 DRF 或任何类型的学习来解决这个问题 material 我可以使用吗?

如果您想修改 ModelViewset 的 retrieve 功能,您可以覆盖它的 retrieve 方法并做任何您想做的事。 mixin'slink

class AirportList(viewsets.ModelViewSet):
    queryset = models.Airport.objects.all()
    serializer_class = AirportSerializer
    def retrieve(self, request, *args, **kwargs):
        # do your customization here
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

如何探索 DRF

我认为管理任何新事物的最佳方式是他们的代码库。对于 ModelViewset,您应该从 viewslink 开始,探索它提供的功能以及我如何自定义它们。

如上面提到的@ 你需要覆盖 retrieve 方法,但是要进行自定义响应你需要在 Try Except 块中包含 self.get_object(),如没有它,如果 get_object 失败,它将回退到默认响应,并且没有机会自定义它。
所以你可以使用类似的东西......

首先是自定义响应 class(例如失败案例)

class ErrorResponse(Response):
    def __init__(self, *args, **kwargs):
        super(ErrorResponse,self).__init__(*args, **kwargs)
        self.status_code = 404
        self.data = {
            'success': False,
            'message': args[0].get('message')
        }

retrieve方法

def retrieve(self, request, *args, **kwargs):
        try:
            instance = self.get_object()
        except Exception as e:
            return ErrorResponse({'message':str(e)})
        else:
            #any additional logic
            serializer = self.get_serializer(instance)
            return Response({'data': serializer.data})

这可能不是问题的确切解决方案,但这是我的解决方案,您默认定义了 lookup_field = "uuid",但您还想使用 slug 进行查找而不定义新的 url 配置(也许你对 ViewSet 使用 DefaultRouter)。

class MyViewSet(ModelViewSet):
    lookup_field = "uuid"

    def get_object(self):
        queryset = self.get_queryset()             # Get the base queryset
        queryset = self.filter_queryset(queryset)  # Apply any filter backends
        lookup_value = self.kwargs["uuid"]
        if is_valid_uuid(lookup_value):
            filter = dict(uuid=lookup_value)
        else:
            filter = dict(slug=lookup_value)
        obj = get_object_or_404(queryset, **filter)  # Lookup the object
        self.check_object_permissions(self.request, obj)
        return obj