Django查询性能:使用ForeignKey对比使用ForeignKey和Bidirectional的单向包含& Related_name

时间:2010-11-17 15:14:50

标签: django django-models foreign-key-relationship django-queryset

全部,

在适当的设计方面,您更喜欢哪一个?清洁度和查询性能?

选项A:(双向参考)

class Country(models.Model):
    name = models.CharField(max_length=128)
    capital = models.ForeignKey('City',related_name="country_capital", null=True)

class State(models.Model):
    name = models.CharField(max_length=128)
    capital = models.ForeignKey('City', related_name="state_capital", null=True)
    country = models.ForeignKey('Country', null=True)

class City(models.Model):
    name = models.CharField(max_length=128)
    state = models.ForeignKey('State', null=True)
    country = models.ForeignKey('Country', null=True)

选项B:(单向参考)

class Country(models.Model):
    name = models.CharField(max_length=128)

class State(models.Model):
    name = models.CharField(max_length=128)
    country = models.ForeignKey('Country', null=True)

class City(models.Model):
    name = models.CharField(max_length=128)
    state = models.ForeignKey('State', null=True)
    state_capital = models.BooleanField(default=False)
    country_capital = models.BooleanField(default=False)


Search will be done as:
Get me all cities where name is Waterloo and country is US.
Get me all cities where country is UK.
Get me all states where country is US.
Get me a country where country is US. and capital is Washington DC.
Get me the capital where country is US.

2 个答案:

答案 0 :(得分:1)

从我的观点来看,选项B存在一些问题。一个是没有什么可以阻止两个或更多城市被标记为特定州或国家的资本。您需要在表单上添加额外的验证,以确保不会发生。

从查询的角度来看,我认为A仍然是可取的。例如,如果你想让所有城市的资本都是城市X,你可以在第一个城市进行:

cities = City.objects.filter(state__capital__name="City X")

在第二步你必须这样做:

cities = City.objects.filter(state=City.objects.get(name="City X"))

解析为子查询,这可能效率较低。

但是,在选项A中,我认为您不一定需要从城市到国家的FK。在您的模型(*)中,所有城市都处于州,因此您可以随时通过州获得国家 - 再次获得额外的FK意味着您需要更多验证以确保您不能将城市分配到与该州的国家。

(*虽然注意到这实际上并不符合现实:并非所有国家都有州议会,甚至那些所有国家都会拥有超出所有州的城市,例如澳大利亚的堪培拉)

答案 1 :(得分:1)

选项A更好,因为它包含相同的信息,而不需要一组几乎总是空白的字段(state_capital和country_capital)。

如您所知,并非每个国家/地区都有州/省,因此您应该同时拥有城市模型的国家/地区和州。在任何情况下,对于巨额回报来说,这是一个非常少量的冗余,并且您不太可能遇到规范化问题(例如,给定状态改变其国家的情况极为罕见)。即使每个城市确实在模型中都有关联状态,添加冗余字段以加快查询速度仍然更好 - 您最多只处理一个表连接而不是两个。

请注意,华盛顿特区由两个地方组成:华盛顿市和DC州。所以你的查询:

  

给我一​​个国家是美国的国家。首都是华盛顿特区。

应该读作

Country.objects.filter(code__iexact='US', capital__name__iexact='Washington', capital__state__code__iexact='DC')

(我在这里假设国家和州模型你实际上是在添加一个代码字段来处理缩写)

我会注意到其中一些查询似乎非常多余:为什么您需要匹配国家/地区名称的资本?