【问题标题】:Four table join django四表连接django
【发布时间】:2016-06-13 08:16:53
【问题描述】:

简介

对 django 比较陌生,好奇如何使用 ORM 为我的特定用例进行 4 路连接。

Django 模型

class Foo( models.Model ):
  attr1 = ...

class Bar( models.Model ):
  foo = models.ForeignKey ( Foo )
  attr2 = ...

class BarOneToOne( models.Model ):
  bar = models.ForeignKey ( Bar ) 
  attr3 = ...

class BarManyToOne( models.Model ):
  bar = models.ForeignKey ( Bar )
  attr4 = ...

问题

需要BarManyToOne 与关联的BarOneToOneBarFoo 数据的列表。想根据Foo ids 过滤。

示例

数据:

Foo                     Bar
--------------        -----------------------
| id | attr1 |        | id | attr2 | foo_id |
--------------        -----------------------
  1    apple           101   larry      1
  2    orange          102   bob        2
  3    pear            103   sue        3
  4    grape           104   laura      1
                       105   nancy      4

BarOneToOne            BarManyToOne
------------------     --------------------
| bar_id | attr3 |     | bar_id |  attr4  |
------------------     --------------------
   101      dog           101     cinnamon
   103      mouse         104     thyme
   104      cat           103     garlic
                          104     sea salt
                          101     chili powder
                          103     paprika

想要的结果:

 --------------------------------------
 | apple | larry | dog |   cinnamon   |
 --------------------------------------
 | apple | laura | cat |    thyme     |
 --------------------------------------
 | apple | laura | cat |   sea salt   |
 --------------------------------------
 | apple | larry | dog | chili powder |
 --------------------------------------

SQL 等效项

SELECT f.attr1, b.attr2, bmto.attr3, bmtoa.attr4
FROM foo f, bar b, bar_one_to_one boto, bar_many_to_one bmto
WHERE bmto.bar_id = boto.bar_id AND b.id = bmto.bar_id
AND b.foo_id = f.id AND f.id = ?;

杂项

到目前为止,我在文档中看到了select_related,感觉非常有用。还有 __ 方法。感觉就像碎片在这里,但还不能把它们放在一起。

就性能/大小而言,Foo、Bar 和 BarOneToOne 表都将很小(每个表低于 500 行,甚至每个表可能低于 100 行)。 BarManyToOne 表会更大。

提前致谢。

【问题讨论】:

    标签: python sql django django-models django-orm


    【解决方案1】:

    您需要根据您的参考框架为您的模型设置related_names。有很多方法可以做到这一点,但为此,我将使用BarManyToOne 表作为主表。

    class Foo( models.Model ):
        attr1 = ...
    
    class Bar( models.Model ):
        foo = models.ForeignKey ( Foo, related_name='foo_bars')
        attr2 = ...
    
    class BarOneToOne( models.Model ):
        bar = models.ForeignKey ( Bar, related_name='bar_baronetoones' ) 
        attr3 = ...
    
    class BarManyToOne( models.Model ):
        bar = models.ForeignKey ( Bar, related_name='bar_barmanytoones' )
        attr4 = ...
    

    使用上面显示的模型设置,这将是您需要调用以获取等效 SQL 查询的代码。

    BarManyToOne.objects.all().select_related(
        'bar',                             # Joins the three other tables
        'bar__foo',                        # with BarManyToOne serving as
        'bar__bar_baronetoones'            # the main table
    ).filter(                              # Your (non join condition) WHERE clauses
        bar__foo_id=<your value here>      # f.id = ?
    ).values(                              # The columns you want
        'bar__foo__attr1',                 # f.attr1
        'bar__attr2',                      # b.attr2
        'bar__bar_baronetoones__attr3',    # boto.attr3
        'attr4'                            # bmto.attr4
    )
    

    您需要阅读related_namethe making queries sectionF() expressions

    【讨论】:

    • 明天会试一试,但看起来正是我需要的。谢谢!
    • 仅供参考,我编辑了 filter() 的参数。一开始我并没有注意到,但仔细一看,额外的 WHERE 条件是 JOIN 条件,在执行 select_related() 时应该已经自动包含在内。
    猜你喜欢
    • 2011-08-03
    • 1970-01-01
    • 1970-01-01
    • 2018-12-27
    • 1970-01-01
    • 1970-01-01
    • 2015-04-15
    • 1970-01-01
    相关资源
    最近更新 更多