adding the same object twice to a ManyToManyField

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.


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".


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