0

I have this form:

class TaskSelectForm(forms.Form):
    def __init__(self, *args, **kwargs):
        # department = kwargs.pop('department')
        
        super(TaskSelectForm, self).__init__(*args, **kwargs)
        (...)

I can call the form in my view with something like this: TaskSelectForm(request.GET) and it'll work fine. When i make a GET request the page loads and the fields are still filed.. Just as expected

However, i need the form to take an extra parameter, something like this TaskSelectForm(request.GET, department = department)

Problem is that for every GET request the form fields become empty. The form doesn't retain the values from the last request.

I want the form fields to keep the last values.. How can i achieve this?

I'll post the whole code below just to make sure i didn't mess up:

class TaskSelectForm(forms.Form):
    def __init__(self, *args, **kwargs):
        department = kwargs.pop('department')
        
        super(TaskSelectForm, self).__init__(*args, **kwargs)

        department_tasks = Task.objects.filter(department = department)
        distinct_cr = [(k['client_repr'], k['client_repr']) for k in department_tasks.values('client_repr').distinct()]
        distinct_td = [(k['task_description'], k['task_description']) for k in department_tasks.values('task_description').distinct()]
        distinct_us = [(x.id, (str(x))) for x in department.users.all()]

        for _ in [distinct_cr, distinct_td, distinct_us]:
            _.sort(key = lambda x: x[0])
            _.insert(0, ('', '---------'))
        
        self.fields['client_repr'] = forms.ChoiceField(choices = distinct_cr, required = False)
        self.fields['task_description'] = forms.ChoiceField(choices = distinct_td, required = False)
        self.fields['from'] = forms.DateField(widget = forms.DateInput())
        self.fields['to'] = forms.DateField(widget = forms.DateInput())
        self.fields['user'] = forms.ChoiceField(choices = distinct_us, required = False)

        for visible in self.visible_fields():
            visible.field.widget.attrs['class'] = 'form-control mb-3'
Ricardo Vilaça
  • 846
  • 1
  • 7
  • 18

2 Answers2

2

Use Sessions (included with Django).

You can save a variable on the server side, but store a reference to the variable on the client using a cookie. This allows you to preserve state for visitors while they are using your site.

You can temporarily save your data (and preserve it for the length of the user's session) using request.session, which is a dictionary. You can access request.session anywhere you have access to a request object:

request.session['your_field'] = form.cleaned_data['your_field']

When you are done with the data, you can delete the key:

del request.session['your_field']

To check for the existence of a session key without throwing a NameError if it doesn't exist:

request.session.get('your_field', '')    

Per this StackOverflow answer, you need to call request.session.modified = True if using a nested key (e.g. request.session['your_field']['your_nested_field']), although this should not be a problem for your use case.

(Note that this requires the browser to have cookies enabled, which shouldn't be a problem for 99.9% of your visitors).

arcanemachine
  • 571
  • 4
  • 9
1

Why don't you use initial?

Like f = ContactForm(initial={'subject': 'Hi there!'})?

Here is documentation - https://docs.djangoproject.com/en/3.1/ref/forms/api/#dynamic-initial-values

UPDATE: Or you can use form wizard - https://django-formtools.readthedocs.io/en/latest/wizard.html

mrvol
  • 2,575
  • 18
  • 21
  • 1
    That was it! I just needed to set the initial to the value of the passed request. Ex: self.fields['client_repr'].initial = request.get('client_repr') – Ricardo Vilaça Sep 21 '20 at 10:08