Doug Smith
Doug Smith

Reputation: 580

Django Form after redirect is empty after successfully submitting a form

I have a template called courses for the url http://127.0.0.1:8000/gradebook/courses/. This template lists existing Course objects loads the CourseForm form. The form successfully creates new objects.

If I go to the addassessment template with url http://127.0.0.1:8000/gradebook/addassessment/7/, it correctly loads the AssessmentForm. I want to submit this form and then return to the previous courses template. The AssessmentForm submits and the object is saved, but when it redirects back to the courses template, the CourseForm does not load. The courses template loads, the expect html loads correctly other than the form fields. I notice that the url for this page is still http://127.0.0.1:8000/gradebook/addassessment/7/ and not ../gradebook/courses/.

app_name = 'gradebook'
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('signup/', SignUpView.as_view(), name='signup'),
    path('courses/', views.courses, name='courses'),
    path('classroom/', views.classroom, name='classroom'),
    path('objective/<int:course_id>/', views.addobjective, name='addobjective'),
    path('addassessment/<int:course_id>/', views.addassessment, name='addassessment'),
]

#urls.py project
urlpatterns = [
    path('', TemplateView.as_view(template_name='home.html'), name='home'),
    path('admin/', admin.site.urls),
    path('gradebook/', include('gradebook.urls')),
    path('gradebook/', include('django.contrib.auth.urls')),
]

#models.py
class Course(models.Model):
    course_name = models.CharField(max_length=10)

class Classroom(models.Model):
    classroom_name = models.CharField(max_length=10)
    course = models.ForeignKey(Course, on_delete=models.CASCADE)

class Assessment(models.Model):
    course = models.ForeignKey(Course, on_delete=models.CASCADE)
    assessment_name = models.CharField(max_length=10)
    objectives = models.ManyToManyField('Objective')

class Objective(models.Model):
    course = models.ForeignKey(Course, on_delete=models.CASCADE)
    objective_name = models.CharField(max_length=10)
    objective_description = models.CharField(max_length=30)
    
#views.py
def courses(request):
    course_list = Course.objects.order_by('course_name')
    context = {'course_list': course_list}

    if request.method == 'POST':
        details = CourseForm(request.POST)

        if details.is_valid():
            course = details.save(commit=False)
            course.save()

            form = CourseForm(None)
            context['form'] = form
            return render(request, "gradebook/courses.html", context)

        else:
            context['form'] = details
            return render(request, "gradebook/courses.html", context)

    else:
        form = CourseForm(None)
        context['form'] = form
        return render(request, "gradebook/courses.html", context)
        
def addassessment(request, course_id):
    course_list = Course.objects.order_by('course_name')
    this_course = Course.objects.get(id=course_id)
    objectives = Objective.objects.filter(course=this_course).order_by('objective_name')
    context = {'this_course': this_course}
    context['objectives'] = objectives
    context['course_list'] = course_list

    if request.method == 'POST':
        form = AssessmentForm(request.POST)

        if form.is_valid():
            assess = form.save(commit=False)
            # save the course that the objective belongs to
            assess.course = this_course
            assess.save()
            form.save_m2m()

            return render(request, "gradebook/courses.html", context)

        else:
            context['form'] = form
            return render(request, "gradebook/addassessment.html", context)

    else:
        form = AssessmentForm(None)
        form.fields["objectives"].queryset = Objective.objects.filter(course=this_course)
    context['form'] = form
    return render(request, "gradebook/addassessment.html", context)
    
#forms.py
class AssessmentForm(ModelForm):
    class Meta:
        model = Assessment
        fields = ('assessment_name', 'objectives',)

class CourseForm(ModelForm):
    class Meta:
        model = Course
        fields = ["course_name"]

    def clean(self):
        super(CourseForm, self).clean()

        course_name = self.cleaned_data.get('course_name')
        if course_name and Course.objects.filter(course_name__iexact=course_name).exists():
            self.add_error(
                'course_name', 'A course with that course name already exists.')
        if len(course_name) > 10:
            self.add_error(
                'Your course name cannot be longer than 10 characters')

        return self.cleaned_data
    
#courses template: course.html
<div class="container">
    <div class="row">
        <div class="twelve columns">
            <h1>Courses</h1>
        </div>
    </div>
    <div class="row">
        <div class="col-md-12">
            {% if course_list %}
                <ul>
                {% for course in course_list %}
                    <li><div class = "row">
                        <div class = "col-md-3">
                            {{ course.course_name }}
                        </div>
                        </div></li>
                {% endfor %}
                </ul>
            {% else %}
                <p>No Courses are available.</p>
            {% endif %}
        </div>
    </div>
    <div class="row">
        <div class="col-md-3">
            <p>Create a new course</p>
        </div>
        <div class="col-md-3">
            <form action="{% url 'gradebook:courses' %}" method="post">
            {% csrf_token %}
            {{ form.as_p }}
                <div class="form-group">
                    <button type="submit" class="btn btn-primary">
                        Submit
                    </button>
                </div>
            </form>
        </div>
    </div>

</div>

#addassessment template: addassessment.html
<div class="container">
  <div class="row">
    <div class="twelve columns">
      <h1>{{ this_course }}</h1>
    </div>
  </div>
  <div class="row">
    <div class="col-md-3">
      <p>Add an assessment to your class</p>
    </div>
    <div class="col-md-3">
      <div class="form-group">
      <form action="" method="post">
        {% csrf_token %} {{ form|crispy }}
        <div class="form-group">
          <button type="submit" class="btn btn-secondary">Submit</button>
        </div>
      </form>
    </div>
    </div>
  </div>
</div>

There are no error messages.

Upvotes: 0

Views: 251

Answers (1)

Daniel Oram
Daniel Oram

Reputation: 8411

When you submit your assessment form at http://127.0.0.1:8000/gradebook/addassessment/7/ your sending a post request back to your addassessment view function to process your form which you know. The url will still be the same as a result, which is what you are seeing.

I would suggest against returning the courses template if your assessment form is valid in the way you have written

#inside addassessment view function
return render(request, "gradebook/courses.html", context)

If you are just wanting to redirect to the courses view upon successfully saving the assessment form I suggest using the redirect shortcut.

# add to your import
from django.shortcuts import render, redirect

#inside addassessment view function - replacing "return render(request, "gradebook/courses.html", context)"
return redirect(courses)

This will send your request object to the courses view function. The redirect will use a GET action instead of a post so you'll just see what you would normally at http://127.0.0.1:8000/gradebook/courses/. This will also be the url!

Upvotes: 1

Related Questions