Auto | arch-x1: 2026-06-05 13:54:39
This commit is contained in:
@@ -87,7 +87,7 @@
|
||||
pre {
|
||||
margin: 10px 0 14px;
|
||||
padding: 12px 14px;
|
||||
overflow-x: auto;
|
||||
overflow-x: hidden;
|
||||
border: 1px solid #d8dee9;
|
||||
border-radius: 8px;
|
||||
background: #111827;
|
||||
@@ -95,6 +95,8 @@
|
||||
font-family: "JetBrains Mono", Consolas, monospace;
|
||||
font-size: 13px;
|
||||
line-height: 1.45;
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.hero {
|
||||
@@ -977,6 +979,87 @@ box-sizing: border-box;</pre>
|
||||
<tr><td><code>annotate()</code></td><td>QuerySet с вычисляемым полем у каждого объекта</td></tr>
|
||||
</table>
|
||||
<p><code>select_related</code> делает SQL JOIN для ForeignKey/OneToOne. <code>prefetch_related</code> делает отдельный запрос для ManyToMany и обратных связей.</p>
|
||||
<h4>Основные термины Django models</h4>
|
||||
<div class="term-grid">
|
||||
<div class="term"><strong>Model</strong>Класс Python, который наследуется от <code>models.Model</code> и описывает таблицу БД.</div>
|
||||
<div class="term"><strong>Field</strong>Поле модели. Определяет колонку таблицы и правила работы со значением.</div>
|
||||
<div class="term"><strong>Primary key</strong>Первичный ключ. Уникально идентифицирует строку таблицы.</div>
|
||||
<div class="term"><strong>Migration</strong>Файл изменения схемы БД. Создаётся из изменений моделей.</div>
|
||||
<div class="term"><strong><code>makemigrations</code></strong>Создаёт файлы миграций.</div>
|
||||
<div class="term"><strong><code>migrate</code></strong>Применяет миграции к базе данных.</div>
|
||||
<div class="term"><strong><code>Class Meta</code></strong>Внутренний класс настроек модели: сортировка, имена, ограничения.</div>
|
||||
<div class="term"><strong>Manager</strong>Объект доступа к запросам, обычно <code>objects</code>.</div>
|
||||
</div>
|
||||
<h4>Поля модели</h4>
|
||||
<table>
|
||||
<tr><th>Поле</th><th>Смысл</th></tr>
|
||||
<tr><td><code>CharField</code></td><td>Короткая строка. Требует <code>max_length</code>.</td></tr>
|
||||
<tr><td><code>TextField</code></td><td>Длинный текст без обязательного лимита длины.</td></tr>
|
||||
<tr><td><code>IntegerField</code></td><td>Целое число.</td></tr>
|
||||
<tr><td><code>DecimalField</code></td><td>Точное десятичное число, удобно для денег. Нужны <code>max_digits</code>, <code>decimal_places</code>.</td></tr>
|
||||
<tr><td><code>BooleanField</code></td><td><code>True</code> или <code>False</code>.</td></tr>
|
||||
<tr><td><code>DateField</code></td><td>Дата без времени.</td></tr>
|
||||
<tr><td><code>DateTimeField</code></td><td>Дата и время.</td></tr>
|
||||
<tr><td><code>EmailField</code></td><td>Строка с email-валидацией на уровне формы/модели.</td></tr>
|
||||
<tr><td><code>FileField</code></td><td>Путь к загруженному файлу.</td></tr>
|
||||
<tr><td><code>ImageField</code></td><td>Файл изображения, требует поддержку обработки изображений.</td></tr>
|
||||
<tr><td><code>ForeignKey</code></td><td>Связь многие-к-одному.</td></tr>
|
||||
<tr><td><code>OneToOneField</code></td><td>Связь один-к-одному.</td></tr>
|
||||
<tr><td><code>ManyToManyField</code></td><td>Связь многие-ко-многим.</td></tr>
|
||||
</table>
|
||||
<h4>Атрибуты полей</h4>
|
||||
<div class="term-grid">
|
||||
<div class="term"><strong><code>max_length</code></strong>Максимальная длина строки. Обязателен для <code>CharField</code>.</div>
|
||||
<div class="term"><strong><code>null=True</code></strong>Разрешает хранить <code>NULL</code> в базе данных.</div>
|
||||
<div class="term"><strong><code>blank=True</code></strong>Разрешает пустое значение в форме и админке.</div>
|
||||
<div class="term"><strong><code>default</code></strong>Значение по умолчанию.</div>
|
||||
<div class="term"><strong><code>primary_key=True</code></strong>Делает поле первичным ключом.</div>
|
||||
<div class="term"><strong><code>unique=True</code></strong>Значение должно быть уникальным.</div>
|
||||
<div class="term"><strong><code>verbose_name</code></strong>Человекочитаемое имя поля.</div>
|
||||
<div class="term"><strong><code>related_name</code></strong>Имя обратной связи для связанных объектов.</div>
|
||||
</div>
|
||||
<h4>Связи</h4>
|
||||
<pre>class Author(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
|
||||
class Book(models.Model):
|
||||
title = models.CharField(max_length=200)
|
||||
author = models.ForeignKey(Author, on_delete=models.PROTECT, related_name="books")</pre>
|
||||
<p>Прямая связь: <code>book.author</code>. Обратная связь через <code>related_name</code>: <code>author.books.all()</code>.</p>
|
||||
<table>
|
||||
<tr><th><code>on_delete</code></th><th>Что делает</th></tr>
|
||||
<tr><td><code>CASCADE</code></td><td>Удаляет зависимые объекты вместе с главным.</td></tr>
|
||||
<tr><td><code>PROTECT</code></td><td>Запрещает удалить объект, если на него есть ссылки.</td></tr>
|
||||
<tr><td><code>SET_NULL</code></td><td>Записывает <code>NULL</code>, требует <code>null=True</code>.</td></tr>
|
||||
<tr><td><code>SET_DEFAULT</code></td><td>Записывает значение по умолчанию.</td></tr>
|
||||
<tr><td><code>DO_NOTHING</code></td><td>Django ничего не делает, ответственность остаётся на БД/коде.</td></tr>
|
||||
</table>
|
||||
<h4>QuerySet и ленивость</h4>
|
||||
<p>QuerySet можно строить цепочкой, и Django не обязательно сразу идёт в БД. Запрос выполняется, когда данные реально нужны: цикл, индексация, вывод, <code>list()</code>, <code>count()</code>, <code>exists()</code>.</p>
|
||||
<pre>qs = Product.objects.filter(is_active=True).order_by("-price")
|
||||
# БД ещё может не быть затронута
|
||||
for product in qs:
|
||||
print(product.name)</pre>
|
||||
<h4>Lookups</h4>
|
||||
<table>
|
||||
<tr><th>Lookup</th><th>Смысл</th></tr>
|
||||
<tr><td><code>exact</code></td><td>Точное совпадение.</td></tr>
|
||||
<tr><td><code>iexact</code></td><td>Точное совпадение без учёта регистра.</td></tr>
|
||||
<tr><td><code>contains</code></td><td>Содержит подстроку с учётом регистра.</td></tr>
|
||||
<tr><td><code>icontains</code></td><td>Содержит подстроку без учёта регистра.</td></tr>
|
||||
<tr><td><code>gt</code>, <code>gte</code></td><td>Больше, больше или равно.</td></tr>
|
||||
<tr><td><code>lt</code>, <code>lte</code></td><td>Меньше, меньше или равно.</td></tr>
|
||||
<tr><td><code>in</code></td><td>Значение входит в список.</td></tr>
|
||||
<tr><td><code>range</code></td><td>Значение в диапазоне.</td></tr>
|
||||
<tr><td><code>isnull</code></td><td>Проверка на <code>NULL</code>.</td></tr>
|
||||
</table>
|
||||
<h4>Q и F</h4>
|
||||
<p><code>Q</code> нужен для сложной логики <code>OR</code>, <code>AND</code>, <code>NOT</code>. <code>F</code> нужен, чтобы обращаться к значениям полей на стороне БД.</p>
|
||||
<pre>Product.objects.filter(Q(name__icontains="web") | Q(description__icontains="web"))
|
||||
Product.objects.update(views=F("views") + 1)</pre>
|
||||
<div class="exam">
|
||||
<code>aggregate()</code> считает один итог по выборке и возвращает словарь. <code>annotate()</code> добавляет вычисляемое поле к каждому объекту.
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="details" id="detail-django-web">
|
||||
@@ -990,6 +1073,108 @@ box-sizing: border-box;</pre>
|
||||
<p><code>path(route, view, kwargs, name)</code> задаёт маршрут. <code>app_name</code> задаёт namespace. В шаблоне URL строится так: <code>{% url 'app:name' %}</code>.</p>
|
||||
<p>В шаблонах переменные пишутся как <code>{{ value }}</code>, теги как <code>{% tag %}</code>, фильтры как <code>{{ value|lower }}</code>. Если переменной нет, обычно выводится пустая строка.</p>
|
||||
<p><code>forms.Form</code> - обычная форма. <code>forms.ModelForm</code> - форма на основе модели. Для связи между полями используют общий метод <code>clean()</code>. После <code>is_valid()</code> доступны <code>cleaned_data</code> и <code>errors</code>.</p>
|
||||
<h4>Views</h4>
|
||||
<div class="term-grid">
|
||||
<div class="term"><strong>View</strong>Код, который принимает HTTP-запрос и возвращает HTTP-ответ.</div>
|
||||
<div class="term"><strong>FBV</strong>Function-Based View. Представление как обычная функция.</div>
|
||||
<div class="term"><strong>CBV</strong>Class-Based View. Представление как класс с готовыми методами.</div>
|
||||
<div class="term"><strong><code>request</code></strong>Объект HTTP-запроса: метод, пользователь, GET/POST-данные, cookies.</div>
|
||||
<div class="term"><strong><code>render()</code></strong>Собирает HTML из шаблона и context, возвращает HTTP-ответ.</div>
|
||||
<div class="term"><strong><code>get_object_or_404()</code></strong>Получает объект или возвращает 404, если объект не найден.</div>
|
||||
</div>
|
||||
<h4>CBV-классы</h4>
|
||||
<table>
|
||||
<tr><th>Класс</th><th>Назначение</th></tr>
|
||||
<tr><td><code>TemplateView</code></td><td>Показать шаблон без обязательной модели.</td></tr>
|
||||
<tr><td><code>ListView</code></td><td>Показать список объектов. Нужен <code>model</code> или <code>queryset</code>.</td></tr>
|
||||
<tr><td><code>DetailView</code></td><td>Показать один объект, обычно по <code>pk</code> или <code>slug</code>.</td></tr>
|
||||
<tr><td><code>CreateView</code></td><td>Создать объект через форму.</td></tr>
|
||||
<tr><td><code>UpdateView</code></td><td>Изменить объект через форму.</td></tr>
|
||||
<tr><td><code>DeleteView</code></td><td>Удалить объект, обычно после подтверждения.</td></tr>
|
||||
</table>
|
||||
<h4>Методы CBV</h4>
|
||||
<table>
|
||||
<tr><th>Метод/атрибут</th><th>Смысл</th></tr>
|
||||
<tr><td><code>as_view()</code></td><td>Превращает класс view в callable для URL-маршрута.</td></tr>
|
||||
<tr><td><code>get_queryset()</code></td><td>Возвращает список объектов для <code>ListView</code>.</td></tr>
|
||||
<tr><td><code>get_object()</code></td><td>Возвращает один объект для <code>DetailView</code>.</td></tr>
|
||||
<tr><td><code>get_context_data()</code></td><td>Возвращает словарь context для шаблона.</td></tr>
|
||||
<tr><td><code>context_object_name</code></td><td>Задаёт имя переменной объекта/списка в шаблоне.</td></tr>
|
||||
<tr><td><code>template_name</code></td><td>Явно задаёт путь к шаблону.</td></tr>
|
||||
<tr><td><code>paginate_by</code></td><td>Включает пагинацию списка.</td></tr>
|
||||
</table>
|
||||
<h4>URLs</h4>
|
||||
<pre>app_name = "blog"
|
||||
|
||||
urlpatterns = [
|
||||
path("posts/", PostListView.as_view(), name="post_list"),
|
||||
path("posts/<int:pk>/", PostDetailView.as_view(), name="post_detail"),
|
||||
]</pre>
|
||||
<div class="term-grid">
|
||||
<div class="term"><strong><code>urlpatterns</code></strong>Список маршрутов приложения или проекта.</div>
|
||||
<div class="term"><strong><code>path()</code></strong>Функция маршрутизации с простыми path-конвертерами.</div>
|
||||
<div class="term"><strong><code>re_path()</code></strong>Маршрут на основе регулярного выражения.</div>
|
||||
<div class="term"><strong><code>reverse()</code></strong>Строит URL по имени маршрута в Python.</div>
|
||||
<div class="term"><strong><code>name</code></strong>Имя маршрута, чтобы не хардкодить URL.</div>
|
||||
<div class="term"><strong><code>app_name</code></strong>Namespace приложения, например <code>blog:post_list</code>.</div>
|
||||
</div>
|
||||
<h4>Path-конвертеры</h4>
|
||||
<table>
|
||||
<tr><th>Конвертер</th><th>Что принимает</th></tr>
|
||||
<tr><td><code><str:name></code></td><td>Строка без слеша. По умолчанию.</td></tr>
|
||||
<tr><td><code><int:pk></code></td><td>Положительное целое число.</td></tr>
|
||||
<tr><td><code><slug:slug></code></td><td>Строка из букв, цифр, дефиса и подчёркивания.</td></tr>
|
||||
<tr><td><code><uuid:id></code></td><td>UUID.</td></tr>
|
||||
<tr><td><code><path:subpath></code></td><td>Строка, которая может содержать слеши.</td></tr>
|
||||
</table>
|
||||
<h4>Django Template Language</h4>
|
||||
<table>
|
||||
<tr><th>Синтаксис</th><th>Смысл</th></tr>
|
||||
<tr><td><code>{{ variable }}</code></td><td>Вывод переменной.</td></tr>
|
||||
<tr><td><code>{% tag %}</code></td><td>Шаблонный тег: цикл, условие, url, block.</td></tr>
|
||||
<tr><td><code>{# comment #}</code></td><td>Комментарий шаблона.</td></tr>
|
||||
<tr><td><code>{{ value|lower }}</code></td><td>Фильтр.</td></tr>
|
||||
<tr><td><code>{% for item in items %}</code></td><td>Цикл.</td></tr>
|
||||
<tr><td><code>{{ forloop.counter }}</code></td><td>Номер итерации цикла с 1.</td></tr>
|
||||
<tr><td><code>{% extends "base.html" %}</code></td><td>Наследование шаблона.</td></tr>
|
||||
<tr><td><code>{% block content %}</code></td><td>Область, которую переопределяет дочерний шаблон.</td></tr>
|
||||
<tr><td><code>{% include "part.html" %}</code></td><td>Включение другого шаблона.</td></tr>
|
||||
<tr><td><code>{% load static %}</code></td><td>Загрузка тегов static.</td></tr>
|
||||
<tr><td><code>{% static "css/app.css" %}</code></td><td>Путь к статическому файлу.</td></tr>
|
||||
</table>
|
||||
<h4>Django forms</h4>
|
||||
<div class="term-grid">
|
||||
<div class="term"><strong><code>forms.Form</code></strong>Форма без прямой привязки к модели.</div>
|
||||
<div class="term"><strong><code>forms.ModelForm</code></strong>Форма на основе модели. Поля задаются через <code>Meta</code>.</div>
|
||||
<div class="term"><strong><code>is_valid()</code></strong>Запускает валидацию формы.</div>
|
||||
<div class="term"><strong><code>cleaned_data</code></strong>Очищенные и приведённые к Python-типам данные.</div>
|
||||
<div class="term"><strong><code>errors</code></strong>Ошибки формы.</div>
|
||||
<div class="term"><strong><code>clean_field()</code></strong>Валидация одного поля.</div>
|
||||
<div class="term"><strong><code>clean()</code></strong>Валидация всей формы, подходит для связи между полями.</div>
|
||||
<div class="term"><strong><code>widget</code></strong>HTML-представление поля, например <code>PasswordInput</code>.</div>
|
||||
</div>
|
||||
<table>
|
||||
<tr><th>Поле формы</th><th>Назначение</th></tr>
|
||||
<tr><td><code>CharField</code></td><td>Строка.</td></tr>
|
||||
<tr><td><code>IntegerField</code></td><td>Целое число.</td></tr>
|
||||
<tr><td><code>BooleanField</code></td><td>Логическое значение.</td></tr>
|
||||
<tr><td><code>ChoiceField</code></td><td>Выбор из списка.</td></tr>
|
||||
<tr><td><code>EmailField</code></td><td>Email.</td></tr>
|
||||
<tr><td><code>DateField</code></td><td>Дата.</td></tr>
|
||||
<tr><td><code>FileField</code></td><td>Файл.</td></tr>
|
||||
</table>
|
||||
<pre>class RegisterForm(forms.Form):
|
||||
password = forms.CharField(widget=forms.PasswordInput)
|
||||
password_repeat = forms.CharField(widget=forms.PasswordInput)
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
if cleaned_data.get("password") != cleaned_data.get("password_repeat"):
|
||||
raise forms.ValidationError("Пароли не совпадают")
|
||||
return cleaned_data</pre>
|
||||
<div class="exam">
|
||||
Для проверки связи между полями нужен общий <code>clean()</code>, а не <code>clean_password()</code>, потому что сравниваются два значения.
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user