四桌加入django

时间:2016-03-01 03:14:46

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

简介

相对较新的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 = ...

问题

想要包含关联的BarManyToOneBarOneToOneBar数据的Foo列表。想要根据Foo ID对其进行过滤。

示例

数据:

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表将更大。

提前致谢。

1 个答案:

答案 0 :(得分:0)

您需要根据参考框架为模型设置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