49 KiB
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 (бесклассовая адресация).
Диапазоны приватных сетей:
- 10.0.0.0 – 10.255.255.255
- 172.16.0.0 – 172.31.255.255
- 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
Правила сокращения:
- Несколько блоков нулей подряд →
::(только один раз в адресе). - Одиночный блок нулей →
0. - Ведущие нули в блоке можно опустить.
Пример: 2041:0000:140F:0000:0000:0000:875B:131B → 2041: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:
- Устанавливает соединение трёхсторонним рукопожатием:
- SYN — запрос на соединение от отправителя.
- SYN-ACK — подтверждение от получателя.
- ACK — начало передачи.
- После каждой порции данных получатель отправляет подтверждение.
- Надёжный, но медленный. Используется там, где важна точность: пароли, транзакции, почта.
UDP (User Datagram Protocol):
- Просто отправляет пакеты без установления соединения.
- Может теряться часть данных или нарушаться порядок.
- Быстрый, но ненадёжный. Используется там, где важна скорость: видеозвонки, стриминг, игры.
DNS (Domain Name System)
DNS — система доменных имён. Аналог: контактная книга (ФИО → номер телефона → домен → IP).
Цепочка разрешения:
- Браузер → кэш браузера.
- → Локальный DNS (файл
hosts). - → Resolver (обычно сервер провайдера или 8.8.8.8).
- → Root server (отвечает за
.). - → TLD server (Top Level Domain):
- gTLD:
.com,.org,.edu - ccTLD:
.ru,.ua,.by,.us
- gTLD:
- → Authoritative nameserver — знает конкретный IP.
Виды запросов:
- Recursive — запрос IP по домену (resolver сам обходит всю цепочку).
- Iterative — запрос IP или следующего сервера.
- 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):
- Client перенаправляет пользователя на Authorization Server.
- Пользователь даёт согласие.
- Authorization Server возвращает code на redirect_uri клиента.
- Client обменивает code на access_token (и refresh_token).
- Client обращается к Resource Server с access_token.
Access token — краткосрочный, используется для запросов. Refresh token — долгосрочный, используется для получения нового access_token.
Блок 2–3. 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>(код). - Пробелы: множественные пробелы схлопываются в один;
— неразрывный пробел.
Списки:
- Маркированный:
<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 обработчика.method—getили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")
Блок 7–10. 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
Имена переменных по умолчанию:
ListView→object_list.DetailView→object.
Пагинация в 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.htmlDetailView→<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})
GET— создать пустую форму → показать страницу.POST— создать форму изrequest.POST→ проверить → действие + redirect.- Ошибки — снова показать форму с сообщениями.
Валидация
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"),