【问题标题】:Prefetch queryset when related_name="+"当related_name="+" 时预取查询集
【发布时间】:2021-02-16 16:31:37
【问题描述】:

是否可以在没有相关名称 (related_name="+") 的情况下预取目标实例上的对象?当然我知道相关名称没有问题,但我不确定没有它是否可能。

示例代码如下:

from django.db import models


class Parent(models.Model):
    name = models.CharField(max_length=50)


class Child(models.Model):
    parent = models.ForeignKey(to=Parent, related_name="+", on_delete=models.CASCADE)
    name = models.CharField(max_length=50)


Parent.objects.all().prefetch_related('child_set')

也许可以使用Prefetch(lookup, queryset=None, to_attr=None) 对象,因为它采用参数列表中的查询集?

【问题讨论】:

  • 您在这里遇到了什么样的问题?您是否尝试过并遇到错误,或者您在问“如果”类似的问题?
  • @Charnel 问题是,在查询集查找中使用了相关名称,所以当未设置相关名称时,它不能在查询集查找中使用,如Parent.objects.filter(child__[insert attribute]=...)。同样的行为也适用于预取。
  • 如果您没有指定相关名称,您仍然可以使用_set 后缀,如fieldname_set。
  • 我有related_name="+" 在问题名称和示例代码中。
  • 如果你想访问反向关系,related_name="+" 有什么意义?

标签: django django-models django-orm


【解决方案1】:

浏览了一下代码,发现了这个line:

rel_obj_descriptor = getattr(instance.__class__, through_attr, None)

这里instance是模型实例,through_attr是要获取的相关实例的字段名。这一行基本上试图获取一个相关的描述符来执行预取查询。在您的情况下,rel_obj_descriptor 将包含 None。
要回答您的问题,至少对于外键来说是不可能的,多对多关系可能存在一些黑客攻击,因为 Django 似乎为它们使用了一些内部描述符。
我建议你不要设置related_name="+",因为你想在这里使用反向关系。您说“这是因为多个应用程序之间的关注点分离”,但这没有多大意义。我们不是为其他各种模型设置了用户模型的外键并且仍然使用相关名称吗?是否存在关注点分离点(用户模型在单独的应用程序中)?

【讨论】:

    【解决方案2】:

    试试

    parent = Parent.objects.get(id=pk)
    parent.child_set.all()
    

    我不知道是否有related_name = '+' 可以防止这种情况,但如果你从不定义related_name,你绝对可以使用这个方法。

    【讨论】:

    • 可以,但related_name="+" 是必需的。
    • 你试过了吗??parent = Parent.objects.get(id=pk) parent.child_set.all()
    • 请再次阅读问题和问题下方的讨论。
    猜你喜欢
    • 2021-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-30
    • 1970-01-01
    • 2018-09-30
    • 2021-09-16
    相关资源
    最近更新 更多