有没有办法将自定义数据添加到对使用Django REST Framework的ModelViewSet的视图的列表API调用返回的结果数据中?
我的ModelViewSet视图附加到Items模型。
除了LIST API调用返回的Items列表之外,我想查询一个单独的Seen模型,并使用Items返回每个Item被查看的次数。
我还想在返回的数据中添加“当天的报价”。
我搜索过DRF文档,但未能找到有关如何执行此操作的提示。
这是我的代码。 Item序列化器是:
class ItemSerializer(serializers.ModelSerializer):
username = serializers.SerializerMethodField()
def get_username(self, obj):
"""
Note that query params can be accessed here as follows:
request = self.context['request']
print request.query_params.get['fields']
"""
value = str(obj.owner)
return value
def get_keywords(self, obj):
value = str(obj.keywords)
return value
class Meta:
model = Item
fields = ('id', 'url', 'item_type', 'title', 'credits_applied', 'credits_left', 'credits_gifted', 'username', 'liked', 'disliked')
View看起来像这样:
class ItemViewSet(viewsets.ModelViewSet):
queryset = Item.objects.all().order_by('-date_added')
serializer_class = ItemSerializer
# When POSTing (creating) a new item add appropriate User instance to the serializer
def perform_create(self, serializer):
creator = User.objects.get(pk=self.request.data['owner_id'])
serializer.save(owner=creator)
def get_queryset(self):
this_user = self.request.query_params.get('user', None)
restrict_to_items_from_user_id = self.request.query_params.get('from', None)
quantity = self.request.query_params.get('num', 20)
# Use query params to determine what to return
if restrict_to_items_from_user_id is not None:
# API: /api/items/from=<id>
# Return items owned by a specific user. Used by someone to get a list of the items they have added
queryset = Item.objects.filter(owner=restrict_to_items_from_user_id, active=True).order_by('-date_added')[0:int(quantity)]
elif this_user is not None:
# API: /api/items/user=<id>
# Return unseen items for the given user's browse feed
# queryset = Item.objects.all().order_by('-date_added')[0:int(quantity)]
queryset = Item.objects.filter(active=True, credits_left__gt=0).exclude(pk__in=Seen.objects.filter(user_id=this_user).values_list('item_id', flat=True))[0:int(quantity)]
# :TO DO: Add option to list the items a user has liked!
else:
# API: /api/items
# Return items not specific to a particular user (used for testing the app or when user wants to see stuff they have seen before)
queryset = Item.objects.filter(active=True, credits_left__gt=0)[0:int(quantity)]
return queryset
Item和Seen模型是:
class Item(models.Model):
ITEM_TYPES = (
('V', 'Vine'),
('Y', 'YouTube'),
('P', 'Photo'), # Photo is stored by us on a CDN somewhere
('F', 'Flickr'),
('I', 'Instagram'),
('D', 'DeviantArt'),
('5', '500px'),
)
owner = models.ForeignKey(User, on_delete=models.CASCADE) # Id of user who owns the item
title = models.CharField(max_length=60, default='') # URL of where item resides (e.g. Vine or YouTube url)
url = models.CharField(max_length=250, default='', unique=True)
# URL of where item resides (e.g. Vine or YouTube url)
item_type = models.CharField(max_length=1, choices=ITEM_TYPES) # Type of item (e.g. Vine|YoutTube|Instagram|etc.)
keywords = models.ManyToManyField(Keyword, related_name='keywords')
# E.g. Art, Travel, Food, etc.
credits_applied = models.IntegerField(default=10, help_text='Total number of credits applied to this item including any given by VeeU admin')
# Records the total number of credits applied to the Item
credits_left = models.IntegerField(default=10, help_text='The number of credits still remaining to show the item')
# Number of credits left (goes down each time item is viewed
credits_gifted = models.IntegerField(default=0, help_text='The number of credits this item has been gifted by other users')
# Number of credits users have gifted to this item
date_added = models.DateTimeField(auto_now_add=True) # When item was added
liked = models.IntegerField(default=0) # Number of times this item has been liked
disliked = models.IntegerField(default=0) # Number of times this item has been disliked
active = models.BooleanField(default=True, help_text='If you mark this item inactive please say why in the comment field. E.g. "Inapproriate content"')
# True if item is available for showing
comment = models.CharField(max_length=100, blank=True) # Comment to be applied if item is inactive to say why
# Add defs here for model related functions
# This to allow url to be a clickable link
def item_url(self):
return u'<a href="%s">%s</a>' % (self.url, self.url)
item_url.allow_tags = True
def __str__(self):
return '%s: Title: %s, URL: %s' % (self.owner, self.title, self.url)
# Record of which items have been viewed, when, and whether they were liked or not
class Seen(models.Model):
item_seen = models.ForeignKey(Item, on_delete=models.CASCADE) # id of the item that has been seen
who_saw = models.ForeignKey(User, on_delete=models.CASCADE) # id of user who viewed it
date_seen = models.DateTimeField(auto_now_add=True) # When item was viewed
liked = models.BooleanField(help_text='If the item was liked this is set to true')
class Meta:
unique_together = ('item_seen', 'who_saw',)
答案 0 :(得分:2)
如果要将新数据附加到常规响应,可以执行以下操作:
class ItemViewSet(viewsets.ModelViewSet):
...
def list(self, request, *args, **kwargs):
custom_data = {
'list_of_items': ItemSerializer(self.get_queryset(),many=true).data # this is the default result you are getting today
}
custom_data.update({
'quote_of_the_day': # code to compute Quote of the day
'number_of_times': # code to compute number of times
})
return Response(custom_data)
...
虽然,并根据您的评论判断:“每个项目被看到的次数。”时间看起来像是每个项目的新属性,所以你也可以这样做:
class ItemViewSet(viewsets.ModelViewSet):
...
def list(self, request, *args, **kwargs):
custom_data = {
'list_of_items': ItemSerializer(self.get_queryset(), many=true).data # this is the default result you are getting today
}
custom_data.update({
'quote_of_the_day': # code to compute Quote of the day
})
return Response(custom_data)
...
class ItemSerializer(serializers.ModelSerializer):
...
number_of_times = serializers.SerializerMethodField()
...
def get_number_of_times(self):
# compute and return the number of times the Item has been seen.
...
答案 1 :(得分:1)
如果使用分页器,则可以使用以下方法:
from collections import OrderedDict
from rest_framework.pagination import LimitOffsetPagination
from rest_framework.response import Response
from rest_framework import viewsets
class CustomLimitOffsetPagination(LimitOffsetPagination):
def get_paginated_response(self, data):
return Response(
OrderedDict([
('count', self.count),
('next', self.get_next_link()),
('previous', self.get_previous_link()),
('results', data),
('extra_field', <your_value>),
]))
class SomeViewset(viewsets.ModelViewSet):
pagination_class = CustomLimitOffsetPagination