Django:使用无外键字段的select_related

Django:使用无外键字段的select_related,django,django-models,django-orm,Django,Django Models,Django Orm,我有两个模型,它们与我不控制的数据库一起使用。两者都设置为managed=False。第一个模型有一个字段,该字段是第二个模型的外键,但它被实现为字符字段,而不是外键 是否可以在第一个模型上使用select_related,以访问第二个模型的关键属性 下面是一个例子: class Foo(models.Model): class Meta: managed = False fieldone = models.CharField(max_length=10)

我有两个模型,它们与我不控制的数据库一起使用。两者都设置为
managed=False
。第一个模型有一个字段,该字段是第二个模型的外键,但它被实现为
字符字段
,而不是
外键

是否可以在第一个模型上使用
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? 

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

但是,如果您(或某些人出于某种原因)存储了来自“相关”对象的ID(或某些唯一值,如
localkey
),则可以基于它执行筛选

foo = Foo.objects.first()  # Pick one Foo object
foo_bar = Bar.objects.get(localkey=foo.myfk)
要使其看起来像
选择\u 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()
foo  # some random Foo object
foo.bar  # this should return the 'related' Bar object
我不确定这是否是个好主意,但您可以将
.bar()
方法装饰为:

然后这样称呼它:

foos = Foo.objects.all()

for foo in foos:
    print foo.bar()
foo  # some random Foo object
foo.bar  # this should return the 'related' Bar object

为什么不能使用
ForeignKey
?我想我不能使用ForeignKey,因为这个模型使用的实际数据库超出了我的控制(因此
managed=False
)。然而,即使这种关系没有在该数据库中实现为真正的外键,在这里使用外键似乎确实有效,我现在可以使用
select\u related
。但是,在为
foos
的每个实例获取
Bar
的实例时,它会遇到额外的db查询。它违背了使用
select\u related
的目的,因为连接数据未被捕获。我认为原始sql应该更符合标准。这并不是这个问题的答案
select\u related
select
添加一个
JOIN
和一组字段。这样做的目的是在以后不会造成额外的DB点击。这个答案正好可以做到这一点——在访问queryset的
.bar
属性(或方法)时,会导致queryset中的每个对象的DB命中。