add value to users manytomany field from form results

I’ve made good progress today with forms but I’ve become stuck with how to update a users manytomany field. I am using the get_success_url method to try and write the created object id to the user model manytomany field event_access but I’m baffled how to do this. A pointer in the right direction would be appreciated.

class EventCreate(CreateView):

    def get_form(self, form_class=None):
        form = super(EventCreate, self).get_form(form_class)
        form.fields['association'].queryset = self.request.user.asc_access
        form.fields['association'].initial = self.kwargs["association_id"]
        form.fields['when'].widget = AdminDateWidget(attrs={'type': 'date'})
        form.fields['time'].widget = AdminDateWidget(attrs={'type': 'time'})
        return form

    def form_invalid(self, form):
        return self.render_to_response(self.get_context_data(form=form))

    def form_valid(self, form):

        self.request.user
        if form.cleaned_data['when'] < timezone.localdate():
            form.add_error('when', 'Date is in the past')
            return self.form_invalid(form)

        return super().form_valid(form)

    def get_success_url(self):
        # Update user's list of allowed events to edit        
        self.request.user.event_access.value = self.object.id
        print(self.object.id)
        breakpoint()
        return reverse("showorderofplay:events", args=[self.kwargs["association_id"]])

    model = Event
    fields = ['name', 'when', 'time', 'description',
              'active', 'cancelled', 'association']
    initial = {}

First, you’d be better off doing this work in form_valid rather than get_success_url.

You should also have your clean function for “when” in the form and not perform any additional validation in the view. The form_valid method should only be called once the entire form has been verified correct.

You can call super in your form_valid method and save the return value in a variable, update the objects, then return that saved value from your form_valid method.

See the docs and examples at Many-to-many relationships | Django documentation | Django for working with ManyToManyFields.

Thank you, I’ve tidied up the form validation but I’m really sorry but I do not understand the part about

you can call super in your form_valid method and save the return value in a variable, update the objects, then return that saved value from your form_valid method.

I have called the parent form_valid but I’m not sure how to access the objects and where do I return the value to from my form_valid?

class EventCreate(CreateView):
    model = Event
    initial = {}
    form_class = EventCreateForm

    def get_form(self, form_class=None):
        form = super(EventCreate, self).get_form(form_class)
        form.fields['association'].queryset = self.request.user.asc_access
        form.fields['association'].initial = self.kwargs["association_id"]
        form.fields['when'].widget = AdminDateWidget(attrs={'type': 'date'})
        form.fields['time'].widget = AdminDateWidget(attrs={'type': 'time'})
        return form

    def form_invalid(self, form):
        return self.render_to_response(self.get_context_data(form=form))

    def form_valid(self, form):
        super_resp = super().form_valid(form)
        print(super_resp)
        return super_resp

    def get_success_url(self):
        return reverse("showorderofplay:events", args=[self.kwargs["association_id"]])
class EventCreateForm(ModelForm):

    class Meta:
        model = Event
        fields = ['name', 'when', 'time', 'description',
                  'active', 'cancelled', 'association']
        labels = {'active': 'Published'}

    def clean_when(self):
        data = self.cleaned_data['when']
        if data < timezone.localdate():
            raise ValidationError(_('Date is in the past'))
        return data

What you’ve got here is 100% the right idea. (Including the return super_resp your form_valid)

If you dig through the code for a CreateView (and the Classy Class-Based Views is a great tool for doing that), you’ll see that ModelFormMixin has the line:
self.object = form.save()
This means that after super has been called, you can access the newly-created Event as self.object.

(I also recommend getting familiar with the CBV diagrams page as well.)

So this is all I needed to do :slight_smile: :tada:

 def form_valid(self, form):
        super_resp = super().form_valid(form)
        self.request.user.event_access.add(self.object.id)
        return super_resp

Thank you for your patience Ken, it must be frustrating at times having these sort of questions from inexpericienced programmers but your help is very gratefully received.