Django LEFT OUTER JOIN在两列上,其中一列不是外键

时间:2010-09-27 21:32:42

标签: sql django join

我有两个这样的模型:

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,它告诉我们如何进行自定义连接,并且我尝试传入列名称的元组来代替要加入的列名称,但这不起作用。合作伙伴表不应该包含在生成的sql查询中,但我会接受包含它的答案,只要它有效地执行我正在尝试对一个查询执行的操作。

3 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

我也遇到了类似的问题。但最后,我发现我提出了一个错误的问题需要解决。

在Django ORM中,SQL连接的条件基于models.Model字段定义的内容。

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

在您的情况下。ObjectLock模型和ObjectImportQueue模型具有相同的字段部分,partner字段和object_id字段.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中,在构建Model时定义关系比使用Query语句来关联表之间的关系更好。

答案 2 :(得分:0)

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

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

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')

然后通过ImportQueueLock在您的Django模型上创建一个ManyToMany,从ObjectLock到ObjectImportQueue

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__ .....)