117

I can't find it anywhere, so your help will be nice for me :) Here is that field:

categories = models.ManyToManyField(fragmentCategory)

FragmentCategory:

class fragmentCategory(models.Model):

        CATEGORY_CHOICES = (
                        ('val1', 'value1'),
                        ('val2', 'value2'),
                        ('val3', 'value3'),
                        )

        name = models.CharField(max_length=20, choices=CATEGORY_CHOICES)

Here is the form to send:

<input type="checkbox" name="val1" />
<input type="checkbox" name="val2" />
<input type="checkbox" name="val3" />

I tried something like this:

categories = fragmentCategory.objects.get(id=1),

Or:

categories = [1,2]
Amir Savand
  • 365
  • 5
  • 13
IProblemFactory
  • 9,551
  • 8
  • 50
  • 66

2 Answers2

209

There's a whole page of the Django documentation devoted to this, well indexed from the contents page.

As that page states, you need to do:

my_obj.categories.add(fragmentCategory.objects.get(id=1))

or

my_obj.categories.create(name='val1')
Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • 29
    Do you then need to call `my_obj.save()` to save the update or is this done automatically? – CpILL Jan 25 '17 at 06:00
  • 7
    @CpILL Seems to be done automatically. Try it out in `python manage.py shell`. – Rikki Mar 13 '17 at 11:03
  • 1
    as this doc you need call .save too : https://docs.djangoproject.com/en/2.2/topics/db/examples/many_to_many/#many-to-many-relationships – mehdi Jul 16 '19 at 06:04
  • 16
    @mehdi You only need to call save the first time that you create the object with the many to many field so that it gets a primary key. After that the behavior is that you can add without saving. – ICW Jul 30 '19 at 16:14
  • Ans is right just need more clarification object of what so sir please edit the answer. – M.Idrish Jan 13 '23 at 09:21
7

In case someone else ends up here struggling to customize admin form Many2Many saving behaviour, you can't call self.instance.my_m2m.add(obj) in your ModelForm.save override, as ModelForm.save later populates your m2m from self.cleaned_data['my_m2m'] which overwrites your changes. Instead call:

my_m2ms = list(self.cleaned_data['my_m2ms'])
my_m2ms.extend(my_custom_new_m2ms)
self.cleaned_data['my_m2ms'] = my_m2ms

(It is fine to convert the incoming QuerySet to a list - the ManyToManyField does that anyway.)

Chris
  • 5,664
  • 6
  • 44
  • 55