2600 lines
215 KiB
HTML
2600 lines
215 KiB
HTML
<!doctype html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>Подготовка к экзамену по веб-разработке</title>
|
||
<style>
|
||
:root {
|
||
color-scheme: light;
|
||
--ink: #1f2933;
|
||
--muted: #5f6c7b;
|
||
--line: #d7dee8;
|
||
--paper: #ffffff;
|
||
--bg: #f5f7fa;
|
||
--accent: #16697a;
|
||
--accent-soft: #e5f4f6;
|
||
--warn-soft: #fff4df;
|
||
}
|
||
|
||
* { box-sizing: border-box; }
|
||
|
||
html { scroll-behavior: smooth; }
|
||
|
||
body {
|
||
margin: 0;
|
||
font-family: Arial, Helvetica, sans-serif;
|
||
line-height: 1.48;
|
||
color: var(--ink);
|
||
background: var(--bg);
|
||
}
|
||
|
||
main {
|
||
width: min(1120px, calc(100% - 32px));
|
||
margin: 0 auto;
|
||
padding: 28px 0 56px;
|
||
}
|
||
|
||
header {
|
||
padding: 28px 0 20px;
|
||
border-bottom: 2px solid var(--line);
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
h1, h2, h3, h4 {
|
||
line-height: 1.2;
|
||
margin: 0 0 12px;
|
||
letter-spacing: 0;
|
||
}
|
||
|
||
h1 { font-size: 34px; }
|
||
h2 { font-size: 25px; margin-top: 34px; }
|
||
h3 { font-size: 18px; }
|
||
h4 { font-size: 16px; margin-top: 18px; }
|
||
|
||
p { margin: 0 0 10px; }
|
||
|
||
a {
|
||
color: var(--accent);
|
||
text-decoration: none;
|
||
border-bottom: 1px solid rgba(22, 105, 122, 0.35);
|
||
}
|
||
|
||
a:hover { border-bottom-color: var(--accent); }
|
||
|
||
code {
|
||
padding: 1px 5px;
|
||
border-radius: 4px;
|
||
background: #edf1f5;
|
||
font-family: "JetBrains Mono", "Consolas", monospace;
|
||
font-size: 0.94em;
|
||
}
|
||
|
||
table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
margin: 12px 0 18px;
|
||
background: var(--paper);
|
||
}
|
||
|
||
th, td {
|
||
border: 1px solid var(--line);
|
||
padding: 8px 10px;
|
||
text-align: left;
|
||
vertical-align: top;
|
||
}
|
||
|
||
th { background: #edf3f7; }
|
||
|
||
ul { margin: 8px 0 12px 20px; padding: 0; }
|
||
li { margin: 4px 0; }
|
||
|
||
img {
|
||
display: block;
|
||
max-width: 100%;
|
||
height: auto;
|
||
margin: 10px auto 14px;
|
||
page-break-inside: avoid;
|
||
}
|
||
|
||
.meta {
|
||
color: var(--muted);
|
||
max-width: 760px;
|
||
}
|
||
|
||
.toc {
|
||
background: var(--paper);
|
||
border: 1px solid var(--line);
|
||
border-radius: 8px;
|
||
padding: 18px;
|
||
margin-bottom: 28px;
|
||
}
|
||
|
||
.toc-block {
|
||
break-inside: avoid;
|
||
margin: 0 0 18px;
|
||
}
|
||
|
||
.toc-block:last-child { margin-bottom: 0; }
|
||
|
||
.toc-links {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px 10px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.toc-links a {
|
||
border: 1px solid var(--line);
|
||
border-radius: 6px;
|
||
padding: 4px 8px;
|
||
background: #fbfcfd;
|
||
}
|
||
|
||
.block {
|
||
margin: 30px 0;
|
||
page-break-inside: avoid;
|
||
}
|
||
|
||
.cards {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||
gap: 12px;
|
||
}
|
||
|
||
.card {
|
||
background: var(--paper);
|
||
border: 1px solid var(--line);
|
||
border-radius: 8px;
|
||
padding: 14px;
|
||
min-height: 160px;
|
||
page-break-inside: avoid;
|
||
}
|
||
|
||
.card p { color: #2d3748; }
|
||
|
||
.detail-link {
|
||
display: inline-block;
|
||
margin-top: 6px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.details {
|
||
margin-top: 44px;
|
||
padding-top: 18px;
|
||
border-top: 3px solid var(--line);
|
||
}
|
||
|
||
.note {
|
||
background: var(--paper);
|
||
border: 1px solid var(--line);
|
||
border-radius: 8px;
|
||
padding: 18px;
|
||
margin: 18px 0;
|
||
page-break-inside: avoid;
|
||
}
|
||
|
||
.note-source {
|
||
padding: 8px 10px;
|
||
border-radius: 6px;
|
||
background: var(--accent-soft);
|
||
color: #24464d;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.exam {
|
||
background: var(--warn-soft);
|
||
border-left: 4px solid #d78b00;
|
||
padding: 10px 12px;
|
||
margin: 12px 0;
|
||
}
|
||
|
||
.back {
|
||
margin-top: 14px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
@media print {
|
||
body { background: #fff; }
|
||
main { width: 100%; padding: 0; }
|
||
.toc, .card, .note { box-shadow: none; }
|
||
a { color: #124f5f; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<main>
|
||
<header id="top">
|
||
<h1>Подготовка к экзамену по веб-разработке</h1>
|
||
<p class="meta">Краткий конспект по темам из файла подготовки. Оглавление ведёт к короткой карточке темы; ссылка в карточке ведёт к подробному блоку внизу; подробный блок возвращает обратно к краткому разделу.</p>
|
||
</header>
|
||
|
||
<nav class="toc" aria-label="Оглавление">
|
||
<h2>Оглавление</h2>
|
||
|
||
<div class="toc-block">
|
||
<h3>Блок 1. Общие вопросы</h3>
|
||
<div class="toc-links">
|
||
<a href="#s-ip-addressing">Адресация, IPv4, IPv6</a>
|
||
<a href="#s-tcp">TCP</a>
|
||
<a href="#s-subnet">Маска подсети</a>
|
||
<a href="#s-nat-localhost">NAT, localhost, подсети</a>
|
||
<a href="#s-dns">DNS</a>
|
||
<a href="#s-http">HTTP</a>
|
||
<a href="#s-http-message">HTTP-запрос/ответ</a>
|
||
<a href="#s-https">HTTPS</a>
|
||
<a href="#s-http3">HTTP/3</a>
|
||
<a href="#s-ports">Порты</a>
|
||
<a href="#s-auth">Идентификация/auth</a>
|
||
<a href="#s-oauth">OAuth 2.0</a>
|
||
<a href="#s-uri">URI, URL, URN</a>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="toc-block">
|
||
<h3>Блок 2. HTML</h3>
|
||
<div class="toc-links">
|
||
<a href="#s-html-structure">Структура документа</a>
|
||
<a href="#s-html-comments">Комментарии</a>
|
||
<a href="#s-head">head</a>
|
||
<a href="#s-meta">Мета-теги</a>
|
||
<a href="#s-flow">Нормальный поток</a>
|
||
<a href="#s-block-inline">Блочные и строчные</a>
|
||
<a href="#s-semantic">Семантика</a>
|
||
<a href="#s-attrs">Атрибуты</a>
|
||
<a href="#s-class">class</a>
|
||
<a href="#s-id">id</a>
|
||
<a href="#s-text-table">Текст, списки, таблицы</a>
|
||
<a href="#s-img-link">Картинки и ссылки</a>
|
||
<a href="#s-whitespace">Пробелы и переносы</a>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="toc-block">
|
||
<h3>Блок 3. HTML Forms</h3>
|
||
<div class="toc-links">
|
||
<a href="#s-form">Форма</a>
|
||
<a href="#s-form-id-name">id/name</a>
|
||
<a href="#s-inputs">radio/checkbox/submit</a>
|
||
<a href="#s-label">label</a>
|
||
<a href="#s-fieldset">Группировка</a>
|
||
<a href="#s-required">required</a>
|
||
<a href="#s-placeholder">placeholder</a>
|
||
<a href="#s-button-type">button type</a>
|
||
<a href="#s-textarea">textarea</a>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="toc-block">
|
||
<h3>Блок 4. CSS</h3>
|
||
<div class="toc-links">
|
||
<a href="#s-css-universal">Универсальный селектор</a>
|
||
<a href="#s-css-basic-selectors">Элемент/class/id</a>
|
||
<a href="#s-css-combinators">Комбинаторы</a>
|
||
<a href="#s-css-attr">Атрибуты</a>
|
||
<a href="#s-css-pseudo">Псевдоклассы</a>
|
||
<a href="#s-css-group">Группировка</a>
|
||
<a href="#s-css-cascade">Каскад</a>
|
||
<a href="#s-css-specificity">Специфичность</a>
|
||
<a href="#s-box-model">Блочная модель</a>
|
||
<a href="#s-background">Фон</a>
|
||
<a href="#s-margin-align">Margin</a>
|
||
<a href="#s-fonts">Шрифты</a>
|
||
<a href="#s-text-align">Текст</a>
|
||
<a href="#s-line-letter">Интервалы</a>
|
||
<a href="#s-text-shadow">Тень текста</a>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="toc-block">
|
||
<h3>Блок 5. Flexbox и Grid</h3>
|
||
<div class="toc-links">
|
||
<a href="#s-flex-container">Flex-контейнер</a>
|
||
<a href="#s-inline-flex">inline-flex</a>
|
||
<a href="#s-flex-align">Выравнивание</a>
|
||
<a href="#s-flex-grow">grow/shrink/basis</a>
|
||
<a href="#s-grid-container">Grid-контейнер</a>
|
||
<a href="#s-fr">fr</a>
|
||
<a href="#s-repeat-minmax">repeat/minmax</a>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="toc-block">
|
||
<h3>Блоки 6-12. Django</h3>
|
||
<div class="toc-links">
|
||
<a href="#s-django-models">Модели</a>
|
||
<a href="#s-primary-key">Первичный ключ</a>
|
||
<a href="#s-migrations">Миграции</a>
|
||
<a href="#s-django-meta">Class Meta</a>
|
||
<a href="#s-null-blank">null/blank</a>
|
||
<a href="#s-charfield">CharField</a>
|
||
<a href="#s-foreignkey">ForeignKey</a>
|
||
<a href="#s-manytomany">Many-to-Many</a>
|
||
<a href="#s-fbv">FBV</a>
|
||
<a href="#s-render">render</a>
|
||
<a href="#s-context">Контекст</a>
|
||
<a href="#s-get-object">get_object_or_404</a>
|
||
<a href="#s-routing-fbv">Маршрутизация FBV</a>
|
||
<a href="#s-cbv-types">Template/List/DetailView</a>
|
||
<a href="#s-cbv-models">CBV и модели</a>
|
||
<a href="#s-cbv-extra">Доп. контекст</a>
|
||
<a href="#s-cbv-default-vars">Переменные по умолчанию</a>
|
||
<a href="#s-cbv-queryset">get_queryset/get_object</a>
|
||
<a href="#s-pagination">Паджинация</a>
|
||
<a href="#s-cbv-templates">Шаблоны CBV</a>
|
||
<a href="#s-cbv-super">super()</a>
|
||
<a href="#s-cbv-routing">Маршрутизация CBV</a>
|
||
<a href="#s-django-urls">Django URLs</a>
|
||
<a href="#s-django-templates">DTL</a>
|
||
<a href="#s-django-queries">Django queries</a>
|
||
<a href="#s-django-forms">Django forms</a>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
|
||
<section class="block" id="block-1">
|
||
<h2>Блок 1. Общие вопросы</h2>
|
||
<div class="cards">
|
||
<article class="card" id="s-ip-addressing">
|
||
<h3>Адресация в Интернете. IPv4. IPv6.</h3>
|
||
<p>В TCP/IP есть физический адрес, IP-адрес и символьное DNS-имя. IPv4 — 32 бита, 4 октета по 0-255; IPv6 — 128 бит, шестнадцатеричная запись и намного больше адресов.</p>
|
||
<a class="detail-link" href="#d-ip">Подробно: IP-адресация</a>
|
||
</article>
|
||
<article class="card" id="s-tcp">
|
||
<h3>Протокол TCP</h3>
|
||
<p>TCP — транспортный протокол с установлением соединения, порядком пакетов, подтверждениями и повторной передачей. Надёжнее UDP, но тяжелее по задержкам.</p>
|
||
<a class="detail-link" href="#d-tcp">Подробно: TCP</a>
|
||
</article>
|
||
<article class="card" id="s-subnet">
|
||
<h3>Маска подсети</h3>
|
||
<p>Маска отделяет сетевую часть IPv4-адреса от хостовой. `/24` значит 24 бита сети и 8 бит хоста; `255.255.255.0` — классический пример такой маски.</p>
|
||
<a class="detail-link" href="#d-subnet">Подробно: подсети</a>
|
||
</article>
|
||
<article class="card" id="s-nat-localhost">
|
||
<h3>Распределение IP, NAT, localhost, подсети</h3>
|
||
<p>Публичные адреса распределяются через ICANN/IANA и региональные регистраторы. NAT переводит приватные адреса во внешний адрес. `127.0.0.1`/`localhost` указывает на сам хост.</p>
|
||
<a class="detail-link" href="#d-nat">Подробно: NAT и localhost</a>
|
||
</article>
|
||
<article class="card" id="s-dns">
|
||
<h3>DNS. DNS-серверы</h3>
|
||
<p>DNS сопоставляет доменные имена с IP-адресами. Цепочка обычно идёт через кэширующий resolver, корневые серверы, TLD-серверы и авторитативные серверы домена.</p>
|
||
<a class="detail-link" href="#d-dns">Подробно: DNS</a>
|
||
</article>
|
||
<article class="card" id="s-http">
|
||
<h3>Протокол HTTP</h3>
|
||
<p>HTTP — прикладной протокол WWW. Клиент отправляет запрос, сервер возвращает ответ. HTTP stateless: связь между запросами не хранится без cookies, сессий или токенов.</p>
|
||
<a class="detail-link" href="#d-http">Подробно: HTTP</a>
|
||
</article>
|
||
<article class="card" id="s-http-message">
|
||
<h3>HTTP-запрос, ответ, методы, заголовки, коды</h3>
|
||
<p>Сообщение состоит из стартовой строки, заголовков, пустой строки и тела. Методы: `GET`, `POST`, `HEAD`, `PUT`, `PATCH`, `DELETE`. Коды: `2xx` успех, `3xx` редирект, `4xx` ошибка клиента, `5xx` ошибка сервера.</p>
|
||
<a class="detail-link" href="#d-http">Подробно: HTTP-сообщения</a>
|
||
</article>
|
||
<article class="card" id="s-https">
|
||
<h3>Протокол HTTPS</h3>
|
||
<p>HTTPS — HTTP поверх TLS. Даёт шифрование, проверку подлинности сервера через сертификат и защиту от подмены данных. Порт по умолчанию — `443`.</p>
|
||
<a class="detail-link" href="#d-http">Подробно: HTTPS</a>
|
||
</article>
|
||
<article class="card" id="s-http3">
|
||
<h3>Протокол HTTP/3</h3>
|
||
<p>HTTP/3 работает поверх QUIC/UDP. Семантика HTTP сохраняется, но транспорт меняется: независимые потоки, встроенный TLS 1.3, меньше блокировок при потере пакетов.</p>
|
||
<a class="detail-link" href="#d-http">Подробно: HTTP/3</a>
|
||
</article>
|
||
<article class="card" id="s-ports">
|
||
<h3>Сетевые порты. HTTP и HTTPS</h3>
|
||
<p>Порт указывает процесс внутри IP-адреса. Всего 0-65535. HTTP обычно `80/tcp`, HTTPS `443/tcp`, DNS `53`, SSH `22`, альтернативный HTTP часто `8080`.</p>
|
||
<a class="detail-link" href="#d-ports">Подробно: порты</a>
|
||
</article>
|
||
<article class="card" id="s-auth">
|
||
<h3>Идентификация, аутентификация, авторизация</h3>
|
||
<p>Идентификация: "кто ты?". Аутентификация: "докажи". Авторизация: "что тебе разрешено?". В HTTP часто встречаются Basic, Digest и Bearer.</p>
|
||
<a class="detail-link" href="#d-auth">Подробно: auth</a>
|
||
</article>
|
||
<article class="card" id="s-oauth">
|
||
<h3>OAuth 2.0</h3>
|
||
<p>OAuth 2.0 — протокол авторизации: приложение получает ограниченный доступ к ресурсам пользователя через токен, не получая пароль пользователя.</p>
|
||
<a class="detail-link" href="#d-oauth">Подробно: OAuth 2.0</a>
|
||
</article>
|
||
<article class="card" id="s-uri">
|
||
<h3>URI, URL, URN</h3>
|
||
<p>URI — общий идентификатор ресурса. URL указывает местоположение и способ получения. URN задаёт устойчивое имя без привязки к расположению. Все URL — URI, но не все URI — URL.</p>
|
||
<a class="detail-link" href="#d-uri">Подробно: URI/URL/URN</a>
|
||
</article>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="block" id="block-2">
|
||
<h2>Блок 2. HTML</h2>
|
||
<div class="cards">
|
||
<article class="card" id="s-html-structure"><h3>Структура документа</h3><p>HTML5-документ начинается с <code><!doctype html></code>, затем <code><html></code>, внутри <code><head></code> с метаданными и <code><body></code> с видимым содержимым.</p><a class="detail-link" href="#d-html">Подробно: HTML</a></article>
|
||
<article class="card" id="s-html-comments"><h3>Комментарии в HTML</h3><p>Комментарий пишется как <code><!-- текст --></code>. Браузер его не отображает, но он виден в исходном коде.</p><a class="detail-link" href="#d-html">Подробно: HTML</a></article>
|
||
<article class="card" id="s-head"><h3>Теги внутри head</h3><p>В <code><head></code> обычно находятся <code><title></code>, <code><meta></code>, <code><link></code>, <code><style></code>, <code><script></code> и технические данные страницы.</p><a class="detail-link" href="#d-html">Подробно: HTML</a></article>
|
||
<article class="card" id="s-meta"><h3>Мета-теги и viewport</h3><p><code><meta charset="utf-8"></code> задаёт кодировку. <code>viewport</code> нужен адаптивной вёрстке: <code>width=device-width, initial-scale=1.0</code>.</p><a class="detail-link" href="#d-html">Подробно: HTML</a></article>
|
||
<article class="card" id="s-flow"><h3>Нормальный поток</h3><p>Нормальный поток — базовое расположение элементов без flex/grid/position: блочные идут сверху вниз, строчные текут внутри строки.</p><a class="detail-link" href="#d-html">Подробно: HTML</a></article>
|
||
<article class="card" id="s-block-inline"><h3>Блочные и строчные элементы</h3><p>Блочные занимают доступную ширину и начинаются с новой строки: `div`, `p`, `section`. Строчные занимают место по содержимому: `span`, `a`, `strong`.</p><a class="detail-link" href="#d-html">Подробно: HTML</a></article>
|
||
<article class="card" id="s-semantic"><h3>Семантические теги</h3><p>`header`, `nav`, `main`, `section`, `article`, `aside`, `footer` описывают смысл блоков. Это важно для доступности, SEO и читаемости кода.</p><a class="detail-link" href="#d-html">Подробно: HTML</a></article>
|
||
<article class="card" id="s-attrs"><h3>Атрибуты тегов</h3><p>Атрибуты уточняют элемент: `href`, `src`, `alt`, `class`, `id`, `name`, `type`. Обычно пишутся в открывающем теге.</p><a class="detail-link" href="#d-html">Подробно: HTML</a></article>
|
||
<article class="card" id="s-class"><h3>Атрибут class</h3><p>`class` задаёт один или несколько CSS-классов. Один класс можно использовать на многих элементах.</p><a class="detail-link" href="#d-html">Подробно: HTML</a></article>
|
||
<article class="card" id="s-id"><h3>Идентификатор элемента</h3><p>`id` должен быть уникален на странице. Используется для якорей, JS и CSS-селектора `#id`.</p><a class="detail-link" href="#d-html">Подробно: HTML</a></article>
|
||
<article class="card" id="s-text-table"><h3>Заголовки, абзацы, списки, таблицы</h3><p>`h1-h6` задают структуру заголовков, `p` — абзац, `ul/ol/li` — списки, `table/tr/th/td` — табличные данные.</p><a class="detail-link" href="#d-html">Подробно: HTML</a></article>
|
||
<article class="card" id="s-img-link"><h3>Картинки и ссылки</h3><p>Ссылка: <code><a href="..."></code>. Картинка: <code><img src="..." alt="..."></code>; <code>alt</code> важен для доступности и случаев, когда изображение не загрузилось.</p><a class="detail-link" href="#d-html">Подробно: HTML</a></article>
|
||
<article class="card" id="s-whitespace"><h3>Переносы строк и пробелы</h3><p>В HTML последовательности пробелов схлопываются. Перенос строки в коде обычно не равен переносу на странице; для явного переноса есть <code><br></code>.</p><a class="detail-link" href="#d-html">Подробно: HTML</a></article>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="block" id="block-3">
|
||
<h2>Блок 3. HTML Forms</h2>
|
||
<div class="cards">
|
||
<article class="card" id="s-form"><h3>Форма и атрибуты</h3><p>`form` собирает пользовательский ввод. Главные атрибуты: `action` — куда отправлять, `method` — `get` или `post`.</p><a class="detail-link" href="#d-html">Подробно: HTML forms</a></article>
|
||
<article class="card" id="s-form-id-name"><h3>id и name</h3><p>`id` связывает поле с `label` и должен быть уникальным. `name` — имя параметра, под которым значение уйдёт на сервер.</p><a class="detail-link" href="#d-html">Подробно: HTML forms</a></article>
|
||
<article class="card" id="s-inputs"><h3>radio, checkbox, submit</h3><p>`radio` выбирает один вариант в группе с одинаковым `name`. `checkbox` — независимый флажок. `submit` отправляет форму.</p><a class="detail-link" href="#d-html">Подробно: HTML forms</a></article>
|
||
<article class="card" id="s-label"><h3>Label</h3><p>`label` подписывает поле и улучшает доступность. Связь делается через `for="field-id"` или вложением input внутрь label.</p><a class="detail-link" href="#d-html">Подробно: HTML forms</a></article>
|
||
<article class="card" id="s-fieldset"><h3>Группировка элементов</h3><p>`fieldset` объединяет связанные поля, `legend` задаёт подпись группы. Часто используется для radio-групп.</p><a class="detail-link" href="#d-html">Подробно: HTML forms</a></article>
|
||
<article class="card" id="s-required"><h3>required</h3><p>`required` запрещает отправку формы браузером, если поле пустое. Серверную валидацию всё равно нужно делать отдельно.</p><a class="detail-link" href="#d-html">Подробно: HTML forms</a></article>
|
||
<article class="card" id="s-placeholder"><h3>Placeholder</h3><p>`placeholder` показывает подсказку внутри пустого поля. Это не замена `label`, потому что исчезает при вводе.</p><a class="detail-link" href="#d-html">Подробно: HTML forms</a></article>
|
||
<article class="card" id="s-button-type"><h3>type для button</h3><p>`button` без `type` внутри формы часто ведёт себя как `submit`. Для обычной кнопки явно пишут `type="button"`.</p><a class="detail-link" href="#d-html">Подробно: HTML forms</a></article>
|
||
<article class="card" id="s-textarea"><h3>Textarea</h3><p>`textarea` — многострочное текстовое поле. Текст по умолчанию пишется между открывающим и закрывающим тегом.</p><a class="detail-link" href="#d-html">Подробно: HTML forms</a></article>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="block" id="block-4">
|
||
<h2>Блок 4. CSS selectors и базовые свойства</h2>
|
||
<div class="cards">
|
||
<article class="card" id="s-css-universal"><h3>Универсальный селектор</h3><p>`*` выбирает все элементы. Часто применяют для сброса `box-sizing`, но специфичность у него нулевая.</p><a class="detail-link" href="#d-css">Подробно: CSS selectors</a></article>
|
||
<article class="card" id="s-css-basic-selectors"><h3>Элемент, класс, идентификатор</h3><p>`p` выбирает теги, `.card` — класс, `#main` — уникальный id. ID специфичнее класса и тега.</p><a class="detail-link" href="#d-css">Подробно: CSS selectors</a></article>
|
||
<article class="card" id="s-css-combinators"><h3>Дочерний, потомок, сестринский</h3><p>`A B` — потомок, `A > B` — прямой ребёнок, `A + B` — следующий сосед, `A ~ B` — последующие соседи.</p><a class="detail-link" href="#d-css">Подробно: CSS selectors</a></article>
|
||
<article class="card" id="s-css-attr"><h3>Селектор атрибута</h3><p>`[attr]`, `[type="email"]`, `a[href^="https"]` выбирают элементы по наличию или значению атрибута.</p><a class="detail-link" href="#d-css">Подробно: CSS selectors</a></article>
|
||
<article class="card" id="s-css-pseudo"><h3>Псевдоклассы</h3><p>`:hover`, `:focus`, `:checked`, `:nth-child()` выбирают состояние или позицию элемента. Структурные псевдоклассы зависят от места в DOM.</p><a class="detail-link" href="#d-css">Подробно: CSS selectors</a></article>
|
||
<article class="card" id="s-css-group"><h3>Группировка селекторов</h3><p>Селекторы через запятую получают одно правило: `h1, h2, h3 { margin: 0; }`.</p><a class="detail-link" href="#d-css">Подробно: CSS selectors</a></article>
|
||
<article class="card" id="s-css-cascade"><h3>Наследование и каскадирование</h3><p>Каскад решает конфликт правил по важности, специфичности и порядку. Наследуются в основном текстовые свойства, например `color` и `font-family`.</p><a class="detail-link" href="#d-css">Подробно: CSS selectors</a></article>
|
||
<article class="card" id="s-css-specificity"><h3>Специфичность</h3><p>Условный вес: inline > ID > классы/атрибуты/псевдоклассы > теги/псевдоэлементы. При равенстве побеждает правило ниже в коде.</p><a class="detail-link" href="#d-css">Подробно: CSS selectors</a></article>
|
||
<article class="card" id="s-box-model"><h3>Блочная модель</h3><p>Блок состоит из content, padding, border и margin. `box-sizing: border-box` включает padding и border в заданную ширину.</p><a class="detail-link" href="#d-css">Подробно: CSS свойства</a></article>
|
||
<article class="card" id="s-background"><h3>Фон элемента</h3><p>Основные свойства: `background-color`, `background-image`, `background-repeat`, `background-position`, `background-size`.</p><a class="detail-link" href="#d-css">Подробно: CSS свойства</a></article>
|
||
<article class="card" id="s-margin-align"><h3>Margin и выравнивание блоков</h3><p>`margin` задаёт внешний отступ. Для центрирования блочного элемента с заданной шириной часто используют `margin-left/right: auto`.</p><a class="detail-link" href="#d-css">Подробно: CSS свойства</a></article>
|
||
<article class="card" id="s-fonts"><h3>Шрифты</h3><p>`font-family`, `font-size`, `font-weight`, `font-style` задают семейство, размер, толщину и наклон текста.</p><a class="detail-link" href="#d-css">Подробно: CSS свойства</a></article>
|
||
<article class="card" id="s-text-align"><h3>Выравнивание и подчёркивание текста</h3><p>`text-align` управляет горизонтальным выравниванием текста, `text-decoration` — подчёркиванием и другими линиями.</p><a class="detail-link" href="#d-css">Подробно: CSS свойства</a></article>
|
||
<article class="card" id="s-line-letter"><h3>line-height и letter-spacing</h3><p>`line-height` задаёт высоту строки, `letter-spacing` — расстояние между буквами. На читаемость влияют сильнее, чем кажется.</p><a class="detail-link" href="#d-css">Подробно: CSS свойства</a></article>
|
||
<article class="card" id="s-text-shadow"><h3>Тень текста</h3><p>`text-shadow: x y blur color;` добавляет тень к тексту. В тестах важно помнить порядок смещения, размытия и цвета.</p><a class="detail-link" href="#d-css">Подробно: CSS свойства</a></article>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="block" id="block-5">
|
||
<h2>Блок 5. Flexbox Layout. Grid Layout</h2>
|
||
<div class="cards">
|
||
<article class="card" id="s-flex-container"><h3>Flex-контейнер и оси</h3><p>`display: flex` создаёт flex-контейнер. Главная ось задаётся `flex-direction`, поперечная идёт перпендикулярно.</p><a class="detail-link" href="#d-layout">Подробно: Flex/Grid</a></article>
|
||
<article class="card" id="s-inline-flex"><h3>Строчный flex-контейнер</h3><p>`display: inline-flex` делает контейнер flex-контейнером, но сам контейнер ведёт себя как строчный элемент во внешнем потоке.</p><a class="detail-link" href="#d-layout">Подробно: Flex/Grid</a></article>
|
||
<article class="card" id="s-flex-align"><h3>Выравнивание по осям</h3><p>`justify-content` выравнивает по главной оси, `align-items` — по поперечной. `align-content` работает при нескольких строках.</p><a class="detail-link" href="#d-layout">Подробно: Flex/Grid</a></article>
|
||
<article class="card" id="s-flex-grow"><h3>flex-grow, shrink, basis</h3><p>`flex-basis` — базовый размер, `flex-grow` — как элемент растёт, `flex-shrink` — как сжимается при нехватке места.</p><a class="detail-link" href="#d-layout">Подробно: Flex/Grid</a></article>
|
||
<article class="card" id="s-grid-container"><h3>Grid-контейнер</h3><p>`display: grid` создаёт двумерную сетку. Колонки задаются `grid-template-columns`, строки — `grid-template-rows`.</p><a class="detail-link" href="#d-layout">Подробно: Flex/Grid</a></article>
|
||
<article class="card" id="s-fr"><h3>Величина fr</h3><p>`fr` — доля свободного пространства grid-контейнера. `1fr 2fr` делит свободное место в пропорции 1 к 2.</p><a class="detail-link" href="#d-layout">Подробно: Flex/Grid</a></article>
|
||
<article class="card" id="s-repeat-minmax"><h3>repeat и minmax</h3><p>`repeat(3, 1fr)` повторяет трек. `minmax(200px, 1fr)` задаёт минимум и максимум размера трека.</p><a class="detail-link" href="#d-layout">Подробно: Flex/Grid</a></article>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="block" id="block-django">
|
||
<h2>Блоки 6-12. Django</h2>
|
||
<div class="cards">
|
||
<article class="card" id="s-django-models"><h3>Создание моделей</h3><p>Модель — класс-наследник `models.Model`; поля класса описывают столбцы таблицы. Модели обычно лежат в `models.py` приложения.</p><a class="detail-link" href="#d-django-models">Подробно: Django models</a></article>
|
||
<article class="card" id="s-primary-key"><h3>Первичный ключ</h3><p>Первичный ключ уникально идентифицирует запись. Если не задать явно, Django создаёт поле `id` автоматически.</p><a class="detail-link" href="#d-django-models">Подробно: Django models</a></article>
|
||
<article class="card" id="s-migrations"><h3>Миграции</h3><p>`makemigrations` создаёт файлы миграций из изменений моделей, `migrate` применяет их к базе данных.</p><a class="detail-link" href="#d-django-models">Подробно: Django models</a></article>
|
||
<article class="card" id="s-django-meta"><h3>Class Meta</h3><p>`class Meta` задаёт метаданные модели: `ordering`, `verbose_name`, `db_table`, ограничения и другие настройки.</p><a class="detail-link" href="#d-django-models">Подробно: Django models</a></article>
|
||
<article class="card" id="s-null-blank"><h3>null=True и blank=True</h3><p>`null=True` разрешает `NULL` в БД. `blank=True` разрешает пустое значение на уровне форм/валидации Django.</p><a class="detail-link" href="#d-django-models">Подробно: Django models</a></article>
|
||
<article class="card" id="s-charfield"><h3>CharField</h3><p>`CharField` хранит короткую строку и требует `max_length`. Для длинного текста обычно берут `TextField`.</p><a class="detail-link" href="#d-django-models">Подробно: Django models</a></article>
|
||
<article class="card" id="s-foreignkey"><h3>ForeignKey</h3><p>`ForeignKey` задаёт связь многие-к-одному. `on_delete` определяет поведение при удалении связанного объекта; `related_name` задаёт имя обратной связи.</p><a class="detail-link" href="#d-django-models">Подробно: Django models</a></article>
|
||
<article class="card" id="s-manytomany"><h3>Many-to-Many</h3><p>`ManyToManyField` задаёт связь многие-ко-многим. Django создаёт промежуточную таблицу автоматически, либо можно указать свою через `through`.</p><a class="detail-link" href="#d-django-models">Подробно: Django models</a></article>
|
||
<article class="card" id="s-fbv"><h3>FBV</h3><p>Function-Based View — функция, которая принимает `request` и возвращает `HttpResponse`, `render`, `redirect` или ошибку.</p><a class="detail-link" href="#d-django-views">Подробно: Django FBV</a></article>
|
||
<article class="card" id="s-render"><h3>render</h3><p>`render(request, template, context)` рендерит шаблон с контекстом и возвращает `HttpResponse`.</p><a class="detail-link" href="#d-django-views">Подробно: Django FBV</a></article>
|
||
<article class="card" id="s-context"><h3>Передача данных в шаблон</h3><p>Данные передаются словарём context: ключи становятся именами переменных в шаблоне.</p><a class="detail-link" href="#d-django-views">Подробно: Django FBV</a></article>
|
||
<article class="card" id="s-get-object"><h3>Объект или 404</h3><p>`get_object_or_404(Model, pk=pk)` возвращает объект или генерирует HTTP 404, если записи нет.</p><a class="detail-link" href="#d-django-views">Подробно: Django FBV</a></article>
|
||
<article class="card" id="s-routing-fbv"><h3>Маршрутизация FBV</h3><p>В `urlpatterns` функция передаётся напрямую: `path("posts/<int:pk>/", views.detail, name="detail")`.</p><a class="detail-link" href="#d-django-views">Подробно: Django FBV</a></article>
|
||
<article class="card" id="s-cbv-types"><h3>TemplateView, DetailView, ListView</h3><p>`TemplateView` показывает шаблон, `DetailView` — один объект, `ListView` — список объектов.</p><a class="detail-link" href="#d-django-views">Подробно: Django CBV</a></article>
|
||
<article class="card" id="s-cbv-models"><h3>CBV и модели</h3><p>Для `ListView`/`DetailView` можно указать `model = Post`; Django сам построит queryset и стандартные имена шаблонов.</p><a class="detail-link" href="#d-django-views">Подробно: Django CBV</a></article>
|
||
<article class="card" id="s-cbv-extra"><h3>Дополнительные данные</h3><p>Дополнительный контекст обычно добавляют через `get_context_data`, вызывая `super()` и дополняя словарь.</p><a class="detail-link" href="#d-django-views">Подробно: Django CBV</a></article>
|
||
<article class="card" id="s-cbv-default-vars"><h3>Переменные по умолчанию</h3><p>`ListView` отдаёт `object_list` и `modelname_list`; `DetailView` отдаёт `object` и `modelname`.</p><a class="detail-link" href="#d-django-views">Подробно: Django CBV</a></article>
|
||
<article class="card" id="s-cbv-queryset"><h3>Переопределение выгрузки</h3><p>`get_queryset()` меняет список объектов, `get_object()` — получение одного объекта. Часто используют фильтрацию по пользователю или статусу.</p><a class="detail-link" href="#d-django-views">Подробно: Django CBV</a></article>
|
||
<article class="card" id="s-pagination"><h3>Паджинация</h3><p>В `ListView` достаточно задать `paginate_by = N`; в шаблоне появится `page_obj`.</p><a class="detail-link" href="#d-django-views">Подробно: Django CBV</a></article>
|
||
<article class="card" id="s-cbv-templates"><h3>Шаблоны по умолчанию</h3><p>Для `DetailView`: `app/model_detail.html`; для `ListView`: `app/model_list.html`, если не задан `template_name`.</p><a class="detail-link" href="#d-django-views">Подробно: Django CBV</a></article>
|
||
<article class="card" id="s-cbv-super"><h3>Вызов базовой логики</h3><p>При переопределении методов вроде `get_context_data` обычно сначала вызывают `super()`, чтобы не потерять стандартный контекст.</p><a class="detail-link" href="#d-django-views">Подробно: Django CBV</a></article>
|
||
<article class="card" id="s-cbv-routing"><h3>Маршрутизация CBV</h3><p>Класс подключается через `.as_view()`: `path("", PostListView.as_view(), name="post_list")`.</p><a class="detail-link" href="#d-django-views">Подробно: Django CBV</a></article>
|
||
<article class="card" id="s-django-urls"><h3>Django URLs</h3><p>`path()` задаёт маршрут, view, kwargs и имя. `re_path()` использует regex. `reverse()` строит URL по имени маршрута.</p><a class="detail-link" href="#d-django-views">Подробно: Django URLs</a></article>
|
||
<article class="card" id="s-django-templates"><h3>Язык шаблонов Django</h3><p>Переменные пишутся как `{{ value }}`, теги как `{% for %}`, фильтры как `{{ name|lower }}`. Наследование делается через `extends` и `block`.</p><a class="detail-link" href="#d-django-views">Подробно: Django templates</a></article>
|
||
<article class="card" id="s-django-queries"><h3>Django queries</h3><p>QuerySet ленивый и цепочечный. Важно знать `get`, `filter`, `exclude`, `order_by`, `annotate`, `aggregate`, `Q`, `F`, `select_related`, `prefetch_related`.</p><a class="detail-link" href="#d-django-models">Подробно: Django queries</a></article>
|
||
<article class="card" id="s-django-forms"><h3>Django forms</h3><p>`forms.Form` — ручная форма, `ModelForm` строится по модели. Валидация через `is_valid`, `cleaned_data`, `clean_field`, `clean`.</p><a class="detail-link" href="#d-django-forms">Подробно: Django forms</a></article>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="details" id="details">
|
||
<h2>Подробные заметки</h2>
|
||
|
||
<article class="note full-note" id="d-ip">
|
||
<h3>IP-адрес и IPv6</h3>
|
||
<p class="note-source">Полный текст исходной заметки.</p>
|
||
<div class="embedded-note" data-note-title="IP-адрес">
|
||
<h1>IP-адрес</h1>
|
||
<p><strong>IP - Internet Protocol -</strong> Сетевой адрес</p>
|
||
<p>IP-адрес - это просто набор из 32 нулей и единиц, который
|
||
преобразовали в 10-ричную систему счисления и разбили на 4 части для
|
||
удобства.</p>
|
||
<p>В стандарте IPv4 мы можем использовать только <strong>4 294 967
|
||
296</strong> адресов, что может не хватить. На замену ему потихоньку
|
||
вводится IPv6 - число из 128 единиц и нулей, переведенный в 16-чную С.С.
|
||
и разбитый на 8 частей. Тут доступно уже сильно больше вариантов…</p>
|
||
<h2>Статическая И Динамическая
|
||
Адресация</h2>
|
||
<p>Статика - задается вручную и не меняется в ходе работы. Динамика -
|
||
задается автоматически посредством DHCP-сервера из определенного ему
|
||
пула IP.</p>
|
||
<p>Т.к. переход на IPv6 дорог, да и иметь всем конкретный IP не очень
|
||
безопасно, придумали NAT (Network Address Translation) и его надстройку
|
||
PAT (Port Address Translation). Суть в том, что много устройств могут
|
||
выходить в сеть под “одним” белым (внешним) IP. Но есть нюанс, при
|
||
маршрутизации трафика к белому IP добавляется порт, который уточняет, к
|
||
какому именно устройству сети и с каким “внутренним” IP направить эти
|
||
пакеты.</p>
|
||
</div>
|
||
<div class="embedded-note" data-note-title="IPv6">
|
||
<h1>IPv6</h1>
|
||
<p>При использовании IPv4 с 4 миллиардами адресов, в какой-то момент
|
||
очевидно столкнулись с проблемой их нехватки. Даже создание PAT и
|
||
использование локальной адресации не сильно спасло ситуацию.</p>
|
||
<p>Решением проблемы стало изобретение IP версии 6, где используется не
|
||
32 бита для кодирования адреса, а 128, при этом, увеличение количества
|
||
бит на единицу, увеличивает кол-во доступных адресов ровно в два раза,
|
||
следовательно, для 128 бит вакантных адресов примерно…</p>
|
||
<p><span class="math display">$$\large 340\ 282\ 366\ 920\ 938\ 463\
|
||
463\ 374\ 607\ 431\ 768\ 211\ 456$$</span></p>
|
||
<p>Это много, даже очень.</p>
|
||
<p>IPv5 А что случилось с IPv5? Хороший вопрос … IP-версия 5 была
|
||
использована для экспериментального проекта под названием “Протокол
|
||
интернет-потока”. Он определен в RFC, если вас интересуют исторические
|
||
причины: <a
|
||
href="http://www.faqs.org/rfcs/rfc1819.html">http://www.faqs.org/rfcs/rfc1819.html</a></p>
|
||
<h2>Отличия IPv4 И IPv6</h2>
|
||
<p>В чем же основная проблема перехода на IPv6? А в том, что нет
|
||
совместимости протоколов для IPv4 и новых поколений.</p>
|
||
<ul>
|
||
<li><strong>OSPF</strong> был обновлен с 2 (IPv4) до 3 (IPv6)
|
||
версии.</li>
|
||
<li><strong>ICMP</strong> был обновлен до ICMP 6.</li>
|
||
<li><strong>ARP</strong> был заменен на <em>NDP</em> (Neighborhood
|
||
Discovery Protocol).</li>
|
||
</ul>
|
||
<p><img src="../../../99 System/Cache/IPv6_image.png" /></p>
|
||
<p>Вместо того чтобы уже добавлять все поля в заголовок, заголовок IPv6
|
||
использует “следующий заголовок”, который ссылается на необязательные
|
||
заголовки. Поскольку заголовок намного проще, маршрутизаторам придется
|
||
выполнять меньше работы.</p>
|
||
<p>Маршрутизация тоже сильно поменялась при переходе на новую
|
||
версию:</p>
|
||
<ol type="1">
|
||
<li>RIP -> RIPng (RIP Next Generation)</li>
|
||
<li>BGP (Border Gateway Protocol) - протокол, объединяющий интернет
|
||
вместе. MP-BGP - Multi-Protocol BGP, он может маршрутизировать IPv6.
|
||
EIGRP также поддерживает IPv6.</li>
|
||
</ol>
|
||
<p>Надо учитывать, что даже при условии поддержки OSPF и EIGRP адресации
|
||
обоих версий, это два <strong>разных протокола</strong>. Из этого
|
||
следует, что сначала надо поднять протокол для одной версии, а потом для
|
||
другой. Использование двух версий IP называется <strong>двойным
|
||
стеком</strong>.</p>
|
||
<blockquote>
|
||
<p>Поскольку эти два протокола несовместимы, в будущем будет происходить
|
||
переход с IPv4 на IPv6. Это означает, что вы будете запускать оба
|
||
протокола в своей сети и, возможно, однажды вы сможете отключить IPv4,
|
||
так как весь интернет будет настроен на IPv6.</p>
|
||
</blockquote>
|
||
<h2>Формат IPv6</h2>
|
||
<pre class="text"><code>2041:0000:140F:0000:0000:0000:875B:131B</code></pre>
|
||
<p>Он сильно длиннее, чем IPv4, состоит из 8 частей, каждая часть
|
||
состоит из 4 шестнадцатиричных чисел.</p>
|
||
<p><img src="../../../99 System/Cache/5_IPv6_image.png" /></p>
|
||
<p>Таблица перевода шестнадцатиричных чисел в двоичные</p>
|
||
<p>Существуют некоторые правила, позволяющие упростить работу с
|
||
адресами:</p>
|
||
<ol type="1">
|
||
<li>Если есть несколько частей с нулями, то их можно убрать, заменив на
|
||
<code>::</code> <code>2041:0000:140F:0000:0000:0000:875B:131B</code>
|
||
-> <code>2041: 0000:140F:: 875B:131B</code></li>
|
||
<li>Если есть одиночный блок с нулями, то можно его заменить на один
|
||
ноль <code>2041: 0000:140F:: 875B:131B</code> ->
|
||
<code>2041:0:140F:: 875B:131B</code></li>
|
||
<li>При наличии в блоке значащих чисел и нулями перед ними, нули можно
|
||
опустить <code>2001:0001:0002:0003:0004:0005:0006:0007</code> ->
|
||
<code>2001:1:2:3:4:5:6:7</code></li>
|
||
</ol>
|
||
<p>При использовании IPv4 и нехватке адресов, люди начали
|
||
адаптироваться, придумав частные сети и VLSM (сегментацию сети),
|
||
использовали NAT и так далее. При переходе на IPv6 такой проблемы уже не
|
||
будет, т.к. пула доступных адресов будет достаточно для снабжения
|
||
адресами нескольких планет, таких, как Земля. Протокол IPv6 предлагает
|
||
два варианта для одноадресной рассылки:</p>
|
||
<ol type="1">
|
||
<li>Global Unicast</li>
|
||
<li>Unique Local</li>
|
||
</ol>
|
||
<p>Ранее, как отголосок IPv4 существовал третий диапазон адресов “site
|
||
local”, который начинался с <code>FEC0::/10</code>. Он предназначался
|
||
для использования во внутренних сетях (аналог
|
||
<code>192.168.0.0/24</code>), но был удален из стандарта IPv6.</p>
|
||
<p><strong>Global Unicast</strong> передачи похожи на публичные IPv4
|
||
адреса. Каждая компания, желающая подключится к интернету, получает пул
|
||
адресов, которые они, на своё усмотрение, делят на более мелкие
|
||
префиксы, чтобы все устройства сети поулчили IPv6 адрес, притом
|
||
уникальный во всем мире. Зарезервированный блорк называется префиксом
|
||
глобальной маршрутизации.</p>
|
||
<h2>Получение Префиксов</h2>
|
||
<ul>
|
||
<li><strong>IANA</strong> отвечает за распределение всех префиксов IPv6.
|
||
Они будут назначать реестрам разные блоки, которыми будут управлять
|
||
региональные компании.</li>
|
||
<li><strong>ISP</strong>, попадлающие под реестр региональной компании,
|
||
заправшивает блок IPv6. Они получают свой пул адресов, которые могут
|
||
распределять между провайдерами. !</li>
|
||
</ul>
|
||
<p><img src="../../../99 System/Cache/4_IPv6_image.png" /></p>
|
||
<blockquote>
|
||
<p>Некоторые префиксы <strong>FD</strong>: Unique Local
|
||
<strong>FF</strong>: Multicast <strong>FE80</strong>: Link-Local</p>
|
||
</blockquote>
|
||
<h2>Local И Link-Local</h2>
|
||
<p>После получения клиентом от провайдера префикса, например,
|
||
<code>2001: 828:105:: / 48</code>, необходимо его разбить на подсети для
|
||
различных VLAN и point-to-point соединений, которые могут быть.
|
||
Поскольку адресное пространство настолько велико, все используют префикс
|
||
<code>/64</code> для подсетей. Не имеет смысла брать меньшие подсети.
|
||
Когда мы используем IPv4, мы вынуждены, для подсетей, дробить хостовую
|
||
часть!</p>
|
||
<p><img src="../../../99 System/Cache/12_IPv6_image.png" /></p>
|
||
<p>Тогда, у нас, в целом, будет меньше хостов на подсеть.</p>
|
||
<p><img src="../../../99 System/Cache/3_IPv6_image.png" /></p>
|
||
<p> В IPv6 такой проблемы нет:</p>
|
||
<p><img src="../../../99 System/Cache/11_IPv6_image.png" /></p>
|
||
<p>Префикс Global Routing был назначен провайдером. Последние 64 бита
|
||
называются <strong>идентификатором интерфейса</strong>, это эквивалетно
|
||
части хоста в IPv4.</p>
|
||
<p>Путем несложно математики, получается, что у нас 16 бит на подсети, а
|
||
это около 65536 подсетей (как правило, этого <em>более чем</em>
|
||
достаточно). В этой же схеме, на хосты в каждой подсети отводится около
|
||
<strong>18 квинтиллионов</strong> хостов.</p>
|
||
<p>Если клиент получил префикс <code>2001: 828: 105:: / 48</code>, то он
|
||
может создать такие подсети: </p>
|
||
<p><img src="../../../99 System/Cache/2_IPv6_image.png" /></p>
|
||
<pre class="text"><code>- 2001:828:105:0000::/64;
|
||
- 2001:828:105:0001::/64;
|
||
- 2001:828:105:0002::/64;
|
||
- 2001:828:105:0003::/64;
|
||
- 2001:828:105:0004::/64;
|
||
- 2001:828:105:0005::/64;
|
||
- 2001:828:105:0006::/64;
|
||
- 2001:828:105:0007::/64;
|
||
- 2001:828:105:0008::/64;
|
||
- 2001:828:105:0009::/64;
|
||
- 2001:828:105:000A::/64;
|
||
- 2001:828:105:000B::/64;
|
||
- 2001:828:105:000C::/64;
|
||
- 2001:828:105:000D::/64;
|
||
- 2001:828:105:000E::/64;
|
||
- 2001:828:105:000F::/64;
|
||
- 2001:828:105:0010::/64;
|
||
- 2001:828:105:0011::/64;
|
||
- 2001:828:105:0012::/64;
|
||
- 2001:828:105:0013::/64;
|
||
- 2001:828:105:0014::/64;
|
||
...</code></pre>
|
||
</div>
|
||
<p class="back">Назад: <a href="#s-ip-addressing">Адресация, IPv4, IPv6</a></p>
|
||
</article>
|
||
|
||
<article class="note full-note" id="d-tcp">
|
||
<h3>TCP vs UDP</h3>
|
||
<p class="note-source">Полный текст исходной заметки.</p>
|
||
<div class="embedded-note" data-note-title="TCP vs UDP">
|
||
<h1>TCP Vs UDP</h1>
|
||
<p>Основные протоколы транспортного уровня модели OSI (L4).</p>
|
||
<h2><strong>TCP</strong></h2>
|
||
<ul>
|
||
<li><p>Transmission Control Protocol Перед передачей данных
|
||
устанавливает соединение трехсторонним рукопожатием.</p></li>
|
||
<li><p>SYN - отправка запроса на возможность передачи данных от
|
||
отправителя.</p></li>
|
||
<li><p>SYNACK - подтверждение получающей стороной.</p></li>
|
||
<li><p>ACK - начало передачи данных.</p></li>
|
||
</ul>
|
||
<p>После отправки части данных, получающая сторона отправляет
|
||
подтверждение передачи.</p>
|
||
<p>Этот протокол надежный, но очень медленный.</p>
|
||
<p>TCP, как протокол, определен в <strong>RFC (Request For Comments)
|
||
793</strong>, выполняет функции, перечисленные в таблице ниже, через
|
||
механизмы, предоставляемые конечными устройствами. Он полагается на IP
|
||
для сквозной доставки данных, включая вопросы маршрутизации. Независимо
|
||
от того, в каких условиях находятся ПК для передачи, TCP работает
|
||
одинаково на своем уровне. </p>
|
||
<p><img src="../../../99 System/Cache/1_TCP%20vs%20UDP_image.png" /></p>
|
||
<p>Функционал TCP</p>
|
||
<figure>
|
||
<img src="../../../99 System/Cache/TCP%20vs%20UDP_2.png"
|
||
alt="Отправка данных с трех приложений Анной Грише" />
|
||
<figcaption aria-hidden="true">Отправка данных с трех приложений Анной
|
||
Грише</figcaption>
|
||
</figure>
|
||
<p>Поля заголовка TCP</p>
|
||
<h2><strong>UDP</strong></h2>
|
||
<ul>
|
||
<li>User Datagram Protocol Просто бросается файлами в “сторону”
|
||
получающей стороны. Может теряться часть данных, или их порядок. В
|
||
случае с видео, звонками, мы можем позволить себе потерю данных.</li>
|
||
</ul>
|
||
<p><img src="../../../99 System/Cache/2_TCP%20vs%20UDP_image.png" /></p>
|
||
</div>
|
||
<p class="back">Назад: <a href="#s-tcp">TCP</a></p>
|
||
</article>
|
||
|
||
<article class="note full-note" id="d-subnet">
|
||
<h3>Подсети и маска подсети</h3>
|
||
<p class="note-source">Полный текст исходной заметки.</p>
|
||
<div class="embedded-note" data-note-title="Подсети и маска подсети">
|
||
<h1>Подсети и маска подсети</h1>
|
||
<p>Маска подсети показывает, какая часть IPv4-адреса относится к сети, а
|
||
какая — к хосту внутри этой сети.</p>
|
||
<h2>Главное</h2>
|
||
<p>IPv4-адрес состоит из 32 бит. Без маски нельзя однозначно понять, где
|
||
заканчивается номер сети и начинается номер хоста.</p>
|
||
<p>Пример:</p>
|
||
<pre class="text"><code>IP: 192.168.123.132
|
||
Маска: 255.255.255.0
|
||
CIDR: /24</code></pre>
|
||
<p><code>/24</code> означает, что первые 24 бита — сеть, оставшиеся 8
|
||
бит — хосты.</p>
|
||
<p>Для примера выше:</p>
|
||
<ul>
|
||
<li>адрес сети: <code>192.168.123.0</code>;</li>
|
||
<li>часть хоста: <code>0.0.0.132</code>;</li>
|
||
<li>маска: <code>255.255.255.0</code>.</li>
|
||
</ul>
|
||
<h2>CIDR</h2>
|
||
<p>CIDR-запись <code>/N</code> показывает количество единиц в маске.</p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>CIDR</th>
|
||
<th>Маска</th>
|
||
<th>Типичный смысл</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><code>/32</code></td>
|
||
<td><code>255.255.255.255</code></td>
|
||
<td>один конкретный IPv4-адрес</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>/24</code></td>
|
||
<td><code>255.255.255.0</code></td>
|
||
<td>256 адресов в подсети</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>/16</code></td>
|
||
<td><code>255.255.0.0</code></td>
|
||
<td>крупная сеть</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>/8</code></td>
|
||
<td><code>255.0.0.0</code></td>
|
||
<td>очень крупная сеть</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>/0</code></td>
|
||
<td><code>0.0.0.0</code></td>
|
||
<td>весь IPv4-интернет, маршрут по умолчанию</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h2>Приватные IPv4-диапазоны</h2>
|
||
<p>Эти адреса не маршрутизируются напрямую в публичном интернете и часто
|
||
используются вместе с NAT:</p>
|
||
<ul>
|
||
<li><code>10.0.0.0/8</code>;</li>
|
||
<li><code>172.16.0.0/12</code>;</li>
|
||
<li><code>192.168.0.0/16</code>.</li>
|
||
</ul>
|
||
<p>Loopback-диапазон:</p>
|
||
<ul>
|
||
<li><code>127.0.0.0/8</code>, чаще всего <code>127.0.0.1</code> как
|
||
<code>localhost</code>.</li>
|
||
</ul>
|
||
<h2>Связи</h2>
|
||
<ul>
|
||
<li>IP-адрес</li>
|
||
<li>IPv6</li>
|
||
<li>NAT</li>
|
||
<li>Сетевые порты</li>
|
||
</ul>
|
||
</div>
|
||
<p class="back">Назад: <a href="#s-subnet">Маска подсети</a></p>
|
||
</article>
|
||
|
||
<article class="note full-note" id="d-nat">
|
||
<h3>NAT, localhost, подсети</h3>
|
||
<p class="note-source">Полный текст исходной заметки.</p>
|
||
<div class="embedded-note" data-note-title="NAT">
|
||
<h1>NAT</h1>
|
||
<p>При использовании IPv4 в какой-то момент возникла глобальная проблема
|
||
нехватки IP-адресов, ведь количество устройств росло семимильными
|
||
темпами, поэтому долгосрочным решением стал ввод IPv6, но это оказалось
|
||
очень долго и дорого, поэтому спасением стала технология NAT - Network
|
||
Assress Translation.</p>
|
||
<p>Сети, обычно, проектируются с учетом приватной адресации,
|
||
например:</p>
|
||
<ul>
|
||
<li><code>10.0.0.0/8</code></li>
|
||
<li><code>172.16.0.0/12</code></li>
|
||
<li><code>192.168.0.0/16</code></li>
|
||
</ul>
|
||
<p>Эти адреса позволяют устройствам внутри сети общаться друг с другом,
|
||
при этом не выводя каждое устройство в сеть на всеобщее обозрение. Чтобы
|
||
локальному устройству “выйти” в сеть и связаться с внешними
|
||
устройствами, нужно его внутренний приватный адрес “перевести” во
|
||
внешний “белый” IP.</p>
|
||
<p>Как раз для этого и нужна технология <em>NAT</em>, она позволяет
|
||
переводить частный адреса в публичные. Это не только позволило, в связке
|
||
с частными IPv4, экономить адреса, но и добавляет конфиденциальность,
|
||
т.к. за одним публичным IP могут скрываться десятки, сотни, а то и
|
||
тысячи устройств.</p>
|
||
<p>Маршрутизаторы с поддержкой NAT могут быть настроены на один или
|
||
несколько “белых” IP-адресов. Этот список называется <strong>пулом
|
||
NAT</strong>. Когда устройство из внутренней сети отправляет трафик во
|
||
внешнюю сеть, маршрутизатор переводит внутренний IP во внешний из пула.
|
||
Для внешних устройств весь входящий и исходящий трафик выглядит, как
|
||
имеющий общедоступный IP-адрес.</p>
|
||
<p>Маршрутизатор с NAT, обычно, работает на границе со
|
||
<strong>Stub-сетью</strong>.</p>
|
||
<blockquote>
|
||
<p><em>Stub-сеть</em> — это тупиковая сеть, в которой весь трафик к
|
||
другим сетям проходит через один-единственный маршрут, обычно через один
|
||
маршрутизатор или шлюз. Такая сеть не используется для транзита чужих
|
||
данных между сетями, а только для подключения собственных устройств к
|
||
внешнему миру, часто по маршруту по умолчанию.</p>
|
||
</blockquote>
|
||
<p><img src="../../../99 System/Cache/4_NAT_image.png" /></p>
|
||
<p>В терминах NAT внутренней сетью является набор сетей, подлежащий
|
||
переводу. Внешняя сеть относится ко всем остальным сетям.</p>
|
||
<p>NAT включает 4 типа адресов:</p>
|
||
<ol type="1">
|
||
<li>Внутренний локальный адрес (Inside Local Address)</li>
|
||
<li>Внутренний глобальный адрес (Inside Global Address)</li>
|
||
<li>Внешний местный адрес (Outside local address)</li>
|
||
<li>Внешний глобальный адрес (Outside global address)</li>
|
||
</ol>
|
||
<p>При определении того, какой тип адреса используется, важно помнить,
|
||
что терминология NAT всегда <em>применяется с точки зрения устройства с
|
||
транслированным адресом</em>:</p>
|
||
<ul>
|
||
<li><strong>Внутренний адрес (Inside address)</strong> - адрес
|
||
устройства, которое транслируется NAT</li>
|
||
<li><strong>Внешний адрес (Outside address)</strong> - адрес устройства
|
||
назначения</li>
|
||
<li><strong>Локальный адрес (Local address)</strong> - это любой адрес,
|
||
который отображается во внутренней части сети</li>
|
||
<li><strong>Глобальный адрес (Global address)</strong> - это любой
|
||
адрес, который отображается во внешней части сети</li>
|
||
</ul>
|
||
<p><img src="../../../99 System/Cache/2_NAT_image.png" /></p>
|
||
<h2>Типы NAT</h2>
|
||
<ol type="1">
|
||
<li>Статическая адресная трансляция (Static NAT) - сопоставление один к
|
||
одному между локальными и глобальными адресами.</li>
|
||
<li>Динамическая адресная трансляция (Dynamic NAT) - сопоставление
|
||
многих ко многим между локальными и глобальными адресами.</li>
|
||
<li>Post Address Translation (PAT) - многоадресное сопоставление
|
||
локальных и глобальных адресов с использованием портов. Также известен,
|
||
как <strong>NAT Overload</strong>.</li>
|
||
</ol>
|
||
<h3>Static NAT</h3>
|
||
<p>Статический NAT использует сопоставление локальных и глобальных
|
||
адресов один к одному. Настраиваются администратором сети и остаются
|
||
постоянными. При отправке пакетов на внешний адрес, он транслируется на
|
||
внутренний, при этом для внешних устройств, они имеют внешний ip-адрес.
|
||
Используются, например, для веб-серверов и иных устройств, которые
|
||
должны иметь согласованный адрес, доступный в интернете. Статический NAT
|
||
требует достаточное количество общедоступных адресов для обеспечения
|
||
всех устройств.</p>
|
||
<p><img src="../../../99 System/Cache/NAT_image.png" /></p>
|
||
<p>Таблица статического NAT</p>
|
||
<h3>Dynamic NAT</h3>
|
||
<p>Динамический, обратно статическому, автоматически назначает и
|
||
освобождает внешние адреса. Занимаются они по принципу “кто первый
|
||
пришел, то и занял”. Аналогично статике, требует достаточного количества
|
||
адресов для удовлетворения общего количества одновременного
|
||
использования всеми устройствами.</p>
|
||
<p><img src="../../../99 System/Cache/1_NAT_image.png" /></p>
|
||
<p>Таблица динамического NAT</p>
|
||
<h3>Port Address Translation
|
||
(PAT)</h3>
|
||
<p>PAT - это совершенно иная по сути работы система. Тут происходит
|
||
параллельная трансляция многих внутренних адресов на один или несколько
|
||
внешних адресов. Такая схема чаще всего используется в домашних
|
||
маршрутизаторах. Хитрость заключается в том, что адресация идет не
|
||
только по адресам, но и для каждого внутреннего адреса, сопоставляется
|
||
номер порта. Когда устройство инициирует сеанс <strong>TCP/IP</strong>,
|
||
оно генерирует значение порта
|
||
источника <strong>TCP</strong> или <strong>UDP</strong> для уникальной
|
||
идентификации сеанса. Когда NAT-маршрутизатор получает пакет от клиента,
|
||
он использует номер своего исходного порта, чтобы однозначно
|
||
идентифицировать конкретный перевод NAT. PAT гарантирует, что устройства
|
||
используют разный номер порта TCP для каждого сеанса. Когда ответ
|
||
возвращается с сервера, номер порта источника, который становится
|
||
номером порта назначения в обратном пути, определяет, какое устройство
|
||
маршрутизатор перенаправляет пакеты.</p>
|
||
<p><img src="../../../99 System/Cache/3_NAT_image.png" /></p>
|
||
<p>Таблица PAT</p>
|
||
<p><strong>А что относительно пакетов IPv4, содержащих данные, отличные
|
||
от TCP или UDP?</strong><br />
|
||
Эти пакеты не содержат номер порта уровня 4. PAT переводит наиболее
|
||
распространенные протоколы, переносимые IPv4, которые не используют TCP
|
||
или UDP в качестве протокола транспортного уровня. Наиболее
|
||
распространенными из них являются <strong>ICMPv4</strong>. Каждый из
|
||
этих типов протоколов по-разному обрабатывается PAT. Например, сообщения
|
||
запроса ICMPv4, эхо-запросы и ответы включают идентификатор запроса
|
||
Query ID. ICMPv4 использует Query ID. для идентификации эхо-запроса с
|
||
соответствующим ответом. Идентификатор запроса увеличивается с каждым
|
||
отправленным эхо-запросом. PAT использует идентификатор запроса вместо
|
||
номера порта уровня 4.</p>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 50%" />
|
||
<col style="width: 50%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr>
|
||
<th>Преимущества NAT</th>
|
||
<th>Недостатки NAT</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Поддержка приватных адресов, экономия публичных IPv4</td>
|
||
<td>Увеличение задержек, особенно для VoIP</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Возможность нескольких пулов (резерв, балансировка нагрузки)</td>
|
||
<td>Потеря сквозной адресации, проблемы с некоторыми приложениями</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Независимость внутренней адресации от провайдера</td>
|
||
<td>Потеря сквозной трассировки, сложнее диагностика</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Повышение безопасности за счёт скрытия внутренней топологии</td>
|
||
<td>Сложности с туннелированием (IPsec и др.)</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Лёгкая смена публичной схемы адресации без перенастройки хостов</td>
|
||
<td>Нарушение работы сервисов, требующих входящих соединений или
|
||
UDP</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h2>Связанные заметки</h2>
|
||
<ul>
|
||
<li>Terraform — NAT-шлюзы и пулы IP-адресов — типовые сетевые ресурсы,
|
||
которые Terraform декларативно управляет в облачной инфраструктуре (VPC,
|
||
subnets)</li>
|
||
</ul>
|
||
</div>
|
||
<p class="back">Назад: <a href="#s-nat-localhost">NAT, localhost, подсети</a></p>
|
||
</article>
|
||
|
||
<article class="note full-note" id="d-dns">
|
||
<h3>DNS</h3>
|
||
<p class="note-source">Полный текст исходной заметки.</p>
|
||
<div class="embedded-note" data-note-title="DNS">
|
||
<h1>DNS</h1>
|
||
<p>DNS - Domain Name System Аналог: контактная книга в телефоне
|
||
(сопоставление ФИО номеру телефона).</p>
|
||
<p>При вводе названия сайта или его доменного имени в поисковую строку
|
||
браузер обращается к кэшу, если вдруг уже заходили на этот сайт с этого
|
||
браузера.</p>
|
||
<p>Далее идет обращение к локальному DNS серверу (для ПК это файл
|
||
<code>hosts</code>).</p>
|
||
<p>Если ничего нет, то идет обращение к <strong>resolver</strong>
|
||
(распознающий). Обычно, это сервер у хостинг-провайдера, но можно задать
|
||
любой другой.</p>
|
||
<p>Тот ищет записи в своем кэше (если его пользователи часто ищут твой
|
||
сайт) А если не находит, то идет к корневому <strong>root</strong>
|
||
серверу, который отвечает за зону <code>.</code>.</p>
|
||
<p>Стоит отметить, что все доменные имена, на самом деле, имеют точку в
|
||
конце адреса: youtube.com. vk.com. mephi.ru. За эту корневую точку и
|
||
отвечают корневые сервера.</p>
|
||
<p>Тот не говорит IP-адрес, но говорит, кто может “подсказать”.</p>
|
||
<p>Он нас пересылает на TLD (Top Level Domain) сервер, который отвечает
|
||
за свою верхнеуровневую доменную зону. Те делятся на:</p>
|
||
<ol type="1">
|
||
<li>gTLD (Generic Top Level Domain) - доменные зоны, не привязанные к
|
||
стране.
|
||
<ul>
|
||
<li><code>.edu</code> - образование</li>
|
||
<li><code>.com</code> - коммерческие</li>
|
||
<li><code>.org</code> - организации и некомерческие</li>
|
||
</ul></li>
|
||
<li>ccTLD (Country Code Top Level Domain) - привязанные к стране:
|
||
<ul>
|
||
<li><code>.ru</code> - Россия</li>
|
||
<li><code>.ua</code> - Украина</li>
|
||
<li><code>.by</code> - Беларусь</li>
|
||
<li><code>.us</code> - США</li>
|
||
</ul></li>
|
||
</ol>
|
||
<p>Т.е. после корневого сервера, resolver пойдет к серверу верхнего
|
||
уровня, но и тот не скажет ему, куда переходить, тот подскажет, к какому
|
||
<em>авторитарному</em> серверу обратиться.</p>
|
||
<p>Авторитарный сервер или сервер авторитативных имен (<em>Authoritative
|
||
nameserver</em>) - это сервер, отвечающий за конкретный пул адресов, как
|
||
правило, такими выступают хостинг-провайдеры, которые регистрируют
|
||
домены. Вот они как раз говорят, какое нужен ip-адрес.</p>
|
||
<p>В терминологии DNS существует 3 вида запросов:</p>
|
||
<ol type="1">
|
||
<li>Recursive (рекурсивный) - запрос IP-адреса по домену.</li>
|
||
<li>Iterative (итеративный) - запрос IP-адреса, либо авторитативного DNS
|
||
сервера.</li>
|
||
<li>Inverse (обратный) - запрос доменного имени по IP-адресу.</li>
|
||
</ol>
|
||
</div>
|
||
<p class="back">Назад: <a href="#s-dns">DNS</a></p>
|
||
</article>
|
||
|
||
<article class="note full-note" id="d-http">
|
||
<h3>HTTP, HTTPS и HTTP/3</h3>
|
||
<p class="note-source">Полный текст исходной заметки.</p>
|
||
<div class="embedded-note" data-note-title="HTTP, HTTPS и HTTP3">
|
||
<h1>HTTP, HTTPS и HTTP/3</h1>
|
||
<p>HTTP (HyperText Transfer Protocol) — прикладной протокол для доступа
|
||
к ресурсам WWW. Клиент и сервер обмениваются отдельными сообщениями:
|
||
клиент отправляет HTTP-запрос, сервер возвращает HTTP-ответ.</p>
|
||
<h2>Главное</h2>
|
||
<ul>
|
||
<li>HTTP сам по себе не хранит состояние между запросами. Сессии поверх
|
||
HTTP обычно поддерживаются через cookies или токены.</li>
|
||
<li>HTTP/1.0 часто открывал новое TCP-соединение на каждый обмен
|
||
запросом и ответом.</li>
|
||
<li>HTTP/1.1 добавил постоянные соединения и конвейерную обработку.</li>
|
||
<li>HTTP/2 использует бинарные фреймы, сжатие заголовков и
|
||
мультиплексирование нескольких потоков в одном TCP-соединении.</li>
|
||
<li>HTTPS — это HTTP поверх TLS. Он защищает конфиденциальность,
|
||
целостность и аутентичность соединения.</li>
|
||
<li>HTTP/3 переносит семантику HTTP на QUIC поверх UDP и уменьшает
|
||
проблему head-of-line blocking.</li>
|
||
</ul>
|
||
<h2>HTTP-запрос</h2>
|
||
<p>Стартовая строка запроса состоит из метода, цели запроса и версии
|
||
протокола:</p>
|
||
<pre class="http"><code>GET /index.html HTTP/1.1</code></pre>
|
||
<p>Основные методы:</p>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Метод</th>
|
||
<th>Что делает</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><code>GET</code></td>
|
||
<td>Получить ресурс; параметры часто передаются в query string.</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>POST</code></td>
|
||
<td>Отправить данные на сервер: форма, JSON, файл.</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>HEAD</code></td>
|
||
<td>Получить только заголовки, как у <code>GET</code>, без тела
|
||
ответа.</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>PUT</code></td>
|
||
<td>Создать или полностью заменить ресурс.</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>PATCH</code></td>
|
||
<td>Частично изменить ресурс.</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>DELETE</code></td>
|
||
<td>Удалить ресурс.</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>OPTIONS</code></td>
|
||
<td>Узнать доступные методы/возможности сервера.</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h2>HTTP-сообщение</h2>
|
||
<p>И запрос, и ответ имеют общую структуру:</p>
|
||
<ol type="1">
|
||
<li>Стартовая строка.</li>
|
||
<li>Заголовки.</li>
|
||
<li>Пустая строка.</li>
|
||
<li>Необязательное тело.</li>
|
||
</ol>
|
||
<p>Заголовок записывается как <code>Имя-Заголовка: значение</code>. Имя
|
||
не чувствительно к регистру.</p>
|
||
<p>Частые заголовки запроса:</p>
|
||
<ul>
|
||
<li><code>Host</code> — конкретный домен или IP, к которому обращается
|
||
клиент.</li>
|
||
<li><code>User-Agent</code> — сведения о клиенте: браузер, ОС,
|
||
версия.</li>
|
||
<li><code>Accept</code> — какие типы данных клиент готов принять.</li>
|
||
<li><code>Cookie</code> — cookies клиента.</li>
|
||
<li><code>Authorization</code> — данные аутентификации, например
|
||
Bearer-токен.</li>
|
||
</ul>
|
||
<h2>HTTP-ответ</h2>
|
||
<p>Строка статуса ответа содержит версию протокола, код состояния и
|
||
текстовое пояснение:</p>
|
||
<pre class="http"><code>HTTP/1.1 200 OK</code></pre>
|
||
<p>Классы кодов:</p>
|
||
<ul>
|
||
<li><code>1xx</code> — информационные.</li>
|
||
<li><code>2xx</code> — успешная обработка.</li>
|
||
<li><code>3xx</code> — перенаправление.</li>
|
||
<li><code>4xx</code> — ошибка клиента.</li>
|
||
<li><code>5xx</code> — ошибка сервера.</li>
|
||
</ul>
|
||
<p>Частые коды:</p>
|
||
<ul>
|
||
<li><code>200 OK</code> — запрос успешно обработан.</li>
|
||
<li><code>302 Found</code> — временное перенаправление.</li>
|
||
<li><code>400 Bad Request</code> — некорректный запрос.</li>
|
||
<li><code>403 Forbidden</code> — доступ запрещён.</li>
|
||
<li><code>404 Not Found</code> — ресурс не найден.</li>
|
||
<li><code>500 Internal Server Error</code> — внутренняя ошибка
|
||
сервера.</li>
|
||
</ul>
|
||
<h2>HTTPS</h2>
|
||
<p>HTTPS использует TLS поверх TCP-соединения. Порт по умолчанию —
|
||
<code>443</code>, у обычного HTTP — <code>80</code>.</p>
|
||
<p>Базовый смысл TLS:</p>
|
||
<ul>
|
||
<li>сервер предъявляет сертификат;</li>
|
||
<li>клиент проверяет сертификат через центр сертификации;</li>
|
||
<li>стороны согласуют ключи;</li>
|
||
<li>дальнейший трафик шифруется и защищается от подмены.</li>
|
||
</ul>
|
||
<p>SSL — устаревшее название семейства протоколов, в современных
|
||
системах фактически используется TLS, но термин “SSL-сертификат” всё ещё
|
||
распространён.</p>
|
||
<h2>HTTP/3</h2>
|
||
<p>HTTP/3 работает поверх QUIC, а QUIC работает поверх UDP. QUIC
|
||
объединяет надёжную доставку, шифрование TLS 1.3 и управление
|
||
потоками.</p>
|
||
<p>Ключевые отличия:</p>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 50%" />
|
||
<col style="width: 50%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr>
|
||
<th>HTTP/2</th>
|
||
<th>HTTP/3</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>Поверх TCP</td>
|
||
<td>Поверх UDP/QUIC</td>
|
||
</tr>
|
||
<tr>
|
||
<td>TLS-хендшейк отдельно</td>
|
||
<td>TLS 1.3 встроен в QUIC</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Потеря TCP-пакета может блокировать все потоки</td>
|
||
<td>Потеря пакета влияет только на конкретный поток</td>
|
||
</tr>
|
||
<tr>
|
||
<td>Соединение привязано к IP/порту</td>
|
||
<td>QUIC поддерживает connection migration через connection ID</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>HTTP/3 не меняет смысл методов, заголовков и кодов ответа. Меняется
|
||
транспортный слой.</p>
|
||
<h2>Связи</h2>
|
||
<ul>
|
||
<li>TCP vs UDP</li>
|
||
<li>IP-адрес</li>
|
||
<li>DNS</li>
|
||
<li>URI, URL, URN</li>
|
||
<li>Сетевые порты</li>
|
||
</ul>
|
||
</div>
|
||
<p class="back">Назад: <a href="#s-http">HTTP</a> · <a href="#s-http-message">HTTP-запрос/ответ</a> · <a href="#s-https">HTTPS</a> · <a href="#s-http3">HTTP/3</a></p>
|
||
</article>
|
||
|
||
<article class="note full-note" id="d-ports">
|
||
<h3>Сетевые порты</h3>
|
||
<p class="note-source">Полный текст исходной заметки.</p>
|
||
<div class="embedded-note" data-note-title="Сетевые порты">
|
||
<h1>Сетевые порты</h1>
|
||
<p>Сетевой порт — числовой идентификатор процесса или сервиса внутри
|
||
одного IP-адреса. IP-адрес указывает хост, порт указывает приложение на
|
||
этом хосте.</p>
|
||
<h2>Главное</h2>
|
||
<ul>
|
||
<li>Порт — число от <code>0</code> до <code>65535</code>.</li>
|
||
<li>Порты используются транспортными протоколами, прежде всего TCP и
|
||
UDP.</li>
|
||
<li>TCP-порт и UDP-порт с одинаковым номером не конфликтуют: это разные
|
||
пространства портов.</li>
|
||
<li>Для веба важно помнить: HTTP обычно использует TCP <code>80</code>,
|
||
HTTPS — TCP <code>443</code>, альтернативный HTTP часто
|
||
<code>8080</code>.</li>
|
||
</ul>
|
||
<h2>Диапазоны</h2>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 45%" />
|
||
<col style="width: 54%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr>
|
||
<th>Диапазон</th>
|
||
<th>Назначение</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><code>0-1023</code></td>
|
||
<td>Well-known/system ports. В Unix/Linux для привязки к ним обычно
|
||
нужны повышенные права.</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>1024-49151</code></td>
|
||
<td>Registered ports. Могут быть зарегистрированы за службами.</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>49152-65535</code></td>
|
||
<td>Dynamic/private ports. Обычно используются клиентскими приложениями
|
||
временно.</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h2>Частые порты</h2>
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Порт</th>
|
||
<th>Сервис</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><code>21</code></td>
|
||
<td>FTP</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>22</code></td>
|
||
<td>SSH</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>25</code></td>
|
||
<td>SMTP</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>53</code></td>
|
||
<td>DNS</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>80</code></td>
|
||
<td>HTTP</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>110</code></td>
|
||
<td>POP3</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>123</code></td>
|
||
<td>NTP</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>143</code></td>
|
||
<td>IMAP</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>443</code></td>
|
||
<td>HTTPS</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>993</code></td>
|
||
<td>IMAPS</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>3306</code></td>
|
||
<td>MySQL</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>3389</code></td>
|
||
<td>RDP</td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>8080</code></td>
|
||
<td>альтернативный HTTP</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h2>Связи</h2>
|
||
<ul>
|
||
<li>HTTP, HTTPS и HTTP3</li>
|
||
<li>TCP vs UDP</li>
|
||
<li>IP-адрес</li>
|
||
<li>NAT</li>
|
||
</ul>
|
||
</div>
|
||
<p class="back">Назад: <a href="#s-ports">Порты</a></p>
|
||
</article>
|
||
|
||
<article class="note full-note" id="d-auth">
|
||
<h3>Веб-аутентификация и авторизация</h3>
|
||
<p class="note-source">Полный текст исходной заметки.</p>
|
||
<div class="embedded-note" data-note-title="Веб-аутентификация и авторизация">
|
||
<h1>Веб-аутентификация и
|
||
авторизация</h1>
|
||
<p>Идентификация, аутентификация и авторизация — разные этапы контроля
|
||
доступа.</p>
|
||
<h2>Термины</h2>
|
||
<ul>
|
||
<li>Идентификация — пользователь сообщает, кто он: логин, email, номер
|
||
телефона, ID.</li>
|
||
<li>Аутентификация — система проверяет, что пользователь действительно
|
||
тот, за кого себя выдаёт: пароль, одноразовый код, ключ,
|
||
сертификат.</li>
|
||
<li>Авторизация — система решает, что уже аутентифицированному
|
||
пользователю разрешено делать.</li>
|
||
</ul>
|
||
<p>Коротко: идентификация отвечает на вопрос “кто ты?”, аутентификация —
|
||
“докажи”, авторизация — “что тебе можно?”.</p>
|
||
<h2>HTTP-аутентификация</h2>
|
||
<p>Распространённые схемы:</p>
|
||
<ul>
|
||
<li><code>Basic</code> — логин и пароль передаются как base64-строка.
|
||
Base64 не является шифрованием, поэтому Basic нельзя использовать без
|
||
HTTPS для чувствительных данных.</li>
|
||
<li><code>Digest</code> — схема с хешированием, исторически безопаснее
|
||
Basic, но сейчас используется реже.</li>
|
||
<li><code>Bearer</code> — клиент передаёт токен, обычно в заголовке
|
||
<code>Authorization</code>.</li>
|
||
</ul>
|
||
<p>Пример Bearer:</p>
|
||
<pre class="http"><code>Authorization: Bearer eyJhbGciOi...</code></pre>
|
||
<p>Bearer-токен даёт доступ тому, кто им владеет. Поэтому токены нужно
|
||
хранить аккуратно, ограничивать срок их жизни и уметь отзывать.</p>
|
||
<h2>Связи</h2>
|
||
<ul>
|
||
<li>OAuth 2.0</li>
|
||
<li>HTTP, HTTPS и HTTP3</li>
|
||
</ul>
|
||
</div>
|
||
<p class="back">Назад: <a href="#s-auth">Идентификация/auth</a></p>
|
||
</article>
|
||
|
||
<article class="note full-note" id="d-oauth">
|
||
<h3>OAuth 2.0</h3>
|
||
<p class="note-source">Полный текст исходной заметки.</p>
|
||
<div class="embedded-note" data-note-title="OAuth 2.0">
|
||
<h1>OAuth 2.0</h1>
|
||
<p>OAuth 2.0 — протокол авторизации, который позволяет приложению
|
||
получить ограниченный доступ к ресурсам пользователя на другом сервисе
|
||
без передачи пароля пользователя этому приложению.</p>
|
||
<h2>Где встречается</h2>
|
||
<ul>
|
||
<li>вход на сайт через Google, GitHub, VK или другую внешнюю учётную
|
||
запись;</li>
|
||
<li>мобильное приложение получает доступ к данным в облаке;</li>
|
||
<li>бот или интеграция получает доступ к API сервиса.</li>
|
||
</ul>
|
||
<h2>Главная идея</h2>
|
||
<p>Пользователь подтверждает доступ на стороне сервиса-владельца данных.
|
||
Клиентское приложение получает токен и использует его для запросов к
|
||
API.</p>
|
||
<p>Пароль пользователя при этом остаётся у сервиса-источника, а
|
||
стороннее приложение получает только ограниченное разрешение.</p>
|
||
<h2>Участники</h2>
|
||
<ul>
|
||
<li>Resource Owner — владелец ресурса, обычно пользователь.</li>
|
||
<li>Client — приложение, которому нужен доступ.</li>
|
||
<li>Authorization Server — сервер, который выдаёт токены.</li>
|
||
<li>Resource Server — API, который принимает токен и отдаёт защищённые
|
||
данные.</li>
|
||
</ul>
|
||
<h2>Токены</h2>
|
||
<ul>
|
||
<li>Access token — используется для доступа к API.</li>
|
||
<li>Refresh token — используется для получения нового access token без
|
||
повторного входа пользователя.</li>
|
||
<li>Scope — набор разрешений, ограничивающий действия клиента.</li>
|
||
</ul>
|
||
<p>OAuth 2.0 — про авторизацию. Сам по себе он не обязан доказывать
|
||
личность пользователя как протокол аутентификации; для входа поверх
|
||
OAuth обычно используют OpenID Connect.</p>
|
||
<h2>Связи</h2>
|
||
<ul>
|
||
<li>Веб-аутентификация и авторизация</li>
|
||
<li>HTTP, HTTPS и HTTP3</li>
|
||
</ul>
|
||
</div>
|
||
<p class="back">Назад: <a href="#s-oauth">OAuth 2.0</a></p>
|
||
</article>
|
||
|
||
<article class="note full-note" id="d-uri">
|
||
<h3>URI, URL, URN</h3>
|
||
<p class="note-source">Полный текст исходной заметки.</p>
|
||
<div class="embedded-note" data-note-title="URI, URL, URN">
|
||
<h1>URI, URL, URN</h1>
|
||
<p>URI, URL и URN — способы идентифицировать ресурс. Для экзамена важно
|
||
различать: URL указывает, где и как получить ресурс; URN даёт устойчивое
|
||
имя; URI — общее понятие.</p>
|
||
<h2>URL</h2>
|
||
<p>URL (Uniform Resource Locator) — адрес ресурса в сети и способ его
|
||
получения.</p>
|
||
<p>Синтаксис:</p>
|
||
<pre class="text"><code>схема://хост:порт/путь?параметры#фрагмент</code></pre>
|
||
<p>Пример:</p>
|
||
<pre class="text"><code>https://home.mephi.ru/study_groups?level=1&organization_id=1&term_id=20</code></pre>
|
||
<p>Компоненты:</p>
|
||
<ul>
|
||
<li>схема — чаще всего <code>http</code> или <code>https</code>;</li>
|
||
<li>хост — домен или IP-адрес;</li>
|
||
<li>порт — необязателен, если используется порт по умолчанию;</li>
|
||
<li>путь — расположение ресурса на сервере;</li>
|
||
<li>query string — параметры после <code>?</code>;</li>
|
||
<li>фрагмент — часть документа после <code>#</code>, часто соответствует
|
||
<code>id</code> HTML-элемента.</li>
|
||
</ul>
|
||
<h2>URN</h2>
|
||
<p>URN (Uniform Resource Name) — имя ресурса без указания его сетевого
|
||
расположения.</p>
|
||
<p>Синтаксис:</p>
|
||
<pre class="text"><code>urn:NID:NSS</code></pre>
|
||
<p>Пример:</p>
|
||
<pre class="text"><code>urn:uuid:d5aa821e-52bb-4f7e-a782-7662ed5eaf5c</code></pre>
|
||
<p>URN полезен, когда ресурс должен сохранять идентичность независимо от
|
||
места хранения. Пример: ISBN книги.</p>
|
||
<h2>URI</h2>
|
||
<p>URI (Uniform Resource Identifier) — общий идентификатор ресурса. URI
|
||
может быть URL, URN или совмещать оба подхода.</p>
|
||
<p>Синтаксис:</p>
|
||
<pre class="text"><code>схема:[//[пользователь:пароль@]хост[:порт]][/]путь[?запрос][#фрагмент]</code></pre>
|
||
<p>Главное правило: все URL являются URI, но не все URI являются
|
||
URL.</p>
|
||
<h2>Связи</h2>
|
||
<ul>
|
||
<li>HTTP, HTTPS и HTTP3</li>
|
||
<li>DNS</li>
|
||
<li>IP-адрес</li>
|
||
</ul>
|
||
</div>
|
||
<p class="back">Назад: <a href="#s-uri">URI, URL, URN</a></p>
|
||
</article>
|
||
|
||
<article class="note full-note" id="d-html">
|
||
<h3>Основы HTML и HTML Forms</h3>
|
||
<p class="note-source">Полный текст исходной заметки.</p>
|
||
<div class="embedded-note" data-note-title="Основы HTML (структура, таблицы, формы)">
|
||
<h1>Основы HTML</h1>
|
||
<p><strong>HTML (Hypertext Markup Language)</strong> — язык разметки для
|
||
структурирования и отображения веб-страниц.</p>
|
||
<h2>Структура HTML-документа</h2>
|
||
<p>Базовый шаблон (HTML5):</p>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode html"><code class="sourceCode html"><span><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="dt"><!DOCTYPE</span> html<span class="dt">></span></span>
|
||
<span><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">html</span><span class="ot"> lang</span><span class="op">=</span><span class="st">"ru"</span><span class="dt">></span></span>
|
||
<span><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">head</span><span class="dt">></span></span>
|
||
<span><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">meta</span><span class="ot"> charset</span><span class="op">=</span><span class="st">"UTF-8"</span><span class="dt">></span></span>
|
||
<span><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">meta</span><span class="ot"> name</span><span class="op">=</span><span class="st">"viewport"</span><span class="ot"> content</span><span class="op">=</span><span class="st">"width=device-width, initial-scale=1.0"</span><span class="dt">></span></span>
|
||
<span><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">title</span><span class="dt">></span>Заголовок страницы<span class="dt"></</span><span class="kw">title</span><span class="dt">></span></span>
|
||
<span><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="dt"></</span><span class="kw">head</span><span class="dt">></span></span>
|
||
<span><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">body</span><span class="dt">></span></span>
|
||
<span><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a> <span class="co"><!-- Контент страницы --></span></span>
|
||
<span><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="dt"></</span><span class="kw">body</span><span class="dt">></span></span>
|
||
<span><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="dt"></</span><span class="kw">html</span><span class="dt">></span></span></code></pre></div>
|
||
<ul>
|
||
<li><code><!DOCTYPE html></code> — объявление типа документа.</li>
|
||
<li><code><head></code> — метаданные (не отображаются в
|
||
браузере).</li>
|
||
<li><code><body></code> — основное содержимое.</li>
|
||
</ul>
|
||
<h3>Метатег Viewport</h3>
|
||
<p>Критичен для мобильных устройств. Позволяет контролировать
|
||
масштаб.</p>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode html"><code class="sourceCode html"><span><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">meta</span><span class="ot"> name</span><span class="op">=</span><span class="st">"viewport"</span><span class="ot"> content</span><span class="op">=</span><span class="st">"width=device-width, initial-scale=1.0"</span><span class="dt">></span></span></code></pre></div>
|
||
<h2>Основные теги и семантика</h2>
|
||
<p><strong>Тег</strong> — элемент разметки, который говорит браузеру,
|
||
что находится на странице: заголовок, абзац, ссылка, форма, таблица.</p>
|
||
<p>Обычно тег состоит из открывающей и закрывающей части:</p>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode html"><code class="sourceCode html"><span><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">p</span><span class="dt">></span>Текст абзаца<span class="dt"></</span><span class="kw">p</span><span class="dt">></span></span></code></pre></div>
|
||
<p>Некоторые теги не имеют закрывающей пары:</p>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode html"><code class="sourceCode html"><span><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">img</span><span class="ot"> src</span><span class="op">=</span><span class="st">"cat.jpg"</span><span class="ot"> alt</span><span class="op">=</span><span class="st">"Кот"</span><span class="dt">></span></span>
|
||
<span><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">br</span><span class="dt">></span></span>
|
||
<span><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">input</span><span class="ot"> type</span><span class="op">=</span><span class="st">"email"</span><span class="ot"> name</span><span class="op">=</span><span class="st">"email"</span><span class="dt">></span></span></code></pre></div>
|
||
<p><strong>Атрибуты</strong> уточняют поведение тега: -
|
||
<code>href</code> — адрес ссылки. - <code>src</code> — путь к
|
||
изображению или файлу. - <code>alt</code> — текстовое описание
|
||
изображения. - <code>class</code> — CSS-класс для стилизации. -
|
||
<code>id</code> — уникальный идентификатор элемента. - <code>name</code>
|
||
— имя поля формы, с которым данные отправляются на сервер.</p>
|
||
<h3>Блочные и строчные элементы</h3>
|
||
<ul>
|
||
<li><strong>Блочные элементы</strong> занимают всю доступную ширину и
|
||
обычно начинаются с новой строки: <code><div></code>,
|
||
<code><p></code>, <code><h1></code>,
|
||
<code><section></code>, <code><form></code>.</li>
|
||
<li><strong>Строчные элементы</strong> находятся внутри строки текста и
|
||
не ломают поток: <code><span></code>, <code><a></code>,
|
||
<code><strong></code>, <code><em></code>,
|
||
<code><code></code>.</li>
|
||
</ul>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode html"><code class="sourceCode html"><span><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">p</span><span class="dt">></span></span>
|
||
<span><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a> Это абзац с <span class="dt"><</span><span class="kw">strong</span><span class="dt">></span>важным текстом<span class="dt"></</span><span class="kw">strong</span><span class="dt">></span> и</span>
|
||
<span><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">a</span><span class="ot"> href</span><span class="op">=</span><span class="st">"/about/"</span><span class="dt">></span>ссылкой<span class="dt"></</span><span class="kw">a</span><span class="dt">></span>.</span>
|
||
<span><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="dt"></</span><span class="kw">p</span><span class="dt">></span></span></code></pre></div>
|
||
<h3>Семантические теги</h3>
|
||
<p>Семантика — это использование тегов по смыслу, а не только ради
|
||
внешнего вида.</p>
|
||
<p>Например, <code><main></code> означает главный контент
|
||
страницы, <code><nav></code> — навигацию,
|
||
<code><article></code> — самостоятельный материал. Это помогает
|
||
браузеру, поисковым системам, скринридерам и другим инструментам лучше
|
||
понимать структуру страницы.</p>
|
||
<ul>
|
||
<li><code><header></code> — верхняя часть страницы или секции:
|
||
логотип, заголовок, навигация.</li>
|
||
<li><code><nav></code> — блок навигационных ссылок.</li>
|
||
<li><code><main></code> — основной контент страницы; обычно один
|
||
на страницу.</li>
|
||
<li><code><section></code> — смысловой раздел страницы.</li>
|
||
<li><code><article></code> — самостоятельный материал: статья,
|
||
пост, карточка новости.</li>
|
||
<li><code><aside></code> — дополнительный контент: боковая панель,
|
||
подсказки, связанные ссылки.</li>
|
||
<li><code><footer></code> — нижняя часть страницы или секции.</li>
|
||
</ul>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode html"><code class="sourceCode html"><span><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">body</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">header</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">h1</span><span class="dt">></span>Блог<span class="dt"></</span><span class="kw">h1</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">nav</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">a</span><span class="ot"> href</span><span class="op">=</span><span class="st">"/"</span><span class="dt">></span>Главная<span class="dt"></</span><span class="kw">a</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">a</span><span class="ot"> href</span><span class="op">=</span><span class="st">"/about/"</span><span class="dt">></span>О проекте<span class="dt"></</span><span class="kw">a</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a> <span class="dt"></</span><span class="kw">nav</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a> <span class="dt"></</span><span class="kw">header</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">main</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">article</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">h2</span><span class="dt">></span>Что такое HTML<span class="dt"></</span><span class="kw">h2</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">p</span><span class="dt">></span>HTML описывает структуру веб-страницы.<span class="dt"></</span><span class="kw">p</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a> <span class="dt"></</span><span class="kw">article</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">aside</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">h2</span><span class="dt">></span>Похожие материалы<span class="dt"></</span><span class="kw">h2</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">a</span><span class="ot"> href</span><span class="op">=</span><span class="st">"/css/"</span><span class="dt">></span>Основы CSS<span class="dt"></</span><span class="kw">a</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-19" aria-hidden="true" tabindex="-1"></a> <span class="dt"></</span><span class="kw">aside</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-20" aria-hidden="true" tabindex="-1"></a> <span class="dt"></</span><span class="kw">main</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-21" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb6-22" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">footer</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-23" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">p</span><span class="dt">></span>2026<span class="dt"></</span><span class="kw">p</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-24" aria-hidden="true" tabindex="-1"></a> <span class="dt"></</span><span class="kw">footer</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-25" aria-hidden="true" tabindex="-1"></a><span class="dt"></</span><span class="kw">body</span><span class="dt">></span></span></code></pre></div>
|
||
<p>Неправильно заменять всё на <code><div></code>, если есть более
|
||
точный тег. <code><div></code> нужен как нейтральный контейнер,
|
||
когда у блока нет отдельного смыслового значения.</p>
|
||
<h3>Текст и форматирование</h3>
|
||
<ul>
|
||
<li><strong>Заголовки:</strong>
|
||
<code><h1></code>…<code><h6></code>.</li>
|
||
<li><strong>Абзацы и переносы:</strong> <code><p></code>,
|
||
<code><br></code>.</li>
|
||
<li><strong>Логическое выделение:</strong> <code><strong></code>
|
||
(важное, жирный), <code><em></code> (акцент, курсив),
|
||
<code><code></code> (код).</li>
|
||
<li><strong>Контейнеры:</strong> <code><div></code> (блочный),
|
||
<code><span></code> (строчный).</li>
|
||
</ul>
|
||
<h3>Списки</h3>
|
||
<ul>
|
||
<li><strong>Маркированный:</strong> <code><ul></code> +
|
||
<code><li></code>.</li>
|
||
<li><strong>Нумерованный:</strong> <code><ol></code> +
|
||
<code><li></code>.</li>
|
||
</ul>
|
||
<h3>Ссылки и изображения</h3>
|
||
<ul>
|
||
<li><strong>Ссылка:</strong>
|
||
<code><a href="URL" target="_blank">Текст</a></code>.</li>
|
||
<li><strong>Изображение:</strong>
|
||
<code><img src="./path" alt="описание" width="500"></code>.</li>
|
||
</ul>
|
||
<hr />
|
||
<h2>Таблицы</h2>
|
||
<p>Используются для отображения структурированных данных. Не
|
||
рекомендуются для верстки макета.</p>
|
||
<p><strong>Структура таблицы:</strong></p>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode html"><code class="sourceCode html"><span><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">table</span><span class="dt">></span></span>
|
||
<span><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">caption</span><span class="dt">></span>Заголовок таблицы<span class="dt"></</span><span class="kw">caption</span><span class="dt">></span></span>
|
||
<span><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">thead</span><span class="dt">></span></span>
|
||
<span><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">tr</span><span class="dt">></span></span>
|
||
<span><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">th</span><span class="dt">></span>Заголовок столбца 1<span class="dt"></</span><span class="kw">th</span><span class="dt">></span></span>
|
||
<span><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">th</span><span class="dt">></span>Заголовок столбца 2<span class="dt"></</span><span class="kw">th</span><span class="dt">></span></span>
|
||
<span><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a> <span class="dt"></</span><span class="kw">tr</span><span class="dt">></span></span>
|
||
<span><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a> <span class="dt"></</span><span class="kw">thead</span><span class="dt">></span></span>
|
||
<span><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">tbody</span><span class="dt">></span></span>
|
||
<span><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">tr</span><span class="dt">></span></span>
|
||
<span><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">td</span><span class="dt">></span>Данные 1<span class="dt"></</span><span class="kw">td</span><span class="dt">></span></span>
|
||
<span><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">td</span><span class="dt">></span>Данные 2<span class="dt"></</span><span class="kw">td</span><span class="dt">></span></span>
|
||
<span><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a> <span class="dt"></</span><span class="kw">tr</span><span class="dt">></span></span>
|
||
<span><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a> <span class="dt"></</span><span class="kw">tbody</span><span class="dt">></span></span>
|
||
<span><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">tfoot</span><span class="dt">></span></span>
|
||
<span><a href="#cb7-16" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">tr</span><span class="dt">></span></span>
|
||
<span><a href="#cb7-17" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">td</span><span class="dt">></span>Итог 1<span class="dt"></</span><span class="kw">td</span><span class="dt">></span></span>
|
||
<span><a href="#cb7-18" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">td</span><span class="dt">></span>Итог 2<span class="dt"></</span><span class="kw">td</span><span class="dt">></span></span>
|
||
<span><a href="#cb7-19" aria-hidden="true" tabindex="-1"></a> <span class="dt"></</span><span class="kw">tr</span><span class="dt">></span></span>
|
||
<span><a href="#cb7-20" aria-hidden="true" tabindex="-1"></a> <span class="dt"></</span><span class="kw">tfoot</span><span class="dt">></span></span>
|
||
<span><a href="#cb7-21" aria-hidden="true" tabindex="-1"></a><span class="dt"></</span><span class="kw">table</span><span class="dt">></span></span></code></pre></div>
|
||
<ul>
|
||
<li><strong>Объединение ячеек:</strong> <code>colspan</code> (по
|
||
горизонтали), <code>rowspan</code> (по вертикали).</li>
|
||
</ul>
|
||
<hr />
|
||
<h2>Формы</h2>
|
||
<p>Инструмент для сбора данных пользователя.</p>
|
||
<p><strong>Базовая форма:</strong></p>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode html"><code class="sourceCode html"><span><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">form</span><span class="ot"> action</span><span class="op">=</span><span class="st">"/handler-url/"</span><span class="ot"> method</span><span class="op">=</span><span class="st">"post"</span><span class="dt">></span></span>
|
||
<span><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">label</span><span class="ot"> for</span><span class="op">=</span><span class="st">"username"</span><span class="dt">></span>Имя:<span class="dt"></</span><span class="kw">label</span><span class="dt">></span></span>
|
||
<span><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">input</span><span class="ot"> type</span><span class="op">=</span><span class="st">"text"</span><span class="ot"> id</span><span class="op">=</span><span class="st">"username"</span><span class="ot"> name</span><span class="op">=</span><span class="st">"name"</span><span class="ot"> placeholder</span><span class="op">=</span><span class="st">"Введите имя"</span><span class="dt">></span></span>
|
||
<span><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a> </span>
|
||
<span><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">button</span><span class="ot"> type</span><span class="op">=</span><span class="st">"submit"</span><span class="dt">></span>Отправить<span class="dt"></</span><span class="kw">button</span><span class="dt">></span></span>
|
||
<span><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a><span class="dt"></</span><span class="kw">form</span><span class="dt">></span></span></code></pre></div>
|
||
<h3>Элементы управления:</h3>
|
||
<ul>
|
||
<li><code><input></code> — универсальное поле ввода. Поведение
|
||
зависит от <code>type</code>.</li>
|
||
<li><code><select></code> + <code><option></code> —
|
||
выпадающий список.</li>
|
||
<li><code><textarea></code> — многострочное поле для текста.</li>
|
||
<li><code><button></code> — кнопка отправки, сброса или обычного
|
||
действия.</li>
|
||
<li><code><fieldset></code> + <code><legend></code> —
|
||
группировка связанных полей с заголовком группы.</li>
|
||
</ul>
|
||
<p>Основные <code>type</code> для <code><input></code>: -
|
||
<code>text</code> — обычная строка. - <code>password</code> — поле
|
||
пароля, символы скрываются. - <code>email</code> — email; браузер
|
||
проверяет базовый формат адреса. - <code>number</code> — числовой ввод.
|
||
- <code>checkbox</code> — независимый флажок: можно выбрать несколько
|
||
вариантов. - <code>radio</code> — выбор одного варианта из группы с
|
||
одинаковым <code>name</code>. - <code>file</code> — загрузка файла. -
|
||
<code>date</code> — выбор даты. - <code>hidden</code> — скрытое поле, не
|
||
видно пользователю, но отправляется с формой.</p>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode html"><code class="sourceCode html"><span><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">label</span><span class="ot"> for</span><span class="op">=</span><span class="st">"email"</span><span class="dt">></span>Email:<span class="dt"></</span><span class="kw">label</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">input</span><span class="ot"> type</span><span class="op">=</span><span class="st">"email"</span><span class="ot"> id</span><span class="op">=</span><span class="st">"email"</span><span class="ot"> name</span><span class="op">=</span><span class="st">"email"</span><span class="ot"> required</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">label</span><span class="ot"> for</span><span class="op">=</span><span class="st">"age"</span><span class="dt">></span>Возраст:<span class="dt"></</span><span class="kw">label</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">input</span><span class="ot"> type</span><span class="op">=</span><span class="st">"number"</span><span class="ot"> id</span><span class="op">=</span><span class="st">"age"</span><span class="ot"> name</span><span class="op">=</span><span class="st">"age"</span><span class="ot"> min</span><span class="op">=</span><span class="st">"18"</span><span class="ot"> max</span><span class="op">=</span><span class="st">"99"</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">label</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">input</span><span class="ot"> type</span><span class="op">=</span><span class="st">"checkbox"</span><span class="ot"> name</span><span class="op">=</span><span class="st">"agreement"</span><span class="ot"> required</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a> Согласен с условиями</span>
|
||
<span><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a><span class="dt"></</span><span class="kw">label</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">fieldset</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">legend</span><span class="dt">></span>Способ связи<span class="dt"></</span><span class="kw">legend</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-14" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb9-15" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">label</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-16" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">input</span><span class="ot"> type</span><span class="op">=</span><span class="st">"radio"</span><span class="ot"> name</span><span class="op">=</span><span class="st">"contact_method"</span><span class="ot"> value</span><span class="op">=</span><span class="st">"email"</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-17" aria-hidden="true" tabindex="-1"></a> Email</span>
|
||
<span><a href="#cb9-18" aria-hidden="true" tabindex="-1"></a> <span class="dt"></</span><span class="kw">label</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-19" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb9-20" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">label</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-21" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">input</span><span class="ot"> type</span><span class="op">=</span><span class="st">"radio"</span><span class="ot"> name</span><span class="op">=</span><span class="st">"contact_method"</span><span class="ot"> value</span><span class="op">=</span><span class="st">"phone"</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-22" aria-hidden="true" tabindex="-1"></a> Телефон</span>
|
||
<span><a href="#cb9-23" aria-hidden="true" tabindex="-1"></a> <span class="dt"></</span><span class="kw">label</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-24" aria-hidden="true" tabindex="-1"></a><span class="dt"></</span><span class="kw">fieldset</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-25" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb9-26" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">label</span><span class="ot"> for</span><span class="op">=</span><span class="st">"city"</span><span class="dt">></span>Город:<span class="dt"></</span><span class="kw">label</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-27" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">select</span><span class="ot"> id</span><span class="op">=</span><span class="st">"city"</span><span class="ot"> name</span><span class="op">=</span><span class="st">"city"</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-28" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">option</span><span class="ot"> value</span><span class="op">=</span><span class="st">"moscow"</span><span class="dt">></span>Москва<span class="dt"></</span><span class="kw">option</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-29" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">option</span><span class="ot"> value</span><span class="op">=</span><span class="st">"spb"</span><span class="dt">></span>Санкт-Петербург<span class="dt"></</span><span class="kw">option</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-30" aria-hidden="true" tabindex="-1"></a><span class="dt"></</span><span class="kw">select</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-31" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb9-32" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">label</span><span class="ot"> for</span><span class="op">=</span><span class="st">"comment"</span><span class="dt">></span>Комментарий:<span class="dt"></</span><span class="kw">label</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-33" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">textarea</span><span class="ot"> id</span><span class="op">=</span><span class="st">"comment"</span><span class="ot"> name</span><span class="op">=</span><span class="st">"comment"</span><span class="ot"> rows</span><span class="op">=</span><span class="st">"5"</span><span class="dt">></</span><span class="kw">textarea</span><span class="dt">></span></span></code></pre></div>
|
||
<h3>Атрибуты валидации:</h3>
|
||
<ul>
|
||
<li><code>required</code> — поле обязательно для заполнения.</li>
|
||
<li><code>minlength</code> — минимальная длина текста.</li>
|
||
<li><code>maxlength</code> — максимальная длина текста.</li>
|
||
<li><code>min</code> — минимальное значение для числа или даты.</li>
|
||
<li><code>max</code> — максимальное значение для числа или даты.</li>
|
||
<li><code>pattern</code> — регулярное выражение, которому должно
|
||
соответствовать значение.</li>
|
||
<li><code>type="email"</code> — проверяет, что введён текст, похожий на
|
||
email.</li>
|
||
<li><code>type="url"</code> — проверяет, что введён URL.</li>
|
||
</ul>
|
||
<p>HTML-валидация работает в браузере до отправки формы. Она удобна для
|
||
пользователя, но не заменяет проверку на сервере: данные можно отправить
|
||
в обход браузера.</p>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode html"><code class="sourceCode html"><span><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">form</span><span class="ot"> action</span><span class="op">=</span><span class="st">"/register/"</span><span class="ot"> method</span><span class="op">=</span><span class="st">"post"</span><span class="dt">></span></span>
|
||
<span><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">label</span><span class="ot"> for</span><span class="op">=</span><span class="st">"username"</span><span class="dt">></span>Логин:<span class="dt"></</span><span class="kw">label</span><span class="dt">></span></span>
|
||
<span><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">input</span></span>
|
||
<span><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="ot"> type</span><span class="op">=</span><span class="st">"text"</span></span>
|
||
<span><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="ot"> id</span><span class="op">=</span><span class="st">"username"</span></span>
|
||
<span><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="ot"> name</span><span class="op">=</span><span class="st">"username"</span></span>
|
||
<span><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a><span class="ot"> required</span></span>
|
||
<span><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a><span class="ot"> minlength</span><span class="op">=</span><span class="st">"3"</span></span>
|
||
<span><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a><span class="ot"> maxlength</span><span class="op">=</span><span class="st">"20"</span></span>
|
||
<span><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a><span class="ot"> pattern</span><span class="op">=</span><span class="st">"[a-zA-Z0-9_]+"</span></span>
|
||
<span><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a><span class="ot"> </span><span class="dt">></span></span>
|
||
<span><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">label</span><span class="ot"> for</span><span class="op">=</span><span class="st">"email"</span><span class="dt">></span>Email:<span class="dt"></</span><span class="kw">label</span><span class="dt">></span></span>
|
||
<span><a href="#cb10-14" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">input</span><span class="ot"> type</span><span class="op">=</span><span class="st">"email"</span><span class="ot"> id</span><span class="op">=</span><span class="st">"email"</span><span class="ot"> name</span><span class="op">=</span><span class="st">"email"</span><span class="ot"> required</span><span class="dt">></span></span>
|
||
<span><a href="#cb10-15" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb10-16" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">label</span><span class="ot"> for</span><span class="op">=</span><span class="st">"age"</span><span class="dt">></span>Возраст:<span class="dt"></</span><span class="kw">label</span><span class="dt">></span></span>
|
||
<span><a href="#cb10-17" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">input</span><span class="ot"> type</span><span class="op">=</span><span class="st">"number"</span><span class="ot"> id</span><span class="op">=</span><span class="st">"age"</span><span class="ot"> name</span><span class="op">=</span><span class="st">"age"</span><span class="ot"> min</span><span class="op">=</span><span class="st">"18"</span><span class="ot"> max</span><span class="op">=</span><span class="st">"99"</span><span class="dt">></span></span>
|
||
<span><a href="#cb10-18" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb10-19" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">button</span><span class="ot"> type</span><span class="op">=</span><span class="st">"submit"</span><span class="dt">></span>Зарегистрироваться<span class="dt"></</span><span class="kw">button</span><span class="dt">></span></span>
|
||
<span><a href="#cb10-20" aria-hidden="true" tabindex="-1"></a><span class="dt"></</span><span class="kw">form</span><span class="dt">></span></span></code></pre></div>
|
||
</div>
|
||
<p class="back">Назад: <a href="#block-2">HTML</a> · <a href="#block-3">HTML Forms</a></p>
|
||
</article>
|
||
|
||
<article class="note full-note" id="d-css">
|
||
<h3>CSS: основы, селекторы и блочная модель</h3>
|
||
<p class="note-source">Полный текст исходной заметки.</p>
|
||
<div class="embedded-note" data-note-title="Основы, селекторы и блочная модель">
|
||
<h1>CSS: Основы и селекторы</h1>
|
||
<p><strong>CSS (Cascading Style Sheets)</strong> — язык таблиц стилей
|
||
для оформления HTML-документов.</p>
|
||
<h2>Подключение CSS</h2>
|
||
<ol type="1">
|
||
<li><strong>Внешняя таблица:</strong>
|
||
<code><link rel="stylesheet" href="style.css"></code>.</li>
|
||
<li><strong>Внутренние стили:</strong> Тег <code><style></code> в
|
||
<code><head></code>.</li>
|
||
<li><strong>Встроенные (inline) стили:</strong> Атрибут
|
||
<code>style</code> у тега.</li>
|
||
</ol>
|
||
<h2>Селекторы</h2>
|
||
<ul>
|
||
<li><strong>Универсальный:</strong> <code>*</code> — все элементы.</li>
|
||
<li><strong>По тегу:</strong> <code>h1</code>, <code>p</code>.</li>
|
||
<li><strong>По классу:</strong> <code>.className</code>.</li>
|
||
<li><strong>По ID:</strong> <code>#idName</code>.</li>
|
||
<li><strong>Потомки:</strong> <code>div p</code> (все <code>p</code>
|
||
внутри <code>div</code>).</li>
|
||
<li><strong>Дочерние:</strong> <code>div > p</code> (только прямые
|
||
наследники).</li>
|
||
<li><strong>Соседние:</strong> <code>h1 + p</code> (первый
|
||
<code>p</code> после <code>h1</code>).</li>
|
||
<li><strong>По атрибуту:</strong> <code>a[href^="https://"]</code>.</li>
|
||
</ul>
|
||
<h3>Псевдоклассы и
|
||
псевдоэлементы</h3>
|
||
<ul>
|
||
<li><code>:hover</code>, <code>:focus</code>, <code>:active</code>.</li>
|
||
<li><code>:nth-child(odd/even/n)</code>.</li>
|
||
<li><code>::before</code>, <code>::after</code> (используются с
|
||
<code>content</code>).</li>
|
||
</ul>
|
||
<h2>Каскадность и Специфичность</h2>
|
||
<p>Если правила конфликтуют, побеждает то, у которого выше
|
||
специфичность: 1. Inline стили (1, 0, 0, 0) 2. ID (0, 1, 0, 0) 3.
|
||
Классы, атрибуты, псевдоклассы (0, 0, 1, 0) 4. Теги и псевдоэлементы (0,
|
||
0, 0, 1)</p>
|
||
<hr />
|
||
<h1>Блочная модель (Box Model)</h1>
|
||
<p>Каждый элемент в CSS — это прямоугольный блок.</p>
|
||
<ul>
|
||
<li><strong>Content:</strong> Содержимое (текст, изображение).</li>
|
||
<li><strong>Padding:</strong> Внутренние поля (между контентом и
|
||
рамкой).</li>
|
||
<li><strong>Border:</strong> Рамка.</li>
|
||
<li><strong>Margin:</strong> Внешние отступы (между рамкой и
|
||
соседями).</li>
|
||
</ul>
|
||
<h2>Box-sizing</h2>
|
||
<ul>
|
||
<li><code>content-box</code> (по умолчанию): <code>width</code> задает
|
||
только ширину контента.</li>
|
||
<li><code>border-box</code>: <code>width</code> включает в себя
|
||
<code>padding</code> и <code>border</code>.</li>
|
||
</ul>
|
||
<h1>Свойство display</h1>
|
||
<ul>
|
||
<li><code>block</code>: Занимает всю ширину, начинается с новой
|
||
строки.</li>
|
||
<li><code>inline</code>: Ширина по контенту, не позволяет задавать
|
||
<code>width/height</code>.</li>
|
||
<li><code>inline-block</code>: Строчный элемент, но с возможностью
|
||
задавать размеры и отступы.</li>
|
||
<li><code>none</code>: Убирает элемент из документа.</li>
|
||
</ul>
|
||
<hr />
|
||
<h1>Базовые свойства оформления</h1>
|
||
<h2>Текст и шрифты</h2>
|
||
<ul>
|
||
<li><code>font-family</code>, <code>font-size</code>,
|
||
<code>font-weight</code>.</li>
|
||
<li><code>text-align</code>, <code>text-transform</code>
|
||
(<code>uppercase</code>, <code>capitalize</code>).</li>
|
||
<li><code>text-decoration</code> (<code>underline</code>,
|
||
<code>none</code>).</li>
|
||
<li><code>line-height</code>, <code>letter-spacing</code>.</li>
|
||
</ul>
|
||
<h2>Фон (Background)</h2>
|
||
<ul>
|
||
<li><code>background-color</code>.</li>
|
||
<li><code>background-image: url(...)</code>.</li>
|
||
<li><code>background-size: cover / contain</code>.</li>
|
||
<li><code>background-repeat: no-repeat</code>.</li>
|
||
<li><code>background-position: center</code>.</li>
|
||
</ul>
|
||
<h2>Границы и тени</h2>
|
||
<ul>
|
||
<li><code>border: 1px solid black;</code>.</li>
|
||
<li><code>border-radius: 5px;</code> (скругление углов).</li>
|
||
<li><code>box-shadow: x y blur spread color;</code>.</li>
|
||
<li><code>transition: 0.3s;</code> (плавные переходы).</li>
|
||
</ul>
|
||
</div>
|
||
<p class="back">Назад: <a href="#block-4">CSS</a></p>
|
||
</article>
|
||
|
||
<article class="note full-note" id="d-layout">
|
||
<h3>Адаптивность, Flexbox и Grid</h3>
|
||
<p class="note-source">Полный текст исходной заметки.</p>
|
||
<div class="embedded-note" data-note-title="Адаптивность, Flexbox и Grid">
|
||
<h1>Адаптивная верстка</h1>
|
||
<p>Адаптивность (AWD) и отзывчивость (RWD) позволяют сайту корректно
|
||
отображаться на любых устройствах.</p>
|
||
<h2>Медиазапросы (<span class="citation"
|
||
data-cites="media">@media</span>)</h2>
|
||
<p>Синтаксис:</p>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode css"><code class="sourceCode css"><span><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="im">@media</span> <span class="an">screen</span> <span class="kw">and</span> <span class="fu">(</span><span class="kw">max-width</span><span class="ch">:</span> <span class="dv">768</span><span class="dt">px</span><span class="fu">)</span> {</span>
|
||
<span><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> <span class="co">/* Стили для планшетов и телефонов */</span></span>
|
||
<span><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
|
||
<ul>
|
||
<li><strong>Mobile First:</strong> Сначала стили для мобильных, затем
|
||
<code>min-width</code>.</li>
|
||
<li><strong>Desktop First:</strong> Сначала для десктопов, затем
|
||
<code>max-width</code>.</li>
|
||
</ul>
|
||
<hr />
|
||
<h1>Flexbox (Flexible Box Layout)</h1>
|
||
<p>Одномерная модель раскладки (по одной оси).</p>
|
||
<ul>
|
||
<li><strong>Контейнер:</strong> <code>display: flex;</code> /
|
||
<code>inline-flex;</code>.</li>
|
||
<li><strong>Направление:</strong>
|
||
<code>flex-direction: row | column | row-reverse</code>.</li>
|
||
<li><strong>Перенос:</strong>
|
||
<code>flex-wrap: wrap | nowrap</code>.</li>
|
||
<li><strong>Выравнивание по главной оси:</strong>
|
||
<code>justify-content: flex-start | center | space-between | space-around</code>.</li>
|
||
<li><strong>Выравнивание по поперечной оси:</strong>
|
||
<code>align-items: center | stretch</code>.</li>
|
||
<li><strong>Свойства элементов:</strong>
|
||
<ul>
|
||
<li><code>flex-grow</code> (коэффициент роста),</li>
|
||
<li><code>flex-shrink</code> (сжатие),</li>
|
||
<li><code>flex-basis</code> (базовый размер),</li>
|
||
<li><code>order</code> (порядок отображения).</li>
|
||
</ul></li>
|
||
</ul>
|
||
<hr />
|
||
<h1>Grid Layout</h1>
|
||
<p>Двумерная модель раскладки (строки + столбцы).</p>
|
||
<ul>
|
||
<li><strong>Контейнер:</strong> <code>display: grid;</code>.</li>
|
||
<li><strong>Определение сетки:</strong>
|
||
<ul>
|
||
<li><code>grid-template-columns: repeat(3, 1fr);</code> (3 колонки
|
||
равной ширины).</li>
|
||
<li><code>grid-template-rows: auto 1fr;</code>.</li>
|
||
</ul></li>
|
||
<li><strong>Единица fr:</strong> Доля свободного пространства.</li>
|
||
<li><strong>Отступы:</strong> <code>gap: 10px;</code>.</li>
|
||
<li><strong>Размещение элементов:</strong>
|
||
<ul>
|
||
<li><code>grid-column: 1 / 3;</code> (от 1-й до 3-й линии).</li>
|
||
<li><code>grid-row: 2 / span 2;</code> (со 2-й линии на 2 ячейки).</li>
|
||
</ul></li>
|
||
<li><strong>Именованные области:</strong></li>
|
||
</ul>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode css"><code class="sourceCode css"><span><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="fu">.container</span> {</span>
|
||
<span><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">grid-template-areas</span><span class="ch">:</span> </span>
|
||
<span><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a> <span class="st">"header header"</span></span>
|
||
<span><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a> <span class="st">"sidebar content"</span></span>
|
||
<span><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a> <span class="st">"footer footer"</span><span class="op">;</span></span>
|
||
<span><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>}</span>
|
||
<span><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>header { <span class="kw">grid-area</span><span class="ch">:</span> <span class="dv">header</span><span class="op">;</span> }</span></code></pre></div>
|
||
<hr />
|
||
<h1>Сравнение Flex и Grid</h1>
|
||
<ul>
|
||
<li><strong>Flexbox:</strong> Лучше для одномерных структур (меню,
|
||
тулбары) и распределения пространства между элементами.</li>
|
||
<li><strong>Grid:</strong> Лучше для сложных макетов всей страницы,
|
||
перекрытия элементов и точного контроля над строками и столбцами
|
||
одновременно.</li>
|
||
</ul>
|
||
</div>
|
||
<p class="back">Назад: <a href="#block-5">Flexbox и Grid</a></p>
|
||
</article>
|
||
|
||
<article class="note full-note" id="d-django-models">
|
||
<h3>Django Модели и ORM</h3>
|
||
<p class="note-source">Полный текст исходной заметки.</p>
|
||
<div class="embedded-note" data-note-title="Модели и ORM">
|
||
<h1>Django Модели и ORM</h1>
|
||
<p><strong>Django ORM (Object-Relational Mapping)</strong> — технология
|
||
связи объектно-ориентированного кода и реляционной БД. Реализует паттерн
|
||
Active Record.</p>
|
||
<h2>Структура проекта</h2>
|
||
<ul>
|
||
<li><code>manage.py</code>: Утилита командной строки.</li>
|
||
<li><code>settings.py</code>: Конфигурация проекта (БД,
|
||
<code>INSTALLED_APPS</code>).</li>
|
||
<li><code>urls.py</code>: Описание маршрутов.</li>
|
||
<li><code>models.py</code>: Определение таблиц БД.</li>
|
||
</ul>
|
||
<pre class="text"><code>project/
|
||
├── manage.py
|
||
├── project/
|
||
│ ├── settings.py
|
||
│ └── urls.py
|
||
└── app/
|
||
└── models.py</code></pre>
|
||
<h2>Определение моделей</h2>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> django.db <span class="im">import</span> models</span>
|
||
<span><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Person(models.Model):</span>
|
||
<span><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a> first_name <span class="op">=</span> models.CharField(<span class="st">"Имя"</span>, max_length<span class="op">=</span><span class="dv">30</span>)</span>
|
||
<span><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a> age <span class="op">=</span> models.IntegerField(default<span class="op">=</span><span class="dv">18</span>)</span>
|
||
<span><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a> bio <span class="op">=</span> models.TextField(blank<span class="op">=</span><span class="va">True</span>)</span>
|
||
<span><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a> </span>
|
||
<span><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">class</span> Meta:</span>
|
||
<span><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a> verbose_name <span class="op">=</span> <span class="st">"Человек"</span></span>
|
||
<span><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a> ordering <span class="op">=</span> [<span class="st">"-first_name"</span>]</span></code></pre></div>
|
||
<h3>Типы полей</h3>
|
||
<ul>
|
||
<li><code>AutoField</code> — автоинкрементный числовой первичный
|
||
ключ.</li>
|
||
<li><code>CharField(max_length=N)</code> — короткая строка фиксированной
|
||
максимальной длины.</li>
|
||
<li><code>TextField</code> — длинный текст без обязательного ограничения
|
||
длины.</li>
|
||
<li><code>IntegerField</code> — целое число.</li>
|
||
<li><code>DecimalField(max_digits, decimal_places)</code> — точное
|
||
десятичное число, удобно для денег и измерений.</li>
|
||
<li><code>BooleanField</code> — логическое значение
|
||
<code>True</code>/<code>False</code>.</li>
|
||
<li><code>DateField</code> — дата без времени.</li>
|
||
<li><code>DateTimeField</code> — дата и время.</li>
|
||
<li><code>EmailField</code> — строка с валидацией email-адреса.</li>
|
||
<li><code>FileField</code> — путь к загруженному файлу.</li>
|
||
<li><code>ImageField</code> — файл изображения с дополнительной
|
||
проверкой формата.</li>
|
||
</ul>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Article(models.Model):</span>
|
||
<span><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a> <span class="bu">id</span> <span class="op">=</span> models.AutoField(primary_key<span class="op">=</span><span class="va">True</span>)</span>
|
||
<span><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a> title <span class="op">=</span> models.CharField(max_length<span class="op">=</span><span class="dv">200</span>)</span>
|
||
<span><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a> body <span class="op">=</span> models.TextField()</span>
|
||
<span><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a> views <span class="op">=</span> models.IntegerField(default<span class="op">=</span><span class="dv">0</span>)</span>
|
||
<span><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a> price <span class="op">=</span> models.DecimalField(max_digits<span class="op">=</span><span class="dv">10</span>, decimal_places<span class="op">=</span><span class="dv">2</span>)</span>
|
||
<span><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a> is_published <span class="op">=</span> models.BooleanField(default<span class="op">=</span><span class="va">False</span>)</span>
|
||
<span><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a> published_at <span class="op">=</span> models.DateTimeField(null<span class="op">=</span><span class="va">True</span>, blank<span class="op">=</span><span class="va">True</span>)</span>
|
||
<span><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a> author_email <span class="op">=</span> models.EmailField()</span>
|
||
<span><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a> attachment <span class="op">=</span> models.FileField(upload_to<span class="op">=</span><span class="st">"files/"</span>, blank<span class="op">=</span><span class="va">True</span>)</span>
|
||
<span><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a> cover <span class="op">=</span> models.ImageField(upload_to<span class="op">=</span><span class="st">"covers/"</span>, blank<span class="op">=</span><span class="va">True</span>)</span></code></pre></div>
|
||
<h3>Отношения</h3>
|
||
<ul>
|
||
<li><code>ForeignKey(Target, on_delete=...)</code> — связь “один ко
|
||
многим”: у одной записи <code>Target</code> может быть много связанных
|
||
записей текущей модели.</li>
|
||
<li><code>OneToOneField(Target, on_delete=...)</code> — связь “один к
|
||
одному”: каждой записи соответствует максимум одна связанная
|
||
запись.</li>
|
||
<li><code>ManyToManyField(Target)</code> — связь “многие ко многим”:
|
||
записи обеих моделей могут ссылаться на несколько записей другой
|
||
модели.</li>
|
||
</ul>
|
||
<p><code>on_delete</code> задаёт, что делать с текущей записью, если
|
||
удаляется связанная запись <code>Target</code>: - <code>CASCADE</code> —
|
||
удалить текущую запись вместе со связанной. - <code>PROTECT</code> —
|
||
запретить удаление связанной записи, пока на неё есть ссылки. -
|
||
<code>SET_NULL</code> — записать <code>NULL</code> в поле связи; требует
|
||
<code>null=True</code>. - <code>SET_DEFAULT</code> — записать значение
|
||
по умолчанию; требует <code>default</code>. - <code>DO_NOTHING</code> —
|
||
ничего не делать на уровне Django, ответственность остаётся на БД и
|
||
разработчике.</p>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Author(models.Model):</span>
|
||
<span><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a> name <span class="op">=</span> models.CharField(max_length<span class="op">=</span><span class="dv">100</span>)</span>
|
||
<span><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Profile(models.Model):</span>
|
||
<span><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a> author <span class="op">=</span> models.OneToOneField(Author, on_delete<span class="op">=</span>models.CASCADE)</span>
|
||
<span><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a> bio <span class="op">=</span> models.TextField()</span>
|
||
<span><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> Book(models.Model):</span>
|
||
<span><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a> title <span class="op">=</span> models.CharField(max_length<span class="op">=</span><span class="dv">200</span>)</span>
|
||
<span><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a> author <span class="op">=</span> models.ForeignKey(Author, on_delete<span class="op">=</span>models.PROTECT)</span>
|
||
<span><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a> co_authors <span class="op">=</span> models.ManyToManyField(Author, related_name<span class="op">=</span><span class="st">"coauthored_books"</span>, blank<span class="op">=</span><span class="va">True</span>)</span></code></pre></div>
|
||
<hr />
|
||
<h2>Миграции</h2>
|
||
<p>Инструмент для синхронизации моделей с БД. -
|
||
<code>python manage.py makemigrations</code> — создать файлы миграций. -
|
||
<code>python manage.py migrate</code> — применить изменения в БД. -
|
||
<code>python manage.py showmigrations</code> — список статусов
|
||
миграций.</p>
|
||
<hr />
|
||
<h2>Работа с QuerySet (Запросы)</h2>
|
||
<p>Django QuerySet ленивы (вычисляются только при обращении) и
|
||
поддерживают цепочки методов.</p>
|
||
<h3>Базовые CRUD операции</h3>
|
||
<ul>
|
||
<li><strong>Create:</strong>
|
||
<code>obj = Person.objects.create(name="Ivan")</code> или
|
||
<code>obj.save()</code>.</li>
|
||
<li><strong>Read:</strong>
|
||
<ul>
|
||
<li><code>Person.objects.all()</code> (все),</li>
|
||
<li><code>Person.objects.get(id=1)</code> (один),</li>
|
||
<li><code>Person.objects.filter(age__gt=20)</code> (фильтрация).</li>
|
||
</ul></li>
|
||
<li><strong>Update:</strong>
|
||
<code>Person.objects.filter(id=1).update(age=25)</code>.</li>
|
||
<li><strong>Delete:</strong> <code>obj.delete()</code> или
|
||
<code>QuerySet.delete()</code>.</li>
|
||
</ul>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Create</span></span>
|
||
<span><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>person <span class="op">=</span> Person.objects.create(first_name<span class="op">=</span><span class="st">"Ivan"</span>, age<span class="op">=</span><span class="dv">25</span>)</span>
|
||
<span><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="co"># Read</span></span>
|
||
<span><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>people <span class="op">=</span> Person.objects.<span class="bu">all</span>()</span>
|
||
<span><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>person <span class="op">=</span> Person.objects.get(<span class="bu">id</span><span class="op">=</span><span class="dv">1</span>)</span>
|
||
<span><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>adults <span class="op">=</span> Person.objects.<span class="bu">filter</span>(age__gte<span class="op">=</span><span class="dv">18</span>)</span>
|
||
<span><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a><span class="co"># Update</span></span>
|
||
<span><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>Person.objects.<span class="bu">filter</span>(<span class="bu">id</span><span class="op">=</span><span class="dv">1</span>).update(age<span class="op">=</span><span class="dv">26</span>)</span>
|
||
<span><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a><span class="co"># Delete</span></span>
|
||
<span><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a>person.delete()</span></code></pre></div>
|
||
<h3>Поиск по полям (Field
|
||
Lookups)</h3>
|
||
<ul>
|
||
<li><code>exact</code>, <code>iexact</code> (регистронезависимо).</li>
|
||
<li><code>gt</code> (>), <code>gte</code> (>=), <code>lt</code>
|
||
(<), <code>lte</code> (<=).</li>
|
||
<li><code>contains</code>, <code>icontains</code>.</li>
|
||
<li><code>in</code> (список), <code>range</code> (диапазон).</li>
|
||
<li><code>isnull=True</code>.</li>
|
||
</ul>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>Person.objects.<span class="bu">filter</span>(first_name__exact<span class="op">=</span><span class="st">"Ivan"</span>)</span>
|
||
<span><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>Person.objects.<span class="bu">filter</span>(first_name__iexact<span class="op">=</span><span class="st">"ivan"</span>)</span>
|
||
<span><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>Person.objects.<span class="bu">filter</span>(age__gt<span class="op">=</span><span class="dv">18</span>)</span>
|
||
<span><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>Person.objects.<span class="bu">filter</span>(age__range<span class="op">=</span>(<span class="dv">18</span>, <span class="dv">30</span>))</span>
|
||
<span><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>Person.objects.<span class="bu">filter</span>(first_name__icontains<span class="op">=</span><span class="st">"iv"</span>)</span>
|
||
<span><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>Person.objects.<span class="bu">filter</span>(id__in<span class="op">=</span>[<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>])</span>
|
||
<span><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>Person.objects.<span class="bu">filter</span>(bio__isnull<span class="op">=</span><span class="va">True</span>)</span></code></pre></div>
|
||
<h3>Оптимизация запросов</h3>
|
||
<ul>
|
||
<li><code>select_related('field')</code> — заранее подтягивает связанную
|
||
запись через <code>JOIN</code>. Подходит для <code>ForeignKey</code> и
|
||
<code>OneToOneField</code>, когда у объекта есть одна связанная
|
||
запись.</li>
|
||
<li><code>prefetch_related('field')</code> — делает отдельный запрос за
|
||
связанными объектами и собирает их в Python. Подходит для
|
||
<code>ManyToManyField</code> и обратных связей, где связанных записей
|
||
может быть много.</li>
|
||
<li><strong>Проблема N+1</strong> — ситуация, когда Django делает один
|
||
запрос за списком объектов, а потом ещё по одному запросу на каждый
|
||
объект в цикле.</li>
|
||
</ul>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="co"># select_related: книга + её автор загружаются одним SQL-запросом</span></span>
|
||
<span><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>books <span class="op">=</span> Book.objects.select_related(<span class="st">"author"</span>)</span>
|
||
<span><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> book <span class="kw">in</span> books:</span>
|
||
<span><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(book.title, book.author.name)</span></code></pre></div>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="co"># prefetch_related: авторы загружаются отдельно, затем Django связывает их с книгами</span></span>
|
||
<span><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>books <span class="op">=</span> Book.objects.prefetch_related(<span class="st">"authors"</span>)</span>
|
||
<span><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> book <span class="kw">in</span> books:</span>
|
||
<span><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(book.title, [author.name <span class="cf">for</span> author <span class="kw">in</span> book.authors.<span class="bu">all</span>()])</span></code></pre></div>
|
||
<h3>Агрегация и аннотация</h3>
|
||
<ul>
|
||
<li><code>aggregate(Avg('rating'))</code> — считает одно итоговое
|
||
значение по всей выборке: среднее, сумму, минимум, максимум, количество.
|
||
Возвращает словарь, а не QuerySet.</li>
|
||
<li><code>annotate(total=Count('entries'))</code> — добавляет
|
||
вычисляемое поле к каждому объекту в выборке.</li>
|
||
</ul>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> django.db.models <span class="im">import</span> Avg, Count</span>
|
||
<span><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="co"># aggregate: одно итоговое значение по всей таблице книг</span></span>
|
||
<span><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>result <span class="op">=</span> Book.objects.aggregate(avg_rating<span class="op">=</span>Avg(<span class="st">"rating"</span>))</span>
|
||
<span><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(result[<span class="st">"avg_rating"</span>])</span>
|
||
<span><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a><span class="co"># annotate: вычисляемое поле для каждого автора</span></span>
|
||
<span><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a>authors <span class="op">=</span> Author.objects.annotate(total_books<span class="op">=</span>Count(<span class="st">"books"</span>))</span>
|
||
<span><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> author <span class="kw">in</span> authors:</span>
|
||
<span><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(author.name, author.total_books)</span></code></pre></div>
|
||
<h3>Логические условия</h3>
|
||
<ul>
|
||
<li><code>Q-объекты</code> нужны для сложных условий в
|
||
<code>filter()</code>: <code>OR</code> (<code>|</code>),
|
||
<code>AND</code> (<code>&</code>), <code>NOT</code>
|
||
(<code>~</code>).</li>
|
||
<li><code>F-выражения</code> позволяют сравнивать и изменять поля прямо
|
||
на стороне БД, не загружая значение в Python.</li>
|
||
</ul>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> django.db.models <span class="im">import</span> F, Q</span>
|
||
<span><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="co"># Q: рейтинг выше 4 или название содержит Django</span></span>
|
||
<span><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>books <span class="op">=</span> Book.objects.<span class="bu">filter</span>(</span>
|
||
<span><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a> Q(rating__gt<span class="op">=</span><span class="dv">4</span>) <span class="op">|</span> Q(title__icontains<span class="op">=</span><span class="st">"Django"</span>)</span>
|
||
<span><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>)</span>
|
||
<span><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a><span class="co"># F: увеличить счётчик просмотров прямо в БД</span></span>
|
||
<span><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a>Book.objects.<span class="bu">filter</span>(<span class="bu">id</span><span class="op">=</span><span class="dv">1</span>).update(views<span class="op">=</span>F(<span class="st">"views"</span>) <span class="op">+</span> <span class="dv">1</span>)</span></code></pre></div>
|
||
</div>
|
||
<p class="back">Назад: <a href="#s-django-models">Django models</a> · <a href="#s-django-queries">Django queries</a></p>
|
||
</article>
|
||
|
||
<article class="note full-note" id="d-django-views">
|
||
<h3>Django: представления, URL, шаблоны и CBV</h3>
|
||
<p class="note-source">Полный текст исходной заметки.</p>
|
||
<div class="embedded-note" data-note-title="Представления, шаблоны и CBV">
|
||
<h1>Django: Представления,
|
||
шаблоны и CBV</h1>
|
||
<h2>Маршрутизация (URL Routing)</h2>
|
||
<ul>
|
||
<li>Описывается в <code>urlpatterns</code> с помощью <code>path()</code>
|
||
и <code>re_path()</code>.</li>
|
||
<li>Конвертеры: <code><int:pk></code>,
|
||
<code><slug:slug></code>, <code><uuid:id></code>.</li>
|
||
<li>Включение других файлов:
|
||
<code>path('blog/', include('blog.urls'))</code>.</li>
|
||
<li>Реверсирование: <code>{% url 'name' %}</code> в шаблонах или
|
||
<code>reverse('name')</code> в Python.</li>
|
||
</ul>
|
||
<p>Конвертеры вытаскивают часть URL, проверяют её тип и передают во view
|
||
как аргумент: - <code><str:name></code> — непустая строка без
|
||
<code>/</code>; используется по умолчанию. - <code><int:pk></code>
|
||
— целое положительное число. - <code><slug:slug></code> — строка
|
||
для человекочитаемого URL: буквы, цифры, <code>_</code>, <code>-</code>.
|
||
- <code><uuid:id></code> — UUID, например
|
||
<code>075194d3-6885-417e-a8a8-6c931e272f00</code>. -
|
||
<code><path:subpath></code> — строка, которая может содержать
|
||
<code>/</code>.</p>
|
||
<p>Маршрутизация связывает URL с view-функцией или view-классом. Имя
|
||
маршрута (<code>name</code>) нужно, чтобы не хардкодить URL в коде и
|
||
шаблонах.</p>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co"># project/urls.py</span></span>
|
||
<span><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> django.urls <span class="im">import</span> include, path</span>
|
||
<span><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>urlpatterns <span class="op">=</span> [</span>
|
||
<span><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a> path(<span class="st">"blog/"</span>, include(<span class="st">"blog.urls"</span>)),</span>
|
||
<span><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>]</span></code></pre></div>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co"># blog/urls.py</span></span>
|
||
<span><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> django.urls <span class="im">import</span> path</span>
|
||
<span><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> . <span class="im">import</span> views</span>
|
||
<span><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>app_name <span class="op">=</span> <span class="st">"blog"</span></span>
|
||
<span><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>urlpatterns <span class="op">=</span> [</span>
|
||
<span><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a> path(<span class="st">""</span>, views.post_list, name<span class="op">=</span><span class="st">"post_list"</span>),</span>
|
||
<span><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a> path(<span class="st">"<int:pk>/"</span>, views.post_detail, name<span class="op">=</span><span class="st">"post_detail"</span>),</span>
|
||
<span><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a> path(<span class="st">"tag/<slug:slug>/"</span>, views.posts_by_tag, name<span class="op">=</span><span class="st">"posts_by_tag"</span>),</span>
|
||
<span><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a> path(<span class="st">"files/<path:subpath>/"</span>, views.file_detail, name<span class="op">=</span><span class="st">"file_detail"</span>),</span>
|
||
<span><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>]</span></code></pre></div>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> post_detail(request, pk):</span>
|
||
<span><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a> <span class="co"># pk уже int</span></span>
|
||
<span><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a> ...</span>
|
||
<span><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> posts_by_tag(request, slug):</span>
|
||
<span><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a> <span class="co"># slug — строка из URL</span></span>
|
||
<span><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a> ...</span></code></pre></div>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> django.urls <span class="im">import</span> reverse</span>
|
||
<span><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>url <span class="op">=</span> reverse(<span class="st">"blog:post_detail"</span>, kwargs<span class="op">=</span>{<span class="st">"pk"</span>: <span class="dv">1</span>})</span></code></pre></div>
|
||
<hr />
|
||
<h2>Представления (Views)</h2>
|
||
<p>Views принимают <code>HttpRequest</code> и возвращают
|
||
<code>HttpResponse</code>.</p>
|
||
<p>View — это точка входа для запроса. В ней обычно читают данные из БД,
|
||
проверяют условия и возвращают HTML, JSON, редирект или ошибку.</p>
|
||
<h3>Функциональные представления
|
||
(FBV)</h3>
|
||
<p>FBV — обычная функция. Удобна, когда логика короткая и
|
||
нестандартная.</p>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> django.shortcuts <span class="im">import</span> render, get_object_or_404</span>
|
||
<span><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> index(request):</span>
|
||
<span><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> latest_items <span class="op">=</span> Model.objects.<span class="bu">all</span>()[:<span class="dv">5</span>]</span>
|
||
<span><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> render(request, <span class="st">"app/index.html"</span>, {<span class="st">"items"</span>: latest_items})</span></code></pre></div>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> django.shortcuts <span class="im">import</span> get_object_or_404, render</span>
|
||
<span><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> .models <span class="im">import</span> Post</span>
|
||
<span><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> post_detail(request, pk):</span>
|
||
<span><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a> post <span class="op">=</span> get_object_or_404(Post, pk<span class="op">=</span>pk)</span>
|
||
<span><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> render(request, <span class="st">"blog/detail.html"</span>, {<span class="st">"post"</span>: post})</span></code></pre></div>
|
||
<h3>Классовые представления (CBV)</h3>
|
||
<p>Абстрагируют типичные задачи. Вызываются в URL через
|
||
<code>.as_view()</code>.</p>
|
||
<ul>
|
||
<li><strong>TemplateView:</strong> Отображение статического
|
||
шаблона.</li>
|
||
<li><strong>ListView:</strong> Автоматический список объектов (данные в
|
||
<code>object_list</code>).</li>
|
||
<li><strong>DetailView:</strong> Детальная информация об одном объекте
|
||
(ищет по <code>pk</code> или <code>slug</code>).</li>
|
||
</ul>
|
||
<p>CBV — класс с готовым поведением. Django сам вызывает нужные методы
|
||
класса: например, <code>get()</code> для GET-запроса или
|
||
<code>get_queryset()</code> для получения списка объектов.</p>
|
||
<p><strong>Пример ListView:</strong></p>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> django.views.generic <span class="im">import</span> DetailView, ListView, TemplateView</span>
|
||
<span><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> .models <span class="im">import</span> Post</span>
|
||
<span><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> AboutView(TemplateView):</span>
|
||
<span><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a> template_name <span class="op">=</span> <span class="st">"blog/about.html"</span></span>
|
||
<span><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> PostListView(ListView):</span>
|
||
<span><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a> model <span class="op">=</span> Post</span>
|
||
<span><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a> template_name <span class="op">=</span> <span class="st">"blog/list.html"</span></span>
|
||
<span><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a> context_object_name <span class="op">=</span> <span class="st">"posts"</span></span>
|
||
<span><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a> paginate_by <span class="op">=</span> <span class="dv">10</span></span>
|
||
<span><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb7-16" aria-hidden="true" tabindex="-1"></a> <span class="kw">def</span> get_queryset(<span class="va">self</span>):</span>
|
||
<span><a href="#cb7-17" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> Post.objects.<span class="bu">filter</span>(is_published<span class="op">=</span><span class="va">True</span>).order_by(<span class="st">"-created_at"</span>)</span>
|
||
<span><a href="#cb7-18" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb7-19" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb7-20" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> PostDetailView(DetailView):</span>
|
||
<span><a href="#cb7-21" aria-hidden="true" tabindex="-1"></a> model <span class="op">=</span> Post</span>
|
||
<span><a href="#cb7-22" aria-hidden="true" tabindex="-1"></a> template_name <span class="op">=</span> <span class="st">"blog/detail.html"</span></span>
|
||
<span><a href="#cb7-23" aria-hidden="true" tabindex="-1"></a> context_object_name <span class="op">=</span> <span class="st">"post"</span></span></code></pre></div>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="co"># blog/urls.py</span></span>
|
||
<span><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> django.urls <span class="im">import</span> path</span>
|
||
<span><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> .views <span class="im">import</span> AboutView, PostDetailView, PostListView</span>
|
||
<span><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a>app_name <span class="op">=</span> <span class="st">"blog"</span></span>
|
||
<span><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a>urlpatterns <span class="op">=</span> [</span>
|
||
<span><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a> path(<span class="st">"about/"</span>, AboutView.as_view(), name<span class="op">=</span><span class="st">"about"</span>),</span>
|
||
<span><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a> path(<span class="st">""</span>, PostListView.as_view(), name<span class="op">=</span><span class="st">"post_list"</span>),</span>
|
||
<span><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a> path(<span class="st">"<int:pk>/"</span>, PostDetailView.as_view(), name<span class="op">=</span><span class="st">"post_detail"</span>),</span>
|
||
<span><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a>]</span></code></pre></div>
|
||
<hr />
|
||
<h2>Шаблоны (Templates)</h2>
|
||
<p>Используют <strong>Django Template Language (DTL)</strong>.</p>
|
||
<h3>Синтаксис</h3>
|
||
<ul>
|
||
<li><strong>Переменные:</strong> <code>{{ var.attr }}</code>.</li>
|
||
<li><strong>Теги:</strong> <code>{% if %}</code>,
|
||
<code>{% for %}</code>, <code>{% url %}</code>,
|
||
<code>{% csrf_token %}</code>.</li>
|
||
<li><strong>Фильтры:</strong> <code>{{ date|date:"Y-m-d" }}</code>,
|
||
<code>{{ list|length }}</code>, <code>{{ text|lower }}</code>.</li>
|
||
</ul>
|
||
<p>Шаблон получает контекст из view. Например, если view передала
|
||
<code>{"posts": posts}</code>, в шаблоне доступна переменная
|
||
<code>posts</code>.</p>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode html"><code class="sourceCode html"><span><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>{% for post in posts %}</span>
|
||
<span><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">article</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">h2</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">a</span><span class="ot"> href</span><span class="op">=</span><span class="st">"{% url 'blog:post_detail' post.pk %}"</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a> {{ post.title|upper }}</span>
|
||
<span><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a> <span class="dt"></</span><span class="kw">a</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a> <span class="dt"></</span><span class="kw">h2</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a> {% if post.is_published %}</span>
|
||
<span><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">p</span><span class="dt">></span>{{ post.created_at|date:"Y-m-d" }}<span class="dt"></</span><span class="kw">p</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a> {% endif %}</span>
|
||
<span><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a> <span class="dt"></</span><span class="kw">article</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a>{% empty %}</span>
|
||
<span><a href="#cb9-14" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">p</span><span class="dt">></span>Постов нет.<span class="dt"></</span><span class="kw">p</span><span class="dt">></span></span>
|
||
<span><a href="#cb9-15" aria-hidden="true" tabindex="-1"></a>{% endfor %}</span></code></pre></div>
|
||
<h3>Наследование шаблонов</h3>
|
||
<p>Позволяет избежать дублирования HTML-кода. - <strong>Базовый шаблон
|
||
(<code>base.html</code>):</strong> Определяет блоки
|
||
<code>{% block content %}{% endblock %}</code>. - <strong>Дочерний
|
||
шаблон:</strong> Использует <code>{% extends "base.html" %}</code> и
|
||
переопределяет блоки.</p>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode html"><code class="sourceCode html"><span><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="co"><!-- templates/base.html --></span></span>
|
||
<span><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="dt"><!doctype</span> html<span class="dt">></span></span>
|
||
<span><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">html</span><span class="ot"> lang</span><span class="op">=</span><span class="st">"ru"</span><span class="dt">></span></span>
|
||
<span><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">head</span><span class="dt">></span></span>
|
||
<span><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">title</span><span class="dt">></span>{% block title %}Сайт{% endblock %}<span class="dt"></</span><span class="kw">title</span><span class="dt">></span></span>
|
||
<span><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a> <span class="dt"></</span><span class="kw">head</span><span class="dt">></span></span>
|
||
<span><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">body</span><span class="dt">></span></span>
|
||
<span><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">main</span><span class="dt">></span></span>
|
||
<span><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a> {% block content %}{% endblock %}</span>
|
||
<span><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a> <span class="dt"></</span><span class="kw">main</span><span class="dt">></span></span>
|
||
<span><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a> <span class="dt"></</span><span class="kw">body</span><span class="dt">></span></span>
|
||
<span><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a><span class="dt"></</span><span class="kw">html</span><span class="dt">></span></span></code></pre></div>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode html"><code class="sourceCode html"><span><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="co"><!-- templates/blog/list.html --></span></span>
|
||
<span><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>{% extends "base.html" %}</span>
|
||
<span><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>{% block title %}Посты{% endblock %}</span>
|
||
<span><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>{% block content %}</span>
|
||
<span><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">h1</span><span class="dt">></span>Посты<span class="dt"></</span><span class="kw">h1</span><span class="dt">></span></span>
|
||
<span><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a> {% for post in posts %}</span>
|
||
<span><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">a</span><span class="ot"> href</span><span class="op">=</span><span class="st">"{% url 'blog:post_detail' post.pk %}"</span><span class="dt">></span></span>
|
||
<span><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a> {{ post.title }}</span>
|
||
<span><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a> <span class="dt"></</span><span class="kw">a</span><span class="dt">></span></span>
|
||
<span><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a> {% endfor %}</span>
|
||
<span><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a>{% endblock %}</span></code></pre></div>
|
||
<hr />
|
||
<h2>Статические файлы (Static)</h2>
|
||
<ul>
|
||
<li>Подключаются через <code>{% load static %}</code>.</li>
|
||
<li>Настройки в <code>settings.py</code>: <code>STATIC_URL</code>,
|
||
<code>STATICFILES_DIRS</code>.</li>
|
||
<li>В продакшне используется команда
|
||
<code>python manage.py collectstatic</code>.</li>
|
||
</ul>
|
||
<p>Статика — это CSS, JavaScript, изображения и другие файлы, которые не
|
||
генерируются view.</p>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="co"># settings.py</span></span>
|
||
<span><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>STATIC_URL <span class="op">=</span> <span class="st">"static/"</span></span>
|
||
<span><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>STATICFILES_DIRS <span class="op">=</span> [BASE_DIR <span class="op">/</span> <span class="st">"static"</span>]</span></code></pre></div>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode html"><code class="sourceCode html"><span><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a>{% load static %}</span>
|
||
<span><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">link</span><span class="ot"> rel</span><span class="op">=</span><span class="st">"stylesheet"</span><span class="ot"> href</span><span class="op">=</span><span class="st">"{% static 'css/app.css' %}"</span><span class="dt">></span></span>
|
||
<span><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">script</span><span class="ot"> src</span><span class="op">=</span><span class="st">"{% static 'js/app.js' %}"</span><span class="dt">></</span><span class="kw">script</span><span class="dt">></span></span></code></pre></div>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode bash"><code class="sourceCode bash"><span><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="ex">python</span> manage.py collectstatic</span></code></pre></div>
|
||
</div>
|
||
<p class="back">Назад: <a href="#s-fbv">Django FBV</a> · <a href="#s-cbv-types">Django CBV</a> · <a href="#s-django-urls">Django URLs</a> · <a href="#s-django-templates">Django templates</a></p>
|
||
</article>
|
||
|
||
<article class="note full-note" id="d-django-forms">
|
||
<h3>Django: Работа с формами и CUD</h3>
|
||
<p class="note-source">Полный текст исходной заметки.</p>
|
||
<div class="embedded-note" data-note-title="Работа с формами и CUD">
|
||
<h1>Django: Работа с формами и
|
||
CUD</h1>
|
||
<p><strong>CUD (Create, Update, Delete)</strong> — операции изменения
|
||
данных: создать, обновить, удалить.</p>
|
||
<p>Форма в Django — это слой между HTML-формой и Python-кодом. Она
|
||
принимает данные от пользователя, проверяет их, приводит к нормальным
|
||
типам и помогает сохранить результат.</p>
|
||
<h2>Типы форм</h2>
|
||
<ul>
|
||
<li><strong><code>forms.Form</code></strong> — обычная форма, не
|
||
привязанная к модели. Подходит для поиска, обратной связи, фильтров,
|
||
отправки email.</li>
|
||
<li><strong><code>forms.ModelForm</code></strong> — форма на основе
|
||
модели. Django сам создаёт поля формы по полям модели и умеет сохранять
|
||
объект через <code>form.save()</code>.</li>
|
||
</ul>
|
||
<p>Если данные не нужно сохранять в таблицу напрямую — чаще подходит
|
||
<code>forms.Form</code>. Если форма создаёт или редактирует модель —
|
||
проще использовать <code>forms.ModelForm</code>.</p>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> django <span class="im">import</span> forms</span>
|
||
<span><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> .models <span class="im">import</span> Blog</span>
|
||
<span><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> BlogForm(forms.ModelForm):</span>
|
||
<span><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">class</span> Meta:</span>
|
||
<span><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a> model <span class="op">=</span> Blog</span>
|
||
<span><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a> fields <span class="op">=</span> [<span class="st">"name"</span>, <span class="st">"tagline"</span>]</span>
|
||
<span><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a> widgets <span class="op">=</span> {</span>
|
||
<span><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a> <span class="st">"name"</span>: forms.TextInput(attrs<span class="op">=</span>{<span class="st">"class"</span>: <span class="st">"form-control"</span>})</span>
|
||
<span><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a> }</span></code></pre></div>
|
||
<hr />
|
||
<h2>Жизненный цикл формы в
|
||
представлении</h2>
|
||
<p>Обычно view работает так: 1. При <code>GET</code> создаёт пустую
|
||
форму и показывает страницу. 2. При <code>POST</code> создаёт форму из
|
||
<code>request.POST</code>. 3. Проверяет данные через
|
||
<code>is_valid()</code>. 4. Если данные корректные — выполняет действие
|
||
и делает <code>redirect</code>. 5. Если есть ошибки — снова показывает
|
||
форму с ошибками.</p>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> django.shortcuts <span class="im">import</span> redirect, render</span>
|
||
<span><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> contact_view(request):</span>
|
||
<span><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> request.method <span class="op">==</span> <span class="st">"POST"</span>:</span>
|
||
<span><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a> form <span class="op">=</span> ContactForm(request.POST)</span>
|
||
<span><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> form.is_valid():</span>
|
||
<span><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a> data <span class="op">=</span> form.cleaned_data</span>
|
||
<span><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a> send_email(data[<span class="st">"email"</span>], data[<span class="st">"message"</span>])</span>
|
||
<span><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> redirect(<span class="st">"success"</span>)</span>
|
||
<span><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span>:</span>
|
||
<span><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a> form <span class="op">=</span> ContactForm()</span>
|
||
<span><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> render(request, <span class="st">"contact.html"</span>, {<span class="st">"form"</span>: form})</span></code></pre></div>
|
||
<hr />
|
||
<h2>Валидация и очистка данных</h2>
|
||
<ul>
|
||
<li><strong><code>is_valid()</code></strong> — запускает проверку формы.
|
||
После него появляются <code>form.cleaned_data</code> и
|
||
<code>form.errors</code>.</li>
|
||
<li><strong>Автоматическая очистка</strong> — Django превращает строки
|
||
из HTML-формы в Python-типы: число в <code>int</code>, дату в
|
||
<code>date</code>, email в строку после проверки формата.</li>
|
||
<li><strong><code>clean_<fieldname>()</code></strong> — проверка
|
||
одного конкретного поля.</li>
|
||
<li><strong><code>clean()</code></strong> — проверка всей формы, когда
|
||
нужно сравнить несколько полей между собой.</li>
|
||
</ul>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> django <span class="im">import</span> forms</span>
|
||
<span><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> RegisterForm(forms.Form):</span>
|
||
<span><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a> username <span class="op">=</span> forms.CharField(max_length<span class="op">=</span><span class="dv">50</span>)</span>
|
||
<span><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a> password <span class="op">=</span> forms.CharField(widget<span class="op">=</span>forms.PasswordInput)</span>
|
||
<span><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a> password_repeat <span class="op">=</span> forms.CharField(widget<span class="op">=</span>forms.PasswordInput)</span>
|
||
<span><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a> <span class="kw">def</span> clean_username(<span class="va">self</span>):</span>
|
||
<span><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a> username <span class="op">=</span> <span class="va">self</span>.cleaned_data[<span class="st">"username"</span>]</span>
|
||
<span><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> username.lower() <span class="op">==</span> <span class="st">"admin"</span>:</span>
|
||
<span><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a> <span class="cf">raise</span> forms.ValidationError(<span class="st">"Это имя нельзя использовать"</span>)</span>
|
||
<span><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> username</span>
|
||
<span><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a> <span class="kw">def</span> clean(<span class="va">self</span>):</span>
|
||
<span><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a> cleaned_data <span class="op">=</span> <span class="bu">super</span>().clean()</span>
|
||
<span><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a> password <span class="op">=</span> cleaned_data.get(<span class="st">"password"</span>)</span>
|
||
<span><a href="#cb3-20" aria-hidden="true" tabindex="-1"></a> password_repeat <span class="op">=</span> cleaned_data.get(<span class="st">"password_repeat"</span>)</span>
|
||
<span><a href="#cb3-21" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb3-22" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> password <span class="kw">and</span> password_repeat <span class="kw">and</span> password <span class="op">!=</span> password_repeat:</span>
|
||
<span><a href="#cb3-23" aria-hidden="true" tabindex="-1"></a> <span class="cf">raise</span> forms.ValidationError(<span class="st">"Пароли не совпадают"</span>)</span>
|
||
<span><a href="#cb3-24" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb3-25" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> cleaned_data</span></code></pre></div>
|
||
<hr />
|
||
<h2>Generic Editing Views (CBV
|
||
для CUD)</h2>
|
||
<p>Django предоставляет готовые классы для типовых страниц
|
||
редактирования: - <strong><code>CreateView</code></strong> — создать
|
||
объект. - <strong><code>UpdateView</code></strong> — изменить объект;
|
||
обычно ищет его по <code>pk</code> из URL. -
|
||
<strong><code>DeleteView</code></strong> — удалить объект; требует
|
||
подтверждения через <code>POST</code>.</p>
|
||
<p>Главная идея: вместо ручной обработки <code>GET</code>,
|
||
<code>POST</code>, <code>is_valid()</code> и <code>save()</code> можно
|
||
описать модель, форму, шаблон и URL после успеха.</p>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> django.urls <span class="im">import</span> reverse_lazy</span>
|
||
<span><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> django.views.generic <span class="im">import</span> CreateView, DeleteView, UpdateView</span>
|
||
<span><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> .forms <span class="im">import</span> BlogForm</span>
|
||
<span><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> .models <span class="im">import</span> Blog</span>
|
||
<span><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> BlogCreateView(CreateView):</span>
|
||
<span><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a> model <span class="op">=</span> Blog</span>
|
||
<span><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a> form_class <span class="op">=</span> BlogForm</span>
|
||
<span><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a> template_name <span class="op">=</span> <span class="st">"blog/blog_form.html"</span></span>
|
||
<span><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a> success_url <span class="op">=</span> reverse_lazy(<span class="st">"blog_list"</span>)</span>
|
||
<span><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> BlogUpdateView(UpdateView):</span>
|
||
<span><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a> model <span class="op">=</span> Blog</span>
|
||
<span><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a> form_class <span class="op">=</span> BlogForm</span>
|
||
<span><a href="#cb4-18" aria-hidden="true" tabindex="-1"></a> template_name <span class="op">=</span> <span class="st">"blog/blog_form.html"</span></span>
|
||
<span><a href="#cb4-19" aria-hidden="true" tabindex="-1"></a> success_url <span class="op">=</span> reverse_lazy(<span class="st">"blog_list"</span>)</span>
|
||
<span><a href="#cb4-20" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb4-21" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb4-22" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> BlogDeleteView(DeleteView):</span>
|
||
<span><a href="#cb4-23" aria-hidden="true" tabindex="-1"></a> model <span class="op">=</span> Blog</span>
|
||
<span><a href="#cb4-24" aria-hidden="true" tabindex="-1"></a> template_name <span class="op">=</span> <span class="st">"blog/blog_confirm_delete.html"</span></span>
|
||
<span><a href="#cb4-25" aria-hidden="true" tabindex="-1"></a> success_url <span class="op">=</span> reverse_lazy(<span class="st">"blog_list"</span>)</span></code></pre></div>
|
||
<h2>Отображение в шаблоне</h2>
|
||
<ul>
|
||
<li><code>{{ form.as_p }}</code> — быстро вывести поля формы в
|
||
<code><p></code>.</li>
|
||
<li><code>{{ form.as_table }}</code> — вывести поля как строки
|
||
таблицы.</li>
|
||
<li>Ручное управление нужно, когда важна HTML-разметка, CSS-классы или
|
||
отдельный вывод ошибок.</li>
|
||
</ul>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode html"><code class="sourceCode html"><span><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">form</span><span class="ot"> method</span><span class="op">=</span><span class="st">"post"</span><span class="dt">></span></span>
|
||
<span><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a> {% csrf_token %}</span>
|
||
<span><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a> {{ form.as_p }}</span>
|
||
<span><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">button</span><span class="ot"> type</span><span class="op">=</span><span class="st">"submit"</span><span class="dt">></span>Сохранить<span class="dt"></</span><span class="kw">button</span><span class="dt">></span></span>
|
||
<span><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="dt"></</span><span class="kw">form</span><span class="dt">></span></span></code></pre></div>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode html"><code class="sourceCode html"><span><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">form</span><span class="ot"> method</span><span class="op">=</span><span class="st">"post"</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a> {% csrf_token %}</span>
|
||
<span><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a> {% for field in form %}</span>
|
||
<span><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">div</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a> {{ field.label_tag }}</span>
|
||
<span><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a> {{ field }}</span>
|
||
<span><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a> {{ field.errors }}</span>
|
||
<span><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a> <span class="dt"></</span><span class="kw">div</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a> {% endfor %}</span>
|
||
<span><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a> <span class="dt"><</span><span class="kw">button</span><span class="ot"> type</span><span class="op">=</span><span class="st">"submit"</span><span class="dt">></span>Сохранить<span class="dt"></</span><span class="kw">button</span><span class="dt">></span></span>
|
||
<span><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a><span class="dt"></</span><span class="kw">form</span><span class="dt">></span></span></code></pre></div>
|
||
<h3>CSRF-токен</h3>
|
||
<p><strong>CSRF (Cross-Site Request Forgery)</strong> — атака, при
|
||
которой чужой сайт пытается отправить запрос от имени уже
|
||
авторизованного пользователя.</p>
|
||
<p>Пример: пользователь залогинен в Django-приложении. Он открывает
|
||
вредную страницу, а она незаметно отправляет <code>POST</code>-запрос на
|
||
удаление объекта. Без защиты браузер приложит cookies пользователя, и
|
||
сервер может принять запрос как настоящий.</p>
|
||
<p><code>{% csrf_token %}</code> добавляет в форму скрытое поле с
|
||
защитным токеном:</p>
|
||
<div class="sourceCode"><pre
|
||
class="sourceCode html"><code class="sourceCode html"><span><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="dt"><</span><span class="kw">input</span><span class="ot"> type</span><span class="op">=</span><span class="st">"hidden"</span><span class="ot"> name</span><span class="op">=</span><span class="st">"csrfmiddlewaretoken"</span><span class="ot"> value</span><span class="op">=</span><span class="st">"..."</span><span class="dt">></span></span></code></pre></div>
|
||
<p>При <code>POST</code> Django сверяет токен из формы с токеном
|
||
пользователя. Если токена нет или он неправильный, запрос
|
||
отклоняется.</p>
|
||
<p>Короткое правило: во все HTML-формы с <code>method="post"</code>
|
||
добавлять <code>{% csrf_token %}</code>.</p>
|
||
</div>
|
||
<p class="back">Назад: <a href="#s-django-forms">Django forms</a></p>
|
||
</article>
|
||
|
||
</section>
|
||
|
||
<p class="back"><a href="#top">Наверх</a></p>
|
||
</main>
|
||
</body>
|
||
</html>
|