Files
SecondBrain/90 Library/Programming/Python/Представления, шаблоны и CBV.md
T
2026-06-05 13:29:15 +03:00

320 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
status: processing
type: concept
tags:
- django
- routing
- templates
- cbv
- fbv
created: 2026-05-30
updated: 2026-06-05
source:
- '[[lec2-django_lec_urls_views_templates-1.pdf]]'
- '[[lec3-django_cbv-1.pdf]]'
- '[[p4-django_cbv-1.pdf]]'
aliases:
- 'Django: Представления, шаблоны и CBV'
---
# Django: Представления, шаблоны и CBV
## Маршрутизация (URL Routing)
- Описывается в `urlpatterns` с помощью `path()` и `re_path()`.
- Конвертеры: `<int:pk>`, `<slug:slug>`, `<uuid:id>`.
- Включение других файлов: `path('blog/', include('blog.urls'))`.
- Реверсирование: `{% url 'name' %}` в шаблонах или `reverse('name')` в Python.
Конвертеры вытаскивают часть URL, проверяют её тип и передают во view как аргумент:
- `<str:name>` — непустая строка без `/`; используется по умолчанию.
- `<int:pk>` — целое положительное число.
- `<slug:slug>` — строка для человекочитаемого URL: буквы, цифры, `_`, `-`.
- `<uuid:id>` — UUID, например `075194d3-6885-417e-a8a8-6c931e272f00`.
- `<path:subpath>` — строка, которая может содержать `/`.
Маршрутизация связывает URL с view-функцией или view-классом. Имя маршрута (`name`) нужно, чтобы не хардкодить URL в коде и шаблонах.
```python
# project/urls.py
from django.urls import include, path
urlpatterns = [
path("blog/", include("blog.urls")),
]
```
```python
# blog/urls.py
from django.urls import path
from . import views
app_name = "blog"
urlpatterns = [
path("", views.post_list, name="post_list"),
path("<int:pk>/", views.post_detail, name="post_detail"),
path("tag/<slug:slug>/", views.posts_by_tag, name="posts_by_tag"),
path("files/<path:subpath>/", views.file_detail, name="file_detail"),
]
```
```python
def post_detail(request, pk):
# pk уже int
...
def posts_by_tag(request, slug):
# slug — строка из URL
...
```
```python
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)
Views принимают `HttpRequest` и возвращают `HttpResponse`.
View — это точка входа для запроса. В ней обычно читают данные из БД, проверяют условия и возвращают HTML, JSON, редирект или ошибку.
### Функциональные представления (FBV)
FBV — обычная функция. Удобна, когда логика короткая и нестандартная.
```python
from django.shortcuts import render, get_object_or_404
def index(request):
latest_items = Model.objects.all()[:5]
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
from .models import Post
def post_detail(request, pk):
post = get_object_or_404(Post, pk=pk)
return render(request, "blog/detail.html", {"post": post})
```
### Классовые представления (CBV)
Абстрагируют типичные задачи. Вызываются в URL через `.as_view()`.
- **TemplateView:** Отображение статического шаблона.
- **ListView:** Автоматический список объектов (данные в `object_list`).
- **DetailView:** Детальная информация об одном объекте (ищет по `pk` или `slug`).
CBV — класс с готовым поведением. Django сам вызывает нужные методы класса: например, `get()` для GET-запроса или `get_queryset()` для получения списка объектов.
**Пример ListView:**
```python
from django.views.generic import DetailView, ListView, TemplateView
from .models import Post
class AboutView(TemplateView):
template_name = "blog/about.html"
class PostListView(ListView):
model = Post
template_name = "blog/list.html"
context_object_name = "posts"
paginate_by = 10
def get_queryset(self):
return Post.objects.filter(is_published=True).order_by("-created_at")
class PostDetailView(DetailView):
model = Post
template_name = "blog/detail.html"
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
from .views import AboutView, PostDetailView, PostListView
app_name = "blog"
urlpatterns = [
path("about/", AboutView.as_view(), name="about"),
path("", PostListView.as_view(), name="post_list"),
path("<int:pk>/", PostDetailView.as_view(), name="post_detail"),
]
```
---
## Шаблоны (Templates)
Используют **Django Template Language (DTL)**.
### Синтаксис
- **Переменные:** `{{ var.attr }}`.
- **Теги:** `{% if %}`, `{% for %}`, `{% url %}`, `{% csrf_token %}`.
- **Фильтры:** `{{ date|date:"Y-m-d" }}`, `{{ list|length }}`, `{{ text|lower }}`.
Шаблон получает контекст из view. Например, если view передала `{"posts": posts}`, в шаблоне доступна переменная `posts`.
Если обратиться к переменной, которой нет в контексте, Django-шаблон обычно выведет пустую строку, а не Python-ошибку.
```html
{% for post in posts %}
<article>
<h2>
<a href="{% url 'blog:post_detail' post.pk %}">
{{ post.title|upper }}
</a>
</h2>
{% if post.is_published %}
<p>{{ post.created_at|date:"Y-m-d" }}</p>
{% endif %}
</article>
{% empty %}
<p>Постов нет.</p>
{% endfor %}
```
### Наследование шаблонов
Позволяет избежать дублирования HTML-кода.
- **Базовый шаблон (`base.html`):** Определяет блоки `{% block content %}{% endblock %}`.
- **Дочерний шаблон:** Использует `{% extends "base.html" %}` и переопределяет блоки.
```html
<!-- templates/base.html -->
<!doctype html>
<html lang="ru">
<head>
<title>{% block title %}Сайт{% endblock %}</title>
</head>
<body>
<main>
{% block content %}{% endblock %}
</main>
</body>
</html>
```
```html
<!-- templates/blog/list.html -->
{% extends "base.html" %}
{% block title %}Посты{% endblock %}
{% block content %}
<h1>Посты</h1>
{% for post in posts %}
<a href="{% url 'blog:post_detail' post.pk %}">
{{ post.title }}
</a>
{% endfor %}
{% endblock %}
```
---
## Статические файлы (Static)
- Подключаются через `{% load static %}`.
- Настройки в `settings.py`: `STATIC_URL`, `STATICFILES_DIRS`.
- В продакшне используется команда `python manage.py collectstatic`.
Статика — это CSS, JavaScript, изображения и другие файлы, которые не генерируются view.
```python
# settings.py
STATIC_URL = "static/"
STATICFILES_DIRS = [BASE_DIR / "static"]
```
```html
{% load static %}
<link rel="stylesheet" href="{% static 'css/app.css' %}">
<script src="{% static 'js/app.js' %}"></script>
```
```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 }}
```