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==True
和has_loved==True
的项目的额外查询过滤。
请注意,这不是最优的,因为:
您正在序列化程序中执行附加查询。 您在不使用适当的 Django 字段(见上文)的情况下手动建模多对多关系。 在这种情况下,我们手动使用SerializerMethodField
,而不是让 DRF 负责显示关系。
【讨论】:
这是我目前正在做的事情,这对数据库产生了很多影响,不过感谢您的反馈以上是关于Django Rest DRF:从反向关系访问外键引用的主要内容,如果未能解决你的问题,请参考以下文章
django admin - 选择反向外键关系(不创建,我想添加可用)
从视图访问消费者以通过 WebSocket (Django-Channelsv2.2 & DRF) 将 api 接收的数据推送给用户