# Set ManyToMany value that is NOT in ModelForm

**URL:** <https://forum.djangoproject.com/t/set-manytomany-value-that-is-not-in-modelform/28949>\
**Category:** Using the ORM\
**Created:** [March 11, 2024, 9:57am UTC](https://forum.djangoproject.com/t/set-manytomany-value-that-is-not-in-modelform/28949 "2024-03-11T09:57:24Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![nmilner1234](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nmilner1234/32/19690_2.png) [@nmilner1234](https://forum.djangoproject.com/u/nmilner1234)\
**Post date:** [March 11, 2024, 9:57am UTC](https://forum.djangoproject.com/t/set-manytomany-value-that-is-not-in-modelform/28949/1 "2024-03-11T09:57:24Z")

</div>

I have this model:

```auto
class EmailToAssociation (models.Model):
    email = models.EmailField(_("Email address"), unique=True)
    association = models.ManyToManyField(showorderofplay.Association)

```

And this ModelForm:

```auto
class ManageAscPeopleCreateForm(forms.ModelForm):
    class Meta:
        model = EmailToAssociation
        fields = ['email']

```

Which only allows the user to enter an email as the association id comes from the server so no point in passing it to the client to then just send it back. I’m trying to write the association in form\_valid but as association was not in the form, it is not having it. Where would I intercept the save of the model data such that I could inject association alongside email?

```auto
class ManageAscPeopleCreate(CreateView):
    model = EmailToAssociation
    form_class = ManageAscPeopleCreateForm

    def get_success_url(self):
        return reverse("showorderofplay:manage-asc-people", args=[self.kwargs["association_id"]])

    def form_valid(self, form):

        super_resp = super().form_valid(form)
        self.model.association.add(self.kwargs["association_id"])
        return super_resp

```

I’m getting this error for the attempt to add association\_id

```auto
AttributeError at /1/add_person_to_asc/
'ManyToManyDescriptor' object has no attribute 'add'

```

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [March 11, 2024, 11:05am UTC](https://forum.djangoproject.com/t/set-manytomany-value-that-is-not-in-modelform/28949/2 "2024-03-11T11:05:12Z")

</div>

The issue is that you’re trying to assign the value to the `EmailToAssociation` model (`self.model`), instead of the instance of the model that was created in the view (`self.object`).

---

<div class="post-metadata">

**Author:** ![nmilner1234](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nmilner1234/32/19690_2.png) [@nmilner1234](https://forum.djangoproject.com/u/nmilner1234)\
**Post date:** [March 11, 2024, 3:18pm UTC](https://forum.djangoproject.com/t/set-manytomany-value-that-is-not-in-modelform/28949/3 "2024-03-11T15:18:28Z")

</div>

What is tripping me up each time is understanding what is available with each object. I tried using

```auto
print (dir(self.object))

```

Which produces :

```auto
' __bool__', ' __class__', ' __delattr__', ' __dir__', ' __doc__', ' __eq__', ' __format__', ' __ge__', 
' __getattribute__', ' __getstate__', ' __gt__', ' __hash__', ' __init__', ' __init_subclass__', ' __le__', 
' __lt__', ' __ne__', ' __new__', ' __reduce__', ' __reduce_ex__', ' __repr__', ' __setattr__', ' __sizeof__', 
' __str__', ' __subclasshook__']

```

So I still don’t know what I then call to access the association value that will be written to the database?

[ccbv CreateView](https://ccbv.co.uk/projects/Django/5.0/django.views.generic.edit/CreateView/) again doesn’t seem to clear to me how I set a model field value.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [March 11, 2024, 4:05pm UTC](https://forum.djangoproject.com/t/set-manytomany-value-that-is-not-in-modelform/28949/4 "2024-03-11T16:05:46Z")

</div>

> [@nmilner1234](#):
>
> ```auto
> print (dir(self.object))
> 
> ```

Where _exactly_ in your view do you have that line?

You set a model field value the same regardless of where you set it:  
`instance.field_name = value`

However, keep in mind that a ManyToManyField is _not_ a field in the model. It’s a reference to a relationship manager for data stored in a “through” table that establishes the connection between the two models. Adding a value to a many-to-many relationship does **not** affect either of the two related models. It’s _only_ the through table that is being changed.

---

<div class="post-metadata">

**Author:** ![nmilner1234](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nmilner1234/32/19690_2.png) [@nmilner1234](https://forum.djangoproject.com/u/nmilner1234)\
**Post date:** [March 11, 2024, 4:42pm UTC](https://forum.djangoproject.com/t/set-manytomany-value-that-is-not-in-modelform/28949/5 "2024-03-11T16:42:37Z")

</div>

I put it in form\_valid as I was trying to see what was available to me

```auto
class ManageAscPeopleCreate(CreateView):
    model = EmailToAssociation
    form_class = ManageAscPeopleCreateForm

    def get_success_url(self):
        return reverse("showorderofplay:manage-asc-people", args=[self.kwargs["association_id"]])

    def form_valid(self, form):
        print (dir(self))
        print (self.assocation)
        self.object.model.association.add(self.kwargs["association_id"])
        return super().form_valid(form)

```

self.association doesn’t work either

```auto
AttributeError: 'ManageAscPeopleCreate' object has no attribute 'assocation'

```

which makes me think I need to add it somewhere because it is not defined in the form as I was trying to avoid sending it to the client and back again?

I used .add() in another class method to add a many to many id to a user so would that not work here as well?

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [March 11, 2024, 4:45pm UTC](https://forum.djangoproject.com/t/set-manytomany-value-that-is-not-in-modelform/28949/6 "2024-03-11T16:45:25Z")

</div>

The `self.object` isn’t created until the form is saved - which happens by default in the `super` method of `form_valid`.

You need to call `super()` _before_ trying to use `self.object`, in exactly the same manner as at [add value to users manytomany field from form results - #5 by nmilner1234](https://forum.djangoproject.com/t/add-value-to-users-manytomany-field-from-form-results/28869/5)

---

<div class="post-metadata">

**Author:** ![nmilner1234](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nmilner1234/32/19690_2.png) [@nmilner1234](https://forum.djangoproject.com/u/nmilner1234)\
**Post date:** [March 11, 2024, 4:48pm UTC](https://forum.djangoproject.com/t/set-manytomany-value-that-is-not-in-modelform/28949/7 "2024-03-11T16:48:36Z")

</div>

The reason I didn’t do it this way round was because I was thinking that after the point of calling super() the record would now already have been created in the EmailToAssociation model and therefore it now  
is too late to set the assocition value. When exactly does the object get saved in the table?

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [March 11, 2024, 4:50pm UTC](https://forum.djangoproject.com/t/set-manytomany-value-that-is-not-in-modelform/28949/8 "2024-03-11T16:50:01Z")

</div>

> [@nmilner1234](#):
>
> therefore it now  
> is too late to set the assocition value.

See the last paragraph of my comment at: [Set ManyToMany value that is NOT in ModelForm - #4 by KenWhitesell](https://forum.djangoproject.com/t/set-manytomany-value-that-is-not-in-modelform/28949/4)

> [@nmilner1234](#):
>
> When exactly does the object get saved in the table?

When the `.save()` method is called on the form.

---

<div class="post-metadata">

**Author:** ![nmilner1234](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nmilner1234/32/19690_2.png) [@nmilner1234](https://forum.djangoproject.com/u/nmilner1234)\
**Post date:** [March 11, 2024, 4:56pm UTC](https://forum.djangoproject.com/t/set-manytomany-value-that-is-not-in-modelform/28949/9 "2024-03-11T16:56:18Z")

</div>

My understanding is that

```auto
super_resp = super().form_valid(form)

```

will save the form into the table (so at the moment the record just has email set, not assoction)

However, the object is now also available in super\_resp so doing this:

```auto
self.object.association.add(self.kwargs["association_id"])

```

Now adds the association id to the object so is that also automatically updating the database record or is it the return of super\_resp that then triggers .save() to then commit to the database?

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [March 11, 2024, 4:58pm UTC](https://forum.djangoproject.com/t/set-manytomany-value-that-is-not-in-modelform/28949/10 "2024-03-11T16:58:34Z")

</div>

No.

Quoting myself directly:

> However, keep in mind that a ManyToManyField is _not_ a field in the model. It’s a reference to a relationship manager for data stored in a “through” table that establishes the connection between the two models.  
> **Adding a value to a many-to-many relationship does not affect either of the two related models.** It’s _only_ the through table that is being changed.

See the docs at [Many-to-many relationships | Django documentation | Django](https://docs.djangoproject.com/en/5.0/topics/db/examples/many_to_many/)

---

<div class="post-metadata">

**Author:** ![nmilner1234](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nmilner1234/32/19690_2.png) [@nmilner1234](https://forum.djangoproject.com/u/nmilner1234)\
**Post date:** [March 11, 2024, 5:21pm UTC](https://forum.djangoproject.com/t/set-manytomany-value-that-is-not-in-modelform/28949/11 "2024-03-11T17:21:39Z")

</div>

Sorry, it was the through table bit I didn’t appreciate.

---

<div class="post-metadata">

**Author:** ![nmilner1234](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nmilner1234/32/19690_2.png) [@nmilner1234](https://forum.djangoproject.com/u/nmilner1234)\
**Post date:** [March 12, 2024, 9:26am UTC](https://forum.djangoproject.com/t/set-manytomany-value-that-is-not-in-modelform/28949/12 "2024-03-12T09:26:08Z")

</div>

I changed the field to a foreign key and this is now my form\_valid() which works but I wondered if this is the best/correct way to do this:

```auto
    def form_valid(self, form):
        the_form = form.save(commit=False)
        the_form.association = Association.objects.get(pk=self.kwargs['association_id'])

        # If the user has an account, also add access to the association
        try:
            user_data = CustomUser.objects.get(email=the_form.email)
            user_data.asc_access.add(self.kwargs["association_id"])
            user_data.save()
        except:
            pass

        return super(ManageAscPeopleCreate, self).form_valid(form)

```

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [March 12, 2024, 11:46am UTC](https://forum.djangoproject.com/t/set-manytomany-value-that-is-not-in-modelform/28949/13 "2024-03-12T11:46:56Z")

</div>

You’re overthinking this. You’re worried about things you don’t need to worry about.

> [@nmilner1234](#):
>
> `the_form = form.save(commit=False)`

To avoid confusion, you should not name the variable `the_form`, because [the `form.save()` method](https://docs.djangoproject.com/en/5.0/topics/forms/modelforms/#the-save-method) returns the **object being saved** , not the form. The `the_form` variable will actually be the instance of `EmailToAssociation`.

One more time.

> [@KenWhitesell](#):
>
> **Adding a value to a many-to-many relationship does not affect either of the two related models.**

This line:

> [@nmilner1234](#):
>
> `user_data.asc_access.add(self.kwargs["association_id"])`

does **not** mean you need to do this:

> [@nmilner1234](#):
>
> `user_data.save()`

because `user_data` is **not** modified by the `add`.

Actually, I’m starting to get lost with the models being used here. To summarize this for future messages on this thread:

- This form is creating an instance of `EmailToAssociation` (?)
- How does this relate to the `Association` object being referenced here?
- Where does CustomUser come into play?

It might be helpful at this point if you post these models. I’m not sure I’m seeing the bigger picture here.

---

<div class="post-metadata">

**Author:** ![nmilner1234](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nmilner1234/32/19690_2.png) [@nmilner1234](https://forum.djangoproject.com/u/nmilner1234)\
**Post date:** [March 12, 2024, 1:40pm UTC](https://forum.djangoproject.com/t/set-manytomany-value-that-is-not-in-modelform/28949/14 "2024-03-12T13:40:48Z")

</div>

I’ve moved away from the manytomany relationship as it turned out to be the wrong relationship I needed.

the model is now:

```auto
class EmailToAssociation (models.Model):
    email = models.EmailField(_("Email address"))
    association = models.ForeignKey(
        Association, on_delete=models.CASCADE)

```

The view as discussed above is:

```auto
class ManageAscPeopleCreate(CreateView):
    model = EmailToAssociation
    form_class = ManageAscPeopleCreateForm

    def get_success_url(self):
        return reverse("showorderofplay:manage-asc-people", args=[self.kwargs["category_id"], self.kwargs["association_id"]])

    def form_valid(self, form):
        the_form = form.save(commit=False)
        the_form.association = Association.objects.get(
            pk=self.kwargs['association_id'])

        # If the user has an account, also add access to the association
        try:
            user_data = CustomUser.objects.get(email=the_form.email)
            user_data.asc_access.add(self.kwargs["association_id"])
            user_data.save()
        except:
            pass

        return super(ManageAscPeopleCreate, self).form_valid(form)

```

and the form is:

```auto
class ManageAscPeopleCreateForm(forms.ModelForm):
    class Meta:
        model = EmailToAssociation
        fields = ['email']

```

The form only looks at the email field hence the view has to add in association

---

<div class="post-metadata">

**Author:** ![nmilner1234](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/nmilner1234/32/19690_2.png) [@nmilner1234](https://forum.djangoproject.com/u/nmilner1234)\
**Post date:** [March 12, 2024, 1:44pm UTC](https://forum.djangoproject.com/t/set-manytomany-value-that-is-not-in-modelform/28949/15 "2024-03-12T13:44:22Z")

</div>

The try: code is to update a user record **not** related to the current logged in user.

---

<div class="post-metadata">

**Author:** ![KenWhitesell](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kenwhitesell/32/280_2.png) [@KenWhitesell](https://forum.djangoproject.com/u/KenWhitesell)\
**Post date:** [March 12, 2024, 2:31pm UTC](https://forum.djangoproject.com/t/set-manytomany-value-that-is-not-in-modelform/28949/16 "2024-03-12T14:31:07Z")

</div>

First, _which_ many-to-many relationship has been removed? It appears you’re still relying upon one for the relationship between Association and CustomUser. If _that_ is the relationship that has been changed, then some of what I’ve written below would not be right.

> [@nmilner1234](#):
>
> The try: code is to update a user record **not** related to the current logged in user.

Except you are **not updating** the user record.

The `CustomUser` object, whichever one it is, is **not being changed** during this process. There is no need to save it.

There’s no need for you to do a query for the Association. You can do this:  
(Renaming `the_form` to `email_association` for clarity.)

```auto
email_association = form.save(commit=False)
email_association.association_id = self.kwargs['association_id']`
email_association.save()

```

You could also avoid the extra query on `CustomUser` if you added the row directly to the join table established for that many-to-many relationship.
