Reputation: 418
I created the FormView below that will dynamically return a form class based on what step in the process that the user is in. I'm having trouble with the get_form
method. It returns the correct form class in a get request, but the post request isn't working.
tournament_form_dict = {
'1':TournamentCreationForm,
'2':TournamentDateForm,
'3':TournamentTimeForm,
'4':TournamentLocationForm,
'5':TournamentRestrictionForm,
'6':TournamentSectionForm,
'7':TournamentSectionRestrictionForm,
'8':TournamentSectionRoundForm,}
class CreateTournament(FormView):
template_name = 'events/create_tournament_step.html'
def __init__(self, *args, **kwargs):
form_class = self.get_form()
success_url = self.get_success_url()
super(CreateTournament, self).__init__(*args, **kwargs)
def get_form(self, **kwargs):
if 'step' not in kwargs:
step = '1'
else:
step = kwargs['step']
return tournament_form_dict[step]
def get_success_url(self, **kwargs):
if 'step' not in kwargs:
step = 1
else:
step = int(kwargs['step'])
step += 1
if 'record_id' not in kwargs:
record_id = 0
else:
record_id = int(kwargs['record_id'])
return 'events/tournaments/create/%d/%d/' % (record_id, step)
The post request fails at the django\views\generic\edit.py
at the get_form
line, which I realize is because I've overwritten it in my FormView:
def post(self, request, *args, **kwargs):
"""
Handle POST requests: instantiate a form instance with the passed
POST variables and then check if it's valid.
"""
form = self.get_form()
if form.is_valid(): …
return self.form_valid(form)
else:
return self.form_invalid(form)
However, when I change the name of my custom get_form
method to say gen_form
, like so:
def __init__(self, *args, **kwargs):
form_class = self.gen_form()
success_url = self.get_success_url()
super(CreateTournament, self).__init__(*args, **kwargs)
def gen_form(self, **kwargs):
if 'step' not in kwargs:
step = '1'
else:
step = kwargs['step']
return tournament_form_dict[step]
my form class doesn't get processed in the get request and evaluates to None
. I'm scratching my head as to why when I override the get_form
method, it works, but my own named method doesn't? Does anyone know what the flaw might be?
Upvotes: 1
Views: 2826
Reputation: 476614
Django's FormMixin
[Django-doc] defines a get_form
function [Django-doc]. You here thus basically subclassed the FormView
and "patched" the get_form
method.
Your attempt with the gen_form
does not work, since you only defined local variables, and thus do not make much difference anyway, only the super(..)
call will have some side effects. The other commands will keep the CPU busy for some time, but at the end, will only assign a reference to a Form
calls to the form_class
variable, but since it is local, you will throw it away.
That being said, your function contains some errors. For example the **kwargs
will usually contain at most one parameter: form_class
. So the step
s will not do much. You can access the URL parameters through self.args
and self.kwargs
, and the querystring parameters through self.request.GET
. Furthermore you probably want to patch the get_form_class
function anyway, since you return a reference to a class, not, as far as I understand it, a reference to an initilized form.
Constructing URLs through string processing is probably not a good idea either, since if you would (slightly) change the URL pattern, then it is likely you will forget to replace the success_url
, and hence you will refer to a path that no longer exists. Using the reverse
function is a safer way, since you pass the name of the view, and parameters, and then this function will "calculate" the correct URL. This is basically the mechanism behind the {% url ... %}
template tag in Django templates.
A better approach is thus:
from django.urls import reverse
class CreateTournament(FormView):
template_name = 'events/create_tournament_step.html'
def get_form_class(self):
return tournament_form_dict[self.kwargs.get('step', '1')]
def get_success_url(self):
new_step = int(self.kwargs.get('step', 1)) + 1
# use a reverse
return reverse('name_of_view', kwargs={'step': new_step})
Upvotes: 3