Я расскажу о там, как создать простой блог на фреймворке Django. Статья будет полезна новичкам в сфере Веб-программирования для того, чтобы разобраться в принципе работы и сути django. И так, поехали!
Проект написан с использованием:
Python 3.6.3 — высокоуровневый язык программирования.
Django 2.0.2 — фреймворк для веб-приложений.
Visual Code — текстовый редактор c поддержкой плагинов
Перед началом работы вам необходимо установить Python для дальнейшей работы с django. Для этого переходим на официальный сайт, скачиваем дистрибутив и устанавливаем его (как обычное приложение), поставив галочку напротив «Add Python to the PATH» (Добавить Python к системной переменной PATH). Если все сделано верно, то прописав в консоли (WIN + R > cmd) python, вы увидите следующее:

Для выхода пропишите exit().
Django установим с помощью менеджера пакетов Python — pip:
|
1 |
pip install django |
Для начала создадим папку для проекта в любом удобном месте и назовем ее «djangoProject». Далее Скопируем адрес этой папки и откроем консоль (WIN + R > cmd).

В консоли перейдем в созданную ранее папку. В моем случае папка находится на другом диске, поэтому сначала следует перейти на него — «d:»
|
1 |
cd <путь до папки> |
Создадим django проект с произвольным именем «myBlog»
|
1 |
django-admin startproject myBlog |
Перейдем в созданную папку и откроем ее в каком-либо текстовом редакторе. Я использую Visual code и запускаю его с помощью команды «code .»
|
1 2 |
cd myBlog code . |
Ненадолго отложим редактор и запустим стандартный проект django (при выполнении команд с обращением к файлу manage.py, например, запуск сервера вы должны находится в непосредственно в папке с этим файлом. В данном случае это D:\djangoProject\myBlog)
|
1 |
python manage.py runserver |

Откроем страницу в браузере по адресу https://127.0.0.1:8000/

Ура! Все работает. Теперь создадим аккаунт администратора, с помощью которого вы сможете добавлять, редактировать и удалять статьи (это конечно не все возможности админки django, но пока их будет достаточно).
Завершим работу запущенного сервера:
|
1 |
Ctrl + C |
Для начала необходимо поработать с миграциями. Миграции в django используются для переноса изменений в моделях на структуру базы данных. Модели в свою очередь отражают данные в виде полей в таблице базы данных. В нашем случае в базу данных необходимо занести таблицы для хранения данных админа.
|
1 |
python manage.py migrate |

Cоздадим суперюзера
|
1 |
python manage.py createsuperuser |
Нам будет предложено ввести логин, e-mail почту и пароль.
Логин для удобства введем admin, почту можно не вводить и пароль (мин. 8 символов). Будьте внимательны, вводимые символы пароля в консоли никак не отображаются (в целях безопасности).

Попробуем залогиниться в админ панели. Для этого запустим сервер:
|
1 |
python manage.py runserver |
Зайдем на страницу по адресу 127.0.0.1:8000/admin. Вводим логин и пароль от админки и жмем «Log in».

В итоге откроется админ панель:

Все работает, стартовый проект создан и создан аккаунт администратора. Сейчас перейдем к созданию Веб-приложения в django. В нашем случае Веб-приложение — это блог, который имеет свой собственный функционал (вывод всех статей и вывод отдельной).
Для этого завершим работу сервера (Ctrl + C) и пропишем следующую команду:
|
1 |
django-admin startapp blog |
Где «blog» — это произвольное название приложения. В итоге в директории djangoProject/myBlog появился новый каталог с именем «blog» и некоторыми .py файлами.

Далее нужно дать понять Django, что нужно использовать в работе наше новое приложение «blog». Для этого в файле settings.py с расположением djangoProject/myBlog/myBlog/settings.py изменяем настройку INSTALLED_APPS следующим образом:
|
1 2 3 4 5 6 7 8 9 |
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'blog', ] |
Поработаем с обработкой url-запросов. Нам необходимо, чтобы при запросе 127.0.0.1:8000 открывалась главная страница со списком всех статей.
Отредактируем файл djangoProject/myBlog/myBlog/urls.py следующим образом:
|
1 2 3 4 5 6 7 |
from django.contrib import admin from django.urls import path, include urlpatterns = [ path('', include('blog.urls')), path('admin/', admin.site.urls), ] |
Если говорить простым языком, то Django сравнивает url-запрос с данными в urlpatterns. Т.е. открыв страницу с адресом 127.0.0.1:8000/ django выполнит строку path(», include(‘blog.urls’)). На основе которой будет «читать» файл по адресу djangoProject/myBlog/blog/urls.py. Создадим и отредактируем этот файл:
|
1 2 3 4 5 6 7 |
from django.urls import path from .import views urlpatterns = [ path('', views.home, name='home'), ] |
Здесь идет переход «чтения» в файл views.py (в этой же папке), в котором используется функция home
Файл djangoProject/myBlog/blog/views.py
|
1 2 3 4 5 6 |
from django.http import HttpResponse from django.shortcuts import render def home(request): return render(request, "partial/home.html") |
С помощью функции render выполняем шаблон home.html. Для этого создаем в папке djangoProject/myBlog новую с именем «templates». В этой папке будут храниться все требуемые шаблоны страниц (главная, шаблон подробного просмотра статьи).
И редактируем в файле djangoProject/myBlog/myBlog/settings.py настройку TEMPLATES:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] |
В созданной папке templates создаем файл base.html:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> {% block head %} <title>Title</title> {% endblock %} </head> <body> {% block body %} {% endblock %} </body> </html> |
Это базовый шаблон, который будет дополнятся другими.
Создадим в папке djangoProject/myBlog/templates новую папку partial, в которой и будут находится .html файлы, расширяющие базовый.
В папке partial создадим файл home.html:
|
1 2 3 4 5 6 7 8 9 10 |
{% extends 'base.html' %} {% block head %} <title>Главная</title> <meta name="description" content="Главная страница блога"/> <meta name="keywords" content="блог"/> {% endblock %} {% block body %} <h1>Главная</h1> {% endblock %} |
При обращении к файлу home.html содержимое блоков head и body в файле base.html заменится содержимым файла home.html. такая система организации шаблонов добавляет динамику и в разы упрощает работу.
Теперь запустив сервер откроется не стандартная страница django, а наш файл base.html, расширенный файлом partial/home.html
|
1 |
python manage.py runserver |
Точно таким же способом добавим страницу для просмотра отдельной статьи, которую назовем partial/single.html:
Отредактируем файл djangoProject/myBlog/blog/urls.py, где <int:id> — указывает, что на этом месте может располагаться число, которое будет считываться в файле djangoProject/myBlog/blog/views в функции single. Это число будет использоваться как номер определенной статьи.
|
1 2 3 4 5 6 7 8 |
from django.urls import path from .import views urlpatterns = [ path('', views.home, name='home'), path('<int:id>/', views.single, name='single'), ] |
В файле djangoProject/myBlog/blog/views.py добавим новую функцию для вывода отдельной статьи
|
1 2 3 4 5 6 7 8 9 |
from django.http import HttpResponse from django.shortcuts import render def home(request): return render(request, "partial/home.html") def single(request, id=None): return render(request, "partial/single.html") |
Создаем шаблон для вывода отдельной статьи djangoProject/myBlog/templates/partial/single.html
|
1 2 3 4 5 6 7 8 9 10 |
{% extends 'base.html' %} {% block head %} <title>Странца статьи</title> <meta name="description" content="Главная страница блога"/> <meta name="keywords" content="блог"/> {% endblock %} {% block body %} <h1>Странца статьи</h1> {% endblock %} |
Теперь после запуска сервера и переходе по ссылке 127.0.0.1:8000/323 откроется нужная страница.
Создадим таблицу в базе данных с помощью моделей. Каждая статья будет содержать следующие поля:
Файл djangoProject\myBlog\blog\models.py
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
from django.db import models # Create your models here. class Post(models.Model): title = models.CharField(max_length=120) description = models.TextField(default='Описание') keywords = models.CharField(max_length=120, default='Ключевые слова') image = models.FileField(null=True, blank=True) content = models.TextField() visible = models.BooleanField(default=1) updated = models.DateTimeField(auto_now=True, auto_now_add=False) timestamp = models.DateTimeField(auto_now=False, auto_now_add=True) def __unicode__(self): return self.title def __str__(self): return self.title def get_absolute_url(self): return "/%s/" %(self.id) class Meta: ordering = ["-id", "-timestamp"] |
Для отображения нашей модели статьи в админ панели отредактируем файл djangoProject\myBlog\blog\admin.py, где list_display — поля, отображающиеся в списке статей; list_display_links — поля, являющиеся ссылками для подробного просмотра полей статьи; list_editable — поля, доступные для редактирования сразу из просмотра списка всех статей; list_filter — фильтры в правой части страницы; search_fields — поля по которым осуществляется поиск.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
from django.contrib import admin # Register your models here. from .models import Post class PostModelAdmin(admin.ModelAdmin): list_display = ["id" ,"title", "updated", "timestamp"] list_display_links = ["id", "updated"] list_editable = ["title"] list_filter = ["updated", "timestamp"] search_fields = ["title", "content"] class Meta: model = Post admin.site.register(Post, PostModelAdmin) |
Укажем папку для сохранения загружаемых изображений (поле image) и паку для хранения статических файлов (например, css файлы, js срипты). Для этого добавим в конце файла djangoProject\myBlog\settings.py следующие 3 строчки
|
1 2 3 4 5 |
MEDIA_URL = '/media/' STATIC_ROOT = os.path.join(BASE_DIR, "static") MEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR), "media") |
И создадим эти папки со следующим расположением: djangoProject/media и djangoProject/static
Помимо сохранения изображений через админ панель необходимо корректно их загружать в шаблон. Для этого отредактируем файл djangoProject\myBlog\views.py
|
1 2 3 4 5 6 7 8 9 10 11 |
from django.contrib import admin from django.urls import path, include from django.conf import settings from django.conf.urls.static import static urlpatterns = [ path('', include('blog.urls')), path('admin/', admin.site.urls), ] urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) |
Запускаем сервер
|
1 |
python manage.py runserver |
Заходим в админ панель — 127.0.0.1:8000/admin > переходим в Posts > add Post (в верхнем правом углу). Заполняем текстовые поля, загружаем изображение и оставляем галочку напротив visible (т.е. не скрывать статью). Нажимаем SAVE. Статья добавлена, изображение сохранилось в папку djangoProject/media

Настало время для вывода статей в шаблон home, т.е. на главную страницу.
Изменяем файл djangoProject/myBlog/blog/views.py. Подключаем модули для работы с пагинацией (постраничный вывод новостей) и модель Post. В функции home получаем все записи из таблицы Post и делим их по 4 на каждую страницу. Словарь context содержит ключи и значения, которые будут далее выводиться в шаблон.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
from django.http import HttpResponse from django.shortcuts import render from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from blog.models import Post def home(request): postList = Post.objects.filter(visible='1') paginator = Paginator(postList, 4) page = request.GET.get('page') querysetGoods = paginator.get_page(page) context = { "postList": postList, "title": "Главная страница блога", "desc": "Описание для главной страницы", "key": "ключевые, слова", } return render(request, "partial/home.html", context) def single(request, id=None): return render(request, "partial/single.html") |
Файл djangoProject\myBlog\templates\partial\home.html
С помощью тега truncatechars, обрежем строку до 70 первых символов.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
{% extends 'base.html' %} {% block head %} <title>Главная</title> <meta name="description" content="{{ desc }}"/> <meta name="keywords" content="{{ key }}"/> {% endblock %} {% block body %} <h1>Главная</h1> {% if not posts %} <b>Статьи не найдены</b> {% else %} {% for obj in posts %} <a href="{{ obj.get_absolute_url }}"><b>{{ obj.title }}</b></a> <img src="{{ obj.image.url }}" alt=""> <p>{{ obj.content|truncatechars:70 }}</p> <span>{{ obj.timestamp }}</span> <br><br><br> {% endfor %} {% endif %} {% if posts.has_previous %} <a href="?page={{ posts.previous_page_number }}">Назад</a> {% endif %} <span>{{ posts.number }} / {{ posts.num_pages }}</span> {% if posts.has_next %} <a href="?page={{ posts.next_page_number }}" >Вперед</a> {% endif %} {% endblock %} |
В базовый шаблон djangoProject\myBlog\templates\base.html добавим css файл, который следует создать с расположением djangoProject\static\css\style.css
|
1 2 3 4 5 |
img { width: 400px; height: auto; display: block; } |
Файл djangoProject\myBlog\templates\base.html
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> {% load static %} <link href="{% static 'css/style.css' %}" rel="stylesheet"> {% block head %} <title>Title</title> {% endblock %} </head> <body> {% block body %} {% endblock %} </body> </html> |
Для проверки пагинации добавим еще несколько статей.

Все работает! При переходе на следующую страницу изменяется параметр «page», указывающий на номер текущей страницы.
![]()
Займемся выводом отдельной статьи (подробной просмотр). Роутинг (в файле djangoProject\myBlog\blog\urls.py) уже настроен, осталось добавить выводимую информацию, в зависимости от id в адресной строке. Отредактируем файл djangoProject\myBlog\blog\views.py, в котором создадим новую функцию «single». Обратите внимание, в начале файле была подключена вспомогательная функция «get_object_or_404», возвращающая необходимую статью (по id) или же исключение 404, если пользователь введет несуществующий id.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
from django.http import HttpResponse from django.shortcuts import render, get_object_or_404 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from blog.models import Post def home(request): postList = Post.objects.filter(visible='1') paginator = Paginator(postList, 2) page = request.GET.get('page') posts = paginator.get_page(page) context = { "posts": posts, "title": "Главная страница блога", "desc": "Описание для главной страницы", "key": "ключевые, слова", } return render(request, "partial/home.html", context) def single(request, id=None): post = get_object_or_404(Post, id=id) context = { "post": post, } return render(request, "partial/single.html", context) |
И файл djangoProject\myBlog\templates\partial\single.html
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
{% extends 'base.html' %} {% block head %} <title>{{ post.title }}</title> <meta name="description" content="{{ post.description }}"/> <meta name="keywords" content="{{ post.keywords }}"/> {% endblock %} {% block body %} {% if post.visible %} <h1>{{ post.title }}</h1> <img src="{{ post.image.url }}" alt=""> <p>{{ post.content }}</p> {% else %} <p>Страница не найдена</p> {% endif %} {% endblock %} |
Наконец готов простой блог на django фреймворке. Итак, что в итоге: