problem with redirect

Hello, could somebody help mi with my code? I need to admit that right now I feel so confused and have no idea how to do what I want to do. I am beginner in Django. I’m trying to create a simple website with some calculator, at first with BMI calculator. I want to take some data from the user in form and then redirect him to another page with the result of calculations. This is my code in views.py:

from django.shortcuts import render, redirect
from .forms import UserDataForm
from django.http import HttpResponseRedirect

def home(request):
   return redirect('bmi')

def bmi_calculator(request):
    if request.method == 'POST':
            form = UserDataForm(request.POST)
            if form.is_valid():
                  height = form.cleaned_data['height']
                weight = form.cleaned_data['weight']
                calculated_bmi = weight / (height * 0.01) ** 2
                return redirect('bmiresult', calculated_bmi=calculated_bmi)
    else:
        form = UserDataForm()
        return render(request, 'calculator/bmi.html', {'form': form})

def bmi_result(request):
     calculated_bmi = request.GET.get('bmi')
     return render(request, 'calculator/bmiresult.html', {'calculated_bmi': calculated_bmi})

And this is my code in urls.py:

from django.urls import path
from . import views

urlpatterns = [    path('', views.home, name='home'),
    path('bmi_calculator/', views.bmi_calculator , name='bmi'),
    path('bmi_calculator/result/', views.bmi_result, name='bmiresult')
]

I guess Django is trying to redirect the user to an url with the BMI result in the url, but i don’t know how to make it just want to display it always on the same page ‘bmi_calculator/result/’'?

In a standard HTTP/HTML environment (“basic Django”), the posting of a form always results in a new page being rendered and sent to the browser. (That’s one of the purposes of the redirect on a successful POST.)

If you want to submit data in a form to a Django view, and then get the response to update the current page, you need to use AJAX in the browser to make the request and receive the response.

Also note that:

is not going to try to create a url to work with this:

That redirect is going to try to build a url with calculated_bmi as a url parameter, not as a GET parameter in the querystring.

It’s the difference between a request like:
/bmi_calculator/result/28/ (what the redirect might create)
and
/bmi_calculator/result/?bmi=28 (which is what your bmi_result view is looking for).

Ok thank you, I understand… So is it also not possible to do it only with a normal “render”? I’m completely beginner with Django and it would be hard for me I think to start doing everything with AJAX with no experience with JavaScript. I’ve just changed my code, deleted ‘redirect’ and modified it into ‘redirect’. Everything works fine but I have to display the result of my calculations on ‘bmi_calculator/’ URL, not on ‘bmi_calculator/result/’ like I initially planned.

I’m sorry, but I’m not following what you’re trying to say here.

Let’s take a step back to basics for a moment:

A browser issues a request.

A web server receives the request and passes it along to Django

Django uses the url in the request to find which view to call - and calls that view

The view receives the request and returns a response.

That response can be one of:

  • HttpResponse (perhaps from the output of a call to render)
  • HttpResponseRedirect
  • FileResponse
  • JsonResponse
  • and others.

Django returns that Response object back out through the web server to the browser.

What the browser does with that response depends upon how the request was made (normal browser request or AJAX), and the type of response.


Now, when you include forms into this mix, it extends this pattern by an extra exchange:

Request #1 - get the form to be filled out
Response #1 - the empty form

Request #2 - the filled-out form
Response #2 - typically either:

  • A redirect going to a different page, which could be the same url as Request # 1
  • The same form, but with errors indicated in the page showing what needs to be corrected to submit the form.

So yes, you could define two different URLs for the same view. One like you have now for the blank form, and a second url that includes a parameter to use to populate the form with the calculated BMI. It’s then up to you to write a view capable of handling both types of requests.

Ok, I see I need to go back to basics to understand everything better. I have just one more question - is it better or easier to use class-based view in similar situations or it does not matter much and as a beginner I should stay with function-based view?

Class-Based Views (CBV) do make some things easier - when you have a number of views that all follow a similar pattern.

The Django-provided generic CBVs are built around a common pattern of:

  • Show a list of objects
  • Create an object
  • Display an object
  • Update an object
  • Delete an object

Using CBVs to perform these operations does a good job of reducing the amount of “boilerplate” code you might otherwise need to write. The further away you get from those basic operations, the less valuable they become, and possibly the more awkward they are to work with.

If you have a system with a number of views that all perform similar functions that go beyond what Django provides, you can create your own CBVs. (That’s the approach we’ve taken in one of our systems.)

From Django’s perspective, there really isn’t much difference between the two. They’re both views. They both provide functions that the url use to call when receiving a request. (The name of the function itself for an FBV and the as_view function within a CBV.) Those functions do the same thing - they receive a request and return a response.

If you are going to become familiar with CBVs, the two external resources that I find most helpful are the Classy Class-Based Views site and the CBV Diagrams page. Those are my go-to reference sites for CBVs.

1 Like