【问题标题】:Add multiple models and custom fields to a json response in Django Rest Framework将多个模型和自定义字段添加到 Django Rest Framework 中的 json 响应
【发布时间】:2020-08-25 12:16:01
【问题描述】:

我是 Python/Django 编程的新手,在我正在做的个人项目中遇到了一些问题。我的问题是我想根据我的应用程序的不同模型返回自定义响应,其中一些值将来自自定义查询,而其他值是模型本身的一部分。

所以,我的应用中有以下模型(删除了一些字段以使帖子不会太长):

class Parking(models.Model):
    google_id = models.CharField(max_length=100)
    short_name = models.CharField(max_length=100)
    long_name = models.CharField(max_length=300)
    price = models.DecimalField(max_digits=4, decimal_places=2, null=True, blank=True)

class ParkingLot(models.Model):        
    parking = models.ForeignKey(Parking, on_delete=models.CASCADE, null=False, related_name='parkinglots')
    size = models.ForeignKey(Size, on_delete=models.DO_NOTHING, null=False, related_name='size')
    width = models.DecimalField(max_digits=3, decimal_places=2, null=True, blank=True)
    height = models.DecimalField(max_digits=3, decimal_places=2, null=True, blank=True)

class ParkingAvailability(models.Model):
    parkinglot = models.ForeignKey(ParkingLot, on_delete=models.CASCADE, null=False, related_name='availability')
    available = models.BooleanField(null=False, blank=False)
    from_hour = models.TimeField(auto_now=False, auto_now_add=False, default='09:00:00')
    to_hour = models.TimeField(auto_now=False, auto_now_add=False, default='21:00:00')

这些模型是我的数据库表的精确表示。都好。我的问题是,现在我想做一个自定义 json 响应,这需要对这些表运行查询,但不显示整个对象,在某些情况下,基于过滤器的自定义字段或我需要在表上运行的操作(对于例如,基于parking_id 和size_id 的停车场数量)。所以,让我们假设我需要一些看起来像这样的东西:

[
    {
        "id": 1,
        "google_id": "JSDKKLAD888737283",
        "short_name": "Fernandez Albano",
        "long_name": "Comunidad Fernandez Albano",
        "price": 18.5,
        "parkinglots": 88, 
        "hours": {
            "from_hour": "09:00:00",
            "to_hour": "21:00:00",
        }
    }
]

前 4 个 json 值来自 Parking 模型,字段parkinglots 是带有一些过滤器(parking_id,size_id)的parkinglots 模型的.count()。可用性是来自 ParkingAvailability 模型的自定义查询,我可以通过我的 parklot_id 值访问它。

到目前为止,我有这样的东西,但在我看来这不太好:

class parkingList(APIView):
    def get(self, request, format=None):
        parkinglotNumber=ParkingLot.objects.filter(parking_id = 2, size_id = 1).count()
        parkinglot = ParkingLot.objects.filter(parking_id = 2, size_id = 1)
        hours = ParkingAvailability.objects.filter(parkinglot__in=parkinglot, available=True).aggregate(Min('from_hour'), Max('to_hour'))

        content = {
            'parkinglots_number': parkinglotNumber,
            'hours': hours
        }

        return Response(content)

所以,我的问题是:

  1. 可以这样运行查询吗?如果想将(例如)我的停车场模型完全添加到该响应中,我需要运行另一个查询,例如“ParkingLot.objects.filter(parking_id = 2, size_id = 1)”并将其添加到我的停车响应中?
  2. 我的序列化程序序列化了所有模型字段,但在这种情况下我不使用它,可以在没有序列化程序类的情况下返回它吗?
  3. 如何构建复杂的 json 响应?就像在这种情况下,我需要从不同的模型和自定义字段向我的 json 添加不同的部分。

感谢您的帮助!对不起,我的英语不是我的母语。

PS:我的序列化程序类返回我的模型的所有信息。类的一部分是这样的:

class ParkingLotSerializer(serializers.ModelSerializer):
    size = SizeSerializer(many=False, read_only=True)
    availability = ParkingAvailabilitySerializer(many=True, read_only=True)
    class Meta:
        model = ParkingLot
        fields = ['id', 'price', 'floor', 'number', 'width', 'size', 'availability']

class ParkingSerializer(serializers.ModelSerializer):
    adress = AdressSerializer(many=False, read_only=True)
    parkinglots = ParkingLotSerializer(many=True, read_only=True)
    class Meta:
        model = Parking
        fields = ['id', 'google_id', 'price', 'short_name', 'long_name', 'adress', 'parkinglots' ]

【问题讨论】:

    标签: json django django-models django-rest-framework django-views


    【解决方案1】:

    您的其他相关模型应该可以通过Parking 对象通过他们的related_name 获得。例如,要访问相关的ParkingLots,您可以使用obj.parkinglots.count()。如果需要,您甚至可以进一步过滤,例如 obj.parkinglots.filter(size_id=1).count()。因此,您可以使用SerializerMethodField

    class ParkingSerializer(serializers.ModelSerializer):
        ...
        parkinglots_count = serializers.SerializerMethodField()
    
        ...
        def get_parkinglots_count(self, obj):
            return obj.parkinglots.count()
    

    您可以将该字段重命名为对您的 api 有意义的任何名称,但使用的方法应为 get_<FIELD_NAME>,并确保将其添加到您的 fields Meta 属性中!如果您想做更多的自定义字段,这可以类似地工作。


    解决您的问题:

    可以这样运行查询吗?如果想将(例如)我的停车场模型完全添加到该响应中,我将需要运行另一个查询,例如“ParkingLot.objects.filter(parking_id = 2, size_id = 1)”并将其添加到我的停车响应中?

    这可能会导致所谓的n+1 问题,因为您需要为每个序列化程序实例运行一个查询。因此,在您的列表中,如果您返回 25 个停车场,您可能会运行 25 个计数查询。您可以通过执行 annotating to your queryset 之类的操作来解决此问题,以帮助减少查询计数。就是说,是的,没关系!这样做真的很常见。

    我的序列化器序列化所有模型字段,但在这种情况下我不使用它,可以在没有序列化器类的情况下返回它吗?

    我想我明白了。你问的是序列化你不使用的字段吗?你绝对可以做到。如果您对动态关闭字段感兴趣(无论是在运行中,还是在使用序列化程序时),请查看django-restql 之类的内容(对不起,无耻的插件!)。

    如何构建复杂的 json 响应?就像在这种情况下,我需要从不同的模型和自定义字段向我的 json 添加不同的部分。

    只要你传入的数据有你需要的,你就可以做一个序列化器。制作一个序列化程序并不少见,您只需将字典传递给它以便在您的 api 上返回它。序列化程序不一定需要绑定到模型,并且如答案中所述,您可以根据需要制作自己的自定义字段来工作。 Django Rest Framework 有一个 good tutorial 涉及非模型序列化程序。

    【讨论】:

    • 感谢您提供如此完整的答案!我已经实施了您回复的第一部分并且效果很好!我还有两件事:如果过滤器来自我的视图(例如,作为我的 api 的参数),我应该在哪里制作过滤器以实现“ParkingLot.objects.filter(parking_id = {{parameter}}, size_id = {{参数}})"?这就是为什么我在我看来要实现它。
    • 这可能是注释的来源,或者您可以将其包含在您的序列化程序上下文中并在那里访问它。序列化器从视图上的get_serializer_context 获取上下文,并且可以通过self.context 在其序列化器方法字段中访问它。它就像一本字典。在使用之前请小心检查上下文中是否存在(以防您在其他地方重用此序列化程序并且不想更改上下文)。
    猜你喜欢
    • 1970-01-01
    • 2013-01-27
    • 1970-01-01
    • 1970-01-01
    • 2013-01-13
    • 2014-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多