Django Tutorial - MVT Architecture, CRUD, and Custom Commands

This article presents a few useful topics that might help beginners to code more than a simple "Hello World" in Django

Django Tutorial - MVT Architecture, CRUD, and Custom Commands

This article presents a few useful topics that might help beginners to code more than a simple "Hello World" in Django. For newcomers, Django is the most popular Python-based web framework initially released in 2003 and currently supported by an impressive community with 2k+ open-source enthusiasts. The "batteries-included" concept and the built-in security pattern provided by experts make Django a reference framework in web development. To make this article more useful  curious minds can apply the concepts using an open-source sample.

  • Django Architecture - MVT Pattern
  • Django CRUD - a simple introduction
  • Custom Commands - How to extend the default Django CLI
  • Free Django Sample - Django Soft Design System

Django Software Architecture

This section explains Django MVT architecture and how is it different from the long-existing MVC architecture.

Introduction

Django is a Python based free and open-source web framework that follows the MVT (Model View Template) architectural pattern. The framework emphasizes reusability and "pluggability" of components, less code, low coupling, rapid development, and the principle of don't repeat yourself. Python is used throughout, even for settings, files, and data models. Django also provides an optional administrative create, read, update and delete (CRUD) interface that is generated dynamically through introspection and configured via admin models.

MVT Architecture
  • Model: The Model is going to act as the interface of your data. It is responsible for maintaining data. It is the logical data structure behind the entire application and is represented by a database (generally relational databases such as MySql, Postgres).
  • View: The View is the user interface what you see in your browser when you render a website. It is represented by HTML/CSS/Javascript and Jinja files.
  • Template: A Template consists of static parts of the desired HTML output as well as some special syntax describing how dynamic content will be inserted.

A simplified graph for the MVT action flow is presented below:

Django - MVT Pattern Flow

Here, a user requests a resource to the Django, Django works as a controller and checks the available resource in the URL. If URL maps, a view is called that interact with model and template, it renders a template. Django responds back to the user and sends a template as a response

The well-known GeeksforGeeks platform has provided a nice comparison regarding MVT and MVC patterns - full article here.

MVT vs MVC - Provided by GeeksforGeeks

Custom Commands

Django comes with a variety of command line utilities that can be either invoked using django-admin.py or the convenient manage.py script. A nice thing about it is that you can also add your own commands.

Introduction - Just before we get started, let’s take a moment to familiarize ourselves with Django’s command-line interface. You are probably already familiar with commands like startproject, runserver or collectstatic. To see a complete list of commands you can run the command below:

$ python manage.py help

Advantage - The main advantage of custom command is that all Django machinery is loaded and ready to be used. That means you can import models, execute queries to the database using Django’s ORM and interact with all your project’s resources.

Structure - We can create our own commands for our apps and include them in the list by creating a management/commands directory inside an app directory, like below:

< PROJECT ROOT >                          <-- project directory
 |-- poll/                                <-- app directory
 |    |-- management/
 |    |	   +-- __init__.py
 |    |    +-- commands/
 |    |         +-- __init__.py
 |    |         +-- my_custom_command.py  <-- module where command is going to live
 |    |-- migrations/
 |    |    +-- __init__.py
 |    |-- __init__.py
 |    |-- admin.py
 |    |-- apps.py
 |    |-- models.py
 |    |-- tests.py
 |    +-- views.py
 |-- core/
 |    |-- __init__.py
 |    |-- settings.py
 |    |-- urls.py
 |    |-- wsgi.py
 +-- manage.py

The name of the command file will be used to invoke using the command line utility. For example, if our command was called my_custom_command.py, then we will be able to execute it via:

$ python manage.py my_custom_command

Let's code a working sample - the custom command should look like this:

management/commands/my_custom_command.py:

from django.core.management.base import BaseCommand
from django.utils import timezone

class Command(BaseCommand):
    help = 'Displays current time'

    def handle(self, *args, **kwargs):
        time = timezone.now().strftime('%X')
        self.stdout.write("It's %s" % time)

Django management command is composed by a class named Command which inherits from BaseCommand. The command code should be defined inside the handle() method.

This command can be executed as:

$ python manage.py my_custom_command

Output:

It's 10:30:00

Well, we've just coded a simple custom command for Django.


Django CRUD

Django is based on MVT (Model View Template) architecture and revolves around CRUD (Create Read Update Delete) operations. In general, CRUD means performing Create, Retrieve, Update and Delete operations on a table in a database.

Django - CRUD Flow

CRUD means basic primitives operations like insert and update executed on database using a public or a private interface:

  • Create: Create or add new entries in a table in the database.
  • Read: Read, retrieve, search, or view existing entries as a list (List View) or retrieve a particular entry in detail (Detail View).
  • Update: Update or edit existing entries in a table in the database.
  • Delete: Delete, deactivate, or remove existing entries in a table in the database.
A simple CRUD Django project to explain the concept

Consider a project named crudtest having an app named poll. Now let’s create a model of which we will be creating instances through our view. In poll/models.py.

from django.db import models

class PollModel(models.Model): 
  
    title = models.CharField(max_length = 200) 
    description = models.TextField() 
  
    # renames the instances of the model with their title name 
    def __str__(self): 
        return self.title

After creating this model, we need to run two commands in order to create the table in the database:

$ python manage.py makemigrations
$ python manage.py migrate

Now we will create a Django ModelForm for this model. to do this create a file forms.py in poll folder.

from django import forms 
from .models import PollModel

class PollForm(forms.ModelForm): 
  
    class Meta: 
        model = PollModel
        fields = ['title', 'description']  # specify fields to be used

Once we have the Database layer up & running we need to code the public interface.


1# - Create View

It's just like taking an input from a user and storing it in a specific table to create an instance of a table in the database.

poll/views.py:

from django.shortcuts import render
from .models import PollModel
from .forms import PollForm

def create_view(request):
    context = {}  # dictionary for initial data with field names as keys

    form = PollForm(request.POST or None)
    if form.is_valid():
        form.save()
    
    context['form'] = form
    return render(request, "create_view.html", context)

Then create a template in templates/create_view.html:

<form method="POST"> 
    {% csrf_token %} <!-- CSRF token for security -->
  
    {{ form.as_p }} 
      
    <input type="submit" value="Create"> 
</form>

2# - List View

Read is basically divided into two types of views, List View and Detail View.

It's used to display multiple types of data or list all or particular instances of a table from the database in a particular order on a single page or view.

poll/views.py:

from django.shortcuts import render  
from .models import PollModel

def list_view(request):
    context = {}   # dictionary for initial data with field names as keys
    context["items"] = PollModel.objects.all()  # add the dictionary during initialization
    return render(request, "list_view.html", context)

Then create a template in templates/list_view.html:

<div class="main"> 
    
    {% for item in items %}
	    <p>{{ item.title }}</p><br/> 
	    <p>{{ item.description }}</p><br/>
	    <hr> 
  	{% endfor %}

</div>

Detail View - It's used to display multiple types of data or a particular instance of a table from the database with all the necessary details on a single page.

poll/urls.py:

from django.urls import path   
from .views import detail_view 
  
urlpatterns = [ 
    path('poll/<int:id>/', detail_view, name='detail_poll'), 
]

poll/views.py:

from django.shortcuts import render 
from .models import PollModel 

def detail_view(request, id): 
    context = {}  # dictionary for initial data with field names as keys  
    context["data"] = PollModel.objects.get(id=id)
    return render(request, "detail_view.html", context)

Then create a template in templates/detail_view.html:

<div class="main"> 
    
    {{ data.title }}
    <br/> 
    {{ data.description }}

</div>

3# - Update View

It's used to update entries for a particular instance of a table from the database.

poll/views.py:

from django.shortcuts import get_object_or_404, render, redirect
from .models import PollModel 
from .forms import PollForm 


# after updating it will redirect to detail_View 
def detail_view(request, id): 
    context = {}  # dictionary for initial data with field names as keys
    context["data"] = PollModel.objects.get(id=id)  # add the dictionary during initialization
    return render(request, "detail_view.html", context)
  
# update view for details 
def update_view(request, id): 
    context = {}  # dictionary for initial data with field names as keys
    obj = get_object_or_404(PollModel, id=id)  # fetch the object related to passed id

    # pass the object as instance in form 
    form = PollForm(request.POST or None, instance=obj) 

    # save the data from the form and redirect to detail_view 
    if form.is_valid(): 
        form.save() 
        return redirect("detail_poll", id)

    context["form"] = form  # add form dictionary to context
    return render(request, "update_view.html", context)

Then create a template in templates/update_view.html:

<div class="main"> 

    <form method="POST"> 
        {% csrf_token %} <!-- CSRF token for security -->
  
        {{ form.as_p }} 
  
        <input type="submit" value="Update">
    </form> 
  
</div>

4# - Delete View

It is used to delete a particular instance of a table from the database.

poll/views.py:

from django.shortcuts import get_object_or_404, render, redirect
from .models import PollModel 


# delete view for details 
def delete_view(request, id): 
    context = {}  # dictionary for initial data with field names as keys 
    obj = get_object_or_404(PollModel, id=id)  # fetch the object related to passed id 

    if request.method =="POST": 
        obj.delete()  # delete object
        return redirect("list_view")  # after deleting redirect to list view
  
    return render(request, "delete_view.html", context)

Now a url poll/urls.py mapping to this view:

from django.urls import path 
from .views import delete_view 

urlpatterns = [ 
    path('poll/<int:id>/delete/', delete_view, name='delete_poll'), 
]

Then create a template in templates/delete_view.html:

<div class="main"> 

    <form method="POST"> 
        {% csrf_token %} 

        <p>Are you want to delete this item ?</p>
        
        <input type="submit" value="Yes" /> 
    </form>

    <a href="/">Cancel </a> 

</div>

Well, we have successfully created a CRUD application using Django.


Django Soft Design System

This open-source starter can be used to apply all above concepts and the source code can be downloaded directly from Github - no registration wall to get and use the code. The Django codebase comes with a simple, intuitive structure, authentication and deployment scripts, all this on top of a modern Bootstrap 5 design - Soft UI Design System.

Soft UI Design System - Free Django Starter.