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

Posted

技术标签:

【中文标题】Django Rest DRF:从反向关系访问外键引用【英文标题】:Django Rest DRF : accessing a foreign key reference from reverse relation 【发布时间】:2018-03-13 04:49:16 【问题描述】:

假设我有两个模型。

型号

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']

【问题讨论】:

你的序列化器在哪里?显示serializers.py。而且你没有在你的视图中声明任何serializer_class 这里没有使用 rest_framework.generics 所以没有 serializer_class,而且我确定我的问题在于我如何使用 Prefetch 查询项目。 你说的是一个序列化错误,如果没有问题你为什么还要说呢? 好吧,我想我可能措辞有点错误,但我的错误原因写在 EDIT 块上方 顺便说一句,我认为您正在考虑序列化程序。据我所知,在发布请求期间发生在可写序列化程序上的错误。这是一个获取请求,所以当我向 api emdpoint 发出正确的获取请求时,我得到的是 Serialozer 错误。重点不是这里的序列化错误,而是如何通过已经存在的反向关系访问正向关系FK对象。 【参考方案1】:

首先:您似乎正在尝试在数据中建模某种多对多关系,使用适当的 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 字段(见上文)的情况下手动建模多对多关系。 在这种情况下,我们手动使用SerializerMethodField,而不是让 DRF 负责显示关系。

【讨论】:

这是我目前正在做的事情,这对数据库产生了很多影响,不过感谢您的反馈

以上是关于Django Rest DRF:从反向关系访问外键引用的主要内容,如果未能解决你的问题,请参考以下文章

Django,在管理员中显示和编辑反向外键关系

父模型具有多个外键时的Django外键反向访问[重复]

django admin - 选择反向外键关系(不创建,我想添加可用)

从视图访问消费者以通过 WebSocket (Django-Channelsv2.2 & DRF) 将 api 接收的数据推送给用户

如何处理 django-rest-framework 中 url 模式中的外键关系

Django 访问值对象中的反向外键数据