How to Add Attribute to Django QuerySet That Will Get Serialized?

时间:2018-03-09 19:07:21

标签: django django-rest-framework

I have two Django 1.8 models that represent lists and items in lists. I also have a view that uses the Django REST framework to act as a REST endpoint and a template containing an jQuery Ajax block that calls this endpoint. This view gets all the lists owned by a particular user and looks to see if a given item is in any of the lists. Whenever it finds such an item, it should add an 'in_list' attribute to the data being passed back to the template. The problem I'm having is that while I can add this extra 'in_list' attribute to the list, it doesn't get picked up by the serializer and added to the serialized data. Here's the code:

# views.py
def get_viewer_lists_checked(request, *args, **kwargs):
    user = User.objects.get(id=kwargs['viewer_id'])
    lists = List.objects.filter(user=user, type=type)
    item = Item.objects.get(value=kwargs['viewed_id'])
    if item:
        for list in lists:
            if List.contains_item(item, list):
                list.in_list = True
            else:
                list.in_list = False

    serializer = MemberListsSerializer(lists, many=True)
    return JSONResponse(serializer.data)

# models.py
class List(models.Model):
    user = models.ForeignKey(User)
    name = models.CharField(_('list'), max_length=128)

    @classmethod
    def contains_item(cls, item, list, *args, **kwargs):
        try:
            item.lists.get(id=list.id)
            return True
        except List.DoesNotExist:
            return False

class Item(models.Model):
    lists = models.ManyToManyField(List, related_name='items')
    value = models.IntegerField(_('value'))

# serializer.py
class MemberListsSerializer(serializers.ModelSerializer):
    class Meta:
        model = List
        fields = ('id', 'user', 'name')

If I run the view through the Python debugger and examine the 'lists' query set right before the serializer variable is set, I can see that an 'in_lists' attribute has been added to each element in the lists query set. But when I execute the call to MemberListsSerializer and examine 'serializer.data', the 'in_list' attribute isn't there. I thought to try adding 'in_list' to the serializer class's 'fields' list, but that doesn't work because 'in_list' isn't a field in the List model (and I don't want to add it to the model as this bit of information doesn't really belong there). I also looked at adding an extra argument to the call to the serializer method, "context={'in_list': in_list}", but this doesn't work as it only adds 'in_list' to the context returned to the template, not to each individual list. What's the correct way to insert this 'in_list' attribute such that it will get picked up by the serializer and inserted into its output?

1 个答案:

答案 0 :(得分:1)

您可以将项目传递到上下文并使用SerializerMethodField检查当前列表中的项目是否为

def get_viewer_lists_checked(request, *args, **kwargs):
    ...
    item = Item.objects.get(value=kwargs['viewed_id'])
    serializer = MemberListsSerializer(lists, many=True, context={'item': item})
    return JSONResponse(serializer.data)

class MemberListsSerializer(serializers.ModelSerializer):
    in_list = serializers.SerializerMethodField('get_in_list')
    class Meta:
        model = List
        fields = ('id', 'user', 'name', 'in_list')

    def get_in_list(self, obj):
        item = self.context['item'] 
        if List.contains_item(item, obj):
            return True
        else:
            return False