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

时间:2019-03-13 17:08:45

标签: django python-3.x django-rest-framework django-views api-design

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

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

文档,我似乎不太了解如何在他们的ViewSet和Serializer中进行以下操作。

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

美国所有可用的机场

返回到美国可用机场的链接的json / csv列表。

  • URL

    /airports

  • 方法:

    GET

  • 成功响应:

    • 代码: 200
      内容:

      [
        {
            "airport": {
                "code": "PHL",
                "name": "Philadelphia, PA: Philadelphia International",
              "id": 123,
                "url": "/airports/123"
            },
        {
            "airport": {
                "code": "AHR",
                "name": "American Hour Rapid",
            "id": 125,
                "url": "/airports/125"
        }
        .
        .
        .
      ]
    

显示机场信息

返回到特定机场运营的承运人的所有链接,到特定月份和年份的相关统计信息的链接以及到机场航线的链接。如果万一未指定年份或月份,则默认值为最近的日期。

  • URL

/airports/:id

  • 方法:

GET

  • URL参数

    必填:

    id=[integer]

  • 成功响应:

{
    "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时,当我尝试仅检索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或我可以使用的任何学习材料来实现这一目标?

2 个答案:

答案 0 :(得分:2)

如果您想修改ModelViewset的retreive功能,则可以覆盖它的retreive方法,并做您想做的事情。 mixin's link

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,您应该从views link开始,探索它提供的功能以及如何自定义它们。

答案 1 :(得分:0)

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

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

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})