Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django - Form across multiple views with progress saving

Tags:

python

django

I'm working on a Django project and to make the forms experience far smoother I want to spread a ModelForm across a few pages. It would be ideal if users who are logged in can save their progress in the form without actually posting the content (in this case, a JobApplication where users can come back to filling in info without actually sending off the application).

Currently I have looked at other answers on SO such as this one; but this only shows me how to utilise caching to store information between the views where the form is present.

Models.py (models, forms and views have been simplified for readability):

class JobApplication(models.Model):
    job = models.ForeignKey(JobPost,on_delete=models.SET_NULL,...)
    user = models.ForeignKey(AUTH_USER_MODEL,...)
    details = models.CharField(max_length=300)
    skills = models.CharField(max_length=300)
    feedback = models.CharField(max_length=300)
    #... [insert more fields] ...

Forms.py:

class Application(forms.ModelForm):
    details = forms.CharField() # To go in page 1 of the form process
    skills = forms.CharField() # To go in page 2
    feedback = forms.CharField() # To go in page 3
    class Meta:
        model = JobApplication
        fields = ['details','skills','feedback']

Views.py:

from . import forms
def view1(request):
    form = forms.Application()
    if request.method == 'POST':
        form = forms.Application(data=request.POST)
        ... some logic here which I am not sure of ...
    return render(request, 'view1.html', {})

def view2(request):
    form = forms.Application()
    if request.method == 'POST':
        form = forms.Application(data=request.POST)
        ...
    return render(request, 'view2.html', {})

def view3(request):
    form = forms.Application()
    if request.method == 'POST':
        form = forms.Application(data=request.POST)
        ...
    return render(request, 'view3.html', {})

Note that I'm happy to edit my forms or models to achieve this multi-page, save progress effect that you may see on job sites.

Let me know if there's any more code I can add that will be useful, since I'm not too sure what else will be required.

Thanks!

like image 558
jayt Avatar asked Mar 17 '18 14:03

jayt


2 Answers

  1. I had a similar use case in my application what I did was created multiple forms out the models and a central view controlling the progress of the form.

    The view has a list of forms it has to propagate through

    GET : /form/<index> => form/0
    POST : Save data to the form
    
  2. Initially the form will have no initial data, for index > 0 the initial data will be the previously saved model object

  3. When user clicks on next increment the URL index counter, Decrease it for prev, Don't save anything on skip

Here is a gist of how it would look. https://gist.github.com/bhavaniravi/b784c57ae9d24fce359ae44e2e90b8e3

I don't know if this is the best optimized method of all times but this is what I did. Any suggestions on improvement is most welcomed

like image 177
Bhavani Ravi Avatar answered Oct 17 '22 17:10

Bhavani Ravi


You will need a Form for each action you need. With it on hands, you can use a feature from Django 1.7 called Form Wizard (Yes, it is built in), the best way achieving this is using Class-Based Views, that is way more flexible, clean and cohesive than FBV in this case.

https://docs.djangoproject.com/en/1.7/ref/contrib/formtools/form-wizard/#

Basically you will define a list of steps and forms, both tied to the same URL. You can use customized templates for each form:

https://docs.djangoproject.com/en/1.7/ref/contrib/formtools/form-wizard/#using-a-different-template-for-each-form

[EDITED]

As jayt said in comments, the formtools was deprecated since version 1.8 and is now apart from core package and can be found in https://github.com/django/django-formtools/

Good luck. =)

like image 2
Andre Machado Avatar answered Oct 17 '22 19:10

Andre Machado