将同一对象两次添加到ManyToManyField

时间:2009-09-13 14:04:57

标签: python django django-models

我有两个django模型类:

class A(models.Model):
     name = models.CharField(max_length = 128)    #irrelevant

class B(models.Model):
     a = models.ManyToManyField(A)
     name = models.CharField(max_length = 128)    #irrelevant

我想做的是以下内容:

a1 = A()
a2 = A()
b = B()

b.a.add(a1)
b.a.add(a1)    #I want to have a1 twice
b.a.add(a2)

assert len(b.a.all()) == 3 #this fails; the length of all() is 2

我猜add()使用set语义,但我怎么能绕过呢?我试着调查自定义管理器,但我不确定这是否正确(似乎很复杂)......

提前致谢!

3 个答案:

答案 0 :(得分:4)

我认为您想要的是使用中间模型使用ManyToManyField中的through关键字参数来形成M2M关系。有点像上面的第一个答案,但更多的是“Django-y”。

class A(models.Model):
    name = models.CharField(max_length=200)

class B(models.Model):
    a = models.ManyToManyField(A, through='C')
    ...

class C(models.Model):
    a = models.ForeignKey(A)
    b = models.ForeignKey(B)

使用through关键字时,通常的M2M操作方法不再可用(这意味着addcreateremove=的分配运营商)。相反,你必须自己创建中间模型,如下所示:

 >>> C.objects.create(a=a1, b=b)

但是,您仍然可以在包含ManyToManyField的模型上使用常规查询操作。换句话说,以下内容仍然有效:

 >>> b.a.filter(a=a1)

但也许更好的例子是这样的:

>>> B.objects.filter(a__name='Test')

只要中间模型上的FK字段未指定为unique,您就可以使用相同的FK创建多个实例。您还可以通过将您喜欢的任何其他字段添加到C来附加有关关系的其他信息。

记录中间模型here

答案 1 :(得分:3)

Django使用关系数据库作为它的底层存储,而且本质上它已经“设置了语义”:没有办法绕过它。因此,如果你想要任何东西的“多组”,你必须用一个数字字段来表示它,它计算每个项目“发生”的次数。 ManyToManyField没有这样做 - 所以,相反,你需要一个单独的Model子类,它明确指出它与之相关的A和B,并且有一个整数属性来“计算多少次”。

答案 2 :(得分:0)

一种方法:

class A(models.Model):
    ...

class B(models.Model):
    ...

class C(models.Model):
    a = models.ForeignKey(A)
    b = models.ForeignKey(B)

然后:

>>> a1 = A()
>>> a2 = A()
>>> b = B()
>>> c1 = C(a=a1, b=b)
>>> c2 = C(a=a2, b=b)
>>> c3 = C(a=a1, b=b)

所以,我们只是:

>>> assert C.objects.filter(b=b).count == 3
>>> for c in C.objects.filter(b=b):
...     # do something with c.a