adding the same object twice to a ManyToManyField

拈花ヽ惹草 提交于 2020-01-21 04:31:12

问题


I have two django model classes:

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

What I want to do is the following:

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

I am guessing that add() uses a set semantic, but how can I circumvent that? I tried looking into custom managers, but I am not sure if this the right way (seems complicated)...

Thanks in advance!


回答1:


I think what you want is to use an intermediary model to form the M2M relationship using the through keyword argument in the ManyToManyField. Sort of like the first answer above, but more "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)

When using the through keyword, the usual M2M manipulation methods are no longer available (this means add, create, remove, or assignment with = operator). Instead you must create the intermediary model itself, like so:

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

However, you will still be able to use the usual querying operations on the model containing the ManyToManyField. In other words the following will still work:

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

But maybe a better example is something like this:

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

As long as the FK fields on the intermediary model are not designated as unique you will be able to create multiple instances with the same FKs. You can also attach additional information about the relationship by adding any other fields you like to C.

Intermediary models are documented here.




回答2:


Django uses a relational DB for its underlying storage, and that intrinsically DOES have "set semantics": no way to circumvent THAT. So if you want a "multi-set" of anything, you have to represent it with a numeric field that counts how many times each item "occurs". ManyToManyField doesn't do that -- so, instead, you'll need a separate Model subclass which explicitly indicates the A and the B it's relating, AND has an integer property to "count how many times".




回答3:


One way to do it:

class A(models.Model):
    ...

class B(models.Model):
    ...

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

Then:

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

So, we simply have:

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


来源:https://stackoverflow.com/questions/1417825/adding-the-same-object-twice-to-a-manytomanyfield

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!