将数据添加到Django REST Framework的ModelViewSet返回的列表中

时间:2016-04-11 16:48:09

标签: django django-rest-framework

有没有办法将自定义数据添加到对使用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',)

2 个答案:

答案 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