Auto | arch-x1: 2026-06-05 13:29:15

This commit is contained in:
Dmitry
2026-06-05 13:29:15 +03:00
parent 8e206fed3a
commit 1acb87897f
6 changed files with 763 additions and 36 deletions
@@ -8,7 +8,7 @@ tags:
- database
- migrations
created: 2026-05-30
updated: 2026-05-31
updated: 2026-06-05
source:
- '[[lec1-django_start_models-1.pdf]]'
- '[[lec4-django_lec_queries.pdf]]'
@@ -77,6 +77,15 @@ class Article(models.Model):
cover = models.ImageField(upload_to="covers/", blank=True)
```
Если не указать `primary_key=True`, Django автоматически создаёт поле `id`. В современных версиях тип поля по умолчанию обычно задаётся настройкой `DEFAULT_AUTO_FIELD`, часто это `BigAutoField`.
`CharField` требует `max_length`, потому что БД должна знать максимальный размер строки.
`null=True` и `blank=True` — не одно и то же:
- `null=True` разрешает хранить `NULL` в базе данных;
- `blank=True` разрешает оставлять поле пустым в формах и админке.
### Отношения
- `ForeignKey(Target, on_delete=...)` — связь "один ко многим": у одной записи `Target` может быть много связанных записей текущей модели.
- `OneToOneField(Target, on_delete=...)` — связь "один к одному": каждой записи соответствует максимум одна связанная запись.
@@ -105,6 +114,32 @@ class Book(models.Model):
co_authors = models.ManyToManyField(Author, related_name="coauthored_books", blank=True)
```
`related_name` задаёт имя обратной связи. Если у книги есть `author = ForeignKey(Author, related_name="books")`, то у автора можно получить книги так:
```python
author.books.all()
```
Для `ManyToManyField` промежуточная модель задаётся через `through`, когда у самой связи есть дополнительные поля:
```python
class Student(models.Model):
name = models.CharField(max_length=100)
class Course(models.Model):
title = models.CharField(max_length=100)
students = models.ManyToManyField(Student, through="Enrollment")
class Enrollment(models.Model):
student = models.ForeignKey(Student, on_delete=models.CASCADE)
course = models.ForeignKey(Course, on_delete=models.CASCADE)
grade = models.IntegerField(null=True, blank=True)
```
Связь можно менять методами `.add()`, `.remove()`, `.set()`, `.clear()`.
---
## Миграции
@@ -214,3 +249,34 @@ books = Book.objects.filter(
# F: увеличить счётчик просмотров прямо в БД
Book.objects.filter(id=1).update(views=F("views") + 1)
```
## Простыми словами для экзамена
Модель Django — это Python-класс, который описывает таблицу БД. Поле модели — это колонка таблицы. Объект модели — это строка таблицы.
`Class Meta` задаёт служебные настройки модели: сортировку, человекочитаемые имена, ограничения, имя таблицы.
Основные методы QuerySet:
- `.all()` — все объекты;
- `.filter()` — несколько объектов по условию;
- `.exclude()` — всё, кроме условия;
- `.get()` — ровно один объект; если ноль или больше одного, будет ошибка;
- `.order_by()` — сортировка;
- `.count()` — количество;
- `.exists()` — есть ли хотя бы одна запись;
- `.distinct()` — убрать дубли;
- `.aggregate()` — один итог по всей выборке, возвращает словарь;
- `.annotate()` — добавляет вычисляемое поле каждому объекту.
Если нужно найти максимум цены по каждой категории, используют `annotate()` на категориях:
```python
Category.objects.annotate(max_price=Max("product__price"))
```
Если нужен один максимум по всем товарам, используют `aggregate()`:
```python
Product.objects.aggregate(max_price=Max("price"))
```
@@ -8,7 +8,7 @@ tags:
- cbv
- fbv
created: 2026-05-30
updated: 2026-05-31
updated: 2026-06-05
source:
- '[[lec2-django_lec_urls_views_templates-1.pdf]]'
- '[[lec3-django_cbv-1.pdf]]'
@@ -76,6 +76,15 @@ from django.urls import reverse
url = reverse("blog:post_detail", kwargs={"pk": 1})
```
`path()` обычно принимает:
- `route` — строка маршрута;
- `view` — функция или `ClassView.as_view()`;
- `kwargs` — дополнительные аргументы view;
- `name` — имя маршрута для `{% url %}` и `reverse()`.
`app_name` задаёт namespace приложения. Тогда маршрут вызывается как `blog:post_detail`, а не просто `post_detail`.
---
## Представления (Views)
@@ -94,6 +103,12 @@ def index(request):
return render(request, "app/index.html", {"items": latest_items})
```
У `render()` первым аргументом должен идти `request`:
```python
return render(request, "index.html", context)
```
```python
from django.shortcuts import get_object_or_404, render
@@ -140,6 +155,35 @@ class PostDetailView(DetailView):
context_object_name = "post"
```
Если в `ListView` не указать ни `model`, ни `queryset`, Django не поймёт, какие объекты показывать, и выдаст ошибку.
Стандартные имена в контексте:
- `ListView``object_list` и дополнительно `<model>_list`, например `post_list`;
- `DetailView``object` и дополнительно `<model>`, например `post`.
Методы, которые часто переопределяют:
- `get_queryset()` — изменить список объектов;
- `get_object()` — изменить получение одного объекта;
- `get_context_data()` — добавить данные в шаблон.
При переопределении `get_context_data()` обычно сначала вызывают базовую логику:
```python
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = "Посты"
return context
```
Паджинация в `ListView` включается через `paginate_by = 10`. В шаблоне появляются `page_obj`, `paginator`, `is_paginated`.
Шаблоны по умолчанию:
- `ListView` ищет `<app>/<model>_list.html`;
- `DetailView` ищет `<app>/<model>_detail.html`.
```python
# blog/urls.py
from django.urls import path
@@ -167,6 +211,8 @@ urlpatterns = [
Шаблон получает контекст из view. Например, если view передала `{"posts": posts}`, в шаблоне доступна переменная `posts`.
Если обратиться к переменной, которой нет в контексте, Django-шаблон обычно выведет пустую строку, а не Python-ошибку.
```html
{% for post in posts %}
<article>
@@ -247,3 +293,27 @@ STATICFILES_DIRS = [BASE_DIR / "static"]
```bash
python manage.py collectstatic
```
## Простыми словами для экзамена
FBV — view как функция. CBV — view как класс с готовой логикой.
Маршрут соединяет URL и view:
```python
path("find/", views.find, name="find")
```
В шаблоне ссылка на именованный маршрут создаётся так:
```html
<a href="{% url 'myapp:find' %}">Поиск</a>
```
Шаблонные переменные пишутся через `{{ variable }}`. Шаблонные теги пишутся через `{% tag %}`. Комментарии пишутся через `{# comment #}`.
Ключ словаря в шаблоне читается через точку:
```django
{{ user_data.name }}
```
@@ -8,7 +8,7 @@ tags:
- validation
- modelform
created: 2026-05-30
updated: 2026-05-31
updated: 2026-06-05
title: "Django: Работа с формами и CUD"
source:
- '[[lec5-django_cud_form.pdf]]'
@@ -43,6 +43,8 @@ class BlogForm(forms.ModelForm):
}
```
В `ModelForm` модель и поля задаются во внутреннем классе `Meta`. `fields` показывает, какие поля модели попадут в форму. `exclude` можно использовать наоборот: указать, какие поля не включать.
---
## Жизненный цикл формы в представлении
@@ -107,6 +109,8 @@ class RegisterForm(forms.Form):
return cleaned_data
```
Для проверки связи между полями используют общий `clean()`. Например, "Пароль" и "Повтор пароля" нельзя нормально проверить через `clean_password()`, потому что нужно сравнить два поля.
---
## Generic Editing Views (CBV для CUD)
@@ -188,3 +192,39 @@ class BlogDeleteView(DeleteView):
При `POST` Django сверяет токен из формы с токеном пользователя. Если токена нет или он неправильный, запрос отклоняется.
Короткое правило: во все HTML-формы с `method="post"` добавлять `{% csrf_token %}`.
## Простыми словами для экзамена
Форма Django делает три вещи:
1. Описывает поля.
2. Валидирует входные данные.
3. Даёт очищенные данные в `cleaned_data`.
Основные поля:
- `CharField` — строка;
- `IntegerField` — целое число;
- `BooleanField``True/False`;
- `ChoiceField` — выбор из списка;
- `EmailField` — email;
- `DateField` — дата;
- `FileField` — файл.
`widget` управляет HTML-представлением поля, а не типом данных. Например, строковое поле можно показать как пароль:
```python
password = forms.CharField(widget=forms.PasswordInput)
```
Подсказка к полю задаётся через `help_text`:
```python
email = forms.EmailField(help_text="Введите рабочую почту")
```
После `form.is_valid()`:
- `form.cleaned_data` содержит нормальные Python-значения;
- `form.errors` содержит ошибки;
- `form.save()` у `ModelForm` сохраняет объект модели.