Руководство Django часть 4: административная панель Django - Изучение веб-разработки

Руководство Django часть 4: административная панель Django
==========================================================

* Назад
* Обзор: Django
* Далее

Теперь, когда модели для сайта местной библиотеки созданы, добавим некоторые "настоящие" данные о книгах, используя административную панель Django Admin. Для начала мы покажем, как зарегистрировать в ней модели, потом как войти и создать какие-нибудь данные. В конце статьи мы покажем некоторые способы дальнейшего улучшения вида админ-панели.

| Предусловия: | Сначала завершите: Руководство часть 3: использование моделей. |
| --- | --- |
| Цель: | Уяснить преимущества и ограничения админ-панели Django, научиться использовать её для создания записей для наших моделей. |

Обзор
-----

*Приложение* Django admin может использовать ваши модели для автоматического создания части сайта, предназначенной для создания, просмотра, обновления и удаления записей. Это может сэкономить вам много времени в процессе разработки, упрощая тестирование ваших моделей на предмет *правильности* данных. Оно также может быть полезным для управления данными на стадии публикации, в зависимости от типа веб-сайта. Проект Django рекомендует это приложение только для управления внутренними данными (т.е.для использования администраторами, либо людьми внутри вашей организации), так как модельно-ориентированный подход не обязательно является наилучшим интерфейсом для всех пользователей и раскрывает много лишних подробностей о моделях.

Все необходимые настройки, которые необходимо включить в admin приложение вашего веб-сайта, были сделаны автоматически, когда вы создали каркас проекта ( информацию о необходимых актуальных зависимостях смотрите здесь - Django docs) . В результате все, что необходимо сделать для того, чтобы добавить модели в приложение admin, это *зарегистрировать* их. В конце этой статьи мы представим краткую демонстрацию того, каким образом можно дополнительно настроить админ-панель для лучшего отображения данные наших моделей.

После регистрации моделей мы покажем как создать нового суперпользователя , войти на сайт от его имени и создать книги, авторов, экземпляры книг и жанры. Это будет полезным для тестирования представлений и шаблонов, которые мы начнём создавать в следующей части руководства.

Регистрация моделей
-------------------

Вначале откройте файл **admin.py** в папке приложения (**/locallibrary/catalog/admin.py**). Пока он выглядит так (заметьте, что он уже содержит импорт `django.contrib.admin)`:

```python
from django.contrib import admin

# Register your models here.
```

Зарегистрируйте модели путём вставки следующего текста в нижнюю часть этого файла. Этот код просто импортирует модели и затем вызывает `admin.site.register` для регистрации каждой из них.

```python
from .models import Author, Genre, Book, BookInstance

admin.site.register(Book)
admin.site.register(Author)
admin.site.register(Genre)
admin.site.register(BookInstance)
```

**Примечание:** Если вы приняли участие в создании модели для представления естественного языка книги (см. обучающую статью о моделях), импортируйте и зарегистрируйте её тоже!

Это самый простой способ регистрации модели или моделей. Админ-панель имеет множество настроек. Мы рассмотрим другие способы регистрации ваших моделей ниже.

Создание суперпользователя
--------------------------

Для того, чтобы войти в админ-панель, нам необходимо иметь учётную запись пользователя со статусом *Staff (сотрудники).* Для просмотра и создания записей, пользователю также понадобится разрешение для управления всеми нашими объектами. Вы можете создать учётную запись "superuser", которая даёт полный доступ к сайту и все необходимые разрешения, используя **manage.py**.

Для создания суперпользователя вызовите следующую команду из той же папки, где расположен **manage.py**. Вас попросят ввести имя пользователя, адрес электронной почты и надёжный пароль.

```bash
python3 manage.py createsuperuser
```

После выполнения этой команды новый суперпользователь будет добавлен в базу данных. Теперь перезапустите сервер, чтобы можно было протестировать вход на сайт:

```bash
python3 manage.py runserver
```

Вход в админ-панель и её использование
--------------------------------------

Для входа в админ-панель откройте ссылку */admin* (например http://127.0.0.1:8000/admin) и введите логин и пароль вашего нового суперпользователя (вас перенаправят на login-страницу и потом обратно на /admin после ввода всех деталей).

В этой части сайта отображаются все наши модели, сгруппированные по установленному приложению. Вы можете кликнуть на названии модели, чтобы получить список всех связанных записей, далее можете кликнуть на этих записях, для их редактирования . Также можно непосредственно кликнуть на ссылку **Add**, расположенную рядом с каждой моделью, чтобы начать создание записи этого типа.

![Admin Site - Home page](/ru/docs/Learn/Server-side/Django/Admin_site/admin_home.png)

Кликните на ссылке **Add** справа от *Books*, чтобы создать новую книгу (появится диалоговое окно как на картинке внизу). Заметьте, что заголовок каждого поля - это тип используемого виджета, и `help_text` (если есть) совпадает со значением, которое вы указали в модели.

Введите значение для полей. Вы можете создавать новых авторов или жанры, нажимая на значок "+ ", расположенный рядом с соответствующим полем (или выберите существующее значение из списков, если вы уже создали их). Когда вы закончили, нажмите на **SAVE,** **Save and add another**, или **Save and continue editing,** чтобы сохранить записи.

![Admin Site - Book Add](/ru/docs/Learn/Server-side/Django/Admin_site/admin_book_add.png)

**Примечание:** А сейчас, хотелось бы, чтобы вы добавили несколько книг, авторов и жанров (например, Фэнтези) в ваше приложение. Удостоверьтесь, что каждый автор и жанр включает пару различных книг (позже, когда мы реализуем представления "list" и "detail", это сделает их более интересными).

После того, когда книги добавлены, для перехода на главную страницу админ-панели кликните на ссылке **Home** в верхней части страницы. Потом кликните на ссылке **Books** для отображения текущего списка книг (или на одной из других ссылок, чтобы увидеть список соответствующей модели). После добавления нескольких книг список может выглядеть наподобие скриншота ниже. Отображается название каждой из книг. Его возвращает метод `__str__()` в модели Book, созданной в предыдущей статье.

![Admin Site - List of book objects](/ru/docs/Learn/Server-side/Django/Admin_site/admin_book_list.png)

Для удаления книги из этого списка выберите чекбокс рядом с ней и действие *delete...* из выпадающего списка *Action*, а затем нажмите кнопку **Go**. Также можно добавить новую книгу, нажав на кнопку **ADD BOOK**.

Вы можете редактировать книгу, кликнув по ссылке с её названием. Страница редактирования книги, приведённая ниже, практически идентична странице добавления новой книги. Основные отличия - это заголовок страницы (*Change book*) и наличие кнопок **Delete**, **HISTORY** и **VIEW ON SITE.** Последняя присутствует, так как мы определили метод `get_absolute_url()` в нашей модели.

![Admin Site - Book Edit](/ru/docs/Learn/Server-side/Django/Admin_site/admin_book_modify.png)

Теперь перейдите назад на страницу **Home** (используя ссылку *Home* в навигационной цепочке вверху страницы) и просмотрите списки **Author** и **Genre**. В них уже должно быть несколько элементов, созданных при добавлении новых книг. Если хотите, добавьте ещё.

Однако у вас не будет ни одного экземпляра книги, потому что они не создаются из модели `Book` (хотя можно создать книгу из модели `BookInstance` — такова природа поля `ForeignKey`). Для отображения страницы *Add book instance* (см. рисунок ниже) вернитесь на страницу *Home* и нажмите кнопку **Add**. Обратите внимание на длинный уникальный Id для идентификации конкретного экземпляра книги в библиотеке.

![Admin Site - BookInstance Add](/ru/docs/Learn/Server-side/Django/Admin_site/admin_bookinstance_add.png)

Создайте несколько экземпляров для каждой из ваших книг. Установите статус *Available (доступен)* для некоторых экземпляров и *On loan (выдан)* для остальных. Если статус экземпляра **not** *Available (недоступен)*, то также установите дату возврата (*Due back)*.

Вот и все! Вы изучили как запустить и использовать админ-панель. Также были созданы записи для `Book`, `BookInstance`, `Genre` и `Author`, которые можно будет использовать после создания наших собственных представлений и шаблонов.

"Продвинутая" конфигурация
--------------------------

Django выполняет неплохую работу по созданию базовой админ-панели используя информацию из зарегистрированных моделей:

* каждая модель имеет список записей, каждая из которых идентифицируется строкой, создаваемой методом `__str__()` модели, и связана с представлением для её редактирования. По умолчанию, в верхней части этого представления находится меню действий, которое может быть использовано для удаления нескольких записей за раз
* Формы для редактирования и добавления записей содержат все поля модели, которые расположены вертикально в порядке их объявления в модели.

Можно настроить интерфейс пользователя для упрощения его использования. Некоторые доступные настройки:

* List views:
    + добавление дополнительных отображаемых полей или информации для каждой записи.
    + добавление фильтров для отбора записей по разным критериям (например, статус выдачи книги).
    + добавление дополнительных вариантов выбора в меню действий и места расположения этого меню на форме.
* Detail views
    + выбор отображаемых полей, их порядка, группирования и т.д.
    + добавление связанных полей к записи (например, возможности добавления и редактирования записей книг при создании записи автора).

В этом разделе рассмотрим некоторые изменения для совершенствования интерфейса пользователя нашей местной библиотеки, а именно: добавление дополнительной информации в списки моделей `Book` и `Author` , а также улучшение расположения элементов соответствующих представлений редактирования. Пользовательский интерфейс моделей `Language` and `Genre` изменять не будем, так как это не даст заметного улучшения, поскольку он содержит только по одному полю!

Полное руководство по всем возможным вариантам настройки админ-панели можно найти в The Django Admin site (документация Django).

### Регистрация класса ModelAdmin

Для изменения отображения модели в пользовательском интерфейсе админ-панели, необходимо определить класс ModelAdmin (он описывает расположение элементов интерфейса, где Model - наименование модели) и зарегистрировать его для использования с этой моделью.

Давайте начнём с модели Author. Откройте файл **admin.py** в каталоге приложения (**/locallibrary/catalog/admin.py**). Закомментируйте исходную регистрацию (используя префикс #) этой модели:

```js
# admin.site.register(Author)
```

Теперь добавьте новый класс `AuthorAdmin` и зарегистрируйте его как показано ниже:

```python
# Define the admin class
class AuthorAdmin(admin.ModelAdmin):
    pass

# Register the admin class with the associated model
admin.site.register(Author, AuthorAdmin)
```

Сейчас мы добавим классы `ModelAdmin` для моделей `Book`, и `BookInstance`. Нам снова нужно закомментировать исходную регистрацию:

```js
#admin.site.register(Book)
#admin.site.register(BookInstance)
```

В этот раз для создания и регистрации новых моделей используем декоратор `@register` (он делает то же самое, что и метод `admin.site.register()`):

```python
# Register the Admin classes for Book using the decorator

@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
    pass

# Register the Admin classes for BookInstance using the decorator

@admin.register(BookInstance)
class BookInstanceAdmin(admin.ModelAdmin):
    pass
```

Пока что все наши admin-классы пустые (см. "`pass"`), поэтому ничего не изменится ! Добавим код для задания особенностей интерфейса моделей.

### Настройка отображения списков

Сейчас приложение *LocalLibrary* отображает всех авторов, используя имя объекта, возвращаемое методом `__str__()` модели. Это приемлемо, когда есть только несколько авторов, но, если их количество значительно, возможны дубликаты. Чтобы различить их или просто отобразить более интересную информацию о каждом авторе, можно использовать list\_display (для добавления дополнительных полей).

Замените класс `AuthorAdmin` кодом, приведённым ниже. Названия полей, которые будут отображаться в списке, перечислены в кортеже list\_display в требуемом порядке (это те же имена, что и в исходной модели).

```python
class AuthorAdmin(admin.ModelAdmin):
    list_display = ('last\_name', 'first\_name', 'date\_of\_birth', 'date\_of\_death')
```

Перезапустите сайт и перейдите к списку авторов. Указанные поля должны отображаться следующим образом:

![Admin Site - Improved Author List](/ru/docs/Learn/Server-side/Django/Admin_site/admin_improved_author_list.png)

Для нашей модели `Book` добавим отображение полей `author` и `genre`. Поле `author` - это внешний ключ (`ForeignKey` ) связи один к одному, поэтому оно будет представлено значением `__str()__` для связанной записи. Замените класс `BookAdmin` на версию, приведённую ниже.

```python
class BookAdmin(admin.ModelAdmin):
    list_display = ('title', 'author', 'display\_genre')
```

К сожалению, мы не можем напрямую поместить поле genre в `list_display`, так как оно является `ManyToManyField` (Django не позволяет это из-за большой "стоимости" доступа к базе данных). Вместо этого мы определим функцию `display_genre` для получения строкового представления информации (вызов этой функции есть в `list_display`, её определение см. ниже).

**Примечание:** Получение здесь значения поля `genre` возможно не самая хорошая идея вследствие "стоимости" операции базы данных. Мы показываем это, потому что вызов функций в ваших моделях может быть очень полезен по другим причинам, например, для добавления ссылки *Delete* рядом с каждым пунктом списка.

Добавьте следующий код в вашу модель `Book` (**models.py**). В нем создаётся строка из первых трёх значений поля `genre` (если они существуют) и `short_description`, которое может быть использовано в админ-панели.

```python
    def display\_genre(self):
        """
 Creates a string for the Genre. This is required to display genre in Admin.
 """
        return ', '.join([ genre.name for genre in self.genre.all()[:3] ])
    display_genre.short_description = 'Genre'
```

После сохранения модели и обновления админ-панели, перезапустите её и перейдите на страницу списка *Books*. Вы должны увидеть список книг, наподобие приведённого ниже:

![Admin Site - Improved Book List](/ru/docs/Learn/Server-side/Django/Admin_site/admin_improved_book_list.png)

Модель `Genre` (и модель `Language`, если вы её определили) имеет единственное поле. Поэтому нет необходимости создания для них дополнительных моделей с целью отображения дополнительных полей.

**Примечание:** целесообразно, чтобы в списке модели `BookInstance` отображались хотя бы статус и ожидаемая дата возврата. Мы добавили это в качестве "испытания" в конце этой статьи!

### Добавление фильтров списка

Если в вашем списке есть множество элементов, может быть полезной возможность фильтрации отображаемых пунктов. Это выполняется путём перечисления их в атрибуте `list_filter`. Замените класс `BookInstanceAdmin` на следующий:

```python
class BookInstanceAdmin(admin.ModelAdmin):
    list_filter = ('status', 'due\_back')
```

Представление списка теперь будет содержать панель фильтрации справа. Обратите внимание, как выбирать даты и статус для фильтрации:

![Admin Site - BookInstance List Filters](/ru/docs/Learn/Server-side/Django/Admin_site/admin_improved_bookinstance_list_filters.png)

### Формирование макета с подробным представлением

По умолчанию в представлениях деталей отображаются все поля по вертикали в порядке их объявления в модели. Вы можете изменить порядок декларации, какие поля отображаются (или исключены), используются ли разделы для организации информации, отображаются ли поля горизонтально или вертикально, и даже какие виджеты редактирования используются в админ-формах.

**Примечание:** Модели LocalLibrary относительно просты, поэтому нам не нужно менять макет, но мы всё равно внесём некоторые изменения, просто чтобы показать вам, как это сделать.

#### Управление отображаемыми и вложенными полями

Обновите ваш AuthorAdmin класс, чтобы добавить строку полей, как показано ниже (выделено полужирным шрифтом):

```python
class AuthorAdmin(admin.ModelAdmin):
    list_display = ('last\_name', 'first\_name', 'date\_of\_birth', 'date\_of\_death')
    fields = ['first\_name', 'last\_name', ('date\_of\_birth', 'date\_of\_death')]
```

Атрибут полей перечисляет только те поля, которые должны отображаться в форме, по порядку. Поля отображаются по вертикали по умолчанию, но будут отображаться горизонтально, если вы дополнительно группируете их в кортеже (как показано в полях «date» выше).

Перезагрузите приложение и перейдите к подробному представлению автора - он должен теперь отображаться, как показано ниже:

![Admin Site - Improved Author Detail](/ru/docs/Learn/Server-side/Django/Admin_site/admin_improved_author_detail.png)

**Примечание:** Так же, вы можете использовать `exclude` атрибут для объявления списка атрибутов, которые будут исключены из формы (все остальные атрибуты в модели, будут отображаться).

#### Разделение на секции/Выделение подробного представления

Вы можете добавлять "разделы" (sections) для группировки связанной информации в модели в форме детализации, используя атрибут fieldsets .

В модели `BookInstance` мы имеем информацию соответствия конкретной книги (т.е. `name`, `imprint`, and `id`) и датой когда она вновь станет доступной (`status`, `due_back`). Мы можем добавить их в разные секции, добавив текст жирным шрифтом в наш `BookInstanceAdmin` класс.

```python
@admin.register(BookInstance)
class BookInstanceAdmin(admin.ModelAdmin):
    list_filter = ('status', 'due\_back')

    fieldsets = (
        (None, {
            'fields': ('book','imprint', 'id')
        }),
        ('Availability', {
            'fields': ('status', 'due\_back')
        }),
    )
```

Каждая секция имеет свой заголовок (или `None`, если заголовок не нужен) и ассоциированный кортеж полей в словаре - формат сложный для описания, но относительно простой для понимания, если вы посмотрите на фрагмент кода, представленный выше.

Перезапустите сайт и перейдите к списку экземпляров; форма должна отображаться следующим образом:

![Admin Site - Improved BookInstance Detail with sections](/ru/docs/Learn/Server-side/Django/Admin_site/admin_improved_bookinstance_detail_sections.png)

### Встроенное редактирование связанных записей

Иногда бывает полезно иметь возможность добавлять связанные записи одновременно. Например, имеет смысл иметь как информацию о книге, так и информацию о конкретных копиях, которые вы получили на той же странице подробностей. К примеру, вполне логично получить и информацию о книге, и информацию о конкретных копиях, зайдя на страницу детализации.

Вы можете это сделать, объявив inlines, и указав тип TabularInline (горизонтальное расположение) или StackedInline (вертикальное расположение, так же как и в модели по умолчанию). Вы можете добавить `BookInstance` информацию в подробное описание `Book` , добавив строки, представленные ниже и располагающиеся рядом с `BookAdmin`:

```python
class BooksInstanceInline(admin.TabularInline):
    model = BookInstance

@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
    list_display = ('title', 'author', 'display\_genre')
    inlines = [BooksInstanceInline]
```

Попробуйте перезапустить приложение, а затем взгляните на представление книги — внизу вы должны увидеть экземпляры книги, относящиеся к этой книге:

![Admin Site - Book with Inlines](/ru/docs/Learn/Server-side/Django/Admin_site/admin_improved_book_detail_inlines.png)

В этом случае, всё, что мы сделали - объявили наш встроенный класс tablular, который просто добавляет все поля из *встроенной* модели. Вы можете указать все виды дополнительной информации для макета, включая отображаемые поля, их порядок, независимо от того, являются ли они только для чтения или нет, и т. д. (См. TabularInline для получения дополнительной информации).

**Примечание:** В этой функции есть некоторые неприятные ограничения! На скриншоте выше у нас есть три существующих экземпляра книги, за которыми следуют три поля для новых экземпляров книги (которые очень похожи!). Было бы лучше НЕ иметь лишних экземпляров книг по умолчанию и просто добавить их с помощью ссылки **Add another Book instance** или иметь возможность просто перечислять `BookInstance`s как нечитаемые здесь ссылки. Первый вариант можно сделать, установив `extra` атрибут в 0 в модели `BookInstanceInline`, попробуйте сами.

Проверьте себя
--------------

Мы многое изучили в этом разделе и теперь настало время вам самостоятельно попробовать несколько вещей:

1. Для представления списка `BookInstance` , добавьте код для отображения книги, статуса, даты возврата, и id (вместо значения по умолчанию возвращаемого `__str__()` ).
2. Добавьте встроенный список перечня `Book` в представление списка `Author` , используя тот же самый подход, который мы применили для `Book`/`BookInstance`.
Заключение
----------

Вот и всё! Теперь вы узнали, как настроить сайт администрирования как в самой простой, так и в улучшенной форме, о создании суперпользователя и о том, как перемещаться по сайту администратора, просматривать, удалять и обновлять записи. По пути вы создали множество книг, экземпляров, жанров и авторов, которые мы сможем перечислить и отобразить, как только мы создадим собственный вид и шаблоны.

Дополнительные материалы
------------------------

* Writing your first Django app, part 2: Introducing the Django Admin (Django docs)
* The Django Admin site (Django Docs)
* Назад
* Обзор: Django
* Далее


Руководство часть 7: Сессии - Изучение веб-разработки

Руководство часть 7: Сессии
===========================

* Назад
* Обзор: Django
* Далее  (en-US)

Эта часть расширяет наш сайт LocalLibrary, добавляя счётчик посещений домашней страницы, реализованного при помощи сессий. Это относительно простой пример, но он демонстрирует то, как при помощи сессий реализовать анализ поведения анонимных пользователей на сайте.

| Требования: | Завершить изучение всех предыдущих разделов, включая Django Руководство Часть 6: Обобщённые отображения списков и детальной информации |
| --- | --- |
| Цель: | Понимать как применять сессии. |

Обзор
-----

В предыдущих частях мы создали сайт LocalLibrary, который позволяет пользователям получать из каталога списки книг и авторов. На данный момент каждый посетитель сайта получает доступ к одним и тем же страницам и типам информации динамически сформированными из базы данных.

В "настоящей" библиотеке вам хотелось бы предоставить пользователю индивидуальные услуги, которые зависят от его предпочтений и предыдущего опыта использования сайта, его настроек и тому подобное. Например, при очередном посещении сайта вы можете скрыть сообщения об ошибках для тех пользователей, которые их уже получали, или сохранить и учитывать пользовательские настройки (например, количество выводимых данных на странице как результат какого-либо поиска).

Сессии позволяют вам реализовать такой род функциональности, который позволит вам хранить и получать произвольные данные, полученные на основе индивидуального поведения пользователя на сайте.

Что такое сессии?
-----------------

Все взаимодействия между браузерами и серверами осуществляются при помощи протокола HTTP, который не сохраняет своё состояние (*stateless)*. Данный факт означает, что сообщения между клиентом и сервером являются полностью независимыми один от другого — то есть не существует какого-либо представления "последовательности", или поведения в зависимости от предыдущих сообщений. В результате, если вы хотите создать сайт, который будет отслеживать взаимодействие с клиентом (браузером), вам нужно реализовать это самостоятельно.

Сессии являются механизмом, который использует Django (да и весь остальной "Интернет") для отслеживания "состояния" между сайтом и каким-либо браузером. Сессии позволяют вам хранить произвольные данные браузера и получать их в тот момент, когда между данным браузером и сайтом устанавливается соединение. Данные получаются и сохраняются в сессии при помощи соответствующего "ключа".

Django использует куки (cookie), которые содержат специальный *идентификатор сессии,* который выделяет среди остальных, каждый браузер и соответствующую сессию. Реальные *данные* сессии, по умолчанию, хранятся в базе данных сайта (это более безопасно, чем сохранять данные в куки, где они могут быть уязвимы для злоумышленников). Однако, у вас есть возможность настроить Django так, чтобы сохранять данные сессий в других местах (кеше, файлах, "безопасных" куки). Но всё же хранение по умолчанию является хорошей и безопасной возможностью.

Подключение сессий
------------------

Сессии стали доступны автоматически в тот момент, когда мы создали скелет сайта (во второй части руководства).

Необходимые конфигурации выполняются в разделах `INSTALLED_APPS` и `MIDDLEWARE` файла проекта (**locallibrary/locallibrary/settings.py**), как показано ниже:

```python
INSTALLED_APPS = [
    ...
    'django.contrib.sessions',
    ....

MIDDLEWARE = [
    ...
    'django.contrib.sessions.middleware.SessionMiddleware',
    ....
```

Применение сессий
-----------------

Вы можете получить доступ к переменной `session`, в соответствующем отображении, через параметр `request` (`HttpRequest` передаётся как первый аргумент в каждое отображение). Переменная сессии является связью с определённым пользователем (или, если быть более точным, связью с определённым *браузером*, который определяется при помощи идентификатора (id) сессии, получаемого из куки браузера).

Переменная (или поле) `session` является объектом-словарём, который служит для чтения и записи неограниченное число раз. С ним вы можете выполнять любые стандартные операции, включая очистку всех данных, проверку наличия ключа, циклы по данным и так далее. Большую часть времени вы будете тратить на обычные "словарные" операции - получения и установки значений.

Ниже представлены фрагменты кода, которые показывают вам как получать, задавать и удалять некоторые данные при помощи ключа "`my_car`", связанного с текущей сессией (браузером).

**Примечание:** Одной из самых грандиозных вещей в Django является то, что вам не надо думать о механизме, который связывает сессию с текущим запросом в отображении. Во фрагменте ниже, всё что вам надо знать, это то, что `my_car` связана с тем браузером, который отправил текущий запрос.

```python
# Получение значения сессии при помощи ключа(то есть, 'my\_car').
# Если такого ключа нет, то возникнет ошибка KeyError
my_car = request.session['my\_car']

# Получение значения сессии. Если значения не существует,
# то вернётся значение по умолчанию ('mini')
my_car = request.session.get('my\_car', 'mini')

# Передача значения в сессию
request.session['my\_car'] = 'mini'

# Удаление значения из сессии
del request.session['my\_car']
```

Данное API имеет другие методы, которые большей частью используются для управления куки, связанных с сессией. Например, существуют методы проверки того, что куки поддерживаются клиентским браузером, другие методы служат для установки и проверки предельных дат жизни куки, а также для очистки просроченных сессий из хранилища. Подробное описание API вы можете найти в разделе Как использовать сессии (Django docs).

Хранение данных сессии
----------------------

По умолчанию Django сохраняет данные сессии в базу данных и отправляет соответствующие куки клиенту только тогда, когда сессия была *изменена*, или *удалена*. Если вы обновляете какие-либо данные при помощи ключа сессии, как показано в предыдущем фрагменте, тогда вам не надо беспокоиться о процессе сохранения! Например:

```python
# Данное присваивание распознается как обновление сессии
# и данные будут сохранены
request.session['my\_car'] = 'mini'
```

Если вы обновите информацию *внутри* данных сессии, тогда Django не распознает эти изменения и не выполнит сохранение данных (например, если вы изменили "`wheels`" внутри переменной "`my_car`", как показано ниже). В таких случаях вам надо явно указывать, что сессия была изменена.

```python
# Объект сессии модифицируется неявно.
# Изменения НЕ БУДУТ сохранены!
request.session['my\_car']['wheels'] = 'alloy'

# Явное указание, что данные изменены.
# Сессия будет сохранена, куки обновлены (если необходимо).
request.session.modified = True
```

**Примечание:** вы можете изменить поведение сессий таким образом, чтобы они записывали любое своё изменение в базу данных и отправляли куки, при каждом запросе, путём установки `SESSION_SAVE_EVERY_REQUEST = True`, в файле настроек проекта (**locallibrary/locallibrary/settings.py**).

Простой пример — получение числа визитов
----------------------------------------

В качестве примера из реального мира мы обновим нашу библиотеку так, чтобы сообщать пользователю количество совершенных им визитов главной страницы сайта *LocalLibrary*.

Откройте **/locallibrary/catalog/views.py** и добавьте изменения, выделенных жирным, ниже.

```python
def index(request):
    ...

    num_authors=Author.objects.count()  # The 'all()' is implied by default.

    # Number of visits to this view, as counted in the session variable.
    num_visits=request.session.get('num\_visits', 0)
    request.session['num\_visits'] = num_visits+1

    # Render the HTML template index.html with the data in the context variable.
    return render(
        request,
        'index.html',
        context={'num\_books':num_books,'num\_instances':num_instances,'num\_instances\_available':num_instances_available,'num\_authors':num_authors,
            'num\_visits':num_visits}, # num\_visits appended
    )
```

В первую очередь мы получаем значение `'num_visits'` из сессии, возвращая 0, если оно не было установлено ранее. Каждый раз при получении запроса, мы увеличиваем данное значение на единицу и сохраняем его обратно в сессии (до следующего посещения данной страницы пользователем). Затем переменная `num_visits` передаётся в шаблон через переменную контекста `context`.

**Примечание:** Можно проверить наличие поддержки куки в браузере (для примера, смотрите Как использовать сессии), или разработать наш UI таким образом, чтобы это не имело значения.

Для показа значения переменной, из следующего фрагмента добавьте нижнюю строчку кода в ваш шаблон главной страницы сайта (**/locallibrary/catalog/templates/index.html**), в его нижний раздел "Dynamic content":

```django
<h2>Dynamic content</h2>

<p>The library has the following record counts:</p>
<ul>
  <li><strong>Books:</strong> {{ num\_books }}</li>
  <li><strong>Copies:</strong> {{ num\_instances }}</li>
  <li><strong>Copies available:</strong> {{ num\_instances\_available }}</li>
  <li><strong>Authors:</strong> {{ num\_authors }}</li>
</ul>

<p>
  You have visited this page {{ num\_visits }}{% if num\_visits == 1 %} time{%
 else %} times{% endif %}.
</p>
```

Сохраните ваши изменения и перезапустите сервер. Данное значение должно изменяться всякий раз, когда вы обновляете страницу.

Итоги
-----

Вы узнали как применять сессии для улучшения взаимодействие с *анонимными* пользователями.

В наших следующих статьях мы рассмотрим фреймворк аутентификации и авторизации (разрешение доступа, permission), и покажем вам как поддерживать пользовательские аккаунты.

Смотрите также
--------------

* Как использовать сессии (Django docs)
* Назад
* Обзор: Django
* Далее


Руководство Django Часть 8: Аутентификация и авторизация пользователя - Изучение веб-разработки

Руководство Django Часть 8: Аутентификация и авторизация пользователя
=====================================================================

* Назад
* Обзор: Django
* Далее

В данном руководстве мы продемонстрируем вам систему входа пользователя на ваш сайт используя его собственный аккаунт. Кроме того, мы покажем как реализовать контроль того, что может видеть и делать пользователь, в зависимости от того, залогинен он, или нет, а также имеет ли он соответствующий уровень прав доступа *(permissions)*. Для того чтобы продемонстрировать все это, мы расширим LocalLibrary, добавив страницы для входа/выхода, а также страницы просмотра/редактирования книг, специфические для пользователя и персонала.

| Требования: | Завершить изучение предыдущих тем руководства, включая Руководство Django Часть 7: Работа с сессиями. |
| --- | --- |
| Цель: | Понимать как настроить и использовать механизм аутентификации пользователя и разграничений прав доступа. |

Обзор
-----

Django предоставляет систему аутентификации и авторизации ("permission") пользователя, реализованную на основе фреймворка работы с сессиями, который мы рассматривали в предыдущей части. Система аутентификации и авторизации позволяет вам проверять учётные данные пользователей и определять какие действия какой пользователь может выполнять. Данный фреймворк включает в себя встроенные модели для `Пользователей` и `Групп` (основной способ применения прав доступа для более чем одного пользователя), непосредственно саму систему прав доступа (permissions)/флаги, которые определяют может ли пользователь выполнить задачу, с какой формой и отображением для авторизованных пользователей, а так же получить доступ к контенту с ограниченным доступом.

**Примечание:** В соответствии с идеологией Django система аутентификации является очень общей и, таким образом, не предоставляет некоторые возможности, которые присутствуют в других системах веб-аутентификации. Решениями некоторых общих задач занимаются пакеты сторонних разработчиков, например, защита от подбора пароля (через стороннюю библиотеку OAuth).

В данном разделе руководства мы покажем вам реализацию аутентификации пользователя на сайте LocalLibrary, создание страниц входа/выхода, добавления разграничения доступа (permissions) к вашим моделям, а также продемонстрируем контроль за доступом к некоторым страницам. Мы будем использовать аутентификацию/авторизацию для показа пользователям и сотрудникам библиотеки, списков книг, которые были взяты на прокат.

Система аутентификации является очень гибкой и позволяет вам формировать свои собственные URL-адреса, формы, отображения, а также шаблоны страниц, если вы пожелаете, с нуля, через простой вызов функций соответствующего API для авторизации пользователя. Тем не менее, в данной статье мы будем использовать "встроенные" в Django методы отображений и форм аутентификации, а также методы построения страниц входа и выхода. Нам все ещё необходимо создавать шаблоны страниц, но это будет достаточно несложно.

Мы покажем вам как реализовать разграничение доступа (permissions), а также выполнять соответствующую проверку статусов авторизации и прав доступа, в отображениях, и в шаблонах страниц.

Подключение аутентификации
--------------------------

Аутентификация была подключена автоматически когда мы создали скелет сайта (в части 2), таким образом на данный момент вам ничего не надо делать.

**Примечание:** Необходимые настройки были выполнены для нас, когда мы создали приложение при помощи команды `django-admin startproject`. Таблицы базы данных для пользователей и модели авторизации были созданы, когда в первый раз выполнили команду `python manage.py migrate`.

Соответствующие настройки сделаны в параметрах `INSTALLED_APPS` и `MIDDLEWARE` файла проекта (**locallibrary/locallibrary/settings.py**), как показано ниже:

```python
INSTALLED_APPS = [
    ...
    'django.contrib.auth',  # Фреймворк аутентификации и моделей по умолчанию.
    'django.contrib.contenttypes',  # Django контент-типовая система (даёт разрешения, связанные с моделями).
    ....

MIDDLEWARE = [
    ...
    'django.contrib.sessions.middleware.SessionMiddleware',  # Управление сессиями между запросами
    ...
    'django.contrib.auth.middleware.AuthenticationMiddleware',  # Связывает пользователей, использующих сессии, запросами.
    ....
```

Создание пользователей и групп
------------------------------

Вы уже создали своего первого пользователя когда мы рассматривали Административная панель сайта Django в части 4 (это был суперпользователь, созданный при помощи команды `python manage.py createsuperuser`). Наш суперпользователь уже авторизован и имеет все необходимые уровни доступа к данным и функциям, таким образом нам необходимо создать тестового пользователя для отработки соответствующей работы сайта. В качестве наиболее быстрого способа, мы будем использовать административную панель сайта для создания соответствующих групп и аккаунтов *locallibrary*.

**Примечание:** вы можете создавать пользователей программно, как показано ниже. Например, вам мог бы подойти данный способ в том случае, если вы разрабатываете интерфейс, который позволяет пользователям создавать их собственные аккаунты (вы не должны предоставлять доступ пользователям к административной панели вашего сайта).

```python
from django.contrib.auth.models import User

# Создайте пользователя и сохраните его в базе данных
user = User.objects.create_user('myusername', 'myemail@crazymail.com', 'mypassword')

# Обновите поля и сохраните их снова
user.first_name = 'John'
user.last_name = 'Citizen'
user.save()
```

Ниже мы создадим группу, а затем пользователя. Несмотря на то, что у нас пока нет никаких разрешений для добавления к нашей библиотеке каких-либо членов, если мы захотим это сделать в будущем, то будет намного проще добавлять их к уже созданной группе, с заданной аутентификацией.

Запустите сервер разработки и перейдите к административной панели вашего сайта (`http://127.0.0.1:8000/admin/`). Залогиньтесь на сайте при помощи параметров (имя пользователя и пароля) аккаунта суперпользователя. Самая "верхняя" страница панели Администратора показывает все наши модели. Для того, чтобы увидеть записи в разделе **Authentication and Authorisation** вы можете нажать на ссылку **Users**, или **Groups**.

![Admin site - add groups or users](/ru/docs/Learn/Server-side/Django/Authentication/admin_authentication_add.png)

В первую очередь, в качестве нового члена нашего сайта, давайте создадим новую группу.

1. Нажмите на кнопку **Add** **(Добавить)** (рядом с Group) и создайте новую *группу*; для данной группы введите **Name (Имя)** "Library Members".
 ![Admin site - add group](/ru/docs/Learn/Server-side/Django/Authentication/admin_authentication_add_group.png)
2. Для данной группы не нужны какие-либо разрешения, поэтому мы просто нажимаем кнопку **SAVE (Сохранить)** (вы перейдёте к списку групп).

Теперь давайте создадим пользователя:

1. Перейдите обратно на домашнюю страницу административной панели
2. Для перехода к диалогу добавления пользователя нажмите на кнопку **Add**, соответствующую строке *Users (Пользователи)*.
 ![Admin site - add user pt1](/ru/docs/Learn/Server-side/Django/Authentication/admin_authentication_add_user_prt1.png)
3. Введите соответствующие **Username** (имя пользователя) и **Password**/**Password confirmation (пароль/подтверждение пароля)** для вашего тестового пользователя
4. Нажмите **SAVE** для завершения процесса создания пользователя.
 Административная часть сайта создаст нового пользователя и немедленно перенаправит вас на страницу *Change user (Изменение параметров пользователя)* где вы можете, соответственно, изменить ваш **username**, а кроме того добавить информацию для дополнительных полей модели User. Эти поля включают в себя имя пользователя, фамилию, адрес электронной почты, статус пользователя, а также соответствующие параметры доступа (может быть установлен только флаг **Active**). Ниже вы можете определить группу для пользователя и необходимые параметры доступа, а кроме того, вы можете увидеть важные даты, относящиеся к пользователю (дату подключения к сайту и дату последнего входа).
 ![Admin site - add user pt2](/ru/docs/Learn/Server-side/Django/Authentication/admin_authentication_add_user_prt2.png)
5. В разделе *Groups*, из списка *Доступные группы* выберите группу **Library Member**, а затем переместите её в блок "Выбранные группы" (нажмите **стрелку-"направо"**, находящуюся между блоками).
 ![Admin site - add user to group](/ru/docs/Learn/Server-side/Django/Authentication/admin_authentication_user_add_group.png)
6. Больше нам не нужно здесь нечего делать, просто нажмите "Save"(Сохранить), и вы вернётесь к списку созданных пользователей.

Вот и все! Теперь у вас есть учётная запись «обычного члена библиотеки», которую вы сможете использовать для тестирования (как только добавим страницы, чтобы пользователи могли войти в систему).

**Примечание:** Попробуйте создать другого пользователя, например "Библиотекаря". Так же создайте группу "Библиотекарей" и добавьте туда своего только что созданного библиотекаря

Настройка представлений проверки
--------------------------------

Django предоставляет почти все, что нужно для создания страниц аутентификации входа, выхода из системы и управления паролями из коробки. Это включает в себя url-адреса, представления (views) и формы,но не включает шаблоны — мы должны создать свой собственный шаблон!

В этом разделе мы покажем, как интегрировать систему по умолчанию в Сайт LocalLibrary и создать шаблоны. Мы поместим их в основные URL проекта.

**Примечание:** вы не должны использовать этот код, но вполне вероятно, что вы хотите, потому что это делает вещи намного проще. Вам почти наверняка потребуется изменить код обработки формы, если вы измените свою модель пользователя (сложная тема!) но даже в этом случае вы всё равно сможете использовать функции просмотра запасов.

>
> \*\*Примечание:\*\*В этом случае мы могли бы разумно поместить страницы аутентификации, включая URL-адреса и шаблоны, в наше приложение каталога. Однако, если бы у нас было несколько приложений, было бы лучше отделить это общее поведение входа в систему и иметь его доступным на всем сайте, так что это то, что мы показали здесь!
>
>
>

### Проектирование URLs

Добавьте следующее в нижней части проекта urls.py файл (**locallibrary/locallibrary/urls.py**) файл:

```python
#Add Django site authentication urls (for login, logout, password management)
urlpatterns += [
    path('accounts/', include('django.contrib.auth.urls')),
]
```

Перейдите по `http://127.0.0.1:8000/accounts/` URL (обратите внимание на косую черту!), Django покажет ошибку, что он не смог найти этот URL, и перечислить все URL, которые он пытался открыть. Из этого вы можете увидеть URL-адреса, которые будут работать, например:

**Примечание:** Примечание. Использование вышеуказанного метода добавляет следующие URL-адреса с именами в квадратных скобках, которые могут использоваться для изменения сопоставлений URL-адресов. Вам не нужно реализовывать что-либо ещё - приведённое выше сопоставление URL-адресов автоматически отображает указанные ниже URL-адреса.

**Примечание:**

```python
accounts/ login/ [name='login']
accounts/ logout/ [name='logout']
accounts/ password_change/ [name='password\_change']
accounts/ password_change/done/ [name='password\_change\_done']
accounts/ password_reset/ [name='password\_reset']
accounts/ password_reset/done/ [name='password\_reset\_done']
accounts/ reset/<uidb64>/<token>/ [name='password\_reset\_confirm']
accounts/ reset/done/ [name='password\_reset\_complete']
```

Теперь попробуйте перейти к URL-адресу входа (`http://127.0.0.1:8000/accounts/login/`). Это приведёт к сбою снова, но с ошибкой, сообщающей вам, что нам не хватает требуемого шаблона (registration / login.html) в пути поиска шаблона. Вы увидите следующие строки, перечисленные в жёлтом разделе вверху:

```python
Exception Type:    TemplateDoesNotExist
Exception Value:    registration/login.html
```

Следующий шаг - создать каталог регистрации в пути поиска, а затем добавить файл login.html.

### Каталог шаблонов

URL-адреса (и неявные представления), которые мы только что добавили, ожидают найти связанные с ними шаблоны в каталоге / регистрации / где-то в пути поиска шаблонов.

Для этого сайта мы разместим наши HTML-страницы в каталоге **templates / registration /**. Этот каталог должен находиться в корневом каталоге проекта, то есть в том же каталоге, что и в каталоге и папках **locallibrary**). Создайте эти папки сейчас.

**Примечание:** ваша структура папок теперь должна выглядеть как показано внизу:
 locallibrary (django project folder)
 |\_catalog
 |\_locallibrary
 |\_templates **(new)**
 |\_registration

Чтобы сделать эти директории видимыми для загрузчика шаблонов (т. е. помещать этот каталог в путь поиска шаблона) откройте настройки проекта (**/locallibrary/locallibrary/settings.py**), и обновите в секции `TEMPLATES` строку `'DIRS'` как показано.

```python
TEMPLATES = [
    {
        ...
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP\_DIRS': True,
        ...
```

### Шаблон аутентификации

**Предупреждение:** **Важно**: Шаблоны аутентификации, представленные в этой статье, являются очень простой / слегка изменённой версией шаблонов логина демонстрации Django. Возможно, вам придётся настроить их для собственного использования!

Создайте новый HTML файл, названный /**locallibrary/templates/registration/login.html**. дайте ему следующее содержание:

```django
{% extends "base\_generic.html" %}

{% block content %}

{% if form.errors %}
  <p>Your username and password didn't match. Please try again.</p>
{% endif %}

{% if next %}
  {% if user.is\_authenticated %}
    <p>Your account doesn't have access to this page. To proceed,
    please login with an account that has access.</p>
  {% else %}
    <p>Please login to see this page.</p>
  {% endif %}
{% endif %}

<form method="post" action="{% url 'login' %}">
{% csrf\_token %}
<table>

<tr>
  <td>{{ form.username.label\_tag }}</td>
  <td>{{ form.username }}</td>
</tr>

<tr>
  <td>{{ form.password.label\_tag }}</td>
  <td>{{ form.password }}</td>
</tr>
</table>

<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</form>

{# Assumes you setup the password\_reset view in your URLconf #}
<p><a href="{% url 'password\_reset' %}">Lost password?</a></p>

{% endblock %}
```

Этот шаблон имеет сходство с тем, что мы видели раньше - он расширяет наш базовый шаблон и переопределяет блок контента. Остальная часть кода - это довольно стандартный код обработки формы, о котором мы поговорим в следующем учебном пособии. Все, что вам нужно знать, это показ формы, в которой вы можете ввести своё имя пользователя и пароль, а если вы введёте недопустимые значения, вам будет предложено ввести правильные значения, когда страница обновится.

Перейдите на страницу входа (`http://127.0.0.1:8000/accounts/login/`) когда вы сохраните свой шаблон, и вы должны увидеть что-то наподобие этого:

![Library login page v1](/ru/docs/Learn/Server-side/Django/Authentication/library_login.png)

Если ваша попытка войти в систему будет успешной, вы будете перенаправлены на другую страницу (по умолчанию это будет `http://127.0.0.1:8000/accounts/profile/`). Проблема здесь в том, что по умолчанию Django ожидает, что после входа в систему вы захотите перейти на страницу профиля, что может быть или не быть. Поскольку вы ещё не определили эту страницу, вы получите ещё одну ошибку!

Откройте настройки проекта (**/locallibrary/locallibrary/settings.py**) и добавьте текст ниже. Теперь, когда вы входите в систему, вы по умолчанию должны перенаправляться на домашнюю страницу сайта.

```python
# Redirect to home URL after login (Default redirects to /accounts/profile/)
LOGIN_REDIRECT_URL = '/'
```

### Шаблон выхода

Если вы перейдёте по URL-адресу выхода (`http://127.0.0.1:8000/accounts/logout/`), то увидите странное поведение - ваш пользователь наверняка выйдет из системы, но вы попадёте на страницу выхода администратора. Это не то, что вам нужно, хотя бы потому, что ссылка для входа на этой странице приведёт вас к экрану входа в систему администратора. (и это доступно только для пользователей, у которых есть разрешение `is_staff`).

Создайте и откройте **/locallibrary/templates/registration/logged\_out.html**. Скопируйте текст ниже:

```django
{% extends "base\_generic.html" %}

{% block content %}
  <p>Logged out!</p>

  <a href="{% url 'login'%}">Click here to login again.</a>
{% endblock %}
```

Этот шаблон очень прост. Он просто отображает сообщение, информирующее вас о том, что вы вышли из системы, и предоставляет ссылку, которую вы можете нажать, чтобы вернуться на экран входа в систему. Если вы снова перейдёте на страницу выхода из системы, вы увидите эту страницу:

![Library logout page v1](/ru/docs/Learn/Server-side/Django/Authentication/library_logout.png)

### Шаблон сброса пароля

Система сброса пароля по умолчанию использует электронную почту, чтобы отправить пользователю ссылку на сброс. Вам необходимо создать формы, чтобы получить адрес электронной почты пользователя, отправить электронное письмо, разрешить им вводить новый пароль и отметить, когда весь процесс будет завершён.

В качестве отправной точки можно использовать следующие шаблоны.

#### Форма сброса пароля

Это форма, используемая для получения адреса электронной почты пользователя (для отправки пароля для сброса пароля). Создайте **/locallibrary/templates/registration/password\_reset\_form.html** и дайте ему следующее содержание:

```django
{% extends "base\_generic.html" %}

{% block content %}
  <form action="" method="post">{% csrf\_token %}
      {% if form.email.errors %} {{ form.email.errors }} {% endif %}
          <p>{{ form.email }}</p>
      <input type="submit" class="btn btn-default btn-lg" value="Reset password" />
  </form>
{% endblock %}
```

#### Сброс пароля

Эта форма отображается после того, как ваш адрес электронной почты будет собран. Создайте **/locallibrary/templates/registration/password\_reset\_done.html**, и дайте ему следующее содержание:

```django
{% extends "base\_generic.html" %}

{% block content %}
  <p>
    We've emailed you instructions for setting your password. If they haven't
    arrived in a few minutes, check your spam folder.
  </p>
{% endblock %}
```

#### Сброс пароля по email

Этот шаблон предоставляет текст электронной почты HTML, содержащий ссылку на сброс, которую мы отправим пользователям. Создайте /locallibrary/templates/registration/password\_reset\_email.html и дайте ему следующее содержание:

```django
Someone asked for password reset for email {{ email }}. Follow the link below:
{{ protocol}}://{{ domain }}{% url 'password\_reset\_confirm' uidb64=uid token=token %}
```

#### Подтверждение на сброс пароля

На этой странице вы вводите новый пароль после нажатия ссылки в электронном письме с возвратом пароля. Создайте /locallibrary/templates/registration/password\_reset\_confirm.html и дайте ему следующее содержание:

```django
{% extends "base\_generic.html" %}

{% block content %}
  {% if validlink %}
    <p>Please enter (and confirm) your new password.</p>
    <form action="" method="post">
      {% csrf\_token %}
      <table>
        <tr>
          <td>
            {{ form.new\_password1.errors }}
            <label for="id\_new\_password1">New password:</label>
          </td>
          <td>{{ form.new\_password1 }}</td>
        </tr>
        <tr>
          <td>
            {{ form.new\_password2.errors }}
            <label for="id\_new\_password2">Confirm password:</label>
          </td>
          <td>{{ form.new\_password2 }}</td>
        </tr>
        <tr>
          <td></td>
          <td><input type="submit" value="Change my password" /></td>
        </tr>
      </table>
    </form>
  {% else %}
    <h1>Password reset failed</h1>
    <p>
      The password reset link was invalid, possibly because it has already been
      used. Please request a new password reset.
    </p>
  {% endif %}
{% endblock %}
```

#### Сброс пароля завершён

Это последний шаблон сброса пароля, который отображается, чтобы уведомить вас о завершении сброса пароля. Создайте /locallibrary/templates/registration/password\_reset\_complete.html и дайте ему следующее содержание:

```django
{% extends "base\_generic.html" %}

{% block content %}
  <h1>The password has been changed!</h1>
  <p><a href="{% url 'login' %}">log in again?</a></p>
{% endblock %}
```

### Тестирование новых страниц аутентификации

Теперь, когда вы добавили конфигурацию URL и создали все эти шаблоны, теперь страницы аутентификации должны работать! Вы можете протестировать новые страницы аутентификации, попытавшись войти в систему, а затем выйдите из учётной записи суперпользователя, используя эти URL-адреса:

* `http://127.0.0.1:8000/accounts/login/`
* `http://127.0.0.1:8000/accounts/logout/`

Вы сможете проверить функцию сброса пароля по ссылке на странице входа. **Имейте в виду, что Django отправляет только сбросные электронные письма на адреса (пользователи), которые уже хранятся в его базе данных!**

**Примечание:** Система сброса пароля требует, чтобы ваш сайт поддерживал электронную почту, что выходит за рамки этой статьи, поэтому эта часть **ещё не будет работать.** Чтобы разрешить тестирование, поместите следующую строку в конец файла settings.py. Это регистрирует любые письма, отправленные на консоль (чтобы вы могли скопировать ссылку на сброс пароля с консоли).

```python
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
```

Для получения дополнительной информации см. Отправка email (Django docs).

Тестирование проверки подлинности пользователей
-----------------------------------------------

В этом разделе мы рассмотрим, что мы можем сделать, чтобы выборочно контролировать контент, который видят пользователи, на основе того, вошли ли они в систему или нет.

### Тестирование в шаблонах

Вы можете получить информацию о текущем зарегистрированном пользователе в шаблонах с переменной шаблона {{user}} (это добавляется в контекст шаблона по умолчанию при настройке проекта, как и в нашем скелете).

Обычно вы сначала проверяете переменную шаблона {{user.is\_authenticated}}, чтобы определить, имеет ли пользователь право видеть конкретный контент. Чтобы продемонстрировать это, мы обновим нашу боковую панель, чтобы отобразить ссылку «Вход», если пользователь вышел из системы, и ссылку «Выход», если он вошёл в систему.

Откройте базовый шаблон (/locallibrary/catalog/templates/base\_generic.html) и скопируйте следующий текст в sidebar блок непосредственно перед тегом шаблона endblock.

```python
  <ul class="sidebar-nav">

    ...

   {% if user.is_authenticated %}
     <li>User: {{ user.get_username }}</li>
     <li><a href="{% url 'logout'%}?next={{request.path}}">Logout</a></li>
   {% else %}
     <li><a href="{% url 'login'%}?next={{request.path}}">Login</a></li>
   {% endif %}
  </ul>
```

Как вы можете видеть, мы используем теги шаблона if-else-endif для условного отображения текста на основе того, является ли {{user.is\_authenticated}} истинным. Если пользователь аутентифицирован, мы знаем, что у нас есть действительный пользователь, поэтому мы вызываем {{user.get\_username}}, чтобы отобразить их имя.

Мы создаём URL-адрес для входа и выхода из системы, используя тег шаблона URL-адреса и имена соответствующих конфигураций URLs. Также обратите внимание на то, как мы добавили `?next={{request.path}}` в конец URLs. Это означает, что следующий URL-адрес содержит адрес (URL) текущей страницы, в конце связанного URL-адреса. После того, как пользователь успешно выполнил вход в систему, представления будут использовать значение "`next`" чтобы перенаправить пользователя обратно на страницу, где они сначала нажали ссылку входа / выхода из системы.

**Примечание:** Попробуйте! Если вы находитесь на главной странице и вы нажимаете «Вход / Выход» на боковой панели, то после завершения операции вы должны вернуться на ту же страницу.

### Тестирование в представлениях

Если вы используете функциональные представления, самым простым способом ограничить доступ к вашим функциям является применение `login_required` декоратор к вашей функции просмотра, как показано ниже. Если пользователь вошёл в систему, ваш код просмотра будет выполняться как обычно. Если пользователь не вошёл в систему, это перенаправит URL-адрес входа, определённый в настройках проекта. (`settings.LOGIN_URL`), передав текущий абсолютный путь в качестве next параметра URL. Если пользователю удастся войти в систему, они будут возвращены на эту страницу, но на этот раз аутентифицированы.

```python
from django.contrib.auth.decorators import login_required

@login\_required
def my\_view(request):
    ...
```

**Примечание:** Вы можете сделать то же самое вручную, путём тестирования `request.user.is_authenticated`, но декоратор намного удобнее!

Аналогичным образом, самый простой способ ограничить доступ к зарегистрированным пользователям в ваших представлениях на основе классов - это производные от `LoginRequiredMixin`. Вы должны объявить этот mixin сначала в списке суперкласса, перед классом основного представления.

```python
from django.contrib.auth.mixins import LoginRequiredMixin

class MyView(LoginRequiredMixin, View):
    ...
```

Это имеет такое же поведение при переадресации, что и `login_required` декоратор. Вы также можете указать альтернативное местоположение для перенаправления пользователя, если он не аутентифицирован (`login_url`), и имя параметра URL вместо "`next`" , чтобы вставить текущий абсолютный путь (`redirect_field_name`).

```python
class MyView(LoginRequiredMixin, View):
    login_url = '/login/'
    redirect_field_name = 'redirect\_to'
```

Для получения дополнительной информации ознакомьтесь с Django docs here.

Пример - перечисление книг текущего пользователя
------------------------------------------------

Теперь, когда мы знаем, как ограничить страницу определённому пользователю, создайте представление о книгах, которые заимствовал текущий пользователь.

К сожалению, у нас пока нет возможности пользователям использовать книги! Поэтому, прежде чем мы сможем создать список книг, мы сначала расширим `BookInstance` модель для поддержки концепции заимствования и использования приложения Django Admin для заимствования ряда книг нашему тестовому пользователю.

### Модели

Прежде всего, мы должны предоставить пользователям возможность кредита на `BookInstance` (у нас уже есть `status` и `due_back` дата, но у нас пока нет связи между этой моделью и пользователем. Мы создадим его с помощью поля `ForeignKey` (один ко многим). Нам также нужен простой механизм для проверки того, просрочена ли заёмная книга.

Откройте **catalog/models.py**, и импортируйте модель `User` из `django.contrib.auth.models` (добавьте это чуть ниже предыдущей строки импорта в верхней части файла, так `User` доступен для последующего кода, что позволяет использовать его):

```python
from django.contrib.auth.models import User
```

Затем добавьте поле `borrower` в модель `BookInstance`:

```python
borrower = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
```

Пока мы здесь, давайте добавим свойство, которое мы можем вызвать из наших шаблонов, чтобы указать, просрочен ли конкретный экземпляр книги. Хотя мы могли бы рассчитать это в самом шаблоне, использование свойства, как показано ниже, будет намного более эффективным. Добавьте это где-нибудь в верхней части файла:
```

from datetime import date
```

Теперь добавьте следующее определение свойства внутри класса BookInstance:

```python
@property
def is\_overdue(self):
    if self.due_back and date.today() > self.due_back:
        return True
    return False
```

**Примечание:** Сначала мы проверим, является ли `due_back` пустым, прежде чем проводить сравнение. Пустое поле `due_back` заставило Django выкидывать ошибку, а не показывать страницу: пустые значения не сопоставимы. Это не то, что мы хотели бы, чтобы наши пользователи испытывали!

Теперь, когда мы обновили наши модели, нам нужно будет внести новые изменения в проект, а затем применить эти миграции:

```bash
python3 manage.py makemigrations
python3 manage.py migrate
```

### Admin

Теперь откройте каталог **catalog/admin.py**, и добавьте поле `borrower` в класс `BookInstanceAdmin` , как в `list_display` , так и в полях `fieldsets` , как показано ниже. Это сделает поле видимым в разделе Admin, так что мы можем при необходимости назначить `User` в `BookInstance`.

```python
@admin.register(BookInstance)
class BookInstanceAdmin(admin.ModelAdmin):
    list_display = ('book', 'status', 'borrower', 'due\_back', 'id')
    list_filter = ('status', 'due\_back')

    fieldsets = (
        (None, {
            'fields': ('book','imprint', 'id')
        }),
        ('Availability', {
            'fields': ('status', 'due\_back','borrower')
        }),
    )
```

### Займите несколько книг

Теперь, когда возможно кредитовать книги конкретному пользователю, зайдите и заработайте на нескольких записей в `BookInstance`. Установите `borrowed` поле вашему тестовому пользователю, сделайте `status` «В займе» и установите сроки оплаты как в будущем, так и в прошлом.

**Примечание:** Мы не будем описывать процесс, так как вы уже знаете, как использовать Admin сайт!

### Займ в представлении

Теперь мы добавим представление для получения списка всех книг, которые были предоставлены текущему пользователю. Мы будем использовать один и тот же общий класс, с которым мы знакомы, но на этот раз мы также будем импортировать и выводить из `LoginRequiredMixin`, так что только вошедший пользователь сможет вызвать это представление. Мы также решили объявить `template_name`, вместо того, чтобы использовать значение по умолчанию, потому что у нас может быть несколько разных списков записей BookInstance, с разными представлениями и шаблонами.

Добавьте следующее в catalog/views.py:

```python
from django.contrib.auth.mixins import LoginRequiredMixin

class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView):
    """
 Generic class-based view listing books on loan to current user.
 """
    model = BookInstance
    template_name ='catalog/bookinstance\_list\_borrowed\_user.html'
    paginate_by = 10

    def get\_queryset(self):
        return BookInstance.objects.filter(borrower=self.request.user).filter(status__exact='o').order_by('due\_back')
```

Чтобы ограничить наш запрос только объектами BookInstance для текущего пользователя, мы повторно реализуем `get_queryset()`, как показано выше. Обратите внимание, что "o" это сохранённый код для "on loan" и мы сортируем по дате `due_back`, чтобы сначала отображались самые старые элементы.

### URL-адрес для заёмных книг

Теперь откройте **/catalog/urls.py** и добавьте `url()` , указывая на приведённое выше представление (вы можете просто скопировать текст ниже в конец файла).

```python
urlpatterns += [
    url(r'^mybooks/$', views.LoanedBooksByUserListView.as_view(), name='my-borrowed'),
]
```

### Шаблон для заёмных книг

Теперь все, что нам нужно сделать для этой страницы, - это добавить шаблон. Сначала создайте файл шаблона **/catalog/templates/catalog/bookinstance\_list\_borrowed\_user.html** и дайте ему следующее содержание:

```python
{% extends "base\_generic.html" %}

{% block content %}
    <h1>Borrowed books</h1>

    {% if bookinstance_list %}
    <ul>

      {% for bookinst in bookinstance_list %}
      <li class="{% if bookinst.is\_overdue %}text-danger{% endif %}">
        <a href="{% url 'book-detail' bookinst.book.pk %}">{{bookinst.book.title}}</a> ({{ bookinst.due_back }})
      </li>
      {% endfor %}
    </ul>

    {% else %}
      <p>There are no books borrowed.</p>
    {% endif %}
{% endblock %}
```

Этот шаблон очень похож на тот, который мы создали ранее для объектов `Book` и `Author`. Единственное, что «новое» здесь, это то, что мы проверяем метод, который мы добавили в модель `(bookinst.is_overdue`) с целью использовать его для изменения цвета просроченных предметов.

Когда сервер разработки запущен, вы должны теперь иметь возможность просматривать список для зарегистрированного пользователя в своём браузере по адресу `http://127.0.0.1:8000/catalog/mybooks/`. Попробуйте это, когда ваш пользователь войдёт в систему и выйдет из системы (во втором случае вы должны быть перенаправлены на страницу входа в систему).

### Добавить список на боковую панель

Последний шаг - добавить ссылку на эту новую страницу в sidebar. Мы поместим это в тот же раздел, где мы покажем другую информацию для зарегистрированного пользователя.

Откройте базовый шаблон (**/locallibrary/catalog/templates/base\_generic.html**) и добавьте выделенную строку из sidebar, как показано на рисунке.

```python
 <ul class="sidebar-nav">
   {% if user.is_authenticated %}
   <li>User: {{ user.get_username }}</li>
   <li><a href="{% url 'my-borrowed' %}">My Borrowed</a></li>
   <li><a href="{% url 'logout'%}?next={{request.path}}">Logout</a></li>
   {% else %}
   <li><a href="{% url 'login'%}?next={{request.path}}">Login</a></li>
   {% endif %}
 </ul>
```

### На что это похоже?

Когда любой пользователь войдёт в систему, он будет видеть ссылку «Мной позаимствовано (*My Borrowed)*» в боковой колонке, и список книг, показанных ниже (первая книга не имеет установленной даты, что является ошибкой, которую мы надеемся исправить в более позднем уроке!).

![Library - borrowed books by user](/ru/docs/Learn/Server-side/Django/Authentication/library_borrowed_by_user.png)

Права доступа
-------------

Права доступа связаны с моделями и определяют операции, которые могут выполняться на экземпляре модели самим пользователем, у которого есть разрешение. По умолчанию Django автоматически даёт *добавить*, *изменить*, и *удалить* разрешения у всех моделей, которые позволяют пользователям с правом доступа выполнять связанные действия через администратора сайта. Вы можете определить свои собственные разрешения для моделей и предоставить их конкретным пользователям. Вы также можете изменить разрешения, связанные с разными экземплярами одной и той же модели. Тестирование разрешений в представлениях и шаблонах очень похоже на тестирование по статусу аутентификации (фактически, тестирование прав доступа также проверяет аутентификацию).

### Модели

Определение разрешений выполняется в разделе моделей "`class Meta`" , используется `permissions` поле. Вы можете указать столько разрешений, сколько необходимо в кортеже, причём каждое разрешение определяется во вложенном кортеже, содержащем имя разрешения и отображаемое значение разрешения. Например, мы можем определить разрешение, позволяющее пользователю отметить, что книга была возвращена, как показано здесь:

```python
class BookInstance(models.Model):
    ...
    class Meta:
        ...
        permissions = (("can\_mark\_returned", "Set book as returned"),)
```

Затем мы могли бы назначить разрешение группе «Библиотекарь» (Librarian) на сайте администратора.

Откройте **catalog/models.py**, и добавьте разрешение, как показано выше. Вам нужно будет повторно выполнить миграцию (вызвав `python3 manage.py makemigrations` и `python3 manage.py migrate`) для надлежащего обновления базы данных.

### Шаблоны

Разрешения текущего пользователя хранятся в переменной шаблона, называемой `{{ perms }}`. Вы можете проверить, имеет ли текущий пользователь определённое разрешение, используя конкретное имя переменной в соответствующем приложении «Django» - например, `{{ perms.catalog.can_mark_returned }}` будет `True` если у пользователя есть это разрешение, а `False` - в противном случае. Обычно мы проверяем разрешение с использованием шаблона `{% if %}`, как показано в:

```python
{% if perms.catalog.can_mark_returned %}
    <!-- We can mark a BookInstance as returned. -->
    <!-- Perhaps add code to link to a "book return" view here. -->
{% endif %}
```

### Представления

Разрешения можно проверить в представлении функции, используя `permission_required` декоратор или в представлении на основе классов, используя `PermissionRequiredMixin`. шаблон и поведение такие же, как для аутентификации входа в систему, хотя, конечно, вы можете разумно добавить несколько разрешений.

Функция в представлении с декоратором:

```python
from django.contrib.auth.decorators import permission_required

@permission\_required('catalog.can\_mark\_returned')
@permission\_required('catalog.can\_edit')
def my\_view(request):
    ...
```

Требуется разрешение mixin для представлений на основе классов.

```python
from django.contrib.auth.mixins import PermissionRequiredMixin

class MyView(PermissionRequiredMixin, View):
    permission_required = 'catalog.can\_mark\_returned'
    # Or multiple permissions
    permission_required = ('catalog.can\_mark\_returned', 'catalog.can\_edit')
    # Note that 'catalog.can\_edit' is just an example
    # the catalog application doesn't have such permission!
```

### Пример

Мы не будем обновлять LocalLibrary здесь; возможно, в следующем уроке!

Испытайте себя
--------------

Ранее в этой статье мы показали вам, как создать страницу для текущего пользователя, в которой перечислены книги, которые они заимствовали. Теперь задача состоит в том, чтобы создать аналогичную страницу, которая видна только для библиотекарей, которая отображает *все* книги, которые были заимствованы, и которая показывает имя каждого заёмщика.

Вы должны следовать той же схеме, что и для другого представления. Главное отличие состоит в том, что вам нужно ограничить представление только библиотекарями. Вы можете сделать это на основе того, является ли пользователь сотрудником (декоратор функции: `staff_member_required`, переменная шаблона: `user.is_staff`) но мы рекомендуем вам вместо этого использовать `can_mark_returned` разрешения и `PermissionRequiredMixin`, как описано в предыдущем разделе.

**Предупреждение:** **Важно**: Не забудьте использовать вашего суперпользователя для тестирования на основе разрешений (проверки разрешений всегда возвращают true для суперпользователей, даже если разрешение ещё не определено!). Вместо этого создайте пользователя-библиотекаря и добавьте необходимые возможности.

Когда вы закончите, ваша страница должна выглядеть примерно, как на скриншоте ниже.

![All borrowed books, restricted to librarian](/ru/docs/Learn/Server-side/Django/Authentication/library_borrowed_all.png)

Подводим итоги
--------------

Отличная работа - теперь вы создали веб-сайт, на котором участники библиотеки могут входить в систему и просматривать собственный контент, и библиотекари (с правом доступа) могут просматривать все заёмные книги с их читателями. На данный момент мы все ещё просто просматриваем контент, но те же принципы и методы используются, когда вы хотите начать изменять и добавлять данные.

В следующей статье мы рассмотрим, как вы можете использовать формы Django для сбора пользовательского ввода, а затем начнём изменять некоторые из наших сохранённых данных.

Смотрите также
--------------

* User authentication in Django (Django docs)
* Using the (default) Django authentication system (Django docs)
* Introduction to class-based views > Decorating class-based views (Django docs)
* Назад
* Обзор: Django
* Далее


Руководство по Django часть 2: создание скелета - Изучение веб-разработки

Руководство по Django часть 2: создание скелета
===============================================

* Назад
* Обзор: Django
* Далее

Это вторая статья из нашего руководства по Django, которая показывает, как можно создать "скелет" сайта, как фундамент, на котором можно строить всё остальное: настройки, ссылки, модели, контроллеры и представления.

| Необходимо: | Настройка окружения. Прочитать первую статью руководства по Django. |
| --- | --- |
| Цель: | Научиться использовать инструменты Django для создания новых веб-сайтов. |

Обзор
-----

Эта статья показывает, как можно создать "скелет"(прототип) сайта, который затем можно расширить при помощи различных настроек, url адресов, моделей, представлений, и шаблонов (эти темы будут объясняться в последующих статьях).

Алгоритм следующий:

1. Использовать `django-admin` для создания папки проекта, шаблонов остальных файлов, и скрипта для управления проектом (**manage.py**).
2. Использовать **manage.py** *для создания одного или нескольких* приложений.

**Примечание:** Сайт может состоять из одной или нескольких различных частей, например: основная часть, блог, вики, раздел загрузок, и так далее. Философия Django подталкивает разработчиков создавать эти части, как разные **приложения**, которые, если понадобится, могут быть использованы повторно в других проектах.
3. Зарегистрировать в настройках эти приложения, чтобы использовать их в проекте.
4. Настроить маршруты url адресов для каждого из приложений.

Для Сайта местной библиотеки папка сайта и проекта будет называться *locallibrary*, и у нас будет одно приложение с названием *catalog*. Верхняя структура проекта будет следующей:

```bash
locallibrary/         # Папка сайта
    manage.py         # Скрипт для управления проектов (создан manage.py)
    locallibrary/     # Папка сайта/проекта (создана manage.py)
    catalog/          # Папка приложения (также создана manage.py)
```

Следующие разделы статьи разложат по полочкам этапы создания "скелета", и покажут вам, как можно проверить сделанные изменения. В конце статьи мы обсудим некоторые другие настройки сайта, которые можно назначить на этом этапе.

Создание проекта
----------------

Для начала откройте командную строку/терминал, перейдите в ту папку, куда вы хотите поместить проект Django(лучше в папке профиля пользователя `C:\Users\user_name`, при запуске командной строки используется именно эта директория), и создайте папку для вашего нового сайта (в данном случае: *locallibrary*). Затем войдите в эту папку, используя команду cd:

```bash
mkdir locallibrary
cd locallibrary
```

Создайте новую папку, используя команду `django-admin startproject` как в примере ниже, и затем зайдите в созданную папку.

```bash
  django-admin startproject locallibrary .
cd locallibrary
```

Команда `django-admin` создаст файловую структуру, как в примере ниже:

```bash
locallibrary/
    manage.py
    locallibrary/
        settings.py
        urls.py
        wsgi.py
```

Подпапка проекта *locallibrary* это ключевая директория нашего проекта:

* **settings.py** содержит в себе все настройки проекта. Здесь мы регистрируем приложения, задаём размещение *статичных* файлов, настройки базы данных и так далее.
* **urls.py** задаёт ассоциации url адресов с представлениями. Несмотря на то, что этот файл может содержать *все* настройки url, обычно его делят на части, по одной на приложение, как будет показано далее.
* **wsgi.py** используется для налаживания связи между вашим Django приложением и веб-сервером. Вы можете воспринимать его, как утилиту.

Скрипт **manage.py** используется для создания приложений, работы с базами данных и для запуска отладочного сервера.

Создание приложения Каталог
---------------------------

Выполнив предыдущие шаги, запустите следующую команду для создания приложения *catalog*, который будет размещён внутри папки locallibrary (команду необходимо выполнять из папки, в которой находится **manage.py**):

```bash
python3 manage.py startapp catalog
```

**Примечание:** приведённая выше команда справедлива для GNU Linux/Mac OS. На Windows команда должна иметь вид: `py -3 manage.py startapp catalog`

Если вы работаете под Windows, заменяйте команду `python3` на `py -3` в этой и следующих статьях.

Эта команда создаст новую папку и наполнит её файлами различных частей приложения (выделенные **полужирным** ниже). Большинство файлов названы, исходя из их назначения (например контроллеры(views) должны находится во **views.py**, модели в **models.py**, тесты в **tests.py**, настройки административной части в **admin.py**, регистрация приложения в **apps.py**) и уже содержат некоторый шаблонный код для работы с вышеназванными объектами.

Обновлённая директория должна выглядеть следующим образом:

```bash
locallibrary/
    manage.py
    locallibrary/
    catalog/
        admin.py
        apps.py
        models.py
        tests.py
        views.py
        __init__.py
        migrations/
```

Кроме перечисленных выше файлов были созданы:

* Папка *migrations* используется, чтобы хранить"миграции" — файлы, которые позволяют вам автоматически обновлять базу данных по мере изменения моделей.
* **\_\_init\_\_.py** — пустой файл для того, чтобы Django и Python распознавали папку как Python модуль и позволяет нам использовать его объекты внутри других частей проекта.

**Примечание:** Заметили, что некоторых файлов не хватает? В то время, как там нашли себе место файлы для контроллеров(views) и моделей(models), файлов для настройки url соотносителя, шаблонов, и статичных файлов создано не было. Далее мы покажем, как их создать (они не обязательны для каждого сайта, но нужны в данном примере).

Регистрация папки с приложением
-------------------------------

После создания приложения, нам нужно зарегистрировать его в проекте, чтобы различные утилиты затрагивали его своим действием (например при добавлении моделей в базу данных). Приложения регистрируются добавлением их названий в список `INSTALLED_APPS` в настройках проекта(который, как мы помним, называется **settings.py**).

Откройте файл **locallibrary/locallibrary/settings.py** и найдите в нём список `INSTALLED_APPS` . Затем добавьте новую строку в конец списка, как показано **полужирным** ниже.

```bash
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'catalog.apps.CatalogConfig',
]
```

Новая строка указывает на файл конфигурации приложения (`CatalogConfig`), который был создан в **/locallibrary/catalog/apps.py** , когда вы создали приложение.

**Примечание:** Легко заметить, что в `INSTALLED_APPS` уже подключено большое количество приложений (и объектов `MIDDLEWARE`, ниже в файле конфигурации). Они добавляют поддержку админ-панели Django и, как следствие, огромное количество функциональности (включая сессии, аутентификацию и прочее).

Настройка базы данных
---------------------

На этом шаге обычно указывают базу данных для будущего проекта — имеет смысл использовать для разработки и размещённого в Сети одну и ту же базу данных, по возможности, чтобы исключить различия в поведении. Про различные варианты вы можете прочитать в документации Django в разделе Базы данных.

Мы будем использовать базу данных SQLite для этого проекта, потому что не предполагаем большое количество одновременных запросов на неё, а ещё потому, что для её настройки совсем не надо ничего делать! Вы можете видеть, что база данных уже настроена в **settings.py** (подробная информация указана ниже):

```python
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}
```

Так как мы используем SQLite, то нам не нужно ничего делать.

Давайте продолжим!

Другие настройки проекта
------------------------

Файл **settings.py** так же применяется и для некоторых других настроек, но на данном шаге имеет смысл поменять разве что TIME\_ZONE — это значение должно быть представлено строкой, указанной в списке часовых поясов tz (колонка TZ в таблице, в строке временной зоны, которая вам нужна). Измените `TIME_ZONE` на одну из строк из таблицы, которая отвечает вашему часовому поясу. Например:

```python
TIME_ZONE = 'Europe/Moscow'
```

В файле присутствует две настройки, которые не нужно менять сейчас, но о назначении которых следует знать:

* `SECRET_KEY`. Это секретный ключ, который используется Django для поддержки безопасности сайта. Если вы раскроете этот ключ в процессе разработки кому-либо, то необходимо будет его сменить (возможно считать его с какого-либо файла на сервере или переменной окружения) когда будете размещать проект на сервер.
* `DEBUG`. Включает подробные сообщения об ошибках, вместо стандартных HTTP статусов ответов. Должно быть изменено на `False` на сервере, так как эта информация очень много расскажет взломщикам.
Подключение URL-адреса
----------------------

При создании сайта, был создан файл сопоставления URL (**urls.py**) в корне проекта. Хотя можно использовать его для обработки всех URL адресов, более целесообразно подключать отдельные файлы сопоставлений для каждого приложения.

Откройте **locallibrary/locallibrary/urls.py** и обратите внимание на закомментированный текст, который объясняет суть происходящего.

```python
"""
locallibrary URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
 https://docs.djangoproject.com/en/1.10/topics/http/urls/
Examples:
Function views
 1. Add an import: from my\_app import views
 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
 1. Add an import: from other\_app.views import Home
 2. Add a URL to urlpatterns: url(r'^$', Home.as\_view(), name='home')
Including another URLconf
 1. Import the include() function: from django.conf.urls import url, include
 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.urls import path
from django.contrib import admin

urlpatterns = [
    path('admin/', admin.site.urls),
]
```

URL соотношения хранятся в переменной `urlpatterns`, которая является списком функций `path()`. Каждая `path()` функция или ассоциирует шаблон URL\_ *с контроллером(views) или же его с другим таким списком (во втором случае, первый URL становится "базовым" для других, которые определяются в дочернем списке). Список `urlpatterns` инициализирует список функции, которая, например, соотносит \_admin/* с модулем `admin.site.urls` , который содержит собственный файл-соотноситель.

Добавьте строчки, приведённые ниже в низ файла **urls.py** , чтобы добавить новый элемент в список `urlpatterns`. Этот элемент содержит `url()` который направляет запросы с URL `catalog/` к модулю `catalog.urls` (файл с относительным путём **/catalog/urls.py**).

```python
# Используйте include() чтобы добавлять URL из каталога приложения
from django.urls import include
from django.urls import path
urlpatterns += [
     path('catalog/', include('catalog.urls')),
]
```

Теперь давайте перенаправим корневой URL нашего сайта (например `127.0.0.1:8000`) на URL `127.0.0.1:8000/catalog/`; это единственное приложение, которое мы собираемся использовать, поэтому это вполне разумно. Чтобы это использовать, нам понадобится специальная функция (`RedirectView`), которая принимает первым параметром новый относительный URL на который следует перенаправлять (`/catalog/`) когда указанный в функции `url()` адрес соотносится с адресом запроса (корневой URL, в данном случае).

Добавьте следующие строчки, тоже в конец файла:

```python
# Добавьте URL соотношения, чтобы перенаправить запросы с корневого URL, на URL приложения
from django.views.generic import RedirectView
urlpatterns += [
    path('', RedirectView.as_view(url='/catalog/', permanent=True)),
]
```

Django не размещает *статические* файлы(CSS, JavaScript, и изображения) по умолчанию, но это было бы крайне полезно на этапе разработки нашего сайта. В самом конце нашего URL соотносителя, можно включить размещение статических файлов.

Добавьте последнюю часть в конец файла:
```

# Используйте static() чтобы добавить соотношения для статических файлов
# Только на период разработки
from django.conf import settings
from django.conf.urls.static import static

urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
```

**Примечание:** Существуют различные способы дополнения списка `urlpatterns` (в примере мы просто добавляли объект, используя оператор `+=` чтобы чётко разделить изначальный и дописанный код). Вместо этого, мы могли бы добавить соотношения внутрь определения переменной:
```

urlpatterns = [   path('admin/', admin.site.urls),
path('catalog/', include('catalog.urls')),path('',
RedirectView.as_view(url='/catalog/', permanent=True)), ] +
static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
```

Кроме того, мы добавили import вниз файла (`from django.urls import include`) ,чтобы видеть, что мы добавили, но обычно все инструкции import добавляются в верхнюю часть файла.

Напоследок, создайте файл **urls.py** внутри папки **catalog**, и добавьте следующий код, чтобы определить (пустой) `urlpatterns`. Сюда мы будем добавлять наши URL соотношения, по мере разработки сайта.

```python
from django.urls import path
from . import views

urlpatterns = [

]
```

Тестирование работы скелета
---------------------------

На этом, мы создали прототип сайта. Пока сайт ничего не умеет делать, но стоит запустить его, чтобы убедиться, что мы ничего не сломали.

До этого, нам предстоит впервые запустить *миграцию базы данных*. Это обновит нашу базу данных и добавит туда необходимые модели (и уберёт некоторые предупреждения, которые были бы показаны при попытке запуска).

### Запуск миграций базы данных

Django использует Объектный Соотноситель Связей (ORM) чтобы соотносить определения моделей в Django приложении со структурами данных, которые используются базой данных. Когда мы меняем наши модели, Django отслеживает изменения и может создать файлы миграций (в папке **/locallibrary/catalog/migrations/**) чтобы применить соответствующие структуры данных к базе, чтобы та соответствовала модели.

При создании сайта, Django автоматически добавил несколько моделей, чтобы мы могли их использовать в админ-панели (о которой мы поговорим позже). Выполните следующие команды, чтобы создать нужные таблицы в базе данных, соответствующие этим моделям (убедитесь, что вы находитесь в папке с **manage.py**):

```bash
python3 manage.py makemigrations
python3 manage.py migrate
```

**Предупреждение:** Необходимо выполнять команды выше каждый раз, когда вы меняете модели таким образом, что структура таблицы изменится(включая добавления и удаления как отдельных полей, так и целых моделей).

`Команда makemigrations` *создаёт* (но не применяет) миграции для всех приложений, которые установлены в ваш проект (вы так же можете указать в конце имя конкретного приложения, чтобы создать миграции только для него). Это даёт вам возможность проверить код перед тем, как их применить — когда вы станете хорошо разбираться в Django, то сможете даже менять их!

Команда `migrate` применяет созданные миграции к базе (Django отслеживает, какие миграции были созданы для данной базы).

**Примечание:** Посмотрите раздел Миграции в документации Django чтобы получить информацию о менее распространённых командах для управления миграциями.

### Запуск сайта

Во время разработки, вы можете проверить свой сайт, разместив его на *встроенном отладочном сервере*, и просмотрев его в своём браузере.

**Примечание:** Отладочный веб-сервер не настолько функционален и производителен, для постоянного размещения , но это самый простой способ запустить свой сайт на Django и проверить его на наличие ошибок. По умолчанию, он разместит сайт на вашем компьютере (`http://127.0.0.1:8000/)`, но вы так же можете указать различные компьютеры в вашей сети для этой цели. Для получения большего количества информации загляните в раздел django-admin и manage.py: отладочный сервер документации Django.

Запустите веб-сервер, используя команду *runserver* (в той же папке, что и **manage.py**):

```bash
python3 manage.py runserver

 Performing system checks...

 System check identified no issues (0 silenced).
 September 22, 2016 - 16:11:26
 Django version 1.10, using settings 'locallibrary.settings'
 Starting development server at http://127.0.0.1:8000/
 Quit the server with CTRL-BREAK.
```

Когда сервер запустится, вы сможете посетить сайт по адресу `http://127.0.0.1:8000/` в вашем веб-браузере. Вы должны увидеть страницу с ошибкой, навроде этой:

![Django debug page for a 404 not found error](/ru/docs/Learn/Server-side/Django/skeleton_website/django_404_debug_page.png)

Не волнуйтесь! Эта страница должна появиться и сообщить нам, что мы ещё не настроили ни одной страницы в модуле `catalogs.urls` (на который мы были перенаправлены запросили корневой URL сайта).

**Примечание:** Показанная выше страница открывает нам одно из замечательных свойств Django — автоматические отчёты об ошибках. На экране с ошибкой отображается множество полезной информации, когда страница не найдена, или ошибка была вызвана кодом. В данном случае, мы видим, что запрошенный URL не соответствует ни одному шаблону (из указанных). Подобные отчёты будут выключены при DEBUG=False (когда мы разместим приложение в Сеть), в этом случае будет показана менее информативная, но более дружелюбная к пользователю страница(которую вам надо будет создать - прим. переводчика).

На данном этапе, мы поняли, что Django работает должным образом!

**Примечание:** вам следует перезапускать миграцию и заново тестировать сайт, после того как вы делаете важные изменения. Поверьте, это не займёт много времени!

Домашнее задание
----------------

Папка **catalog/** содержит файлы контроллеров(views), моделей(models), и других частей приложения. Просмотрите эти файлы.

Как было написано выше, URL соотноситель для админ-панели был подключён в файле **urls.py**. Войдите в административную часть и посмотрите, что произойдёт (вы можете найти URL из соотношения выше).

Подводя итоги
-------------

Теперь вы создали полноценный скелет веб-приложения, который теперь вы можете расширить url соотносителями, контроллерами(views) и моделями(models).

Теперь скелет Сайта местной библиотеки сделан и запущен, теперь самое время начать писать код, который научит сайт делать то, что он должен делать.

Также посмотрите эти статьи
---------------------------

* Пишем своё первое приложение на Django - часть 1 (документация Django)
* Приложения (документация Django). содержит информацию о настройке приложений.
* Назад
* Обзор: Django
* Далее