0% found this document useful (0 votes)
49 views44 pages

Django Sample

The document is a beginner's guide to building real-world applications using Django, focusing on creating a To-Do app and a blog application with various features. It covers environment setup, project structure, and step-by-step instructions for implementing core functionalities like CRUD operations, user authentication, and deploying the blog project. The guide emphasizes practical coding over theoretical concepts, providing clear instructions and resources for each stage of the development process.

Uploaded by

raifbinrafi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
49 views44 pages

Django Sample

The document is a beginner's guide to building real-world applications using Django, focusing on creating a To-Do app and a blog application with various features. It covers environment setup, project structure, and step-by-step instructions for implementing core functionalities like CRUD operations, user authentication, and deploying the blog project. The guide emphasizes practical coding over theoretical concepts, providing clear instructions and resources for each stage of the development process.

Uploaded by

raifbinrafi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 44

Django Unchained For Beginners

First Edition

Build Real World Application From Scratch

All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or
transmitted in form or by any means, without the prior written permission of the author, except
in the case of brief quotations embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the
information presented. However, the information contained in this book is sold without
warranty, either express or implied.

Copyright © 2025, Muhammad Hasan


1

Table of Contents

HOW TO FOLLOW?................................................................................................................................ 2

WHAT WE’RE BUILDING? ........................................................................................................................... 2


BLOG APPLICATION DEMO .......................................................................................................................... 2

ENVIRONMENT SETUP: ......................................................................................................................... 3

VISUAL STUDIO CODE SETUP: ............................................................................................................... 5

FIRST PROJECT SETUP: TODO APP ........................................................................................................ 6

PROJECT SETUP AND VIRTUAL ENVIRONMENT ACTIVATION ........................................................................ 6


INSTALL DJANGO AND START A PROJECT: ........................................................................................................ 9
INSTALL TAILWIND .................................................................................................................................. 12
DATABASE SETUP: .............................................................................................................................. 20
IMPLEMENTING A BASIC CRUD SYSTEM ....................................................................................................... 23
CREATING TASK: .................................................................................................................................... 26
MVT ARCHITECTURE: .............................................................................................................................. 35
TASK STATUS ......................................................................................................................................... 36
UPDATE TASK: .................................................................................................................................... 40

BLOG PROJECT SETUP: ....................................................................................................................... 43

BLOG PROJECT: FULL AUTHENTICATION .............................................................................................. 67

BLOG FEATURE SETUP: ....................................................................................................................... 99

INSTALL BLOG APPLICATION: ..................................................................................................................... 99


CONFIGURE BLOG MODEL: ..................................................................................................................... 100
CONFIGURE HOMEPAGE: ........................................................................................................................ 108
IMPLEMENT PAGINATION IN CATEGORY POST PAGE: ...................................................................................... 114
IMPLEMENT SINGLE BLOG POST PAGE WITH RELATED POSTS: .......................................................................... 121
IMPLEMENT NEWSLETTER FEATURE: .......................................................................................................... 125
IMPLEMENT COMMENT FEATURE TO BLOG POST: .......................................................................................... 131
IMPLEMENTING SEARCH FUNCTIONALITY: ................................................................................................... 135
INSTALL AND CONFIGURE CKEDITOR5: ...................................................................................................... 138

DEPLOY BLOG PROJECT ON RENDER: ................................................................................................ 142

Djnago Unchained for Beginners


2
How to follow?
In this book, we followed the DRY (Don't Repeat Yourself) principle. If a concept is explained once, we
didn’t explain it again. The same applies to code: when a file is introduced for the first time, we provide the
full code. If the file is modified later, we only include the modified parts, using code blocks (```) to
indicate changes within existing code.

We also highlight important code for better understanding. Every time we reference a file, we clearly
mention its directory path. If you see a file path mentioned but cannot find the file, that means it’s a new
file — you should create it and proceed accordingly.

Please follow the steps carefully and pay close attention to file names and paths to avoid confusion.

What We’re Building?

We’ll build two projects:

1. To-Do App – Basic CRUD functionality to understand Django fundamentals.


2. Blog Application – Full-featured project with:

§ Newsletter
§ Comments
§ Rich Text Editor
§ Clean, professional design

No extra theory or fluff. Just code, structure, and principles.

Blog Application Demo

Here is the exact blog application we’ll build: https://blog-project-10td.onrender.com/

We’ll provide the GitHub repository link for each project in the final chapter.

Djnago Unchained for Beginners


3
Environment Setup:

Install Visual Studio Code:


👉https://code.visualstudio.com/download.
Using VS Code is not mandatory — you may use any code editor of your choice. However, in this project,
we will use VS Code for consistency.
Install Python:
👉 https://www.python.org/downloads/
💡 Make sure to check the option "Add Python to PATH" during installation — this is mandatory.

Install Node.js:
👉 https://nodejs.org/en/download
Install PostgreSQL and pgAdmin:
Follow these guides to install PostgreSQL and connect it using pgAdmin:
Þ https://www.w3schools.com/postgresql/postgresql_install.php

Þ https://www.w3schools.com/postgresql/postgresql_pgadmin4.php

During installation, make sure to remember the password for the postgres user. Forgetting it can lead to
unnecessary hassle.
Install Git and Setup GitHub:
Þ https://youtu.be/p0Js7IF17yI?si=2sPdYb98x2kqAb7Q (macOS)
Þ https://youtu.be/AdzKzlp66sQ?si=JVuLYN6fLuZs-kin (Windows)
❓ If you get stuck, you can always search on YouTube — there are plenty of helpful tutorials on installing
these tools. And remember, ChatGPT is always there to help you out!

Djnago Unchained for Beginners


4
Let’s now check if all the tools have been installed properly. Open your shell:

Shell(macOS)
macbook@MacBooks-MacBook-Pro ~ % python3 --version
Python 3.13.3

Shell(Windows)
PS C:\Users\Gonzalo> python --version
Python 3.13.3

❗Whenever you see the command python3, Windows users should use python instead. macOS users should
continue using python3. I won’t show separate shells just for this difference. Thanks!

Shell
# node --version
v.22.15.0

Shell
# npm --version
10.9.2

Shell
# psql --version
psql (PostgreSQL) 17.4

Shell
# git --version
git version 2.49.0

Throughout this course, I’ll use a shell interface — meaning the commands shown will work for both macOS
and Windows. In cases where the commands differ between operating systems, I’ll clearly mention which
shell or platform they apply to, so you won’t face any confusion.

Djnago Unchained for Beginners


5
Visual Studio Code Setup:
Now open VS Code on your device and install the following extensions. Click on each name to go directly to
its extension page for easy access. Since there are many extensions with similar names, make sure to install
the official ones.

1. Python
2. Python-Debugger
3. Django
4. Django-Snippets
5. Prettier-Code-formatter
6. Tailwind-CSS-IntelliSense
7. Auto-Close-Tag
8. Auto-Rename-Tag

Once VS Code is open, your editor should look like this. Click the square icon with four squares (for
Extensions) and the arrow icon or terminal/shell tab to open the Extensions panel and the Terminal/Shell,
respectively.

Djnago Unchained for Beginners


6
First Project Setup: TODO App
Project Setup and Virtual Environment Activation
Now navigate to your target directory using the VS Code terminal or your system's shell, and run the
following commands:
Shell
# mkdir todo_project
# cd todo_project_project
# code .

This will create a new folder called todo_project, move into it, and open it in VS Code.

⚠ Note: If you get the following error after running code .


Shell
command not found: code

Follow these steps:


1. Press Cmd (Ctrl for windows) + Shift + P to open the Command Palette.
2. Search for:
Shell Command: Install 'code' command in PATH

1. Select it and press Enter.


2. Now, try running code . again — it should open the todo_project folder in VS Code.

Djnago Unchained for Beginners


7
Now check that are you inside this todo_project folder or not?
Shell
# pwd
/Users/macbook/Project/todo_project

If you're inside the todo_project folder, you're all set to move forward. If not, please revisit this chapter and
follow the steps carefully from the beginning.
Let’s continue! 🚀
Create and activate virtual environment:
Shell(macOS)
# python3 -m venv env
# source env/bin/activate

Shell(Windows)
# python -m venv env
# env/Scripts/activate

You can name your virtual environment anything — it doesn’t have to be env. After activation, you’ll see the
environment name (like (env)) appear at the beginning of your terminal line.

Djnago Unchained for Beginners


8
Explanation

What is a Virtual Environment?


A virtual environment is an isolated workspace that allows you to manage Python packages
independently for each project.
Why You Need It?
Without a virtual environment:
Þ All your Python projects share the same global packages.
Þ One project’s package version can break another.
With a virtual environment:
Þ Each project has its own clean space to install and manage packages.
Þ No conflicts between projects.
Benefits
Þ Keeps dependencies organized.
Þ Makes collaboration and deployment easier.
Þ Avoids version clashes.

📌 Remember: Every time you open this project (or any Django project), your first task is to activate the
virtual environment. You know how to do that now — right?

Shell(macOS)
# source env/bin/activate

Shell(Windows)
# env/Scripts/activate

How to deactivate?
Shell
# deactivate

You don’t need to actually use this deactivate command!

Djnago Unchained for Beginners


9
Install Django and Start a Project:

Before moving ahead, double-check that your virtual environment is actually activated. You should see the
environment name (like (env)) at the beginning of your terminal line.

If you don’t see it, activate it again using the appropriate command.

Now, Let’s install Django:

Shell
# python3 -m pip install Django

Windows user? Remember, I have told you earlier that you should use python instead python3—right?

Now check is it correctly installed or not?

Shell
# django-admin --version
5.2.1

Now start a project:

Shell
# django-admin startproject config .

📌 Remember: You can name your project anything — it doesn’t have to be config. Don’t forget the dot (.)
and the space after config. Missing the dot will create an extra nested folder, which can be confusing later.

Djnago Unchained for Beginners


10
Now, let’s check if the Django project is set up correctly. Run this command:

Shell
# python3 manage.py runserver
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations
for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
May 15, 2025 - 15:32:21
Django version 5.2.1, using settings 'config.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

WARNING: This is a development server. Do not use it in a production setting. Use a production WSGI
or ASGI server instead.
For more information on production servers see:
https://docs.djangoproject.com/en/5.2/howto/deployment/

Hold Cmd (on macOS) or Ctrl (on Windows) and click the link below (In shell) to open it in Chrome (or your
default browser, I strongly prefer to use chrome): http://127.0.0.1:8000/
You should see Django’s welcome page if everything is working correctly.

Djnago Unchained for Beginners


11
Let’s Get Familiar with the Django Project Files:

Explanation: Quick Note About Project Structure


config/ is your actual Django project — you can name it anything when you create it.
Þ __init__.py : Marks this directory as a Python package
Þ asgi.py: For handling **ASGI** (used for async servers)
Þ settings.py: is where most configuration happens — like registering apps, setting up
databases, and adding static files.
Þ urls.py : Where you define your **site’s routes (URLs)**
Þ wsgi.py : For **WSGI** (used for deployment)
db sqlite3: Default **SQLite database** file
manage.py: is like your project’s remote control — you’ll use it to run the server, create apps,
apply migrations, and more.
env/ holds all your project’s dependencies in isolation — this is your virtual environment.

Django creates a default SQLite database (db.sqlite3). Since we’ll use PostgreSQL, let’s delete it.
You can manually delete it or hit this command:

Shell(macOS)
# rm db.sqlite3

Shell(Windows)
# del db.sqlite3

Djnago Unchained for Beginners


12
Install Tailwind
Let’s setup tailwind latest version:

Shell
# npm install tailwindcss @tailwindcss/cli

After running the command, you’ll see that two files — package.json and package-lock.json — and a node_modules
folder have been added to the root (todo_project) folder. This indicates that Tailwind was successfully
initialized.

Now, inside the root folder, create a static folder. Within it, create a src folder → then a css folder inside src →
and finally an input.css file inside the css folder.

Now open input.css file and add this line:

todo_projects/static/src/css/input.css
@import "tailwindcss";

Now make change to package.json file:

todo_projects/package.json
{
"dependencies": {
"@tailwindcss/cli": "^4.1.7",
"tailwindcss": "^4.1.7"
},
"scripts": {
"dev": "npx @tailwindcss/cli -i ./static/src/css/input.css -o ./static/src/css/output.css --
watch"
}
}

Now in terminal/shell run this command:

Shell
# npm run dev

Now you’ll see that inside css folder a file created namely output.css file. If not you can manually create it
and run the command again.

Now let’s check is tailwindcss working or not. Crate a folder namely templates inside root (todo_projects)
folder. Inside this folder create base.html file.

Djnago Unchained for Beginners


13
Now let’s add some line there:
todo_projects/templates/base.html
<!DOCTYPE html>
< lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>TODO LIST - Home</title>
</head>
<body>
<h1 class="text-orange-500">Hello world!</h1>
</body>
</html>

Now create a Django app namely todo, you can choose anything instead of todo:
Shell
# django-admin startapp todo

After running this command, now you’ll notice a folder namely todo created within the root(todo_projects)
folder with some files. Your project structure will now look like this:

Whenever you create any app in Django you have to mention this settings.py file project (config) folder.
Let’s do this:
todo_project/config/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Django app
'todo',

Djnago Unchained for Beginners


14
Explanation: Quick Note About todo App Folder
config/ is your actual Django project — you can name it anything when you create it.
Þ __init__.py : Marks this directory as a Python package, making it importable.
Þ migrations/: Stores database migration files generated by Django's ORM.
Þ apps.py: Contains the app configuration class for your Django application.
Þ models.py : Defines database models using Python classes (Django's ORM).
Þ tests.py : Contains test cases for your application's functionality.
Þ views.py: Handles HTTP requests and returns responses (business logic).

Now go to views.py file of todo app folder and add these lines:

todo_project/todo/views.py
from django.shortcuts import render

# Create your views here.


def welcome_page(request):
return render(request, "base.html")

Explanation: What actually this welcome_page function do?

1. It takes a request parameter (contains HTTP request data)


2. Returns a rendered HTML response using:
Þ Django's render() shortcut function.
Þ The template "base.html".
In simple terms: When this view is accessed, it will display the base.html template as the webpage.

Now to access this view function, we have to mention this function in urls.py file of config folder. Let’s do
this.

todo_project/config/urls.py
from django.contrib import admin
from django.urls import path
from todo.views import welcome_page

urlpatterns = [
path('admin/', admin.site.urls),
path('', welcome_page), when someone visit the root url, show them welcome_page view
]

Now let’s check does this bring our base.html file in our webpage. Run this command:

Djnago Unchained for Beginners


15
Shell
# python3 manage.py runserver

OOOPPS! It’s Shows an error!

What happened! Oh! We created a templates folder but didn’t mention this or configure this in our settings.py
file! Let’s do this. Open settings.py file:

todo_project/config/settings.py
INSTALLED_APPS = [
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR/ 'templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]

Now refresh the page again! Yeap! It’s working!

Djnago Unchained for Beginners


16

But not exactly what we expected! We expected that tailwind will also be implemented! But it’s not.
Let’s figure it out!
Two things we maybe forgot to do! Let’s check the base.html. Yeap! We didn’t mention the output.css file in
our <head> section. Let’s mention this.
todo_project/templates/base.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="{% static 'src/css/output.css' %}" />
<title>TODO LIST - Home</title>
</head>
<body>
<h1 class="text-orange-500">Hello world!</h1>
</body>
</html>

Now refresh the page again! It’s not working! We expected to see an orange color normal “Hello world!”
message! What happened this time?

Oh! We have created a static folder inside root (todo_project) but didn’t configure it in settings.py file.
Let’s configure it: Add the highlighted line.

todo_project/config/settings.py
STATIC_URL = 'static/'
STATICFILES_DIRS = [BASE_DIR/ "static"]

Now refresh the page once again! BOOM! It’s working!

Now add another line to the base.html file with tailwindcss red color:
todo_project/templates/base.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="{% static 'src/css/output.css' %}" />
<title>TODO LIST - Home</title>

Djnago Unchained for Beginners


17
</head>
<body>
<h1 class="text-orange-500">Hello world!</h1>
<h1 class="text-red-500">Hello world 2!</h1>
</body>
</html>

Go to the page. Nothing happened! Refresh the page! It is working! But how many time we have to refresh?
Every time we made a tiny change we have to refresh! It’s boring right? Let’s solve it.
Even for this small project, we’ll install a package that automatically reloads the browser whenever we
make changes to our HTML files. This way, you won’t need to manually press the refresh button — changes
will appear instantly. Let’s install the django-browser-reload package.
Shell
# pip install django-browser-reload

Now let’s configure settings.py. I’ve highlighted the lines where changes or additions have been made.

todo_projects/config/settings.py
# Application definition

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Django app
'todo',
# Installed third party apps
'django_browser_reload'
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',

"django_browser_reload.middleware.BrowserReloadMiddleware", #related to
django_browser_reload
]

todo_project/config/urls.py
from django.contrib import admin
from django.urls import path, include

Djnago Unchained for Beginners


18
from todo.views import welcome_page

urlpatterns = [
path('admin/', admin.site.urls),
path('', welcome_page),
path("__reload__/", include("django_browser_reload.urls")),
]

It’s done! Now, any changes you make in the HTML file will automatically reload the browser — no need to
refresh manually. This feature is often referred to as HOT RELOAD.

Currently, the way we’ve defined the URL for welcome_page isn’t ideal. While it's fine for a small app, in larger
applications with multiple apps — like one for user management, another for blogging, etc. — it’s better to
define the URLs related to a specific app within that app. This keeps the business logic organized and makes
the project easier to maintain.

Let’s redefine the URL for the welcome_page in a more structured and maintainable way. First, we need to
include the todo app in the project’s urls.py file. Let’s do it.

todo_project/config/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path('admin/', admin.site.urls),
path('', include('todo.urls')),
path("__reload__/", include("django_browser_reload.urls")),
]

The highlighted line, path('', include('todo.urls')), means: “Look for an app named todo in the project, and if
it has a urls.py file, include its URL patterns here.”
So, whenever someone visits a URL, Django will first check this urlpatterns list. If it matches the empty string
'', it will then look into the todo/urls.py file for further matching. This helps keep each app's routing organized

and allows Django to delegate URL handling to the specific app responsible for that logic.
Now, we don’t have a urls.py file inside the todo app, so let’s create one and add the following code:
todo_project/todo/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.welcome_page),
]

Djnago Unchained for Beginners


19
Explanation:

The first line imports Django’s path function.


The second line imports the views.py file from the current todo app.
In the urlpatterns list, the empty string '' indicates the root URL.
It maps this URL to the welcome_page function in views.py, which we defined earlier to render the
base.html file.

We actually need two terminals:


Þ One to run the Django server using: python3 manage.py runserver
Þ Another to run Tailwind CSS with: npm run dev

In VS Code, look at the top-right corner of the terminal panel — you’ll see a plus (+) icon. Click it to
open a second terminal. Now you can switch between them by simply clicking on each tab.

📌 Remember: Always activate your virtual environment in each terminal before running any commands.

Djnago Unchained for Beginners


20
DATABASE SETUP:
Let’s Connect PostgreSQL Database to Our Django Project

Earlier, we deleted the default db.sqlite3, so now we need to create a new PostgreSQL database.

Steps to Create a Database Using pgAdmin:

1. Open pgAdmin.
2. On the top-left, expand Servers → then expand the PostgreSQL server.
3. Right-click on Databases → click Create → then Database.
4. A popup window will appear.
Þ Set a name for the database (e.g., todo_db).
5. On the bottom-right of the popup, click Save.

Done! Your PostgreSQL database is now created and ready to be connected to your Django project. Like
this way:

Djnago Unchained for Beginners


21

Now that the database is created, let’s connect it with our Django project. To do that, we need to install a
package called psycopg2, which allows Django to communicate with PostgreSQL.

Shell
# pip install psycopg2

todo_project/config/settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'todo_db', # name of the database you created
'USER': 'postgres', # your PostgreSQL username
'PASSWORD': '87654321', # your PostgreSQL password
'HOST': 'localhost',
'PORT': '5432',
}
}

Now run this command:


Shell
# python3 manage.py migrate

Djnago Unchained for Beginners


22

Yeap! Now it is successfully connected! Let’s check the database.

All the migrations applied.

Djnago Unchained for Beginners


23
Implementing a Basic CRUD System

In this section, we’ll build a basic CRUD (Create, Read, Update, Delete) application. CRUD represents the
core functionalities of most web apps.

To begin, we’ll redesign our homepage by updating the base.html template to support these operations. This
will serve as the starting point for adding tasks and managing them through a user-friendly interface.

todo_project/templates/base.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="{% static 'src/css/output.css' %}" />
<!-- Font Awesome (Optional) -->
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
/>
<title>TODO LIST - Home</title>
</head>
<body class="bg-gray-100 text-gray-900">
<div class="max-w-6xl mx-auto px-4 py-8">
<h3 class="text-3xl font-bold text-center mb-8">Django ToDo App</h3>

<div class="grid grid-cols-1 md:grid-cols-2 gap-6">


<!-- My Day -->
<div>
<h4 class="text-xl font-semibold mb-4">My Day</h4>
<div class="h-[450px] overflow-y-scroll space-y-2 pr-2">
<div
class="bg-white shadow rounded p-4 flex justify-between items-center"
>
<span></span>
<div class="space-x-2">
<a
href="#"
class="bg-green-500 text-white px-3 py-1 rounded hover:bg-green-600 text-sm"
>
<i class="fa fa-check"></i> Done
</a>
<a
href="#"
class="bg-red-500 text-white px-3 py-1 rounded hover:bg-red-600 text-sm"
>
<i class="fa fa-trash"></i>
</a>
<a
href=""
Djnago Unchained for Beginners
24
class="bg-blue-500 text-white px-3 py-1 rounded hover:bg-blue-600 text-sm"
>
<i class="fa fa-pencil"></i>
</a>
</div>
</div>
</div>
</div>

<!-- Completed Tasks -->


<div>
<h5 class="text-xl font-semibold mb-4">Completed Tasks</h5>
<div class="space-y-2">
<div
class="bg-white shadow rounded p-4 flex justify-between items-center"
>
<span></span>
<a
href="#"
class="bg-red-500 text-white px-3 py-1 rounded hover:bg-red-600 text-sm"
>
<i class="fa fa-times"></i> Undone
</a>
</div>
</div>
</div>
</div>

<!-- Add Task Form -->


<div
class="mt-10 fixed bottom-12 left-1/2 -translate-x-1/2 w-full max-w-xl"
>
<form action="" method="POST" class="bg-white p-4 shadow rounded">
<div class="flex gap-2">
<input
type="text"
name="task"
class="flex-1 px-4 py-2 border border-gray-300 rounded focus:outline-none
focus:ring-2 focus:ring-blue-400"
placeholder="Add a task"
/>
<button
type="submit"
class="bg-blue-500 text-white px-5 py-2 rounded hover:bg-blue-600"
>
<i class="fa fa-plus"></i> Add
</button>
</div>
</form>
</div>
</div>
</body>
</html>

Djnago Unchained for Beginners


25

After updating, let’s check the browser now. BOOM! Our design is ready to work!

Djnago Unchained for Beginners


26
Creating Task:

Now let’s define our data structure by writing a few lines in the models.py file.

The models.py file is where we define the database schema for our Django app. It contains classes that
represent tables in the database. Each class is a model, and the attributes of the class represent fields/columns
in the table.

todo_project/todo/models.py
from django.db import models

# Create your models here.


class Task(models.Model):
task_name = models.CharField(max_length=250)
is_completed = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

Explanation:
class Task(models.Model):
Þ class Task: Defines a new model (i.e., database table) named Task.
Þ models.Model: Inherits from Django’s base model, giving Task all the functionality of a Django model.
task_name = models.CharField(max_length=250)
Þ task_name: This is a field (column) in the database.
Þ CharField: A text field for short strings.
Þ max_length=250: Limits the maximum length of the task name to 250 characters.
is_completed = models.BooleanField(default=False)
Þ is_completed: A field to track whether the task is done or not.

Þ BooleanField: Stores True or False values.

Þ default=False: By default, the task is not completed.

created_at = models.DateTimeField(auto_now_add=True)
Þ created_at: A field to automatically record when the task is created.

Þ DateTimeField: Stores date and time.

Þ auto_now_add=True: Automatically sets the field to the current time when the object is first created.

updated_at = models.DateTimeField(auto_now=True)
Þ updated_at: A field to automatically record when the task is last updated.
Þ auto_now=True: Updates this field to the current time every time the object is saved.

This is how models work in Django. The next step is to apply these changes to the database. To do that, we
need to run two important commands:
1. makemigrations – This generates a migration file based on the changes made to the models.py file.

Djnago Unchained for Beginners


27
2. migrate – This applies those migrations to the actual database.
Shell
# python3 manage.py makemigrations
# python3 manage.py migrate

This will look like this:

Now let’s check our database.

Djnago Unchained for Beginners


28
You might notice that an extra id field (or column) is automatically created in the database. Don’t worry —
this is Django’s default behavior. If you don’t explicitly define a primary key in your model, Django will
automatically create an id field and set it as the primary key.

Now let’s define our logic or view in views.py file. let’s do it:

todo_project/todo/views.py
from django.shortcuts import render, redirect
from .models import Task

# Create your views here.


def welcome_page(request):
return render(request, "base.html")

def create_task(request):
task = request.POST['task']
Task.objects.create(task_name=task)
return redirect('welcome_page')

Explanation:
from .models import Task
Þ This line imports the Task model from the current app’s models.py file.
def addTask(request):
Þ This defines a function named addTask that takes in the HTTP request object as a parameter.
Þ It's meant to handle a form submission (typically via POST) for adding a new task.
task = request.POST['task']
Þ This line extracts the value submitted in the form under the key "task".
Þ request.POST is a dictionary-like object containing all form data sent via a POST request.
Þ For example, if your HTML form had an input like <input name="task">, this line captures that
value. Check base.html, you’ll find this.
Task.objects.create(task_name=task)
Þ This line creates a new Task object and saves it to the database.
Þ Task.objects.create(...) = create a new row in the Task table with the given data.
Þ task_name=task means: the model’s task field is being set to the value retrieved from the form.
return redirect('welcome_page')
Þ After saving the task, this line redirects the user to the 'welcome_page' URL (usually defined in
urls.py with name='welcome_page'). We’ll define it in the very next step.

Djnago Unchained for Beginners


29
Let’s define URL for this create_task view. Open urls.py file:

todo_project/todo/urls.py
from django.urls import path
from . import views

urlpatterns = [
path('', views.welcome_page),
path('create_task/', views.create_task, name='welcome_page'),
]

Explanation:
path('create_task/', views.create_task, name='create_task'),

Þ path – A Django function used to define a URL route.


Þ 'create_task/' – The URL pattern users will visit (e.g., http://127.0.01.1:8000/create_task/).
Þ views.create_task – Refers to the create_task function inside the views.py file. This function will
handle the request when someone visits the URL.
Þ name='welcome_page' – Assigns a name to this URL pattern so it can be referenced elsewhere in the
project (like in templates or redirects) using this name instead of the hardcoded URL.

So this line tells Django: “When someone visits /create_task/, call the create_task function from
views.py, and let us refer to this URL pattern by the name 'create_task'.”

Now, we have to configure these changes to our ‘base.html’ file. so that our changes work accordingly.

todo_project/templates/base.html
‘’’
<form
action="{% url 'create_task' %}"
method="POST"
class="bg-white p-4 shadow rounded"
>
{% csrf_token %}
<div class="flex gap-2">
<input
type="text"
name="task"
class="flex-1 px-4 py-2 border border-gray-300 rounded focus:outline-none
focus:ring-2 focus:ring-blue-400"
placeholder="Add a task"
/>
<button
type="submit"
class="bg-blue-500 text-white px-5 py-2 rounded hover:bg-blue-600"
>
<i class="fa fa-plus"></i> Add

Djnago Unchained for Beginners


30
</button>
</div>
</form>
‘’’

Now, when you submit the form, the data goes to the server since we're using the POST method.

Explanation:
action="{% url 'create_task' %}"
Þ action: This is an HTML attribute of the <form> tag. It tells the browser where to send the form data
when the form is submitted.
Þ "{% ... %}": This is a Django template tag. It allows dynamic content to be inserted in templates.
Þ url: A Django template tag that reverses a URL pattern name into the actual URL. So you don’t hard-
code URLs.
Þ 'create_task': This is the name of a URL pattern that you defined in your urls.py. Django will
look for a path with name='create_task' and insert its URL here.
method="POST"
Þ method: Another HTML attribute of the <form> tag. It specifies how the form data should be sent.
Þ "POST": A method type. It means the data will be sent securely in the body of the HTTP request, not
in the URL (as with GET).
{% csrf_token %}
Þ csrf_token: Stands for “Cross-Site Request Forgery token.” Django generates a hidden token that
protects your form from malicious submissions from other sites.

We have added some data.

Djnago Unchained for Beginners


31
Let’s check the database:

We’re almost done! But there’s one important thing left — we should be able to see the list of tasks we’ve
added on our Home page. For that we have to configure our welcome_page view. Let’s implement that
now.
todo_project/todo/views.py
‘’’
def welcome_page(request):
task_list = Task.objects.filter(is_completed=False).order_by('-updated_at')
context = {
'task_list': task_list,
}
return render(request, "base.html", context)
‘’’

Explanation:
task_list = Task.objects.filter(is_completed=False).order_by('-updated_at')
Þ task_list: A variable that will store a list of tasks we want to display.
Þ Task: This is the model we created to represent a task in the database.
Þ .objects: This gives us access to query the database (Django ORM).
Þ .filter(is_completed=False): This filters the tasks to get only those that are not completed
(unchecked tasks).
Þ .order_by('-updated_at'): This sorts the tasks by their last updated time, newest first (the - sign
means descending order).
context = { 'task_list': task_list,}
Þ context – A dictionary that passes data to the template (HTML file).
Þ 'task_list' – The key used in the template to access the data.
Þ task_list – The variable we created above, containing filtered and sorted tasks.
return render(request, "base.html", context)
Þ context – The data we’re sending to that template (so it can show the tasks).

Note:

Djnago Unchained for Beginners


32
Look at these two lines: which we have added two different functions.
task_list = Task.objects.filter(is_completed=False).order_by('-updated_at')
Task.objects.create(task_name=task)

Here the format is: Model.objects.query()


So what does objects mean?
Þ Task is your model class (a blueprint for a database table).

Þ objects is the manager attached to the Task model.

Þ The manager (objects) gives you access to query methods, like:

§ .create() → to create and save a new object.

§ .all() → to retrieve all records.

§ .filter() → to filter records based on some conditions.

§ .get() → to get a single object that matches the query.

§ .update() and .delete() → to modify or remove records.

Now let’s implement the changes to the templates (base.html):

todo_project/templates/base.html
‘’’
<!-- My Day -->
<div>
<h4 class="text-xl font-semibold mb-4">My Day</h4>
<div class="h-[450px] overflow-y-scroll space-y-2 pr-2">
{% for task in task_list %}
<div
class="bg-white shadow rounded p-4 flex justify-between items-center"
>
<span>{{ task.task_name }}</span>
<div class="space-x-2">
<a
href="#"
class="bg-green-500 text-white px-3 py-1 rounded hover:bg-green-600 text-sm"
>
<i class="fa fa-check"></i> Done
</a>
<a
href="#S"
class="bg-red-500 text-white px-3 py-1 rounded hover:bg-red-600 text-sm"
>
<i class="fa fa-trash"></i>
</a>
<a
href=""
class="bg-blue-500 text-white px-3 py-1 rounded hover:bg-blue-600 text-sm"
>
<i class="fa fa-pencil"></i>
</a>

Djnago Unchained for Beginners


33
</div>
</div>
{% endfor %}
</div>
</div>
‘’’

Explanation:
{% for task in task_list %}
Þ {% ... %} – This is a template tag in Django. It tells the template to perform logic (not just display

text).
Þ for – A loop keyword, just like in Python. It means we want to go through a list, one item at a time.

Þ task – A temporary variable name we choose. In each loop, this will represent one task from the

list.
Þ in – A keyword that connects the variable (task) to the list (task_list) we are looping over.

Þ task_list – This is the name of the variable we passed from the view using cotext (a list of tasks not

completed).
{{ task.task_name }}
Þ {{ ... }} – This is a template expression that tells Django to display the value inside.
Þ task – This refers to the current task from the loop.
Þ task_name – This is the field from the model. It shows the name of the task.
{% endfor %}
Þ endfor – Tells Django that the loop is finished.
This block of code loops through all the tasks in task_list and displays each task’s name.

Let’s check the browser:

Great job! You've just learned one of the core concepts of Django — the MVT (Model-View-Template)
architecture.
Djnago Unchained for Beginners
34
Let’s understand what is connected with what:

Sometimes it can be confusing to understand how everything is connected in a Django project. But if you
carefully study the diagram, you'll gain a clear and confident understanding of how each part interacts with
the others.

Djnago Unchained for Beginners


35
MVT Architecture:

What is MVT?

Django follows the MVT architectural pattern, which is very similar to MVC (Model-View-Controller),
but Django does a bit of the controller work internally for you.
Þ Model: Handles the data (database).

Þ View: Handles the logic (Python code).

Þ Template: Handles the presentation (HTML/CSS).

Figure 1:MVT (freecodecamp)

Let’s say a user submits a new task using a form.

1. User submits the form.


2. URLConf (urls.py) routes the request to the right view (create_task).
3. View (views.py) processes the data and saves it using the Model.
4. Model (models.py) interacts with the database to save the new task.
5. The view then loads a Template (base.html) with updated task list.
6. The Template displays the tasks, and the user sees them on the browser.

Djnago Unchained for Beginners


36
Task Status

In a to-do application, we create tasks that need to be done. Once we complete a task, we check the box to
mark it as done — right? But sometimes, our boss might say, "No, this task isn’t finished yet. Please complete
it properly." In that case, we need to uncheck the task again. So, let’s implement that feature now!
todo_project/todo/views.py
from django.shortcuts import render, redirect, get_object_or_404
,,,
def task_checked(request, id):
task = get_object_or_404(Task, id=id)
task.is_completed = True
task.save()
return redirect('welcome_page')
,,,

Explanation:
def task_checked(request, id):
Þ id: A URL parameter that contains the ID of the task to be marked as completed.
task = get_object_or_404(Task, id=id)
Þ get_object_or_404(...): A Django shortcut function that:

1. Tries to retrieve an object from the database (Task model in this case).
2. If the object does not exist, it automatically returns an HTTP 404 (Not Found) response.
Þ id=id: Look for a task in the database where the task’s id (in the database) is the same as the id we

got from the URL.


This view function takes the task ID from the URL, finds that task from the database, marks it as completed,
saves the change, and sends the user back to the homepage.

Then define URL for this view:

todo_project/todo/urls.py
from django.urls import path
from . import views

urlpatterns = [
path('', views.welcome_page, name='welcome_page'),
path('create_task/', views.create_task, name='create_task'),
path('task_checked/<int:id>/', views.task_checked, name='task_checked'),
]

Explanation:
path('task_checked/<int:id>/', views.task_checked, name='task_checked'),
Þ 'task_checked/<int:id>/':
§ task_checked/: The URL starts with this static path.

Djnago Unchained for Beginners


37
§ <int:id>/: A dynamic segment that captures an integer value from the URL and passes it to the

view as a parameter named id.


Where does id come from?
The id usually comes from the frontend (like a template or a form), often passed in a link or button like
this: <a href="{% url 'task_checked' task.id %}">Done</a>
Here, task.id is the id of a specific task object passed from the view to the template. So the expected url
will look like this: http://127.0.0.1:8000/task_checked/2

Let’s modify base.html file accordingly:


todo_project/templates/base.html
‘’’
<a
href="{% url 'task_checked' task.id %}"
class="bg-green-500 text-white px-3 py-1 rounded hover:bg-green-600 text-sm">
‘’’

Now, mark a few of your tasks as completed and check the database to see the updates.

Yes! It’s working. The tasks we marked as completed are now showing with their boolean value set to True.
Let’s check this in the browser.

Djnago Unchained for Beginners


38
The tasks we marked as completed are no longer showing in the main list — that’s expected. But now, we
want to display them in the “Completed Tasks” section. Let’s implement that.
todo_project/todo/views.py
def welcome_page(request):
task_list = Task.objects.filter(is_completed=False).order_by('-updated_at')
completed_task_list = Task.objects.filter(is_completed=True).order_by('-updated_at')
context = {
'task_list': task_list,
'completed_task_list': completed_task_list,
}
return render(request, "base.html", context)

Let’s display the completed tasks in the “Completed Tasks” section.

todo_project/templates/base.html
‘’’
<!-- Completed Tasks -->
<div>
<h5 class="text-xl font-semibold mb-4">Completed Tasks</h5>
{% for task in completed_task_list %}
<div class="space-y-2">
<div
class="bg-white shadow rounded p-4 flex justify-between items-center"
>
<span>{{task.task_name}}</span>
<a
href="#"
class="bg-red-500 text-white px-3 py-1 rounded hover:bg-red-600 text-sm"
>
<i class="fa fa-times"></i> Undone
</a>
</div>
</div>
{% endfor %}
</div>
</div>
‘’’

Djnago Unchained for Beginners


39
Now check the browser:

Great job! But sometimes, our teacher or friends say our completed task isn’t really done. In that case, we
need to uncheck it. Let’s see how—it’s simple and almost the same!
Let’s define view for that:

todo_project/todo/views.py
def task_unchecked(request, id):
task = get_object_or_404(Task, id=id)
task.is_completed = False
task.save()
return redirect('welcome_page')

todo_project/todo/urls.py
from django.urls import path
from . import views

urlpatterns = [
path('', views.welcome_page, name='welcome_page'),
path('create_task/', views.create_task, name='create_task'),
path('task_checked/<int:id>/', views.task_checked, name='task_checked'),
path('task_unchecked/<int:id>/', views.task_unchecked, name='task_unchecked'),
]

todo_project/templates/base.html
‘’’
<span>{{task.task_name}}</span>
<a
href="{% url 'task_unchecked' task.id %}"
class="bg-red-500 text-white px-3 py-1 rounded hover:bg-red-600 text-sm"
>
<i class="fa fa-times"></i> Undone
</a>
‘’’

Djnago Unchained for Beginners


40
UPDATE TASK:
Sometimes we may have to edit the title of our task. let’s do it.

todo_project/todo/views.py
def update_task(request, id):
get_task = get_object_or_404(Task, id=id)
if request.method == ‘POST’:
updated_task = request.POST[‘task’]
get_task.task_name = updated_task
get_task.save()
return redirect(‘welcome_page’)
else:
context = {
‘get_task’: get_task,
}
return render(request, ‘update_task.html’, context)

Explanation:
This view handles updating a task. It first fetches the task by its ID. If the request is a POST (form
submitted), it updates the task name with the new value and saves it, then redirects to the welcome page. If
it's a GET request, it renders a form with the current task data for editing.

todo_project/todo/urls.py
from django.urls import path
from . import views

urlpatterns = [
path('', views.welcome_page, name='welcome_page'),
path('create_task/', views.create_task, name='create_task'),
path('task_checked/<int:id>/', views.task_checked, name='task_checked'),
path('task_unchecked/<int:id>/', views.task_unchecked, name='task_unchecked'),
path('update_task/<int:id>/', views.update_task, name='update_task'),
]

todo_project/templates/base.html
‘’’
<a
href="{% url 'update_task' task.id %}"
class="bg-blue-500 text-white px-3 py-1 rounded hover:bg-blue-600 text-sm">
<i class="fa fa-pencil"></i>
</a>
‘’’

todo_project/templates/update_task.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />

Djnago Unchained for Beginners


41
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="{% static 'src/css/output.css' %}" />
<title>Update Task - Django TODO App</title>

<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
/>
</head>
<body class="bg-gray-100 min-h-screen flex items-center justify-center">
<div class="w-full max-w-md bg-white p-6 rounded shadow">
<h3 class="text-2xl font-bold text-center mb-6">
Django TODO App - Update Task
</h3>
<form
action="{% url 'update_task' get_task.id %}"
method="POST"
class="space-y-4">
{% csrf_token %}
<div>
<div class="flex gap-2">
<input
type="text"
name="task"
class="w-full border border-gray-300 rounded px-4 py-2 focus:outline-none
focus:ring-2 focus:ring-blue-400"
placeholder="Update your task"
value="{{get_task.task_name}}"
/>
<button
type="submit"
class="w-40 bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700 transition"
>
<i class="fa fa-plus mr-1"></i> Update
</button>
</div>
</div>
</form>
</div>
</body>
</html>

If we now click the edit button, it will show the update_task.html file:

Djnago Unchained for Beginners


42
Now update the task and check the database.

Yeah! It’s updated. Sometimes we no longer need a task, so we should delete it. Let’s implement this feature
too—it’s very simple, and you might already know how to do it!
todo_project/todo/views.py
def delete_task(request, id):
task = get_object_or_404(Task, id=id)
task.delete() # This delete the task from the database
return redirect('welcome_page')

todo_project/todo/urls.py
from django.urls import path
from . import views

urlpatterns = [
path('', views.welcome_page, name='welcome_page'),
path('create_task/', views.create_task, name='create_task'),
path('task_checked/<int:id>/', views.task_checked, name='task_checked'),
path('task_unchecked/<int:id>/', views.task_unchecked, name='task_unchecked'),
path('update_task/<int:id>/', views.update_task, name='update_task'),
path('delete_task/<int:id>/', views.delete_task, name='delete_task'),
]

todo_project/templates/base.html
,,,
<a href="{% url 'delete_task' task.id %}"
class="bg-red-500 text-white px-3 py-1 rounded hover:bg-red-600 text-sm">
<i class="fa fa-trash"></i>
</a>
,,,

Now click the delete icon button and check the database. Yeap, First task has been deleted!

We’ve successfully finished our todo project! Now, let’s move on and start our blog project!
Djnago Unchained for Beginners

You might also like