owned this note
owned this note
Published
Linked with GitHub
# Модели и шаблоны
---
## Словарь терминов
----
Проект - совокупность всего программного кода, составляющего разрабатываемый сайт. Физически он представляет собой папку, в которой находятся папки и файлы с исходным кодом.
----
папка Конфигурации (название условное) - пакет языка Python, содержащий модули, которые относятся к проекту целиком и задают его конфигурацию (в частности, ключевые настройки). Название этого пакета совпадает с названием проекта, и менять его не стоит — в противном случае придется вносить в код обширные правки.
----
Пакет в Python – это каталог, включающий в себя другие каталоги и модули, но при этом дополнительно содержащий файл `__init__.py`. Пакеты используются для формирования пространства имен, что позволяет работать с модулями через указание уровня вложенности (через точку).
----
Приложение в терминологии Django — это отдельный фрагмент функциональности разрабатываемого сайта, более или менее независимый от других таких же фрагментов и входящий в состав проекта. Приложение может реализовывать работу всего сайта, его раздела или же какой-либо внутренней подсистемы сайта, используемой другими приложениями. Любое приложение представляется обычным пакетом Python.
----
Контроллер Django (он же view или представление) — это код, запускаемый при обращении по интернет-адресу определенного формата и в ответ выводящий на экран определенную веб-страницу.
----
Контроллер Django может представлять собой как функцию (контроллер-функция), так и класс (контроллер-класс). Первые более универсальны, но зачастую трудоемки в программировании, вторые позволяют выполнить типовые задачи, наподобие вывода списка каких-либо позиций, минимумом кода.
----
Путь — это часть интернет-адреса, находящаяся между адресом хоста и набором GET-параметров (например, интернет-адрес http://localhost:8000/bboard/34/edit/ содержит путь bboard/34/edit/).
----
Маршрутизатор - Важнейшей частью любого Web-фреймворка является механизм, отвечающий за маршрутизацию. В Django для этого используется свой небольшой eDSL, описывающий urlpatterns — набор образцов, с которыми сопоставляются пути из каждого входящего запроса.
----
Каждый образец состоит из описания статических и динамических частей пути в виде строки или регулярного выражения. Статические части пути в образце просто проверяются на равенство соответствующим участкам пути в запросе. Динамические же участки пути позволяют захватывать значения и передавать во view в качестве аргументов.
----
Как только выясняется, что путь или его начало совпали с образцом, происходит либо вызов view, либо передача оставшейся части пути во вложенный блок urlpatterns. В большинстве больших Django-проектов urlpatterns вложены друг в друга и представляют собой дерево.
---
## Модели
----
Модель — это класс, описывающий определенную таблицу в базе данных, в частности набор имеющихся в ней полей. Отдельный экземпляр класса модели представляет отдельную запись таблицы, позволяет получать значения, хранящиеся в полях записи, и заносить в них новые значения. Модель никак не привязана к конкретному формату базы данных.
----
Объявим модель Bb, представляющую объявление, со следующими полями:
```
* title — заголовок объявления с названием продаваемого
товара (тип — строковый, длина — 50 символов).
Поле, обязательное к заполнению;
* content — сам текст объявления,
описание товара (тип — текст);
* price — цена (тип — вещественное число);
* published— дата публикации (тип— временная отметка,
значение по умолчанию — текущие дата и время,
индексированное).
```
----
Завершим работу отладочного веб-сервера. Откроем модуль models.py пакета приложения bboard и запишем в него следующий код
```
from django.db import models
class Bb(models.Model):
title = models.CharField(max_length=50)
content = models.TextField(null=True, blank=True)
price = models.FloatField(null=True, blank=True)
published = models.DateTimeField(auto_now_add=True,
db_index=True)
```
----
Рассмотрим использованные нами классы полей и их параметры:
* CharField
* TextField
* FloatField
* DateTimeField
----
Миграция — это программа, сгенерированная на основе заданной модели и создающая в базе данных все описанные этой моделью структуры: таблицу, поля, индексы, правила и связи.
----
Чтобы сгенерировать миграцию на основе модели `Bb`, переключимся в командную строку, проверим, остановлен ли отладочный веб-сервер и находимся ли мы в папке проекта, и дадим команду:
`python manage.py makemigrations bboard`
----
Модуль с кодом нашей первой миграции будет иметь имя `OOO1_initial.py.`
```
from django.db inport migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [ ]
operations = [
migrations.CreateModel(
name='Bb’,
fields=[
...
],
) ,
]
```
----
```
fields=[
(’id’, models.AutoField(auto_created=True,
primary_key=True,
serialize=False,
verbose name=’ID’)),
(’title’,
models.CharField(max_length=50)),
(’content',
models.TextField(blank=True, null=True)),
('price',
models.FloatField(blank=True, null=True)),
('published',
models.DateTimeField(auto_now_add=True,
db_index=True)),],
```
----
Миграция при выполнении порождает команды на языке SQL, создающие в базе необходимые структуры. Посмотрим на SQL-код, создаваемый нашей миграцией, задав в командной строке команду:
`python manage.py sqlmigrate bboard 0001`
----
После команды sqlmigrate, выводящей SQL-код, мы поставили имя приложения и числовую часть имени модуля с миграцией:
```
BEGIN;
— Create model Bb
CREATE TABLE "bboard_bb" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"title" varchar(50) NOT NULL,
"content" text NULL,
"price" real NULL,
"published" datetime NOT NULL
);
CREATE INDEX "bboard_bb_published_58fde1b5"
ON "bboard_bb" ("published");
COMMIT;
```
----
Для выполнения первой миграции наберем в командной строке команду:
`python manage.py migrate`
----

----
Создадим первое объявление — первую запись модели Bb:
:::info
Для операций дальше нужно активировать консоль Django командой `python manage.py shell`
:::
```
from bboard.models import Bb
bl = Bb(title='Дача',
content='Общество "Двухэтажники". Два этажа,
кирпич, свет, газ, канализация',
price=500000)
```
----
Чтобы сохранить запись в базу данных, достаточно вызвать у нее метод `save()` о без параметров:
`bl.save()`
----
Проверим, сохранилось ли наше первое объявление, получив значение ключевого поля:
`bl.pk`
----
Мы можем обратиться к любому полю записи, воспользовавшись соответствующимему атрибутом класса модели:
```
bl.title
’Дача’
bl.content
'Общество "Двухэтажники". Два этажа,
кирпич, свет, газ, канализация'
bl.price
500000
bl.published
datetime.datetime(2019, 11, 21,
15, 17, 31, 695200, tzinfo=<UTC>)
bl.id
1
```
----
Создадим еще одно объявление:
```
b2 = Bb()
b2.title = 'Автомобиль'
b2.content = "Жигули"
b2.save ()
b2.рк
2
```
----
Давайте дополним ее:
```
b2.content = '"Жигули",
1980 года,
ржавая,
некрашеная,
сильно битая'
b2.save()
```
----
Добавим еще одно объявление:
```
Bb.objects.create(title='Дом',
content='Трехэтажный, кирпич',
price=50000000)
<Bb: Bb obj ect (3)>
```
----
Все классы моделей поддерживают атрибут класса objects. Он хранит диспетчер записей — объект, представляющий все имеющиеся в модели записи и являющийся экземпляром класса Manager.
Метод `create()` диспетчера записей создает новую запись модели, принимая в качестве набора именованных параметров значения ее полей, сразу же сохраняет ее ивозвращает в качестве результата.
----
Выведем ключи и заголовки всех объявлений, имеющихся в модели Bb:
```
for b in Bb.objects.all():
print(b.pk, ': ', b.title)
```
----
Метод `all` диспетчера записей возвращает набор записей— последовательность из всех записей модели, которую можно перебрать в цикле.
----
Отсортируем записи модели по заголовку:
```
for b in Bb.objects.order_by('title'):
print(b.pk, ': ', b.title)
```
----
Метод `order_by()` диспетчера записей сортирует записи по значению поля, имя которого указано в параметре, и сразу же возвращает набор записей, получившийся в результате сортировки.
Извлечем объявления о продаже домов:
```
for b in Bb.objects.filter(title='Дом'):
print(b.pk, ': ', b.title)
```
----
Метод `filter()` диспетчера записей фильтрует записи по заданным критериям.
----
Объявление о продаже автомобиля имеет ключ 2. Отыщем его:
```
b = Bb.objects.get(pk=2)
b.title
```
----
Метод `get()` диспетчера записей имеет то же назначение, что и метод `filter()`, и вызывается аналогичным образом. Однако он ищет не все подходящие записи, а лишь одну и возвращает ее в качестве результата.
----
Давайте удалим эту запись:
`b.delete()`
Метод delete () модели, как уже понятно, удаляет текущую запись и возвращает сведения о количестве удаленных записей, обычно малополезные.
:::info
Чтобы выйти из консоли, наберите команду exit()
:::
----
Откроем модуль views.py пакета приложения bboard и исправим хранящийся в нем код:
```
from django.http import HttpResponse
from .models import Bb
def index(request):
s = 'Список объявлений\r\n\r\n\r\n'
for bb in Bb.objects.order_by('-published'):
s += bb.title + '\r\n' + bb.content + '\r\n\r\n'
return HttpResponse(s,
content_type='text/plain; charset=utf-8')
```
----

----
Рекомендации при создании базы данных:
* Каждая модель должна представлять только один упрощенный объект реального мира.
* При создании связей таблиц (об этом поговорим на будующих занятиях), убедитесь, что эта связь не заставляет вас дублировать записи.
* В случае, если связь требует дублировать записи таблицы, то выделите "разводящую" таблицу.
---
## Шаблоны
----
Шаблон — это образец для генерирования веб-страницы, отправляемой клиенту в составе ответа. Генерированием страниц на основе шаблонов занимается подсистема Django, называемая шаблонизатором.
----
Шаблон Django — это файл с HTML-кодом страницы, содержащий особые команды шаблонизатора: директивы, теги и фильтры. Директивы указывают поместить в заданное место HTML-кода какое-либо значение, теги управляют генерированием содержимого, а фильтры выполняют какие-либо преобразования указанного значения перед выводом.
----
В файле `settings.py` нахдим строку `from pathlib import Path` и заменяем её на `from pathlib import Path, os`
----
Далее нам неоюнодимо добавить строку `os.path.join(BASE_DIR, 'templates')` в параметр `'DIRS': []`. Это позволит задать папку для шаблонов по умолчанию.
```
TEMPLATES = [
{
...
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {...},
},
]
```
----
Создадим в папке пакета приложения bboard папку templates, а в ней — вложенную папку bboard. Сохраним в этой папке наш первый шаблон index.html
```
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Главная :: Доска объявлений</title>
</head>
<body>
<h1>0бъявления</h1>
{% for bb in bbs %}
<div>
<h2>{{ bb.title }}</h2>
<p>{{ bb.content }}</p>
<p>{{ bb.published|date:"d.m.Y H:i:s"
}}</p>
</div>
{% endfor %}
</body>
</html>
```
----
Рассмотрим первый тег шаблонизатора:
```
{% for bb in bbs %}
...
{% endfor %}
```
----
Теперь познакомимся с директивой шаблонизатора:
`{{ bb.title }}`
----
И, наконец, фильтр date:
`<р>{{ bb.published|date: "d.m.Y H:i:s" }}</p>`
----
Откроем модуль `views.py` пакета приложения bboard и внесем исправления в его код.
```
from django.http import HttpResponse
from django.template import loader
from .models import Bb
def index(request) :
template = loader.get_template('bboard/index.html')
bbs = Bb.objects.order_by('-published')
context = {'bbs': bbs}
return HttpResponse(template.render(context, request))
```
----

----
В коде контроллера `index()` для рендеринга мы использовали низкоуровневые инструменты, несколько усложнив код. Но Django предоставляет средства более высокого уровня — функции-сокращения. Так, функция-сокращение `render()` из модуля django.shortcuts выполняет и загрузку, и рендеринг шаблона.
----
Попробуем ее в деле, исправив код модуля `views.py`:
```
from django.shortcuts import render
from .models import Bb
def index(request):
bbs = Bb.objects.order_by('-published')
return render(request, 'bboard/index.html',
{'bbs': bbs})
```