忽略Django ORM查询中的基本模型

4

我有以下这些模型:

class Foo(models.Model):
    some_field = models.CharField()
    class Meta:
        pass

class Bar(Foo):
    some_other_field = models.CharField()
    class Meta:
        pass

这个例子是简化的,在实际情况中,这两个模型都有很多字段。

当我查询 Bar 时,Django ORM会创建一个包含与 Foo 的内部连接的查询。
我不需要 Foo 中的信息。

问题:有没有一种方法可以查询 Bar 而不必使用与 Foo 的内部连接?

我意识到删除 Bar 继承 Foo 并将其作为外键是解决此问题的更好方法。然而,有很多旧代码依赖于它,所以在我有时间和勇气重构应用程序的旧部分之前,我更喜欢快速解决方案。

我也意识到我可以自己编写 SQL 查询,但我更喜欢使用 ORM 的解决方案。

3个回答

3
我处理这种情况的方式是使用一个新的非托管模型来管理该实例。
class SkinnyBar(models.Model):
    some_other_field = models.CharField()

    class Meta:
        managed = False
        db_table = "app_bar"

这将允许您使用ORM。

如果您想避免重复,可以尝试将大部分属性和方法添加到元类中。

class BaseBar(models.Model):
    some_other_field = models.CharField()

    def some_common_method(self):
        return True

    class Meta:
        abstract = True


class Bar(BaseBar, Foo):

    def some_method_that_requires_foo(self):
        return self.some_field == 1


class SkinnyBar(BaseBar):

    class Meta:
        managed = False
        db_table = "app_bar"

感谢您的回答。我认为这个方法可能对我有用,但我还有一个问题:我的实际 Bar 模型对象中有很多字段和方法,有没有一种方法可以将它们添加/混合到 SkinnyBar 中而不重复呢? - Blaise

0
正确的做法是在元数据中添加 abstract = True,将 Foo 模型设为抽象。在你的情况下,some_field 在 app_foo 表中,需要 join 来完全创建 Bar 对象。如果你不需要 some_field,可以随时转到原始 SQL 上。但如果要检索它,必须连接 app_bar 和 app_foo 表。

为了澄清我的问题:在这种情况下,我不需要some_field,但我确实需要在所有其他(遗留)情况下使其正常工作。将两个表迁移到一个表不是我想做的事情,因为数据集太大了。- 你确定没有使用ORM的解决方案吗? - Blaise
除了原始查询之外,没有其他的。连接是显式的。对象需要它才能完整。 - dekomote

0

你遇到了一个有趣的问题。

单独使用内连接不应该是什么大问题,只要你的查询设置得当。你试图限制它的主要原因是什么,我猜是性能吧?你能发布一些关于如何处理这些模型的代码吗?

我不确定这是否有效,但你可以考虑在查询集上使用'defer'函数。这个函数实际上只适用于高级用例,可能不适用于此处。本质上,defer不会尝试查询你指定的字段。如果你延迟了'some_field',也许它就不会进行连接。缺点是,一旦你尝试从对象中访问'some_field',它将执行一个查询(迭代将导致n个额外的查询)。


  1. жҳҜзҡ„пјҢиҝҷжҳҜдёәдәҶжҖ§иғҪиҖғиҷ‘гҖӮ
  2. дё»иҰҒдҪҝз”Ё Bar.objects.filter() е’Ң Bar.objects.get()гҖӮ
  3. жҲ‘е·Із»Ҹе°қиҜ•иҝҮ defer е’Ң onlyпјҢдҪҶдҫӢеҰӮ Bar.objects.all().only('some_other_field') 并дёҚиғҪж¶ҲйҷӨеҶ…иҝһжҺҘгҖӮ
- Blaise

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接