【问题标题】:Django LEFT OUTER JOIN on TWO columns where one isn't a foreign keyDjango LEFT OUTER JOIN 在两列上,其中一列不是外键
【发布时间】:2010-09-27 21:32:41
【问题描述】:

我有两个这样的模型:

class ObjectLock(models.Model):
    partner = models.ForeignKey(Partner)
    object_id = models.CharField(max_length=100)

    class Meta:
        unique_together = (('partner', 'object_id'),)

class ObjectImportQueue(models.Model):
    partner = models.ForeignKey(Partner)
    object_id = models.CharField(max_length=100)
    ... # other fields
    created = models.DateTimeField(auto_now_add = True)
    modified = models.DateTimeField(auto_now = True, db_index=True)

    class Meta:
        ordering = ('modified', 'created')

上面提到的第三个模型(合作伙伴)没有什么值得注意的。

我想得到类似的东西:

SELECT * FROM ObjectImportQueue q LEFT OUTER JOIN ObjectLock l ON
q.partner_id=l.partner_id AND q.object_id=l.object_id WHERE l.object_id
IS NULL and l.partner_id IS NULL;

我遇到了this page,它告诉我如何进行自定义连接,我尝试传入一个列名的元组来代替要连接的列名,但这没有用。 Partner 表不需要包含在生成的 sql 查询中,但我会接受包含它的答案,只要它有效地执行我尝试对一个查询执行的操作。

【问题讨论】:

  • 也许我这里出了点问题,但是为什么不寻找 object_id = NULL 和 partner_id = NULL 而不加入呢?应该给你同样的结果吗?
  • 我正在尝试在队列表中查找没有在锁定表中有相应行的行。

标签: sql django join


【解决方案1】:

如果你使用的是 Django 1.2+ 并且知道你想要的 SQL,你总是可以回退到 Raw Query.

【讨论】:

    【解决方案2】:

    我也遇到了类似的问题。但是最后,我发现我问错了问题。

    在Django ORM中,SQL join的条件是基于models.Model字段定义的。

    有多对一关系(ForeignKey)、多对多关系(ManyToManyField)、一对一关系(OneToOneField)。

    在您的情况下。ObjectLockModel 和 ObjectImportQueueModel 具有相同的字段部分,partnerfield 和 object_idfield.yon 应该使用一对一的关系。

    你可以像这样改变你的模型:

    class ObjectImportQueue(models.Model):
        partner = models.ForeignKey(Partner)
        object_id = models.CharField(max_length=100)
        created = models.DateTimeField(auto_now_add = True)
        modified = models.DateTimeField(auto_now = True, db_index=True)
    
        def __unicode__(self):
            return u"%s:%s" % (self.partner, self.object_id)
    
        class Meta:
            ordering = ('modified', 'created')
    
    class ObjectLock(models.Model):
        lock = models.OneToOneField(ObjectImportQueue, null=True)
    
        class Meta:
            unique_together = (('lock',),)
    

    模型的顺序是导入,OneToOneField参数模型必须在前。

    >>> p1 = Partner.objects.get(pk=1)
    >>> p2 = Partner.objects.get(pk=2)
    >>> Q1 = ObjectImportQueue.objects.create(partner=p1,object_id='id_Q1')
    >>> Q2 = ObjectImportQueue.objects.create(partner=p2,object_id='id_Q2')
    >>> ObjectImportQueue.objects.filter(lock__isnull=True)
    [<ObjectImportQueue: Partner object:id_Q1>, <ObjectImportQueue: Partner object:id_Q2>]
    >>> L1 = ObjectLock.objects.create(lock=Q1)
    >>> ObjectImportQueue.objects.filter(lock__isnull=True)
    [<ObjectImportQueue: Partner object:id_Q2>]
    

    ObjectLock.objects.create锁定一个对象 ObjectImportQueue.objects.filter(lock__isnull=True)选择对象不要被锁定。

    如果你使用适当的关系,生成ORM查询会很容易。在Django中,在构建模型时定义关系比使用Query语句来关系表之间的关系更好。

    【讨论】:

    • 我认为是针对我的具体案例的最佳答案。但是我很久以前就问过这个问题,我不知道它是否会实际上起作用,但我想应该会。标记为答案。这不是“两列左外连接”的最佳一般答案。
    【解决方案3】:

    我刚刚找到了解决这个问题的方法。

    您必须创建一个为您执行连接的视图

    CREATE VIEW ImporQueueLock AS (
      SELECT q.id, l.id
        FROM ObjectImportQueue q
        LEFT OUTER JOIN ObjectLock l
            ON q.partner_id=l.partner_id AND q.object_id=l.object_id
      )
    

    然后为该视图制作一个 django 模型

    class ImportQueueLock(models.Model):
    
        queue = models.ForeignKey(ObjectImportQueue, db_column='q')
        lock = models.ForeignKey(ObjectLock, db_column='l')
    

    然后在您的 Django 模型上通过 ImportQueueLock 从 ObjectLock 到 ObjectImportQueue 进行 ManyToMany

    class ObjectLock(models.Model):
        partner = models.ForeignKey(Partner)
        object_id = models.CharField(max_length=100)
        queue = models.ManyToManyField(ObjectImportQueue, through = ImportQueueLock)
    

    你将能够做到

    ObjectLock.objects.filter(importqueuelock__objectimportqueue__ .....)
    

    【讨论】:

      猜你喜欢
      • 2020-11-22
      • 1970-01-01
      • 1970-01-01
      • 2013-03-10
      • 1970-01-01
      • 1970-01-01
      • 2015-07-28
      • 2010-09-29
      相关资源
      最近更新 更多