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

1380 lines
49 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
created: 2026-06-01
updated: 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: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:**
- Устанавливает соединение трёхсторонним рукопожатием:
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_token****refresh_token**).
5. Client обращается к Resource Server с access_token.
**Access token** — краткосрочный, используется для запросов.
**Refresh token** — долгосрочный, используется для получения нового access_token.
---
## Блок 23. HTML
**HTML (Hypertext Markup Language)** — язык разметки для структурирования веб-страниц.
### Структура документа
```html
<!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** — критичен для мобильных устройств:
```html
<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>`.
**Ссылки и изображения:**
```html
<a href="https://example.com" target="_blank">Текст</a>
<img src="cat.jpg" alt="Кот" width="500">
```
---
### Таблицы
Для структурированных данных. Не для вёрстки макета.
```html
<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` — объединение ячеек по вертикали.
---
### Формы
```html
<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` | Кнопка отправки |
```html
<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.
### Подключение
```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` — убирает элемент из документа.
---
### Базовые свойства
**Текст и шрифты:**
```css
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;
```
**Тени текста:**
```css
text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
```
**Фон:**
```css
background-color: #fff;
background-image: url("bg.jpg");
background-size: cover;
background-repeat: no-repeat;
background-position: center;
```
**Границы и тени блока:**
```css
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)
```css
/* Desktop First: стили для телефонов */
@media screen and (max-width: 768px) {
.container { flex-direction: column; }
}
/* Mobile First: стили для планшетов и выше */
@media screen and (min-width: 768px) {
.container { display: flex; }
}
```
---
### Flexbox
**Одномерная** модель раскладки (по одной оси).
```css
.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):**
```css
.item {
flex-grow: 1; /* коэффициент растяжения */
flex-shrink: 1; /* коэффициент сжатия */
flex-basis: 200px; /* базовый размер до распределения */
order: 2; /* порядок отображения */
}
/* Сокращение: flex: grow shrink basis */
.item { flex: 1 1 200px; }
```
---
### Grid Layout
**Двумерная** модель раскладки (строки + столбцы).
```css
.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)`** — задать диапазон размера.
**Размещение элементов:**
```css
.item {
grid-column: 1 / 3; /* от 1-й до 3-й линии */
grid-row: 2 / span 2; /* со 2-й линии на 2 ячейки */
}
```
**Именованные области:**
```css
.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.
### Структура проекта
```text
project/
├── manage.py
├── project/
│ ├── settings.py # конфигурация (БД, INSTALLED_APPS)
│ └── urls.py # корневые маршруты
└── app/
├── models.py # модели (таблицы)
├── views.py
└── urls.py
```
---
### Определение моделей
```python
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`** — разрешить пустое значение на уровне валидации формы.
---
### Отношения
```python
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** — используется, когда нужно хранить дополнительные данные о связи:
```python
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")
```
---
### Миграции
```bash
python manage.py makemigrations # создать файлы миграций
python manage.py migrate # применить к БД
python manage.py showmigrations # статусы миграций
```
---
## Блок 11. Django: QuerySet и ORM-запросы
**QuerySet ленив** — запрос к БД выполняется только при обращении к данным (итерация, срез, `list()`, `len()`).
### Базовые методы
```python
# Все объекты
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 (операторы поиска)
```python
# Точное совпадение
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)
```
### Агрегация и аннотация
```python
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-объекты (сложные условия)
```python
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-выражения (операции в БД)
```python
from django.db.models import F
# Увеличить счётчик просмотров прямо в БД, без загрузки в Python
Book.objects.filter(id=1).update(views=F("views") + 1)
```
### Цепочки методов
```python
queryset = (
Person.objects
.filter(age__gte=18)
.exclude(is_active=False)
.order_by("first_name")
.distinct()
)
```
### Проблема N+1 и оптимизация
**N+1** — один запрос за списком + N запросов в цикле на каждый связанный объект.
```python
# Плохо: 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)
```python
# project/urls.py
from django.urls import include, path
urlpatterns = [
path("blog/", include("blog.urls")),
]
```
```python
# 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`** — маршрут с регулярным выражением:
```python
from django.urls import re_path
re_path(r"^post/(?P<pk>[0-9]+)/$", views.post_detail)
```
**Реверс URL:**
```python
from django.urls import reverse
url = reverse("blog:post_detail", kwargs={"pk": 1})
```
```html
{% url 'blog:post_detail' post.pk %}
```
---
### Функциональные представления (FBV)
```python
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()`.
```python
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:**
```html
{% 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)
**Переменные:**
```html
{{ post.title }}
{{ user.get_full_name }}
```
**Теги:**
```html
{% 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` — первый/последний элемент.
**Фильтры:**
```html
{{ post.created_at|date:"Y-m-d" }}
{{ text|lower }}
{{ text|upper }}
{{ list|length }}
{{ value|default:"нет" }}
{{ price|floatformat:2 }}
```
---
### Наследование шаблонов
```html
<!-- 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>
```
```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 шаблонов:**
```html
{% include "blog/partials/card.html" %}
{% include "blog/partials/card.html" with post=item only %}
```
**Статические файлы:**
```html
{% load static %}
<img src="{% static 'images/logo.png' %}" alt="Логотип">
```
**Вызов методов в шаблонах:** Django вызывает методы без аргументов автоматически:
```html
{{ user.get_full_name }} {# вызов get_full_name() #}
{{ post.get_absolute_url }} {# вызов get_absolute_url() #}
```
Методы с аргументами напрямую вызвать нельзя — логику нужно вынести во view или templatetag.
---
## Блок 12. Django: Формы
### forms.Form
```python
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
```python
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
```python
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()`** — проверка формы целиком (сравнение нескольких полей).
```python
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
```
---
### Виджеты и подсказки
```python
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 символов."}
```
---
### Отображение в шаблоне
```html
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Сохранить</button>
</form>
```
```html
<!-- Ручной контроль -->
<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)
```python
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")
```
```python
# 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"),
```