Как мы видим из прошлого урока, у нас в папке "Блог" есть следующие файлы:
- migrations (папка)
- __init__.py
- admin.py (нужен этот)
- apps.py
- models.py (нужен этот)
- tests.py
- views.py
Создание модели статьи для блога на Django
И так, заходим в редактирование models.py, и давайте добавим нашу первую модель. Но первое, что мы сделаем, это установим необходимые зависимости для изображений (превью) и конечно для категорий, так как я хочу использовать вложенные категории в виде дерева.
В терминале вводим и устанавливаем следующие зависимости:
pip install Pillow django-mptt
- Pillow отвечает за работу с изображениями, если прочитать документацию, в ней очень много чего интересного.
- Django-mptt отвечает за создание моделей в виде иерархии, дерева. Например, категория: Программирование -> Python -> Django. Все здесь вложено.
В терминале должно выдать следующее:
(venv) PS C:\Users\Razilator\Desktop\Courses\App\backend> pip install django-mptt Pillow
Collecting django-mptt
Installing collected packages: Pillow, django-js-asset, django-mptt
Successfully installed Pillow-9.2.0 django-js-asset-2.0.0 django-mptt-0.13.4
Заранее подключим Django-mptt в INSTALLED_APPS в файле settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'modules.blog.apps.BlogConfig',
'mptt',
]
После установки добавим нашу модель Article (Статьи), пока без категорий в models.py
from django.contrib.auth.models import User
from django.core.validators import FileExtensionValidator
from django.db import models
class Article(models.Model):
"""
Модель статей для проекта
"""
title = models.CharField(verbose_name='Заголовок', max_length=255)
slug = models.SlugField(verbose_name='URL', max_length=255, blank=True)
short_description = models.TextField(max_length=300, verbose_name='Краткое описание')
full_description = models.TextField(verbose_name='Описание')
author = models.ForeignKey(User, verbose_name='Автор материала', on_delete=models.PROTECT, related_name='article_author')
updated_by = models.ForeignKey(User, verbose_name='Автор обновления', on_delete=models.CASCADE, related_name='article_updated_by', blank=True, null=True)
created_at = models.DateTimeField(verbose_name='Дата добавления', auto_now_add=True, db_index=True)
updated_at = models.DateTimeField(verbose_name='Дата обновления', auto_now=True, db_index=True)
reason = models.CharField(verbose_name='Причина обновления', blank=True, max_length=100)
is_fixed = models.BooleanField(verbose_name='Зафиксировано', default=False, db_index=True)
is_published = models.BooleanField(verbose_name='Опубликовано', default=True)
thumbnail = models.ImageField(
verbose_name='Превью поста',
blank=True,
upload_to='images/thumbnails/',
validators=[FileExtensionValidator(
allowed_extensions=('png', 'jpg', 'webp', 'jpeg', 'gif'))
]
)
class Meta:
"""
Сортировка, название модели в админ панели, таблица в данными
"""
ordering = ('-is_fixed', '-created_at')
verbose_name = 'Статья'
verbose_name_plural = 'Статьи'
db_table = 'app_articles'
def __str__(self):
"""
Возвращение строки в виде заголовка статьи
"""
return self.title
Пояснения за поля:
- title - заголовок, с максимальным количеством символов 255
- slug - ссылка на материал (латиница), с максимальным количеством символов 255, blank (необязательно к заполнению)
- short_description - текстовое поле, ограниченное 300 символами.
- full_description - аналогично, без ограничений.
- author - ключ ссылаемый на пользователя из другой таблицы (пользователей) c on_delete=models.PROTECT (при удалении происходит защита, что не позволяет так просто удалить пользователя с его статьями, чтоб вы могли передать статьи другому человеку)
- updated_by - аналогично, только если при обновлении статьи выводить того, кто редактировал (добавлять, если вам это нужно) c on_delete=models.CASCADE (при удалении просто убирается значение того, кто обновил у статей каскадно)
- reason - причина редактирования
- is_fixed - булево значение, по умолчанию False (зафиксировано)
- is_published - булево значение, по умолчанию True (опубликовано)
Также добавлены db_index=True к полям, которые используются в сортировке.
- ordering - сортировка, ставим -created_at, чтобы выводились статьи в обратном порядке (сначала новые, потом старые).
- verbose_name - название модели в админке в ед.ч
- verbose_name_plural - в мн.числе
- db_table - название таблицы в БД. (можно не добавлять, будет создано автоматически)
Также мы применили валидатор FileExtensionValidator для расширений изображений, которые мы разрешаем к загрузке.
Подключение Django модели в Административную модель
Открываем файл admin.py и вставляем следующее содержимое
from django.contrib import admin
from modules.blog.models import Article
admin.site.register(Article)
Миграция модели в базу данных Django
И так, предпоследний шаг для появлений рабочей модели: мы должны создать миграции и применить их, делается это следующим образом:
python manage.py makemigrations
python manage.py migrate
Если все сделали верно, то в консоли будет следующее содержимое:
(venv) PS C:\Users\Razilator\Desktop\Courses\App\backend> python manage.py makemigrations
Migrations for 'blog':
modules\blog\migrations\0001_initial.py
- Create model Article
(venv) PS C:\Users\Razilator\Desktop\Courses\App\backend> python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, blog, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying auth.0012_alter_user_first_name_max_length... OK
Applying blog.0001_initial... OK
Applying sessions.0001_initial... OK
(venv) PS C:\Users\Razilator\Desktop\Courses\App\backend>
Теперь нам нужно создать суперпользователя для доступа к админ.панели!
Создание суперпользователя в Django
Для этого мы выполняем следующую команду:
python manage.py createsuperuser
Задаем логин, email и пароль.
Давайте зайдем в панель управления и увидим нашу добавленную модель. Логинимся через только что созданного суперпользователя и видимо следующее:


В следующем уроке мы поставим русский язык, а также добавим вложенные категории.
tipa_dev
в этой строке почему-то ошибка: from modules.blog.models import Article
импортировал так: from .models import Article
Razilator
tipa_dev, да, можно так, зависит от расположения папок, и файла init.py. Я на курсе по Django 2023 на другом сайте уже также импортирую)
qulok99
Razilator, а что за курс и где можно посмотреть?
Razilator
qulok99, почти аналогичный существующему, только грамотнее, код немного другой, и в 50 уроков уместил больше информации, и тоже мой. Держите proghunter.ru. Это мой новый сайт, он сделан на двух технологиях, Django + Next.js, он работает намного быстрее, и вскоре notehunter мне придется закрыть, ибо не повезло с доменом, его плохо кушают боты, а гугл вообще дал бан из-за своего обновления. И посещаемость там уже на 500 больше.
qulok99
Razilator, спасибо, главное не сдавайтесь, у вас достойный контент и сайты тоже
Razilator
qulok99, спасибо. Да видите, с этим notehunter.net не повезло, зато с прогхантером повезло, там будет весь контент, поэтому лучше туда переходите и в группу телеграмм, в которой скоро организую чат.