1

我在编写 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. 此外,aHouse可能会两次引用相同的配置。

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条目,我希望能够关联不同数量的房屋(对象)。也许以后还会有马:)我希望你明白。

4

1 回答 1

5

该问题已更新以解释您可能希望将每个房屋的某些数量与配置相关联。为了在 Django 中执行此操作,您需要一个新模型,Django 调用一个中间模型。像这样:

class ConfigHouses(model.Model):
    config = model.ForeignKey('Config')
    house = model.ForeignKey('House')
    count = model.PositiveIntegerField()
    class Meta:
        unique_together = ('config', 'house')

然后在Config类中声明 aManyToManyField并将中间模型分配给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应该是 a ManyToManyField)是正确的想法。只是为了House在定义之前引用类,需要传递类的名称。请参阅Django 文档

如果您需要在尚未定义的模型上创建关系,您可以使用模型的名称,而不是模型对象本身。

拥有一个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 接口更新多对多关系:有方法addcreateremoveclear,或者您可以只分配给它:

config.houses = House.objects.filter(color = 'red')
于 2012-08-27T16:22:46.730 回答