DEV Community

Cover image for BUILDING A SIMPLE APP WITH DJANGO'S CLASS BASED VIEWS.
Osahenru
Osahenru

Posted on

BUILDING A SIMPLE APP WITH DJANGO'S CLASS BASED VIEWS.

Part III

This is the concluding part of a 3 part series in part I we took a holistic view on the concepts of function based views and class based views and some disparities between these concepts, in part II we built an app using a function based view and in this concluding part we will be building same application with same functionalities but this time with a class based view approach.

As a prerequisite for getting the best out of this article will be to have a working understanding of Django’s Model Views Template structure, how to start a project and an application as well and lastly a basic understanding of Django's function based views.

CLASS BASED VIEWS
Class based views are simply Django views written as python classes, they provide an object-oriented way of your view codes.

One major advantage class based view has is it’s use of inheritance; you can inherit another class and it can be modified for different uses

Below are some benefits that come with a class based views approach.

1. Inheritance; reusable and DRY(don't repeat yourself) codes.
2. Eliminate redundant codes.
3. Separate each code by POST or GET method.

Class based views are really powerful and great but come at the expense of simplicity

Even as minor as omitting a forward slash in your urls.py can result in an error, class based views forces you to do things the right way.

View Class
It’s okay to say this is the grand Daddy of all other views, the ListView, UpdateView, DetailView... at one point all inherit from this view.

TaskList view class

class TaskList(LoginRequiredMixin, ListView):
    model = Task
    template_name = '../templates/tasklist.html'
    context_object_name = 'tasks'
    # login_url = 'login' An alternative to LOGIN_URL = 'login' in settings.py

    def get_context_data(self):
        context = super(TaskList, self).get_context_data()
        context['tasks'] = context['tasks'].filter(user=self.request.user)
        context['count'] = context['tasks'].filter(completed=False).count()

        search_input = self.request.GET.get('search-area') or ''
        if search_input:
            context['tasks'] = context['tasks'].filter(title__icontains=search_input)
            context['search_input'] = search_input
        return context
Enter fullscreen mode Exit fullscreen mode

This class Inherits from the LoginRequiredMixin and the Listview

LoginRequiredMixin needs a login url to send non authenticated users to, you can achieve this in two ways

  1. add login_url = '/login/' to every class where every LoginRequiredMixin is needed.
  2. add a default LOGIN_URL = 'login' to settings.py where every login url inherits from

Difference between login_url and redirect_field_name
login_url
Deals with the url you want a user to be taken to if a certain condition is met or not.
redirect_field_name
Deals with a field box which is set to a default parameter of =next

Just as the name, the user needs to be a logged in user to view the template of this view function.

Most class based view (if not all) must have a model attribute.

the default template name for this view is task_list.html we override that by creating a directory for all templates and create a template file tasklist.html

the default context name for objects of this view is object_list we also override that and give our context object the name tasks

get_context_data is similar to function based views context dictionary context = {}

In a class based view approach we have two ways of passing the data into a context.

  1. get_context_data
  2. extra_context In this article we make use of nos.1

We make use of the get_context_data function when we want to modify the objects in our template(to add extra elements to our templates).

We filter the task by the requested user, and also filter the requested user task by it's complete status completed=False, we count this filtered attributed and save the object.

Search Functionality
we add a search function to our task as we did in our function based view so, the request method from our search form is either going to have an actual word search or an empty search, we want same action performed for both conditions;

So, if a search(empty or not) is made filter the tasks context but this time by the title and include the search_input to the context dictionary

title__icontains=search_input, if the user performs a search we want to filter the search this time by the title.

icontains V contains
icontains will filter the object regardless of the case(upper of lower) of the string, while contains makes a search that is case sensitive.

We make use of the context dictionary for objects we intend to use with our template engine.

TaskDetail view function

class TaskDetail(LoginRequiredMixin, DetailView):
    model = Task
    template_name = '../templates/taskdetail.html'
    context_object_name = 'task'
Enter fullscreen mode Exit fullscreen mode

Inherits from the DetailView, approaches like the class based views help reduce the amount of DRY codes, again we define a model attribute, a template and a name for our context objects.

This view function takes in a PrimaryKey id, we don't include it when creating our function, Django's class based view handles that for us, we just pass it in our urls.py file.

TaskEdit view function

class TaskEdit(LoginRequiredMixin, UpdateView):
    model = Task
    template_name = '../templates/taskedit.html'
    fields = ['title', 'description', 'completed']
    success_url = reverse_lazy('tasklist')
Enter fullscreen mode Exit fullscreen mode

Inherits from the UpdateView, this view function has a fields attribute and also returns an instance of a submitted form.

fields as the name imply are the HTML fields that'll be rendered in the frontend of our application, we don't need to create an instance of the this form, again Django's class based view handles that for us, what a beauty!

After a successful form has been created, where do we redirect the user to? this time we use Django's class based views reverse_lazy to redirect the user back to the urls they were coming from.

TaskDelete view function

class TaskDelete(LoginRequiredMixin, DeleteView):
    model = Task
    template_name = '../templates/taskdelete.html'
    context_object_name = 'task'
    success_url = reverse_lazy('tasklist')
Enter fullscreen mode Exit fullscreen mode

This is similar to TaskEdit with a few peculiarities; does not have the fields attribute and also doesn’t return an instance of any submitted form, it takes in the PrimaryKey of the task to be deleted and under the hood performs the delete() function for us which we do not see.

TaskCreate view function

class TaskCreate(LoginRequiredMixin, CreateView):
    model = Task
    template_name = '../templates/taskcreate.html'
    fields = ['title', 'description']
    success_url = reverse_lazy('tasklist')

    def form_valid(self, form):
        form.instance.user = self.request.user
        return super(TaskCreate, self).form_valid(form)
Enter fullscreen mode Exit fullscreen mode

Very similar to TaskEdit as a matter of fact they both have same parent views.generic.edit we add a tweak to this class, by modifying the form; we assign each user to it’s task created.

The super function can be used to gain access to inherited methods-from a parent or sibling class- that has been overwritten in a class object, all this is big grammer what this means is that the super() function allows the function in which it is been used to make use of methods in its above class

CustomLogin view function

class CustomLogin(LoginView):
    redirect_authenticated_user = True
    template_name = '../templates/login.html'
    form_class = CleanForm
    # next_page = 'tasklist' Alternative to the get_success_url

    def get_success_url(self):
        return reverse_lazy('tasklist')
Enter fullscreen mode Exit fullscreen mode

Inherits from the LoginView and has AunthenticationForm as it's default form_class

We want to disable already authenticated users from logging again, we achieve this by setting the redirected_authenticated_user attribute of this class to True so once a user has been authenticated, they can’t be authenticated again.

We perform a clean operation before we log the user in, more info on how we did this down below.

next_page = handles where an authenticated user should be taken to, this attribute and the get_success_url perform the same function.

Register view function

class Register(FormView):
    form_class = UserCreationForm
    success_url = reverse_lazy('logout')
    template_name = '../templates/register.html'

    # Function for a valid form
    def form_valid(self, form):
        user = form.save(commit=False)
        user.username = user.username.lower()
        user = form.save()
        if user is not None:
            login(self.request, user)
            return redirect('logout')
        return super(Register, self).form_valid(form)

    # Function to redirect authenticated user
    def get(self, request):
        if self.request.user.is_authenticated:
            return redirect('tasklist')
        return super(Register, self).get(request)
Enter fullscreen mode Exit fullscreen mode

Inherits from the FromView model also has UserCreationForm as it’s form class for creating users in Django.

We make a few modification to our UserCreationForm, if the form is valid, we commit a false save to clean our data, to ensure it’s not case sensitive, save the user after, return this created user to the logout page once they have been created.

We want to be able to also redirect authenticated users, although this view class doesn’t come with that attribute hence, we create one using get(self, request) redirect the authenticated user back to the tasklist page if they try to register after they have been authenticated, and lastly return the class with the super function that just continues with everything this function was meant to do.

CleanForm in forms.py
from django.contrib.auth.forms import AuthenticationForm


class CleanForm(AuthenticationForm):

    def clean_username(self):
        return self.cleaned_data['username'].lower()
Enter fullscreen mode Exit fullscreen mode

Since we know that our LoginView has a from class called AuthenticationForm we want to tweak that form a bit by cleaning the username just as we did with our function based views.

Miscellaneous
Self
self is used to represent the instance of a class; one is able to access the attributes and method in which this self function is used.

Mixins
Are simply classes that contain methods to be used by other classes. We use mixins when we want to add a particular feature that will be made available in multiple child objects, they should be used to take care of one specific task, in function based views we have decorators for this.

Difference between ModelForm, FormView and CreateView
ModelForm
Django's ModelForm is used to directly convert a model into a Django form
FormView
A view that can be used for various purpose and not restricted to creating objects does not necesarily inherit from your custom made model, it usually to display and verify a form(when registering in class based views is where I mostly use it). it fields don't necessarily need to be created in models.py
CreateView
Mostly used when you want to create objects(not restricted to this alone), makes use of an in-built ModelForm

Below is the github repo to the full project.
kanyi-v-1.1

Below is the link to where this project is been deployed.
Kanyi-v-1.1

Top comments (0)