首页 > 解决方案 > 在 DRF 3.0 中的响应输出中添加额外字段

问题描述

我有以下型号

class Restaurant(models.Model):
    name_of_the_restaurant = models.CharField(max_length=30, blank=True)
    opening_time = models.TimeField(auto_now=False, auto_now_add=False)
    closing_time = models.TimeField(auto_now=False, auto_now_add=False)

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    bio = models.TextField(max_length=500, blank=True)
    city = models.CharField(max_length=30, blank=True)
    country = models.CharField(max_length=30, blank=True)
    postal_code = models.CharField(max_length=30, blank=True)
    birth_date = models.DateField(null=True, blank=True)
    favourite_restaurant = models.ManyToManyField(Restaurant,
                                                  blank=True,
                                                  related_name='favourite_restaurant',
                                                  related_query_name='favourite_restaurant')

我为 Restaurant 模型定义了一个序列化程序,主要是:

class RestaurantSerializer(serializers.ModelSerializer):

    class Meta:
        model = Restaurant
        fields = '__all__'

现在在我的 ViewSet 逻辑中,我正在执行以下操作:

class RestaurantListView(generics.ListAPIView):
    serializer_class = RestaurantSerializer

    def get_queryset(self):
        queryset = {'Error': 'Please pass valid url parameters'}
        city = self.request.query_params.get('city', None)
        postal_code = self.request.query_params.get('postalcode', None)
        country = self.request.query_params.get('country', None)
        if city is not None or postal_code is not None:
            queryset = Restaurant.objects.filter(
                Q(city=city) | Q(pincode=postal_code))
        if country and city is not None and postal_code is None:
            queryset = Restaurant.objects.filter(country=country, city=city)
        return queryset

    def get(self, request, format=None):
        restaurant_qs = self.get_queryset()
        ids_list = [restaurant.id for restaurant in restaurant_qs]
        favourite_restaurant = is_favourite_restaurant(ids_list, self.request.user)
        serializer = RestaurantSerializer(restaurant_qs, many=True)
        return Response(serializer.data)

whereis_favourite_restaurant是一个自定义函数函数,它返回用户最喜欢的餐厅的查询集。现在在这个 GET 请求的输出中,我得到的结果是:

[
    {
        "id": 2,
        "name_of_the_restaurant": "Aniket",
        "opening_time": "14:08:33.413402",
        "closing_time": "22:08:33.413414"
    },
    {
        "id": 3,
        "name_of_the_restaurant": "Aniket-1",
        "opening_time": "14:13:37.656385",
        "closing_time": "22:13:37.656397"
    }
]

而我想要的所需输出是将一个额外的字段附加is_favourite:true到用户之前标记为最喜欢的那家餐厅。因此输出应该是

[
    {
        "id": 2,
        "name_of_the_restaurant": "Aniket",
        "opening_time": "14:08:33.413402",
        "closing_time": "22:08:33.413414",
        "is_favourite": true, 
    },
    {
        "id": 3,
        "name_of_the_restaurant": "Aniket-1",
        "opening_time": "14:13:37.656385",
        "closing_time": "22:13:37.656397"
    }
]

编辑 :

is_favourite_restaurant 函数的定义:

def is_favourite_restaurant(restaurant_qs, user):
    favourite_restaurant_qs = Profile.objects.get(user=user).favourite_restaurant.filter(
        pk__in=restaurant_qs.values_list('id', flat=True))
    return favourite_restaurant_qs

标签: pythondjangodjango-rest-frameworkdjango-serializer

解决方案


您可以使用 SerializerMethodField。SerializerMethodField 允许添加额外的字段,该字段是只读的。

class RestaurantSerializer(serializers.ModelSerializer):
    is_favorite = serializers.SerializerMethodField()

    class Meta:
        model = Restaurant
        fields = ('your', 'fields', 'is_favorite')

    def get_is_like(self, obj):
        return is_favourite_restaurant(obj.id, self.context['request'].user)

通常,ListAPIView 将上下文添加到序列化程序。当您使用您的 create 方法时,您应该手动添加。

serializer = RestaurantSerializer(restaurant_qs, many=True, context={'request': self.request})

上下文允许访问我们从视图发送的一些数据。
由于您没有显示您的 is_favourite_restaurant,我不能说您应该在该功能中做什么。我想您应该将 ids 参数从数组更改为一个 id。

您的回复看起来像

[
    {
        "id": 2,
        "name_of_the_restaurant": "Aniket",
        "opening_time": "14:08:33.413402",
        "closing_time": "22:08:33.413414",
        "is_favourite": True, 
    },
    {
        "id": 3,
        "name_of_the_restaurant": "Aniket-1",
        "opening_time": "14:13:37.656385",
        "closing_time": "22:13:37.656397",
        "is_favourite": False, 

    }
]

def is_favourite_restaurant(restaurant_id, user):
    favourite_restaurant_qs = Profile.objects.get(user=user).favourite_restaurant.filter(
        pk=restaurant_id).exists()
    return favourite_restaurant_qs

推荐阅读