0

This question have been answered before, e.g here: Proper way to handle multiple forms on one page in Django

So before it gets marked as a duplicate. I'll try to explain why its different.

I've got three tables, Project, ProjectUser and User. ProjectUser is a join table to indicate what users belongs to what project.

I'm trying to create a view that lets users update project details (e.g. name of project), and also add users to the project (which is indicated by a dropdown that shows all available users like the standard one for models with foreign keys in the django admin panel). All works fine until I'm trying to pass an id from the views to the formclass and submit.

views.py

class ProjectUpdateView(UpdateView):
    form_class = ProjectUpdateForm
    second_form_class = ProjectUserAddForm
    template_name = 'projects/project_edit.html'
    success_url = reverse_lazy('projects:list')


    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        id_ = self.kwargs.get("id")
        project = Project.objects.get(id=id_)
        if 'form' not in context:
            context['form'] = self.form_class()
        if 'form2' not in context:
            team = Organization.objects.get(id=project.organization_id)
            context['form2'] = self.second_form_class(queryset=team) # <-- here is where I wish to pass a queryset, which fails when trying to submit form2.


        context['project_users'] = ProjectUser.objects.filter(project__id=project.id).select_related("project")
        context['team'] = Organization.objects.get(id=project.organization_id)


        return context

    def get_object(self):
        id_ = self.kwargs.get("id")
        return get_object_or_404(Project, id=id_)

    def form_invalid(self, **kwargs):
        return self.render_to_response(self.get_context_data(**kwargs))

    def form_valid(self, form):
        project_id = self.kwargs.get("id")
        if self.request.POST.get("form2") == 'Add':
            ProjectUser.objects.create(user_id=self.request.POST.get("user"), project_id=project_id)
        form.save()

        success_url = reverse("projects:edit", args=(project_id,))

        return HttpResponseRedirect(success_url)



    def post(self, request, *args, **kwargs):

        # get the user instance
        self.object = self.get_object()

        # determine which form is being submitted
        # uses the name of the form's submit button
        if 'form' in request.POST:
            # get the primary form
            form_class = self.get_form_class() 
            form_name = 'form'
        else:
            # get the secondary form
            form_class = self.second_form_class
            form_name = 'form2'

        # get the form
        form = self.get_form(form_class)
        # validate
        if form.is_valid():
            return self.form_valid(form)
        else:
            return self.form_invalid(**{form_name: form})

projects_edit.html

    <form action="{% url 'projects:edit' project.id %}" method="post" enctype="multipart/form-data">
      {% csrf_token %}
      {{form.name|as_crispy_field}}
      <input name="form" value="Update" type="submit"></input>
    </form>
    <form action="{% url 'projects:edit' project.id %}" method="post" enctype="multipart/form-data">
      {% csrf_token %}
      {{form2.user}}
      <input name="form2" value="Add" type="submit"></input>
    </form>

forms.py

class ProjectUpdateForm(ModelForm):
    class Meta:
        model = Project
        fields = ["name"]


class ProjectUserAddForm(ModelForm):
     def __init__(self, queryset, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['user'].queryset = User.objects.filter(organizations_organizationuser__organization__id=queryset.id) # here is where I wish to pass the id of the queryset from the form class

    class Meta:
        model = ProjectUser
        fields = ["user"]

Rendering the forms works just fine with the desired queryset, but when I try to submit the second form (adding a user to the ProjectUserForm, I just get a

__init__() missing 1 required positional argument: 'queryset' error. Any ideas on how to solve this? Perhaps I'm making it way more complicated than it should

I have also added a screenshot if it helps: https://imgur.com/a/uqu0UeB

erikvm
  • 465
  • 5
  • 15
  • Your `ProjectUseerAddForm` has a `queryset` as parameter. But in your `post` method, you set `form_class = self.second_form_class`, and then call `form = self.get_form(form_class)`, which will thus omit passing the queryset. – Willem Van Onsem Feb 15 '20 at 18:55
  • But if I try to pass something in the `POST` method, e.g `form_class = self.second_form_class(queryset=team)`. I just get 'ProjectUserAddForm' object is not callable – erikvm Feb 15 '20 at 19:01
  • Yes, that is because you use `.get_form(..)` after that. You need two *separate* methods I think that each construct their form, and encapsulate the kwargs for the second form in a method. – Willem Van Onsem Feb 15 '20 at 19:02
  • Okay, thanks for your tip - any guidelines? Not sure how/what that would look like – erikvm Feb 15 '20 at 19:07

0 Answers0