Transistioning from function-based views to class-based views

Whatever your opinion on which style of view is 'better', newcomers can get confused by class based views (CBV) and there close relatives generic class based views (GCBV). The typical pattern is jumping straight to the generic views without understanding what is going on and why there are certain methods or attributes to override.

Today we are going to take a step back and just consider transistioning from a class function view to the most basic class based view.

Below is a very typical function based view, which deals with rendering and processing a form depending on whether is HTTP method is a GET or POST.

def get_name(request):
    # if this is a POST request we need to process the form data
    if request.method == "POST":
        # create a form instance and populate it with data from the request:
        form = NameForm(request.POST)
        # check whether it's valid:
        if form.is_valid():
            # process the data in form.cleaned_data as required
            form.save()
            # redirect to a new URL:
            return HttpResponseRedirect("/thanks/")

    # if a GET (or any other method) we'll create a blank form
    else:
        form = NameForm()

    return render(request, "name.html", {"form": form})

In a class based view the methods to typically interact with are methods that represent the HTTP method, so from above we have GET and POST which correspond to def get(...) and def post(...) respectively. This means that any code not indented inside a conditional that checks the request method should live in both class methods, and any code that is located within the conditional needs to be moved into their respective class methods.

So in our example above the following line needs to be migrated to both methods:

return render(request, "name.html", {"form": form})

Then the following lines are within the POST conditional so should be moved to the post method:

form = NameForm(request.POST)
# check whether it's valid:
if form.is_valid():
    # process the data in form.cleaned_data as required
    form.save()
    # redirect to a new URL:
    return HttpResponseRedirect("/thanks/")

and finally the following code needs to be moved to the get method:

form = NameForm()

which results in the following class:

class GetNameView(View):
    def get(self, request, *args, **kwargs):
        form = NameForm()
        return render(request, "name.html", {"form": form})

    def post(self, request, *args, **kwargs):
        form = NameForm(request.POST)
        # check whether it's valid:
        if form.is_valid():
            # process the data in form.cleaned_data as required
            form.save()
            # redirect to a new URL:
            return HttpResponseRedirect("/thanks/")
        return render(request, "name.html", {"form": form})

As you can see there is some minor duplication of code now, which we will address tomorrow!