当然,我并不打算做prefetch_related已经做的事情。
我想模仿它的作用 我想做的是以下内容。
我有一个MyModel实例列表
用户可以follows
或doesn't follow
每个实例。
my_models = MyModel.objects.filter(**kwargs)
for my_model in my_models:
my_model.is_following = Follow.objects.filter(user=user, target_id=my_model.id, target_content_type=MY_MODEL_CTYPE)
这里我有n + 1查询问题,我想我可以借用prefetch_related
在这里做的事情。 prefetch_related
的描述说,它执行所有对象的查询,当需要相关属性时,它从预先执行的查询集中获取。
这正是我所追求的,对我感兴趣的所有对象执行is_following
的查询,并使用查询而不是N个人查询。
另外一个方面是,我想附加查询集而不是附加实际值,这样我就可以推迟评估直到分页。
如果这个含糊不清的语句,我想将附有my_models
信息的is_following
查询集提供给另一个函数(例如DRF序列化程序)。
prefetch_related
如何完成上述内容?
答案 0 :(得分:0)
不确定这是否是最佳方法,我怀疑这是prefetch_related的作用,因为我加入了这里。
我找到了在您的查询中选择extra
列的方法。
extra_select = """
EXISTS(SELECT * FROM follow_follow
WHERE follow_follow.target_object_id = myapp_mymodel.id AND
follow_follow.target_content_type_id = %s AND
follow_follow.user_id = %s)
"""
qs = self.extra(
select={'is_following': extra_select},
select_params=[CONTENT_TYPE_ID, user.id]
)
所以你可以通过加入来做到这一点。
prefetch_related
这样做的方式是separate queryset
,并在查询集中查找属性。
答案 1 :(得分:0)
通过is_following
子查询可以获得只能获得.extra
位的解决方案。
class MyModelQuerySet(models.QuerySet):
def annotate_is_follwing(self, user):
return self.extra(
select = {'is_following': 'EXISTS( \
SELECT `id` FROM `follow` \
WHERE `follow`.`target_id` = `mymodel`.id \
AND `follow`.`user_id` = %s)' % user.id
}
)
class MyModel(models.Model):
objects = MyModelQuerySet.as_manager()
用法:
my_models = MyModel.objects.filter(**kwargs).annotate_is_follwing(request.user)
following
个对象的完整列表。由于GFK
课程中有Follow
,您需要通过GenericRelation手动创建reverse
关系。类似的东西:
class MyModelQuerySet(models.QuerySet):
def with_user_following(self, user):
return self.prefetch_related(
Prefetch(
'following',
queryset=Follow.objects.filter(user=user) \
.select_related('user'),
to_attr='following_user'
)
)
class MyModel(models.Model):
following = GenericRelation(Follow,
content_type_field='target_content_type',
object_id_field='target_id'
related_query_name='mymodels'
)
objects = MyModelQuerySet.as_manager()
def get_first_following_object(self):
if hasattr(self, 'following_user') and len(self.following_user) > 0:
return self.following_user[0]
return None
用法:
my_models = MyModel.objects.filter(**kwargs).with_user_following(request.user)
现在您可以访问following_user
属性 - 包含follow
个所有mymodel
个对象的列表,或者您可以使用get_first_following_object
之类的方法。