Files
SecondBrain/.trash/Экзамен - Полный конспект.md
2026-06-01 15:16:31 +03:00

49 KiB
Raw Permalink Blame History

created, updated
created updated
2026-06-01 2026-06-01

Экзамен — Разработка веб-ориентированных информационных систем


Блок 1. Общие вопросы

Модель OSI

Модель OSI (Open Systems Interconnection) — теоретическая база, определяющая протоколы, равномерно распределяя их на 7 логических уровней.

Протокол — набор правил, определяющий, как происходит обмен данными.

Уровень Название Что делает Устройства/Протоколы
1 Физический (Physical) Передаёт физические сигналы (токи, свет, радио) Хабы, репитеры, Ethernet (L1)
2 Канальный (Data Link) Проверяет ошибки; оперирует кадрами (frame) и MAC-адресами Коммутаторы, Ethernet (L1+L2)
3 Сетевой (Network) Маршрутизация; оперирует пакетами и IP-адресами; ARP Маршрутизаторы
4 Транспортный (Transport) Надёжная передача; TCP / UDP
5 Сеансовый (Session) Управляет сессиями
6 Представления (Presentation) Кодирование, сжатие (JPEG, GIF)
7 Прикладной (Application) Сетевые службы: HTTP(S), SMTP, FTP

Инкапсуляция — добавление служебной информации при движении вниз по уровням; деинкапсуляция — обратный процесс.

MAC-адрес — уникальный идентификатор устройства на канальном уровне.

ARP (Address Resolution Protocol) — определяет MAC-адрес по IP-адресу в локальной сети.


IPv4, маска подсети, подсети (VLSM)

IP-адрес имеет две части: адрес сети и адрес узла.

Маска сети — 32-битное число из подряд идущих единиц. Примеры:

  • Класс A → 255.0.0.0 (/8)
  • Класс B → 255.255.0.0 (/16)
  • Класс C → 255.255.255.0 (/24)

Современный стандарт — CIDR (бесклассовая адресация).

Диапазоны приватных сетей:

  1. 10.0.0.0 10.255.255.255
  2. 172.16.0.0 172.31.255.255
  3. 192.168.0.0 192.168.255.255

Специальные адреса:

  • 0.0.0.0 — используется DHCP при первом запросе.
  • 255.255.255.255 — широковещательный (broadcast).
  • 127.*.*.* — loopback (обращение к самому себе; localhost = 127.0.0.1).

Количество хостов в подсети:

H = 2^{n} - 2

где n — число бит под номер хоста.

Количество подсетей:

N = 2^{n}

где n — число бит, заимствованных из хостовой части.

VLSM (Variable Length Subnet Mask) — маска переменной длины. Позволяет делить пространство на подсети разного размера, чтобы никто не перехватил трафик и каждому устройству достался адрес.

Запись: 192.168.25.0/24, где 24 — число единиц в маске (= 255.255.255.0).

Пример: 192.168.1.0/24 — 254 хоста, адрес сети 192.168.1.0, широковещательный 192.168.1.255.

Выделение адресов: IANA → Региональные регистраторы (RIPE для Европы) → Национальные регистраторы → Провайдеры.


IPv6

Причина появления: IPv4 даёт ~4 млрд адресов — их не хватает. IPv6 использует 128 бит.

340\ 282\ 366\ 920\ 938\ 463\ 463\ 374\ 607\ 431\ 768\ 211\ 456 \text{ адресов}

Формат: 8 групп по 4 шестнадцатеричных цифры:

2041:0000:140F:0000:0000:0000:875B:131B

Правила сокращения:

  1. Несколько блоков нулей подряд → :: (только один раз в адресе).
  2. Одиночный блок нулей → 0.
  3. Ведущие нули в блоке можно опустить.

Пример: 2041:0000:140F:0000:0000:0000:875B:131B2041:0:140F::875B:131B

Отличия от IPv4:

  • OSPF v2 → OSPFv3; ICMP → ICMPv6; ARP → NDP (Neighbor Discovery Protocol).
  • RIP → RIPng; BGP → MP-BGP; EIGRP поддерживает оба.
  • Двойной стек — одновременная работа IPv4 и IPv6.

Типы адресов:

  • Global Unicast — публичные, аналог белых IPv4.
  • Unique Local (префикс FD) — аналог приватных IPv4.
  • Link-Local (префикс FE80) — для связи внутри сегмента.
  • Multicast (префикс FF).

Подсети в IPv6: стандартный префикс подсети — /64. Первые 64 бита — префикс сети, последние 64 — идентификатор интерфейса. Число подсетей при /48 от провайдера: 2^16 ≈ 65 536.

Получение префиксов: IANA → Региональные реестры → ISP → Клиент.


NAT (Network Address Translation)

Проблема: нехватка публичных IPv4. Решение: NAT переводит приватные адреса в публичные.

Термины:

  • Inside Local — приватный адрес устройства внутри сети.
  • Inside Global — публичный адрес, под которым виден пакет снаружи.
  • Outside Local — адрес внешнего устройства во внутренней топологии.
  • Outside Global — реальный адрес внешнего устройства.

Типы NAT:

Тип Суть
Static NAT 1:1 — один внутренний ↔ один внешний (для серверов)
Dynamic NAT Пул внутренних ↔ пул внешних (автоматически)
PAT (NAT Overload) Многие внутренние → один внешний + уникальные порты (домашние роутеры)

PAT: использует номер порта TCP/UDP для разделения сессий. ICMPv4 использует Query ID вместо порта.

Stub-сеть — тупиковая сеть, весь трафик которой выходит через один маршрутизатор.

Преимущества NAT Недостатки NAT
Экономия публичных IPv4 Увеличение задержки
Конфиденциальность топологии Проблемы с IPsec, входящими соединениями
Независимость от провайдера Потеря сквозной трассировки

TCP и UDP

Основные протоколы транспортного уровня (L4).

TCP (Transmission Control Protocol) — RFC 793:

  • Устанавливает соединение трёхсторонним рукопожатием:
    1. SYN — запрос на соединение от отправителя.
    2. SYN-ACK — подтверждение от получателя.
    3. ACK — начало передачи.
  • После каждой порции данных получатель отправляет подтверждение.
  • Надёжный, но медленный. Используется там, где важна точность: пароли, транзакции, почта.

UDP (User Datagram Protocol):

  • Просто отправляет пакеты без установления соединения.
  • Может теряться часть данных или нарушаться порядок.
  • Быстрый, но ненадёжный. Используется там, где важна скорость: видеозвонки, стриминг, игры.

DNS (Domain Name System)

DNS — система доменных имён. Аналог: контактная книга (ФИО → номер телефона → домен → IP).

Цепочка разрешения:

  1. Браузер → кэш браузера.
  2. → Локальный DNS (файл hosts).
  3. Resolver (обычно сервер провайдера или 8.8.8.8).
  4. Root server (отвечает за .).
  5. TLD server (Top Level Domain):
    • gTLD: .com, .org, .edu
    • ccTLD: .ru, .ua, .by, .us
  6. Authoritative nameserver — знает конкретный IP.

Виды запросов:

  1. Recursive — запрос IP по домену (resolver сам обходит всю цепочку).
  2. Iterative — запрос IP или следующего сервера.
  3. Inverse — запрос домена по IP.

Localhost и порты

localhost — стандартное доменное имя для loopback-адреса 127.0.0.1 (IPv4) или ::1 (IPv6). Означает "этот же компьютер".

Стандартные порты:

Протокол Порт
HTTP 80
HTTPS 443
FTP 21
SSH 22
DNS 53
SMTP 25

HTTP / HTTPS / HTTP/3

HTTP (HyperText Transfer Protocol) — протокол прикладного уровня (L7) для передачи данных в вебе.

Структура HTTP-запроса:

METHOD /path HTTP/1.1
Host: example.com
Content-Type: application/json

[тело запроса]

Основные методы:

Метод Назначение
GET Получить ресурс
POST Создать / отправить данные
PUT Заменить ресурс целиком
PATCH Частично обновить
DELETE Удалить

Структура HTTP-ответа:

HTTP/1.1 200 OK
Content-Type: text/html

[тело ответа]

Коды ответов:

Диапазон Смысл Примеры
1xx Информационные 100 Continue
2xx Успех 200 OK, 201 Created, 204 No Content
3xx Перенаправление 301 Moved Permanently, 302 Found
4xx Ошибка клиента 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found
5xx Ошибка сервера 500 Internal Server Error, 503 Service Unavailable

HTTPS — HTTP поверх TLS/SSL. Шифрует передачу данных; порт 443. Сертификат подтверждает подлинность сервера.

HTTP/2: мультиплексирование запросов в одном TCP-соединении, сжатие заголовков, server push.

HTTP/3: работает поверх QUIC (UDP вместо TCP), встроенное шифрование TLS 1.3, устраняет проблему блокировки заголовка (head-of-line blocking).


URI, URL, URN

  • URI (Uniform Resource Identifier) — общее понятие; любой идентификатор ресурса.
  • URL (Uniform Resource Locator) — URI с указанием местонахождения и протокола доступа.
  • URN (Uniform Resource Name) — URI без указания местонахождения; постоянное имя.
URL: https://example.com:8080/path/page?q=test#section
      схема  хост       порт путь      запрос якорь

URN: urn:isbn:978-5-17-084585-3

URL ⊆ URI; URN ⊆ URI.


Идентификация, аутентификация, авторизация

  • Идентификация — присвоение субъектам уникальных идентификаторов (логин, email).
  • Аутентификация — проверка подлинности: "ты действительно тот, кем представляешься?" (пароль, токен, биометрия).
  • Авторизация — проверка прав: "что тебе разрешено делать?" (роли, разрешения).

Модель CIA:

  • Конфиденциальность — данные недоступны неавторизованным.
  • Целостность — данные не искажены.
  • Доступность — система доступна легитимным пользователям.

Принципы защиты:

  • Простота (меньше поверхность атаки).
  • Безопасные настройки по умолчанию (запрещено, если не разрешено явно).
  • Минимизация полномочий.
  • Разделение ответственности.

Уязвимость → Угроза → Атака:

  • Уязвимость — слабое место (ошибка в коде, слабый пароль, неверные права).
  • Угроза — потенциальное нарушение безопасности.
  • Атака — реализованная угроза.

OAuth 2.0

OAuth 2.0 — протокол авторизации, позволяющий приложению получить ограниченный доступ к ресурсам пользователя на другом сервисе без передачи пароля.

Роли:

  • Resource Owner — пользователь, владелец данных.
  • Client — приложение, запрашивающее доступ.
  • Authorization Server — выдаёт токены (например, Google, GitHub).
  • Resource Server — хранит защищённые данные.

Базовый flow (Authorization Code):

  1. Client перенаправляет пользователя на Authorization Server.
  2. Пользователь даёт согласие.
  3. Authorization Server возвращает code на redirect_uri клиента.
  4. Client обменивает code на access_tokenrefresh_token).
  5. Client обращается к Resource Server с access_token.

Access token — краткосрочный, используется для запросов. Refresh token — долгосрочный, используется для получения нового access_token.


Блок 23. HTML

HTML (Hypertext Markup Language) — язык разметки для структурирования веб-страниц.

Структура документа

<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Заголовок страницы</title>
</head>
<body>
    <!-- Контент страницы -->
</body>
</html>
  • <!DOCTYPE html> — объявление типа документа (HTML5).
  • <head> — метаданные: не отображаются в браузере.
  • <body> — основное содержимое.
  • <!-- ... --> — комментарий.

Метатег viewport — критичен для мобильных устройств:

<meta name="viewport" content="width=device-width, initial-scale=1.0">

Нормальный поток. Блочные и строчные элементы

Нормальный поток — стандартное поведение: блочные элементы идут сверху вниз, строчные — слева направо внутри строки.

  • Блочные элементы занимают всю доступную ширину и начинаются с новой строки: <div>, <p>, <h1><h6>, <section>, <form>.
  • Строчные элементы находятся внутри строки и не ломают поток: <span>, <a>, <strong>, <em>, <code>.

Семантические теги

Семантика — использование тегов по смыслу.

Тег Назначение
<header> Верхняя часть страницы или секции
<nav> Навигационные ссылки
<main> Основной контент (один на страницу)
<section> Смысловой раздел
<article> Самостоятельный материал
<aside> Дополнительный контент, боковая панель
<footer> Нижняя часть страницы или секции

<div> — нейтральный контейнер без семыслового значения.


Основные теги

Атрибуты:

  • href — адрес ссылки.
  • src — путь к изображению/файлу.
  • alt — текстовое описание изображения.
  • class — CSS-класс.
  • id — уникальный идентификатор.
  • name — имя поля формы (отправляется на сервер).

Текст и форматирование:

  • Заголовки: <h1><h6>.
  • Абзац: <p>.
  • Перенос строки: <br>.
  • Выделение: <strong> (жирный), <em> (курсив), <code> (код).
  • Пробелы: множественные пробелы схлопываются в один; &nbsp; — неразрывный пробел.

Списки:

  • Маркированный: <ul> + <li>.
  • Нумерованный: <ol> + <li>.

Ссылки и изображения:

<a href="https://example.com" target="_blank">Текст</a>
<img src="cat.jpg" alt="Кот" width="500">

Таблицы

Для структурированных данных. Не для вёрстки макета.

<table>
    <caption>Заголовок таблицы</caption>
    <thead>
        <tr>
            <th>Столбец 1</th>
            <th>Столбец 2</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Данные 1</td>
            <td>Данные 2</td>
        </tr>
    </tbody>
    <tfoot>
        <tr>
            <td>Итог 1</td>
            <td>Итог 2</td>
        </tr>
    </tfoot>
</table>
  • colspan — объединение ячеек по горизонтали.
  • rowspan — объединение ячеек по вертикали.

Формы

<form action="/handler-url/" method="post">
    <label for="username">Имя:</label>
    <input type="text" id="username" name="name" placeholder="Введите имя" required>

    <button type="submit">Отправить</button>
</form>

Атрибуты <form>:

  • action — URL обработчика.
  • methodget или post.

Элементы управления:

  • <input> — универсальное поле ввода.
  • <select> + <option> — выпадающий список.
  • <textarea> — многострочное поле.
  • <button> — кнопка (type="submit", type="reset", type="button").
  • <fieldset> + <legend> — группировка полей.
  • <label for="id"> — подпись к полю (клик по label фокусирует input).

Типы <input>:

type Назначение
text Обычная строка
password Пароль (символы скрываются)
email Email с базовой проверкой формата
number Числовой ввод
checkbox Флажок (можно выбрать несколько)
radio Выбор одного из группы (одинаковый name)
file Загрузка файла
date Выбор даты
hidden Скрытое поле
submit Кнопка отправки
<fieldset>
  <legend>Способ связи</legend>
  <label>
    <input type="radio" name="contact" value="email"> Email
  </label>
  <label>
    <input type="radio" name="contact" value="phone"> Телефон
  </label>
</fieldset>

<label>
  <input type="checkbox" name="agreement" required>
  Согласен с условиями
</label>

<label for="comment">Комментарий:</label>
<textarea id="comment" name="comment" rows="5"></textarea>

Атрибуты валидации:

  • required — поле обязательно.
  • minlength / maxlength — длина строки.
  • min / max — диапазон числа или даты.
  • pattern — регулярное выражение.

HTML-валидация — на стороне браузера. Не заменяет проверку на сервере.


Блок 4. CSS: Селекторы и блочная модель

CSS (Cascading Style Sheets) — язык таблиц стилей для оформления HTML.

Подключение

<!-- Внешняя таблица (предпочтительно) -->
<link rel="stylesheet" href="style.css">

<!-- Внутри <head> -->
<style> p { color: red; } </style>

<!-- Inline (наивысший приоритет, но засоряет HTML) -->
<p style="color: red;">Текст</p>

Селекторы

Селектор Пример Описание
Универсальный * Все элементы
По тегу h1, p Конкретный тег
По классу .card Элементы с классом
По ID #header Элемент с id
Потомок div p Все p внутри div
Дочерний div > p Прямые наследники
Соседний h1 + p Первый p сразу после h1
По атрибуту a[href^="https"] По значению атрибута

Группировка: h1, h2, p { ... }

Псевдоклассы:

  • :hover, :focus, :active.
  • :first-child, :last-child, :nth-child(2n), :nth-child(odd).

Псевдоэлементы:

  • ::before, ::after — вставляют контент до/после (используют content).

Наследование и каскад

Наследование: некоторые свойства (color, font-*) передаются от родителя к потомкам.

Специфичность (кто побеждает при конфликте):

Тип Вес
Inline-стили 1,0,0,0
ID (#id) 0,1,0,0
Класс, атрибут, псевдокласс 0,0,1,0
Тег, псевдоэлемент 0,0,0,1

При равной специфичности побеждает последнее объявление.


Блочная модель (Box Model)

Каждый элемент — прямоугольный блок:

┌──────────────────────────────┐
│          margin              │
│  ┌────────────────────────┐  │
│  │        border          │  │
│  │  ┌──────────────────┐  │  │
│  │  │     padding      │  │  │
│  │  │  ┌────────────┐  │  │  │
│  │  │  │  content   │  │  │  │
│  │  │  └────────────┘  │  │  │
│  │  └──────────────────┘  │  │
│  └────────────────────────┘  │
└──────────────────────────────┘
  • Content — содержимое.
  • Padding — внутренние поля.
  • Border — рамка.
  • Margin — внешние отступы.

box-sizing:

  • content-box (по умолчанию): width = ширина только контента.
  • border-box: width включает padding и border.

Свойство display

  • block — занимает всю ширину, с новой строки.
  • inline — по контенту, нельзя задать width/height.
  • inline-block — строчный, но с размерами.
  • none — убирает элемент из документа.

Базовые свойства

Текст и шрифты:

font-family: Arial, sans-serif;
font-size: 16px;
font-weight: bold;
text-align: center;
text-transform: uppercase;
text-decoration: underline;
line-height: 1.5;
letter-spacing: 2px;

Тени текста:

text-shadow: 2px 2px 4px rgba(0,0,0,0.5);

Фон:

background-color: #fff;
background-image: url("bg.jpg");
background-size: cover;
background-repeat: no-repeat;
background-position: center;

Границы и тени блока:

border: 1px solid black;
border-radius: 8px;
box-shadow: 2px 4px 8px rgba(0,0,0,0.2);

Выравнивание блоков:

  • margin: 0 auto; — горизонтальное центрирование блока с заданной шириной.

Блок 5. CSS: Адаптивность, Flexbox и Grid

Медиазапросы (@media)

/* Desktop First: стили для телефонов */
@media screen and (max-width: 768px) {
    .container { flex-direction: column; }
}

/* Mobile First: стили для планшетов и выше */
@media screen and (min-width: 768px) {
    .container { display: flex; }
}

Flexbox

Одномерная модель раскладки (по одной оси).

.container {
    display: flex;          /* или inline-flex */
    flex-direction: row;    /* row | column | row-reverse | column-reverse */
    flex-wrap: wrap;        /* wrap | nowrap */
    justify-content: space-between; /* выравнивание по главной оси */
    align-items: center;    /* выравнивание по поперечной оси */
    gap: 16px;
}

Главная ось — задаётся flex-direction (по умолчанию горизонтальная).
Поперечная ось — перпендикулярна главной.

justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly.

align-items: flex-start | flex-end | center | stretch | baseline.

Свойства элементов (flex-items):

.item {
    flex-grow: 1;    /* коэффициент растяжения */
    flex-shrink: 1;  /* коэффициент сжатия */
    flex-basis: 200px; /* базовый размер до распределения */
    order: 2;        /* порядок отображения */
}
/* Сокращение: flex: grow shrink basis */
.item { flex: 1 1 200px; }

Grid Layout

Двумерная модель раскладки (строки + столбцы).

.container {
    display: grid;
    grid-template-columns: repeat(3, 1fr);  /* 3 колонки равной ширины */
    grid-template-rows: auto 1fr;
    gap: 16px;
}
  • fr — доля свободного пространства.
  • repeat(n, size) — повторить n раз.
  • minmax(min, max) — задать диапазон размера.

Размещение элементов:

.item {
    grid-column: 1 / 3;   /* от 1-й до 3-й линии */
    grid-row: 2 / span 2; /* со 2-й линии на 2 ячейки */
}

Именованные области:

.container {
    grid-template-areas:
        "header header"
        "sidebar content"
        "footer footer";
}
header  { grid-area: header; }
.sidebar { grid-area: sidebar; }

Flex vs Grid

  • Flexbox — одномерные структуры: меню, тулбары, строки карточек.
  • Grid — двумерные макеты: раскладки всей страницы, сложные сетки.

Блок 6. Django: Модели

Django ORM — связывает Python-код с реляционной БД. Паттерн Active Record.

Структура проекта

project/
├── manage.py
├── project/
│   ├── settings.py      # конфигурация (БД, INSTALLED_APPS)
│   └── urls.py          # корневые маршруты
└── app/
    ├── models.py        # модели (таблицы)
    ├── views.py
    └── urls.py

Определение моделей

from django.db import models

class Person(models.Model):
    first_name = models.CharField("Имя", max_length=30)
    age = models.IntegerField(default=18)
    bio = models.TextField(blank=True)

    class Meta:
        verbose_name = "Человек"
        ordering = ["-first_name"]

class Meta — метаданные модели: verbose_name, ordering, db_table, unique_together.


Типы полей

Поле Описание
AutoField Автоинкрементный первичный ключ (добавляется автоматически)
CharField(max_length=N) Короткая строка
TextField Длинный текст
IntegerField Целое число
DecimalField(max_digits, decimal_places) Точное десятичное (деньги)
BooleanField True/False
DateField Дата
DateTimeField Дата + время
EmailField Строка с валидацией email
FileField Путь к файлу
ImageField Файл изображения

null=True — разрешить NULL в БД.
blank=True — разрешить пустое значение на уровне валидации формы.


Отношения

class Author(models.Model):
    name = models.CharField(max_length=100)

class Profile(models.Model):
    author = models.OneToOneField(Author, on_delete=models.CASCADE)
    bio = models.TextField()

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(Author, on_delete=models.PROTECT,
                               related_name="books")
    co_authors = models.ManyToManyField(Author,
                                        related_name="coauthored_books",
                                        blank=True)
  • ForeignKey — "один ко многим": у одного автора много книг.
  • OneToOneField — "один к одному".
  • ManyToManyField — "многие ко многим"; Django автоматически создаёт промежуточную таблицу.

on_delete:

Значение Поведение
CASCADE Удалить текущую запись вместе со связанной
PROTECT Запретить удаление, пока есть ссылки
SET_NULL Записать NULL (нужен null=True)
SET_DEFAULT Записать значение по умолчанию
DO_NOTHING Ничего не делать

related_name — имя обратной связи: author.books.all().

Промежуточная модель Many-to-Many — используется, когда нужно хранить дополнительные данные о связи:

class Membership(models.Model):
    person = models.ForeignKey("Person", on_delete=models.CASCADE)
    group = models.ForeignKey("Group", on_delete=models.CASCADE)
    date_joined = models.DateField()
    role = models.CharField(max_length=50)

class Group(models.Model):
    name = models.CharField(max_length=100)
    members = models.ManyToManyField("Person", through="Membership")

Миграции

python manage.py makemigrations   # создать файлы миграций
python manage.py migrate          # применить к БД
python manage.py showmigrations   # статусы миграций

Блок 11. Django: QuerySet и ORM-запросы

QuerySet ленив — запрос к БД выполняется только при обращении к данным (итерация, срез, list(), len()).

Базовые методы

# Все объекты
Person.objects.all()

# Один объект (исключение если нет или несколько)
Person.objects.get(id=1)

# Фильтрация
Person.objects.filter(age__gte=18)
Person.objects.exclude(age__lt=18)

# Порядок
Person.objects.order_by("-age")   # минус = DESC

# Уникальные значения
Person.objects.distinct()

# Количество
Person.objects.count()

# Проверка существования (не загружает объекты)
Person.objects.filter(age=18).exists()

Field Lookups (операторы поиска)

# Точное совпадение
filter(name__exact="Ivan")
filter(name__iexact="ivan")      # без учёта регистра

# Сравнение чисел
filter(age__gt=18)    # >
filter(age__gte=18)   # >=
filter(age__lt=30)    # <
filter(age__lte=30)   # <=

# Вхождение
filter(name__contains="van")
filter(name__icontains="van")    # без учёта регистра

# Список / диапазон
filter(id__in=[1, 2, 3])
filter(age__range=(18, 30))

# NULL
filter(bio__isnull=True)

Агрегация и аннотация

from django.db.models import Avg, Count, Sum, Min, Max

# aggregate — одно итоговое значение; возвращает dict
result = Book.objects.aggregate(avg_rating=Avg("rating"))
print(result["avg_rating"])

# annotate — вычисляемое поле для каждого объекта
authors = Author.objects.annotate(total_books=Count("books"))
for a in authors:
    print(a.name, a.total_books)

Q-объекты (сложные условия)

from django.db.models import Q

# OR
books = Book.objects.filter(Q(rating__gt=4) | Q(title__icontains="Django"))

# AND
books = Book.objects.filter(Q(rating__gt=4) & Q(is_published=True))

# NOT
books = Book.objects.filter(~Q(rating__lt=3))

F-выражения (операции в БД)

from django.db.models import F

# Увеличить счётчик просмотров прямо в БД, без загрузки в Python
Book.objects.filter(id=1).update(views=F("views") + 1)

Цепочки методов

queryset = (
    Person.objects
    .filter(age__gte=18)
    .exclude(is_active=False)
    .order_by("first_name")
    .distinct()
)

Проблема N+1 и оптимизация

N+1 — один запрос за списком + N запросов в цикле на каждый связанный объект.

# Плохо: N+1
books = Book.objects.all()
for book in books:
    print(book.author.name)  # запрос на каждую итерацию

# Хорошо: select_related (JOIN) для ForeignKey/OneToOne
books = Book.objects.select_related("author")

# Хорошо: prefetch_related (отдельный запрос) для ManyToMany / обратные связи
books = Book.objects.prefetch_related("authors")

Блок 710. Django: Views, URLs, Templates

Маршрутизация (URLs)

# project/urls.py
from django.urls import include, path

urlpatterns = [
    path("blog/", include("blog.urls")),
]
# blog/urls.py
from django.urls import path
from . import views
from .views import PostListView, PostDetailView, AboutView

app_name = "blog"

urlpatterns = [
    path("", views.post_list, name="post_list"),          # FBV
    path("<int:pk>/", PostDetailView.as_view(), name="post_detail"),  # CBV
    path("about/", AboutView.as_view(), name="about"),
    path("tag/<slug:slug>/", views.posts_by_tag, name="posts_by_tag"),
]

Конвертеры пути:

Конвертер Тип Пример URL
<str:name> Строка без / /user/ivan/
<int:pk> Целое положительное /post/42/
<slug:slug> Буквы, цифры, _, - /tag/django-orm/
<uuid:id> UUID /item/075194d3-...
<path:subpath> Строка с / /files/a/b/c.txt

re_path — маршрут с регулярным выражением:

from django.urls import re_path
re_path(r"^post/(?P<pk>[0-9]+)/$", views.post_detail)

Реверс URL:

from django.urls import reverse
url = reverse("blog:post_detail", kwargs={"pk": 1})
{% url 'blog:post_detail' post.pk %}

Функциональные представления (FBV)

from django.shortcuts import render, get_object_or_404

def post_list(request):
    posts = Post.objects.all()[:5]
    return render(request, "blog/list.html", {"posts": posts})

def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, "blog/detail.html", {"post": post})
  • Принимают HttpRequest, возвращают HttpResponse.
  • render(request, template, context) — собирает ответ.
  • get_object_or_404 — возвращает объект или 404.

Классовые представления (CBV)

Вызываются через .as_view().

from django.views.generic import TemplateView, ListView, DetailView

class AboutView(TemplateView):
    template_name = "blog/about.html"


class PostListView(ListView):
    model = Post
    template_name = "blog/list.html"
    context_object_name = "posts"   # по умолчанию: object_list
    paginate_by = 10

    def get_queryset(self):
        return Post.objects.filter(is_published=True).order_by("-created_at")

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["extra"] = "доп. данные"
        return context


class PostDetailView(DetailView):
    model = Post
    template_name = "blog/detail.html"
    context_object_name = "post"    # по умолчанию: object

Имена переменных по умолчанию:

  • ListViewobject_list.
  • DetailViewobject.

Пагинация в ListView:

{% if is_paginated %}
  {% if page_obj.has_previous %}
    <a href="?page={{ page_obj.previous_page_number }}">Назад</a>
  {% endif %}
  Страница {{ page_obj.number }} из {{ page_obj.paginator.num_pages }}
  {% if page_obj.has_next %}
    <a href="?page={{ page_obj.next_page_number }}">Вперёд</a>
  {% endif %}
{% endif %}

Шаблоны по умолчанию (если не задан template_name):

  • ListView<app>/<model>_list.html
  • DetailView<app>/<model>_detail.html

Шаблоны (Django Template Language)

Переменные:

{{ post.title }}
{{ user.get_full_name }}

Теги:

{% if post.is_published %}
  <p>Опубликовано</p>
{% elif post.is_draft %}
  <p>Черновик</p>
{% else %}
  <p>Архив</p>
{% endif %}

{% for post in posts %}
  <p>{{ forloop.counter }}. {{ post.title }}</p>
{% empty %}
  <p>Постов нет.</p>
{% endfor %}

forloop:

  • forloop.counter — счётчик с 1.
  • forloop.counter0 — счётчик с 0.
  • forloop.first / forloop.last — первый/последний элемент.

Фильтры:

{{ post.created_at|date:"Y-m-d" }}
{{ text|lower }}
{{ text|upper }}
{{ list|length }}
{{ value|default:"нет" }}
{{ price|floatformat:2 }}

Наследование шаблонов

<!-- templates/base.html -->
<!doctype html>
<html lang="ru">
<head>
  <title>{% block title %}Сайт{% endblock %}</title>
  {% load static %}
  <link rel="stylesheet" href="{% static 'css/app.css' %}">
</head>
<body>
  <nav>...</nav>
  <main>
    {% block content %}{% endblock %}
  </main>
</body>
</html>
<!-- templates/blog/list.html -->
{% extends "base.html" %}

{% block title %}Посты{% endblock %}

{% block content %}
  <h1>Посты</h1>
  {% for post in posts %}
    <a href="{% url 'blog:post_detail' post.pk %}">{{ post.title }}</a>
  {% endfor %}
{% endblock %}

Include шаблонов:

{% include "blog/partials/card.html" %}
{% include "blog/partials/card.html" with post=item only %}

Статические файлы:

{% load static %}
<img src="{% static 'images/logo.png' %}" alt="Логотип">

Вызов методов в шаблонах: Django вызывает методы без аргументов автоматически:

{{ user.get_full_name }}     {# вызов get_full_name() #}
{{ post.get_absolute_url }}  {# вызов get_absolute_url() #}

Методы с аргументами напрямую вызвать нельзя — логику нужно вынести во view или templatetag.


Блок 12. Django: Формы

forms.Form

from django import forms

class ContactForm(forms.Form):
    name = forms.CharField(max_length=100)
    email = forms.EmailField()
    message = forms.CharField(widget=forms.Textarea)

forms.ModelForm

from django import forms
from .models import Blog

class BlogForm(forms.ModelForm):
    class Meta:
        model = Blog
        fields = ["name", "tagline"]
        widgets = {
            "name": forms.TextInput(attrs={"class": "form-control"})
        }

Жизненный цикл формы во view

from django.shortcuts import redirect, render

def contact_view(request):
    if request.method == "POST":
        form = ContactForm(request.POST)
        if form.is_valid():
            data = form.cleaned_data
            send_email(data["email"], data["message"])
            return redirect("success")
    else:
        form = ContactForm()
    return render(request, "contact.html", {"form": form})
  1. GET — создать пустую форму → показать страницу.
  2. POST — создать форму из request.POST → проверить → действие + redirect.
  3. Ошибки — снова показать форму с сообщениями.

Валидация

  • is_valid() — запускает проверку; после него появляются cleaned_data и errors.
  • clean_<fieldname>() — проверка одного поля.
  • clean() — проверка формы целиком (сравнение нескольких полей).
class RegisterForm(forms.Form):
    username = forms.CharField(max_length=50)
    password = forms.CharField(widget=forms.PasswordInput)
    password_repeat = forms.CharField(widget=forms.PasswordInput)

    def clean_username(self):
        username = self.cleaned_data["username"]
        if username.lower() == "admin":
            raise forms.ValidationError("Это имя нельзя использовать")
        return username

    def clean(self):
        cleaned_data = super().clean()
        password = cleaned_data.get("password")
        password_repeat = cleaned_data.get("password_repeat")
        if password and password_repeat and password != password_repeat:
            raise forms.ValidationError("Пароли не совпадают")
        return cleaned_data

Виджеты и подсказки

class ProfileForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ["bio", "birth_date"]
        widgets = {
            "bio": forms.Textarea(attrs={"rows": 3, "placeholder": "О себе"}),
            "birth_date": forms.DateInput(attrs={"type": "date"}),
        }
        labels = {"bio": "Биография"}
        help_texts = {"bio": "Не более 500 символов."}

Отображение в шаблоне

<form method="post">
  {% csrf_token %}
  {{ form.as_p }}
  <button type="submit">Сохранить</button>
</form>
<!-- Ручной контроль -->
<form method="post">
  {% csrf_token %}
  {% for field in form %}
    <div>
      {{ field.label_tag }}
      {{ field }}
      {% if field.errors %}
        <ul class="errors">
          {% for error in field.errors %}
            <li>{{ error }}</li>
          {% endfor %}
        </ul>
      {% endif %}
    </div>
  {% endfor %}
  <button type="submit">Сохранить</button>
</form>

CSRF-токен — защита от Cross-Site Request Forgery: {% csrf_token %} обязателен во всех method="post" формах.


Generic Editing Views (CBV для CUD)

from django.urls import reverse_lazy
from django.views.generic import CreateView, UpdateView, DeleteView
from .models import Blog
from .forms import BlogForm

class BlogCreateView(CreateView):
    model = Blog
    form_class = BlogForm
    template_name = "blog/blog_form.html"
    success_url = reverse_lazy("blog_list")

class BlogUpdateView(UpdateView):
    model = Blog
    form_class = BlogForm
    template_name = "blog/blog_form.html"
    success_url = reverse_lazy("blog_list")

class BlogDeleteView(DeleteView):
    model = Blog
    template_name = "blog/blog_confirm_delete.html"
    success_url = reverse_lazy("blog_list")
# urls.py
path("create/", BlogCreateView.as_view(), name="blog_create"),
path("<int:pk>/edit/", BlogUpdateView.as_view(), name="blog_update"),
path("<int:pk>/delete/", BlogDeleteView.as_view(), name="blog_delete"),