Django multiple page form
Please, help me with my question :) I have a three models:
# Genre model
class Genre(models.Model):
title = models.CharField(...)
# Author model
class Author(models.Model):
name = models.CharField(...)
genre = models.ForeignKey(Author)
# Book model
class Book(models.Model):
genre = models.ForeignKey(Genre)
title = models.CharField开发者_JAVA百科(...)
author = models.ForeignKey(Author)
I want to create two-step-form for Book model:
1st page - choose a Genre, 2nd page - title and related to selected genre AuthorHow I can do this without ajax and javascript?
I've done this in Django and other environments. The way I've done it most recently is this: Make only the absolute minimum number of fields required. Collect these on the first page of the form. When the user submits (I suggest post on redirect), store them in the database and then show the rest of the fields on the second form.
I use this in a registration form. Step one creates the account. A long registration form deters users. If they don't complete step 2, it's not a terrible lost. I know who they are and they can complete the rest later. If they do complete step 2 then I do an update and add the additional non-required fields. (oh, and by "not required" I mean that the db allows null)
Another option which I don't suggest is to store the variables in the session. The problem with this is that sometimes sessions time out before the user completes the form. Boo.
A better way than that is to keep the fields from step one in hidden fields in the 2nd form.
In both of these later cases, if the user leaves you have nothing. Maybe that's OK with your use case.
You can use FormWizard for this. The implementation instructions are explained very clearly on the Django Docs.
To summarize, you start by creating forms representing each of your steps. In your case it could be ModelForm
s for your Genre
and Book
models. Then define a subclass of WizardView
that defines how you want to process the final data using the done method. For example:
from django.http import HttpResponseRedirect
from django.contrib.formtools.wizard.views import SessionWizardView
class BookWizardView(SessionWizardView):
def done(self, form_list, **kwargs):
create_book_form_data(form_list).save()
return HttpResponseRedirect('/page-to-redirect-to-when-done/')
Then you create a template for the forms in your wizard. The template must be located at formtools/wizard/wizard_form.html
, or at the location that you overrode template_name
attribute to, or at the location returned by an overridden get_template_names
method. Finally, you hook your view to an URLconf passing an actual list of form classes that represent the steps in your wizard:
from django.conf.urls import patterns
from myapp.forms import GenreForm, BookAuthorForm
from myapp.views import BookWizardView
urlpatterns = patterns('',
(r'^contact/$', BookWizardView.as_view([GenreForm, BookAuthorForm])),
)
I highly second newz2000's method over the formWizard. The most important reason is as newz2000 said, not to lose the user's critical information they have filled out already if they goof up, let's say, on the last form in the multi-step.
Secondly, you don't need to indulge in the additional complexity of form wizardry, when it's not saving you that much anyway - you still have to define the individual forms, handle all fields and have multiple templates for the form wizard.
Thirdly you have the advantage of being able to use the model form using fields.keyorder to present the fields in each form (making sure to always send the instance if exists).
The only drawback I see with newz2000's method, if you can even call it that, is that you don't get to enforce mandatory field at the model level for those fields that come in the later steps and they need to be done at the form level.
Another potential for error (but this is easy to handle) is if your application logic for that model object has some dependency on the other mandatory type fields that may be left unfilled, but you should be checking for null condition on those fields anyway in the views / functions before operating on them. We can even add one "status_complete" type field to the model that stores values such as 1, 2, 3 for the levels of steps completed for the multi-form. This can then be used for conditional code branching to suggest form-completion reminders to user or a cleanup action if desired.
精彩评论