class EmailToAssociation (models.Model):
email = models.EmailField(_("Email address"), unique=True)
association = models.ManyToManyField(showorderofplay.Association)
And this ModelForm:
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?
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).
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.
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?
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?
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?
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.
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:
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)
You’re overthinking this. You’re worried about things you don’t need to worry about.
To avoid confusion, you should not name the variable the_form, because the form.save() method returns the object being saved, not the form. The the_form variable will actually be the instance of EmailToAssociation.
One more time.
This line:
does not mean you need to do this:
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.
I’ve moved away from the manytomany relationship as it turned out to be the wrong relationship I needed.
the model is now:
class EmailToAssociation (models.Model):
email = models.EmailField(_("Email address"))
association = models.ForeignKey(
Association, on_delete=models.CASCADE)
The view as discussed above is:
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:
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
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.
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.)