Django Rest DRF:从反向关系访问外键引用

时间:2017-10-02 05:38:44

标签: django rest django-rest-framework foreign-keys reverse

我们说我有两个模特。

  

模型

class Item(models.Model):
    name = models.CharField(max_length=32)
    # other fields

class ItemRelation(models.Model):
    item = models.ForeignKey(Item, related_name='relations_item')
    user = models.ForeignKey(User, related_name='relations_user')
    has_viewed = models.BooleanField(default=False)
    has_loved = models.BooleanFields(default=False)

现在,我想要的是获取一个用户的个人资料,其中包含与该用户相关联的项目,其中has_loved = True且has_viewed = True。

在我的views.py文件中,我有类似的东西。

class UserProfile(APIView):
    def get(self, request, format=None):
        id = self.request.query_params.get('id')
        user = User.objects.filter(id=id).prefetch_related(Prefetch(
            'relations_user', queryset=ItemRelation.objects.select_related('item').filter(has_viewed=True),
             to_attr='item_viewed'
    ))

我确信我错了,并且我也遇到了序列化程序错误,因为我尝试使用将Item作为其模型的序列化程序来序列化ItemRelation对象。

  

修改

serializers.py

class ItemSerializer(seralizer.ModelSerializer):
    class Meta:
        model = Item
        fields = ['name']

class UserSerializer(serializers.ModelSerializer):
    relations_user = ItemSerializer(read_only=True, many=True)
    class Meta:
        model = User
        fields = ['username', 'relations_user']

1 个答案:

答案 0 :(得分:0)

首先:您似乎正在尝试在数据中建立某种多对多关系,并且使用适当的Django ManyToManyField会更好。

话虽如此,您问题的可能解决方案可能如下所示,通过SerializerMethodField实现:

<强> views.py

class UserProfile(APIView):
    def get(self, request, format=None):
        pk = self.request.query_params.get('id')

        # consider using get_object_or_404 here or implement some
        # other sort of error handling for a failed lookup
        user = User.objects.get(pk=pk)

<强> serializers.py

from .models import Item


class ItemSerializer(seralizer.ModelSerializer):
    class Meta:
        model = Item
        fields = ['name']

class UserSerializer(serializers.ModelSerializer):
    items = serializers.SerializerMethodField()

    class Meta:
        model = User
        fields = ['username', 'items']

    def get_items(self, obj):
        # obj is the User instance you call the serializer with
        items = Item.objects.filter(
                    relations_item__user=obj,
                    relations_item__has_viewed=True,
                    relations_item__has_loved=True,
                )

        # serialize the items with your ItemSerializer defined above
        serializer = ItemSerializer(items, many=True)

        return serializer.data

基本上,您使用SerializerMethodField启动对与用户相关且具有属性has_viewed==Truehas_loved==True的项目的附加查询过滤。

请注意,这不是最佳选择,因为:

  • 您正在序列化程序中执行其他查询。
  • 您在不使用相应的Django Field(参见上文)的情况下手动建模多对多关系。
  • 在这种情况下,我们手动使用SerializerMethodField而不是让DRF负责显示关系。