【问题标题】:Django: Use select_related without a ForeignKey fieldDjango:在没有 ForeignKey 字段的情况下使用 select_related
【发布时间】:2015-10-22 19:43:06
【问题描述】:

我有两个模型用于我无法控制的数据库。两者都设置为managed = False。第一个模型有一个字段,它是第二个模型的外键,但它被实现为CharField,而不是ForeignKey

是否可以在第一个模型上使用select_related 来访问密钥的第二个模型的属性?

这是一个例子:

class Foo(models.Model):
    class Meta:
        managed = False
    fieldone = models.CharField(max_length=10)
    myfk = models.CharField(max_length=20) # In practice, this points to Bar.localkey

class Bar(models.Model):
    class Meta:
        managed = False
    localkey = models.CharField(max_length=20)
    someotherattribute = models.CharField(max_length=100)

Foo.objects.all().select_related('Bar') # I know this won't work, but is there something that will? 

【问题讨论】:

  • 为什么不能使用ForeignKey
  • 我认为我无法使用 ForeignKey,因为该模型使用的实际数据库超出了我的控制范围(因此 managed=False)。但是,即使这种关系在该数据库中没有作为真正的外键实现,但在此处使用 ForeignKey 似乎确实有效,我现在可以使用 select_related

标签: django django-models django-orm


【解决方案1】:

没有,因为没有什么相关的。

但如果您(或某人出于某种原因)存储了“相关”对象的 ID(或某些唯一值,例如 localkey),则可以基于它执行过滤器。

foo = Foo.objects.first()  # Pick one Foo object
foo_bar = Bar.objects.get(localkey=foo.myfk)

要使它看起来像select_related,你可以试试这个:

class Foo(models.Model):
    class Meta:
        managed = False
    fieldone = models.CharField(max_length=10)
    myfk = models.CharField(max_length=20)

    def bar(self):
        return Bar.objects.get(localkey=self.myfk)
        # probably you will need to manage common error when performing a .get()
        # DoesNotExist and MultipleObjectsReturned

然后像这样使用:

foos = Foo.objects.all()

for foo in foos:
    print foo.bar()

我不确定这是否是个好主意,但您可以将 .bar() 方法装饰为 property

...

@property
def bar(self):
    return Bar.objects.get(localkey=self.myfk)

然后这样称呼它:

foo  # some random Foo object
foo.bar  # this should return the 'related' Bar object

【讨论】:

  • 它会在为每个foos 实例获取Bar 实例时遇到额外的数据库查询。它违背了使用select_related 的目的,因为未捕获连接数据。我认为原始 sql 会更符合要求。
  • 不是这个问题的真正答案。 select_relatedJOIN 和一堆字段添加到SELECT。这样做的目的是在之后造成额外的数据库命中。这个答案将完全做到这一点 - 在访问其 .bar 属性(或方法)时,导致查询集中每个对象的数据库命中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-01
  • 2023-01-06
  • 2018-11-03
  • 1970-01-01
  • 2019-07-22
  • 2020-01-14
  • 2018-11-23
相关资源
最近更新 更多