简体   繁体   中英

django form populate request.POST instance if form is invalid

I have a student application form, and upon user form submission, if there are errors in the form (for example, telephone number keyed in wrongly), i want django to populate the form with the previous POST data.

If i'm not mistaken, I need to use instance to achieve this. But I am not sure how to get this to work.

views.py

def add_new_student(request):

    if request.user.is_authenticated:
        lesson_plans = LessonPlans.objects.all()
        if 'submit_new_student' in request.POST:
            form = NewStudentForm(request.POST)
            if form.is_valid():
                #todo: add cleaned data
                form.save()  # save into DB
            else:  # this is where form is not valid, and where the POST data should fill up the form with the previous `post` data.
                form = NewStudentForm(request.POST, instance=form)
        else:
            form = NewStudentForm()
        args = {
            'form': form,
            'lesson_plans': lesson_plans
        }
        return render(request, 'static/html/new_student.html', args)

The trace error that I receive is 'ModelFormOptions' object has no attribute 'concrete_fields'

Any ideas how I can achieve this?


Update

forms.py

class NewStudentForm(forms.ModelForm):
    class Meta:
        model = models.Student
        fields = [
            'first_name', 'last_name', 'DOB', 'residential_address',
            'medical_history', 'preferred_doctor',
            'parent1_first_name', 'parent1_last_name', 'relationship1_to_student', 'parent1_contact_number',
            'parent1_contact_email',
            'parent2_first_name', 'parent2_last_name', 'relationship2_to_student', 'parent2_contact_number',
            'parent2_contact_email',
            'emergency_contact_name', 'emergency_contact_number',
            'deregistration_date', 'proficiency_level'
        ]


class NewLessonPlansForm(forms.ModelForm):
    class Meta:
        model = LessonPlans
        fields = ['level', 'lesson', 'description']

There's a few ways you can do this:

Store the posted data into the context and return this to the page on an unsuccessful submission, making sure you handle this on the template side. You can do this using something like:

form = ContactForm(initial={'subject': 'Hi there!'})

What can also do with this built in Django solution is check if the data “has changed” from this initial state, throwing an error if not.

However, if you want all of the data back, rather than specific fields that are valid, simply use:

form = ContactForm(request.POST)

So provided you have their previous answers stored in the request.POST object you can then set the initial value every time they are unsuccessful.

Reference here: https://docs.djangoproject.com/en/2.1/ref/forms/api/#s-dynamic-initial-values

Or...you can use local storage. Store their values in local storage and whenever they return back, even days later (provided they haven't refreshed their browser cache) you can grab and use their previously stored answers.


Specific to your setup, you could use something like:

def add_new_student(request):

    if request.user.is_authenticated:
        lesson_plans = LessonPlans.objects.all()
        if 'submit_new_student' in request.POST:
            form = NewStudentForm(request.POST)
            if form.is_valid():
                #todo: add cleaned data
                form.save()  # save into DB
            else:  # this is where form is not valid, and where the POST data should fill up the form with any combination of validated data from the previous `post` data.
                data = {
                   'first_name': request.POST.get('first_name'), 
                   'last_name': request.POST.get('last_name')
                }
                form = ContactForm(data, initial=data)
        else:
            form = NewStudentForm()
        args = {
            'form': form,
            'lesson_plans': lesson_plans
        }
        return render(request, 'static/html/new_student.html', args)

With the above data and initial values set, you can then also check if the form has changed on submission and if not, throw back another custom error:

if form.has_changed():
   # do something here

Redisplaying the form with the POST data is the default thing to do. You prevent it with your first else block. Remove that.

    if 'submit_new_student' in request.POST:
        form = NewStudentForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect('...')
        # no else; invalid form is automatically passed into args below
    else:
        form = NewStudentForm()
    args = {
        'form': form,
        'lesson_plans': lesson_plans
    }
    return render(request, 'static/html/new_student.html', args)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM