📖 Теория: конспект Django-блока (Уроки 13–24)

🎯 Итоговое повторение К оглавлению урока

⚡ Краткий конспект

  • __str__ — читаемое представление объекта в admin, логах и консоли.
  • Meta — управляет таблицей (db_table), сортировкой (ordering), именами (verbose_name), уникальностью (unique_together) и индексами (indexes).
  • ModelAdmin — list_display, search_fields, list_filter, ordering, fields, list_per_page, actions.
  • Инлайны — TabularInline (таблица) / StackedInline (вертикаль). extra = количество пустых форм.
  • User — django.contrib.auth.models.User. Кастомная: AbstractBaseUser + PermissionsMixin + AUTH_USER_MODEL.
  • ORM-менеджер — Model.objects. create/save, all/filter/get/exclude, update/delete, Q, F, bulk_create/bulk_update.
  • Shellpython manage.py shell, затем импорт моделей.

1. Метод __str__ и класс Meta

Метод __str__

Определяет строковое представление объекта модели. Используется в admin-панели, Django Shell и в логах. Без него объекты отображаются как Book object (1).

from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.CharField(max_length=100)
    published_date = models.DateField()

    def __str__(self):
        return f"{self.title} by {self.author}"

Преимущества __str__

  • Удобное отображение в административной панели
  • Читаемость в консольных выводах и Django Shell
  • Улучшение читаемости логов и сообщений об ошибках

Класс Meta

Позволяет добавлять метаданные к модели: управлять именем таблицы, порядком сортировки, читаемыми именами, уникальностью и индексами.

АтрибутОписаниеПример
db_tableИмя таблицы в БД'library_book'
orderingПорядок сортировки записей['-published_date']
verbose_nameЧитаемое имя модели (ед. ч.)'fiction book'
verbose_name_pluralЧитаемое имя модели (мн. ч.)'fiction books'
get_latest_byПоле для latest()/earliest()'published_date'
default_related_nameИмя обратной связи для FK'books'
unique_togetherУникальность по комбинации полей('title', 'author')
indexesСписок индексовсм. ниже
constraintsОграничения уровня БДUniqueConstraint
class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.CharField(max_length=100)
    published_date = models.DateField()

    class Meta:
        db_table = 'library_book'
        ordering = ['-published_date']
        verbose_name = 'fiction book'
        verbose_name_plural = 'fiction books'
        unique_together = ('title', 'author')
        get_latest_by = 'published_date'
        indexes = [
            models.Index(fields=['title', 'author']),
            models.Index(fields=['published_date'], name='published_idx'),
        ]

2. Административная панель Django

Django Admin — встроенный CRUD-интерфейс для моделей. Доступен по адресу /admin/. Автоматически генерирует страницы создания, чтения, обновления и удаления объектов.

Два способа регистрации модели

# Способ 1: admin.site.register
from django.contrib import admin
from .models import Book

admin.site.register(Book)  # простая регистрация

class BookAdmin(admin.ModelAdmin):
    list_display = ('title', 'author', 'published_date')
    search_fields = ('title', 'author__name')
    list_filter = ('author', 'published_date')
    ordering = ('-author', 'title')
    fields = ('author', 'title', 'published_date')
    list_per_page = 2

admin.site.register(Book, BookAdmin)

# Способ 2: декоратор @admin.register
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
    list_display = ('title', 'author', 'published_date')
    search_fields = ('title', 'author')
    list_filter = ('author', 'published_date')
    ordering = ('-author', 'title')
    list_per_page = 2

Ключевые атрибуты ModelAdmin

АтрибутНазначение
list_displayПоля в списке объектов
search_fieldsПоля для полнотекстового поиска
list_filterБоковые фильтры
orderingПорядок сортировки в admin
fieldsНабор полей в форме редактирования
list_per_pageКоличество объектов на странице
actionsСписок пользовательских действий
inlinesСписок инлайн-форм

Пользовательские действия (actions)

from django.contrib import admin
from django.utils import timezone
from .models import Book

def update_created_at(modeladmin, request, queryset):
    queryset.update(created_at=timezone.now())

update_created_at.short_description = "Update created_at to current time"

@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
    list_display = ('title', 'author', 'publisher', 'published_date', 'created_at')
    actions = [update_created_at]

3. Инлайн-формы

Инлайн-формы позволяют редактировать связанные объекты прямо на странице основной модели. Полезны для связей «один-ко-многим» (ForeignKey).

КлассФорматКогда использовать
TabularInlineТабличный (горизонтальный)Много объектов, мало полей
StackedInlineВертикальный (карточками)Объекты с большим числом полей
from django.contrib import admin
from .models import Book, Publisher

class BookInline(admin.TabularInline):  # или StackedInline
    model = Book
    extra = 1  # количество пустых форм для новых объектов

class PublisherAdmin(admin.ModelAdmin):
    inlines = [BookInline]

admin.site.register(Publisher, PublisherAdmin)
admin.site.register(Book)

4. Модель User

Django предоставляет встроенную модель User из django.contrib.auth.models. Содержит все необходимые поля и методы для аутентификации.

Поля модели User

ПолеТипОписание
usernameCharField (150)Уникальный идентификатор. Обязательный
passwordCharFieldХэшированный пароль. Обязательный
emailEmailFieldАдрес e-mail. Необязательный
first_nameCharFieldИмя пользователя. Необязательный
last_nameCharFieldФамилия. Необязательный
is_staffBooleanFieldДоступ в admin. По умолчанию False
is_activeBooleanFieldАктивный аккаунт. По умолчанию True
is_superuserBooleanFieldВсе права. По умолчанию False
last_loginDateTimeFieldДата последнего входа. Может быть null
date_joinedDateTimeFieldДата регистрации

Иерархия наследования User

  • AbstractBaseUser — базовый класс: поля password, last_login; методы set_password(), check_password(), get_session_auth_hash().
  • PermissionsMixin — поля is_superuser, groups, user_permissions; методы has_perm(), has_perms(), has_module_perms().
  • AbstractUser — полная реализация с username, email, first_name и т.д. Наследуется от AbstractBaseUser + PermissionsMixin.
  • User — финальный класс, наследующийся от AbstractUser. Используется «из коробки».

Кастомная модель User

# models.py
from django.utils import timezone
from django.contrib.auth.base_user import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin, UserManager
from django.utils.translation import gettext_lazy as _
from django.db import models

class CustomUser(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(max_length=30, unique=True)
    email = models.EmailField(_('email address'), unique=True)
    first_name = models.CharField(_('first name'), max_length=30, blank=True)
    last_name = models.CharField(_('last name'), max_length=30, blank=True)
    is_staff = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    date_joined = models.DateTimeField(default=timezone.now)
    birth_date = models.DateField(null=True, blank=True)

    objects = UserManager()

    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = ['email', 'birth_date']

    def __str__(self):
        return self.email

# settings.py
AUTH_USER_MODEL = 'myapp.CustomUser'

5. Django ORM — запросы

Менеджер моделей

Каждая модель Django имеет менеджер по умолчанию — objects. Через него выполняются все запросы к БД.

Создание записей

# Метод create() — создаёт и сохраняет в одном шаге
new_book = Book.objects.create(
    title="The Great Gatsby",
    author="F. Scott Fitzgerald",
    published_date="1925-04-10"
)

# Метод save() — создаём объект, меняем, сохраняем
book = Book(title="1984", author="George Orwell", published_date="1949-06-08")
book.title = "Nineteen Eighty-Four"
book.save()

Чтение записей

# QuerySet — набор записей, поддерживает цепочки методов
all_books = Book.objects.all()
first_book = Book.objects.all().first()   # первая или None
last_book = Book.objects.all().last()     # последняя или None
count = Book.objects.all().count()        # количество
exists = Book.objects.all().exists()      # True / False
values = Book.objects.all().values('title', 'author')  # список словарей

Метод get()

from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned

try:
    book = Book.objects.get(title="The Great Gatsby")
except ObjectDoesNotExist:
    print("Книга не найдена.")
except MultipleObjectsReturned:
    print("Найдено несколько книг.")

Фильтры и Lookups

LookupОписаниеПример
exactТочное совпадениеtitle__exact="1984"
iexactБез учёта регистраtitle__iexact="1984"
containsСодержит подстрокуtitle__contains="Gatsby"
icontainsСодержит (регистронезависимо)title__icontains="gatsby"
inВходит в списокid__in=[1, 2, 3]
gt / gteБольше / больше или равноpublished_date__gt="2000-01-01"
lt / lteМеньше / меньше или равноprice__lt=20
isnullЯвляется NULLpublished_date__isnull=True
startswithНачинается сtitle__startswith="The"
endswithЗаканчивается наtitle__endswith="ing"
rangeВ диапазоне (включительно)published_date__range=["2020-01-01","2023-01-01"]

Класс Q — сложные условия

from django.db.models import Q

# OR
books = Book.objects.filter(Q(is_bestseller=True) | Q(published_date__gt="2000-01-01"))

# AND
books = Book.objects.filter(Q(is_bestseller=True) & Q(published_date__gt="2000-01-01"))

# NOT
books = Book.objects.filter(~Q(is_bestseller=True))

# Комбинированное
books = Book.objects.filter(
    (Q(is_bestseller=True) | Q(published_date__gt="2000-01-01")) & ~Q(author="George Orwell")
)

Класс F — операции над полями

from django.db.models import F

# Увеличить цену всех книг на 10%
Book.objects.update(price=F('price') * 1.10)

# Скопировать значение поля со скидкой
Book.objects.update(discounted_price=F('price') * 0.9)

# Фильтр: книги, у которых discounted_price < price
books = Book.objects.filter(discounted_price__lt=F('price'))

Обновление и удаление

# Обновление одной записи через save()
book = Book.objects.get(id=1)
book.title = "New Title"
book.save()

# Массовое обновление через update()
Book.objects.filter(author="F. Scott Fitzgerald").update(price=9.99)

# Удаление одной записи
book = Book.objects.get(id=1)
book.delete()

# Удаление нескольких записей
deleted_count, _ = Book.objects.filter(author="F. Scott Fitzgerald").delete()

Bulk-операции

from decimal import Decimal

# bulk_create — одним SQL-запросом
books = [
    Book(title="Book 1", author="Author 1", published_date="2021-01-01", price=12.99),
    Book(title="Book 2", author="Author 2", published_date="2022-01-01", price=14.99),
]
Book.objects.bulk_create(books)

# bulk_update — обновление нескольких объектов
books = list(Book.objects.all())
for book in books:
    book.price += Decimal("1.0")
Book.objects.bulk_update(books, ['price'])

6. Django Shell

Django Shell — интерактивная Python-оболочка с настроенным Django-окружением.

# Запуск
python manage.py shell

# Импорт моделей
from store.models import Book, Publisher

# Использование ORM
all_books = Book.objects.all()
for book in all_books:
    print(book)