解决Django的ManyToManyField外键限制问题

时间:2012-06-09 19:49:12

标签: django django-models

我有一个Django应用程序,必须使用另一个源提供的数据库。 我无法更改架构。以下所有内容均由inspectdb生成:

class Family(models.Model):
    persistanceid = models.BigIntegerField(primary_key=True)

class Spouseref(models.Model):
    persistanceid = models.BigIntegerField(primary_key=True)

class Family_spouseref(models.Model):
    family_persistanceid = models.ForeignKey(Family, db_column='family_persistanceid')
    wiferefs_persistanceid = models.ForeignKey(Spouseref, unique=True, null=True, db_column='wiferefs_persistanceid', blank=True, related_name='wiferefs')
    husbandrefs_persistanceid = models.ForeignKey(Spouseref, unique=True, null=True, db_column='husbandrefs_persistanceid', blank=True, related_name='husbandrefs')
    childrefs_persistanceid = models.ForeignKey(Spouseref, unique=True, null=True, db_column='childrefs_persistanceid', blank=True, related_name='childrefs')

ManyToManyField在Family下不起作用,因为映射表Family_spouseref具有Spouseref的多个外键。鉴于这种模式,完成这样的事情的最有效方法是什么:

fam = Family.objects.get(persistanceid=id)
husbands = fam.husbands.all()
wives = fam.wives.all()
children = fam.children.all()

更新

根据要求......我试图在上面的Family模型中添加以下函数。

我尝试了原始SQL:

    def husbands(self):
        return Spouseref.objects.raw ('SELECT * FROM spouseref WHERE spouseref.persistanceid IN (SELECT husbandrefs_persistanceid FROM family_spouseref WHERE family_persistanceid=%s);', [self.persistanceid])

哪个有效,但原始SQL真的是最好的方法吗?我通过这种方式失去了许多常用的对象方法,似乎就是这样。

当我尝试通过ORM执行此操作时,它一直想要认为Family_spouseref表具有列ID,但显然没有。

Family_spouseref.objects.get(family_persistanceid=self.persistanceid)

制作人:

[DEBUG] django.db.backends: (0.001) SELECT "family_spouseref"."id", "family_spouseref"."family_persistanceid", "family_spouseref"."wiferefs_persistanceid", "family_spouseref"."husbandrefs_persistanceid", "family_spouseref"."childrefs_persistanceid" FROM "family_spouseref" WHERE "family_spouseref"."family_persistanceid" = 45036  LIMIT 21; args=(45036,)
DatabaseError: column family_spouseref.id does not exist
LINE 1: SELECT "family_spouseref"."id", "family_spouseref"."family_p...

我也尝试过:

Family_spouseref.objects.get(Q(family_persistanceid=self.persistanceid) | Q(husbandrefs_persistanceid__isnull=False))

它产生了相同的ID错误,但确实试图遵循FK关系:

[DEBUG] django.db.backends: (0.000) SELECT "family_spouseref"."id", "family_spouseref"."family_persistanceid", "family_spouseref"."wiferefs_persistanceid", "family_spouseref"."husbandrefs_persistanceid", "family_spouseref"."childrefs_persistanceid" FROM "family_spouseref" LEFT OUTER JOIN "spouseref" ON ("family_spouseref"."husbandrefs_persistanceid" = "spouseref"."persistanceid") WHERE ("family_spouseref"."family_persistanceid" = 45036  OR "spouseref"."persistanceid" IS NOT NULL) LIMIT 21; args=(45036,)
DatabaseError: column family_spouseref.id does not exist
LINE 1: SELECT "family_spouseref"."id", "family_spouseref"."family_p...

我还惊恐地看到调试它调用相同(坏)语句(8次)与原始SQL(它调用两次)的频率。 (仍然,两次!)

我真的想知道正式的Django遍历这些表的方法,而不是完全忽略ORM并执行原始SQL。感谢。

1 个答案:

答案 0 :(得分:2)

你得到的错误是因为Django默认设置了一个“id”字段作为主键,如果没有字段将“primary_key = True”声明为参数(例如你在Family模型中那样做)。因此,当您尝试获取模型对象时,您将始终收到如下错误:

DatabaseError: column family_spouseref.id does not exist

首先,给该模型一个主键。我打赌它有一个。如果不是,也许您只想阅读this。现在,关于你的效率问题,你可以这样做:

def husbands(self):
    husbandrefs_for_family = Family_spouseref.objects.filter(
        family_persistanceid=self.persistanceid,
    ).values_list('husbandrefs_persistanceid',flat=True)

    return Spouseref.objects.filter(
        persistanceid__in=husbandrefs_for_family,
    )

虽然看起来你正在进行2次查询,但你会看到Django只创建了一个(好吧,这是一个带有子查询的查询,就像你在SQL中做的那样)。

子查询的values_list部分用于仅显示所需表的列。我是你想要的SLQ语句的select husbandrefs_persistanceid部分。

希望它有所帮助!