In this tutorial, we will create a basic blog using Django. In coming series, we will add new functionalities to the blog.
Prerequisite
- Python 3.8 or greater check python version
python3 -V
Python 3.9.12
if python version is not 3.8 or greater, run below command to installed Python in Mac
brew install python3
Creating project directory
We will create a project directory which will be used for storing all project code and python dependencies.
mkdir django-blog
Creating virtual environment
We will create a virtual environment to isolate python version and dependencies from system python. Creating a virtual environemnt is recommended for almost all python projects.
cd django-blog
python3 -m venv venv
After running above commands, below folder structure is created
django-blog
└── venv
In venv directory we will installed our local version of python3. This local python will be used for our proejct development.
Activating virtual environment
Before using a virtual environment, we have to activate the environemnt. For activating the virtual environment, run below command.
source venv/bin/activate
Once the virtual environment is activated, the python installed in venv
directory will be used.
To verify which python is being used, run below command after activating the virtual environemnt.
which python
/Users/vinodpandey/Projects/django-blog/venv/bin/python
In my case, it shows the /venv/bin/python
inside django-blog
. /Users/vinodpandey/Projects
is where is created this directory. This path will be different, but django-blog/venv/bin/python
will be same.
Installing Django in virtual environment
Make sure you are in django-blog
directory and run below command
pip install Django==4.0.5
since we are using virtual environment, Django will be installed in venv directory we created earlier.
If we run below command, it will show Django 4.0.5 installed directories
ls venv/lib/python3.9/site-packages/
Django-4.0.5.dist-info pip-22.0.4.dist-info
_distutils_hack pkg_resources
asgiref setuptools
asgiref-3.5.2.dist-info setuptools-60.10.0.dist-info
distutils-precedence.pth sqlparse
django sqlparse-0.4.2.dist-info
pip
Creating Django project
We will use django-admin
command to create project. This command was installed when we installed Django.
To view the django-admin
command location, run below command
ls venv/bin/
Activate.ps1 activate.fish pip3 python3
activate django-admin pip3.9 python3.9
activate.csh pip python sqlformat
Run below command to create the project
django-admin startproject project .
After running the project, below folder structure ic created
django-blog
├── project
│ ├── __init__.py
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── manage.py
└── venv
If we don't use the .
in above command and run django-admin startproject project
, it creates below structure with project
directory inside project
directory and we don't want that. So, we use django-admin startproject project .
to create simple directory strucure.
Below is the structure when we don't use .
django-blog
.
├── project
│ ├── project
│ └── manage.py
└── venv
Setting Sqlite as database for Django blog
Run below command to create Django related database tables
python manage.py migrate
By default Django uses sqlite database because of the below default configuration in project/settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
We will keep the setting as-is. In later series, we will use MySQL instead of Sqlite database.
The database file in created in django-blog
directory itself. To view the file, run below command in django-blog
directory.
ls
db.sqlite3 manage.py project venv
db.sqlite3
is the database file where all our blog related data will be stored.
At this stage, we can run bleow command to verify that the server is running fine.
python manage.py runserver
Below is the output of above command
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
June 13, 2022 - 12:14:35
Django version 4.0.5, using settings 'project.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Open browser and access http://127.0.0.1:8000/
To quit the server use CONTROL-C
Setting up admin account and access admin section
Quit the server using CONTROL-C
and run below command to create admin user
python manage.py createsuperuser
Username (leave blank to use 'vinodpandey'): admin
Email address: admin@admin.com
Password:
Password (again):
The password is too similar to the username.
This password is too short. It must contain at least 8 characters.
This password is too common.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.
We are using username: admin
and password: admin
during development. Never use this combination in production.
Run the server using python manage.py runserver
and access http://127.0.0.1:8000/admin/
. It will show the admin section.
Creating blog application
Stop the server if it is already running. Make sure you are in django-blog
directory and virtual environment is activated.
Quit the server with CONTROL-C
(if it is already running) and run below command to create the blog app.
python manage.py startapp blog
This command will create a blog
directory inside django-blog
directory will bunch of other files.
Below is the directory structure now:
django-blog
├── blog
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── db.sqlite3
├── manage.py
├── project
│ ├── __init__.py
│ ├── __pycache__
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── venv
To register blog
app in Django, open project/settings.py
and search for INSTALLED_APPS
. In INSTALLED_APPS
, add blog
at the end of existing entries after django.contrib.staticfiles
as mentioned below.
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog'
]
Creating model for blog
We will create a model Post
which will be used for creating and storing blog posts. In blog/models.py
add below content.
# Create your models here.
from django.db import models
from django.contrib.auth.models import User
STATUS = (
(0, "Draft"),
(1, "Published")
)
class Post(models.Model):
title = models.CharField(max_length=250, unique=True)
slug = models.SlugField(max_length=250, unique=True)
created_by = models.ForeignKey(User, on_delete= models.CASCADE,related_name="%(app_label)s_%(class)s_created_by")
content = models.TextField()
status = models.IntegerField(choices=STATUS, default=0)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now= True)
class Meta:
ordering = ['-created_at']
def __str__(self):
return self.title
We have created the model Post
and now we have to create the corresponding database tables in sqlite
.
For creating tables, run below command:
python manage.py makemigrations
Migrations for 'blog':
blog/migrations/0001_initial.py
- Create model Post
Above command created a migration file 0001_initial.py
in blog/migrations/
directory.
ls blog/migrations
0001_initial.py
Next step is to apply the migrations and create the database tables.
python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, blog, contenttypes, sessions
Running migrations:
Applying blog.0001_initial... OK
Enabling admin functionality for models for entering data
In blog/admin.py
add below content. This will enable django admin backend for blog
app.
from .models import Post
admin.site.register(Post)
Run django server using python manage.py runserver
and access http://localhost:8000/admin/
. It should show Django administration
page.
Create a new blog post which we will use for testing.
title: Hello World
slug: hell-world
author: admin
content: Hello world
Status: Published
Creating blog views and urls
We will create views, urls and couple of other files. Stop the Django server and once all below files are created, start it again.
Creating view
In blog/views.py
add below code
from django.views import generic
from .models import Post
class PostList(generic.ListView):
queryset = Post.objects.filter(status=1).order_by('-created_at')
template_name = 'blog/index.html'
class PostDetail(generic.DetailView):
model = Post
template_name = 'blog/detail.html'
Creating template
Create blog template directory
mkdir -p blog/templates/blog/
create file index.html
in blog/templates/blog/
directory and add below content
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Django Blog</title>
</head>
<body>
<h1>Posts:</h1>
{% for post in object_list %}
<ul>
<li>
<a href="{% url 'blog_post_detail' post.slug %}">{{ post.title }}</a>
</li>
</ul>
{% endfor %}
{% if not object_list %}
<p>No post available.</p>
{% endif %}
</body>
create file detail.html
in blog/templates/blog/
directory and add below content
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ object.title }}</title>
</head>
<body>
<p> <a href="{% url 'blog_home' %}"><< Back</a></p>
<h1>{{ object.title }}</h1>
<p>{{ object.content }}</p>
</body>
</html>
Creating urls
Create a new file urls.py
in blog
directory and add below code in blog/urls.py
. You will see views.py
in same directory.
from . import views
from django.urls import path
urlpatterns = [
path('', views.PostList.as_view(), name='blog_home'),
path('<slug:slug>/', views.PostDetail.as_view(), name='blog_post_detail'),
]
In project/urls.py
append path('', include('blog.urls')),
below path('admin/', admin.site.urls),
as specified below. Also update the import as from django.urls import path, include
. We have added include
in existing import.
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('blog.urls')),
]
Accessing blog application
Now run the server again
python manage.py runserver
And access http://localhost:8000
. It should show the blog post we created earlier. On clicking the link, it will open individual blog post.
In upcoming series, we will add new functionality to blog and enhance the UI.