我在编写django数据模型时遇到问题,该模型可以将同一类型的多个对象链接回单个数据条目。以下是我目前的型号:
class House(models.Model):
name = models.CharField(max_length=200, unique=True)
color = models.CharField(max_length=200, unique=True)
class Config(models.Model)
name = models.CharField(max_length=200)
nbr_houses = models.PositiveIntegerField()
houses = models.ManyToManyField(House) # this does not work, since I can only map a house once back to Config.
我想做以下(伪代码):
# define a new config and enforce that is should have houses.
$ a = Config(name = 'new_config', nbr_houses = 3)
# associate individual houses with this config
$ a.houses[0] = House(pk= 1)
# associate the same house a second time with this config
$ a.houses[1] = House(pk= 1)
# associate a third house to config.
$ a.houses[2] = House(pk= 2)
我创建了一个新的Config
对象new_config
,并说这个配置应该有3个房子。然后,我的模型应自动检查并强制我将正确数量的房屋链接回Config
。此外,House
可能会引用两次相同的配置。
我正在考虑以下列方式编写Config
class Config(models.Model)
name = models.CharField(max_length=200)
nbr_houses = models.PositiveIntegerField()
houses = models.ManyToManyField(House, related_name='house0')
houses1 = models.ManyToManyField(House, related_name='house1')
houses2 = models.ManyToManyField(House, related_name='house2')
houses3 = models.ManyToManyField(House, related_name='house3')
基本上反映了可能的最大关联数,但这有点不灵活。有什么更好的方法来实现这个目标?
编辑:想象一下以下用例:
您想编写一个计算机游戏,您可以在其中定义场景的复杂性。每个场景都保存为Config
。每个场景,我可以放置许多房屋x
。房子没有区别,它们只是模板。因此可以制作10个红色房屋,2个蓝色房屋和1个黄色房屋。因此,对于每个Config
条目,我希望能够关联不同数量的房屋(对象)。也许以后也会有马:)我希望你能得到这个想法。
答案 0 :(得分:5)
问题已更新,以解释您可能希望将每个房屋的某些数字与配置相关联。为了在Django中执行此操作,您需要一个新模型,Django称之为intermediate model。像这样:
class ConfigHouses(model.Model):
config = model.ForeignKey('Config')
house = model.ForeignKey('House')
count = model.PositiveIntegerField()
class Meta:
unique_together = ('config', 'house')
然后在Config
类中声明ManyToManyField
并将中间模型分配给through
参数:
class Config(model.Model):
# ...
houses = model.ManyToManyField('House', through = 'ConfigHouses')
要在配置中添加房屋,您需要创建中间模型的新实例:
# Level 1 contains 4 red houses and 5 yellow houses
c = Config.objects.get_or_create(name = 'level-1')
red = House.objects.get_or_create(name = 'red')
ch = ConfigHouses(config = c, house = red, count = 4)
ch.save()
yellow = House.objects.get_or_create(name = 'yellow')
ch = ConfigHouses(config = c, house = yellow, count = 5)
ch.save()
执行上述查询后,数据库将如下所示:
CONFIG TABLE
----------------
| pk | name |
|----|---------|
| 1 | level-1 |
----------------
HOUSE TABLE
----------------
| pk | name |
|----|---------|
| 1 | red |
| 2 | yellow |
----------------
CONFIGHOUSES TABLE
-------------------------------
| pk | config | house | count |
|----|--------|-------|-------|
| 1 | 1 | 1 | 4 |
| 2 | 1 | 2 | 5 |
-------------------------------
要了解特定配置中特定类型的房屋数量,您可以直接或通过其中一个模型查询中间表:
>>> ConfigHouses.objects.get(config = c, house__name = 'red').count
4
>>> c.confighouses.get(house__name = 'red').count
4
>>> yellow.confighouses_set.get(config = c).count
5
(最初的问题并没有明确表示多对多关系需要多重性,但我会留下原始答案,以防它有用。)
您最初的想法(houses
应该是ManyToManyField
)是正确的想法。只是为了在定义它之前引用House
类,您需要传递类的名称。见the Django documentation:
如果需要在尚未定义的模型上创建关系,可以使用模型的名称,而不是模型对象本身。
拥有nbr_houses
字段也是一个坏主意,因为如果有人更新多对多关系而又不记得更新nbr_houses
字段,那么该字段可能会变得不正确。您可以使用houses.count()
获取相关房屋的数量。
所以你的Config
课应该是这样的:
class Config(models.Model)
name = models.CharField(max_length=200)
# The class House is not yet defined, so refer to it by name.
houses = models.ManyToManyField('House')
您可以使用RelatedManager interface更新多对多关系:有方法add
,create
,remove
,clear
,或者你可以分配给它:
config.houses = House.objects.filter(color = 'red')