aboutsummaryrefslogtreecommitdiff
path: root/files/ru/learn/server-side
diff options
context:
space:
mode:
Diffstat (limited to 'files/ru/learn/server-side')
-rw-r--r--files/ru/learn/server-side/apache_configuration_htaccess/index.html38
-rw-r--r--files/ru/learn/server-side/django/admin_site/index.html340
-rw-r--r--files/ru/learn/server-side/django/development_environment/index.html398
-rw-r--r--files/ru/learn/server-side/django/django_assessment_blog/index.html320
-rw-r--r--files/ru/learn/server-side/django/forms/index.html650
-rw-r--r--files/ru/learn/server-side/django/generic_views/index.html605
-rw-r--r--files/ru/learn/server-side/django/home_page/index.html359
-rw-r--r--files/ru/learn/server-side/django/index.html66
-rw-r--r--files/ru/learn/server-side/django/models/index.html448
-rw-r--r--files/ru/learn/server-side/django/skeleton_website/index.html357
-rw-r--r--files/ru/learn/server-side/django/testing/index.html892
-rw-r--r--files/ru/learn/server-side/django/tutorial_local_library_website/index.html74
-rw-r--r--files/ru/learn/server-side/django/web_application_security/index.html179
-rw-r--r--files/ru/learn/server-side/django/аутентификация/index.html688
-rw-r--r--files/ru/learn/server-side/django/введение/index.html259
-rw-r--r--files/ru/learn/server-side/django/разворачивание/index.html680
-rw-r--r--files/ru/learn/server-side/django/сессии/index.html181
-rw-r--r--files/ru/learn/server-side/express_nodejs/development_environment/index.html391
-rw-r--r--files/ru/learn/server-side/express_nodejs/displaying_data/author_list_page/index.html85
-rw-r--r--files/ru/learn/server-side/express_nodejs/displaying_data/book_list_page/index.html68
-rw-r--r--files/ru/learn/server-side/express_nodejs/displaying_data/bookinstance_list_page/index.html69
-rw-r--r--files/ru/learn/server-side/express_nodejs/displaying_data/date_formatting_using_moment/index.html60
-rw-r--r--files/ru/learn/server-side/express_nodejs/displaying_data/flow_control_using_async/index.html138
-rw-r--r--files/ru/learn/server-side/express_nodejs/displaying_data/genre_detail_page/index.html121
-rw-r--r--files/ru/learn/server-side/express_nodejs/displaying_data/home_page/index.html134
-rw-r--r--files/ru/learn/server-side/express_nodejs/displaying_data/index.html83
-rw-r--r--files/ru/learn/server-side/express_nodejs/displaying_data/locallibrary_base_template/index.html69
-rw-r--r--files/ru/learn/server-side/express_nodejs/displaying_data/template_primer/index.html149
-rw-r--r--files/ru/learn/server-side/express_nodejs/forms/create_bookinstance_form/index.html151
-rw-r--r--files/ru/learn/server-side/express_nodejs/forms/create_genre_form/index.html199
-rw-r--r--files/ru/learn/server-side/express_nodejs/forms/delete_author_form/index.html165
-rw-r--r--files/ru/learn/server-side/express_nodejs/forms/index.html269
-rw-r--r--files/ru/learn/server-side/express_nodejs/forms/update_book_form/index.html189
-rw-r--r--files/ru/learn/server-side/express_nodejs/index.html77
-rw-r--r--files/ru/learn/server-side/express_nodejs/introduction/index.html512
-rw-r--r--files/ru/learn/server-side/express_nodejs/mongoose/index.html800
-rw-r--r--files/ru/learn/server-side/express_nodejs/routes/index.html655
-rw-r--r--files/ru/learn/server-side/express_nodejs/skeleton_website/index.html507
-rw-r--r--files/ru/learn/server-side/express_nodejs/учебник_сайт_local_library/index.html73
-rw-r--r--files/ru/learn/server-side/first_steps/client-server_overview/index.html325
-rw-r--r--files/ru/learn/server-side/first_steps/index.html49
-rw-r--r--files/ru/learn/server-side/first_steps/introduction/index.html217
-rw-r--r--files/ru/learn/server-side/first_steps/web_frameworks/index.html306
-rw-r--r--files/ru/learn/server-side/first_steps/веб_безопасность/index.html169
-rw-r--r--files/ru/learn/server-side/index.html54
-rw-r--r--files/ru/learn/server-side/node_server_without_framework/index.html84
46 files changed, 12702 insertions, 0 deletions
diff --git a/files/ru/learn/server-side/apache_configuration_htaccess/index.html b/files/ru/learn/server-side/apache_configuration_htaccess/index.html
new file mode 100644
index 0000000000..fafabc17f8
--- /dev/null
+++ b/files/ru/learn/server-side/apache_configuration_htaccess/index.html
@@ -0,0 +1,38 @@
+---
+title: .htaccess ( hypertext access )
+slug: Learn/Server-side/Apache_Configuration_htaccess
+translation_of: Learn/Server-side/Apache_Configuration_htaccess
+---
+<p>Название .htaccess происходит от "hypertext access". Это файл с расширением HTACCESS, который содержит различные настройки сервера apache. Он позволяет настраивать для текущей директории защиту паролем, редиректы и многое другое.</p>
+
+<p><strong>Доступ к файлу</strong>: файл htaccess  может быть открыт для редактивания любым текстовым редактором, таким как стандартный блокнот Windows, Vin, Sublime text editor или любым другим. Подсветка синтаксиса для файлов .htaccess встречается редко.</p>
+
+<h2 id="Применение">Применение</h2>
+
+<p><strong>Перенаправления</strong>: htaccess файлы часто используют для перенаправления трафика между веб-страницами, а также между разными доменами. Это простой и эффективный способ перенаправления трафика, так как перенаправление происходит до обработки запроса на стороне сервера. Перенаправление может быть временным и постоянным, с установкой соответствующего кода статуса.</p>
+
+<pre>Redirect 301 / http://example.com/ # Постоянное перенаправление на example.com
+Redirect 302 / http://example.com/ # Временное перенаправление на example.com
+</pre>
+
+<p><strong>Блокирование</strong>: htaccess также может блокировать доступ с определенного IP адреса или диапазопа IP адресов. Блокирование часто используется, чтобы запретить доступ к директории для различных ботов и поисковых пауков.</p>
+
+<pre>deny from 146.0.74.205 # Блокирует все запросы с адреса 146.0.74.205</pre>
+
+<p><strong>SSI или Server Side Include</strong> : С помощью файла .htaccess можно настроить автоматическое подключение файлов в документ. При каждом запросе пользователя, указанные файлы автоматически будут подключены в начало или в конец документа. При этом в самом документе их подключать не нужно.</p>
+
+<pre>php_value auto_prepend_file "/real/path/to/file/functions.php" # Подключит файл function.php в начало документа
+php_value auto_append_file "/real/path/to/file/footer.php" # Подключит файл footer.html в конец документа
+</pre>
+
+<p><strong>Настройка страниц с ошибками:</strong> с помощью .htaccess можно перенаправлять пользователя на определенные страницы, при возникновении ошибок на сервере.</p>
+
+<pre>ErrorDocument 404 /notfound.html # Перенаправит пользователя на страницу notfound.html , при возникновении ошибки с кодом 404
+ErrorDocument 500 /serverr.html  # Перенаправит пользователя на страницу serverr.html , при возникновении ошибки с кодом 500
+</pre>
+
+<p>Для дополнительной информации читайте статью <a href="http://techstream.org/Web-Development/HTACCESS/Error-Documents">Redirect your Traffic for Error Handling</a>.</p>
+
+<p><strong>Кэширование: </strong>файл <span style="line-height: 1.572;">.htaccess может управлять кэшированием данных веб-браузером пользователя. Это ускорит загрузку страниц и сократит количество передаваемой информации меджу сервером и клиентом.</span></p>
+
+<p><strong>MIME типы</strong>: смотрите статью <a href="/en-US/docs/Properly_Configuring_Server_MIME_Types" title="Properly_Configuring_Server_MIME_Types">correct MIME types</a> для большей информации.</p>
diff --git a/files/ru/learn/server-side/django/admin_site/index.html b/files/ru/learn/server-side/django/admin_site/index.html
new file mode 100644
index 0000000000..e8094df592
--- /dev/null
+++ b/files/ru/learn/server-side/django/admin_site/index.html
@@ -0,0 +1,340 @@
+---
+title: 'Руководство Django часть 4: административная панель Django'
+slug: Learn/Server-side/Django/Admin_site
+translation_of: Learn/Server-side/Django/Admin_site
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Django/Models", "Learn/Server-side/Django/Home_page", "Learn/Server-side/Django")}}</div>
+
+<p class="summary">Теперь, когда модели для сайта <a href="https://developer.mozilla.org/ru-RU/docs/Learn/Server-side/Django/Tutorial_local_library_website">местной библиотеки</a> созданы, добавим некоторые "настоящие" данные о книгах, используя административную панель Django Admin. Для начала мы покажем, как зарегистрировать в ней модели, потом как войти и создать какие-нибудь данные. В конце статьи мы покажем некоторые способы дальнейшего улучшения вида админ-панели.</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Предусловия:</th>
+ <td>Сначала завершите: <a href="/ru-RU/docs/Learn/Server-side/Django/Models">Руководство часть 3: </a>использование моделей.</td>
+ </tr>
+ <tr>
+ <th scope="row">Цель:</th>
+ <td>
+ <p>Уяснить преимущества и ограничения админ-панели Django, научиться использовать её для создания записей для наших моделей.</p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Обзор">Обзор</h2>
+
+<p><em>Приложение</em> Django admin может использовать ваши модели для автоматического создания части сайта, предназначенной для создания, просмотра, обновления и удаления записей. Это может сэкономить вам много времени в процессе разработки, упрощая тестирование ваших моделей на предмет <em>правильности</em> данных. Оно также может быть полезным для управления данными на стадии публикации, в зависимости от типа веб-сайта. Проект Django рекомендует это приложение только для управления внутренними данными (т.е.для использования администраторами, либо людьми внутри вашей организации), так как модельно-ориентированный подход не обязательно является наилучшим интерфейсом для всех пользователей и раскрывает много лишних подробностей о моделях.</p>
+
+<p>Все необходимые настройки, которые необходимо включить  в admin приложение вашего веб-сайта, были сделаны автоматически, когда вы <a href="/ru-RU/docs/Learn/Server-side/Django/skeleton_website">создали каркас проекта</a> ( информацию о необходимых актуальных зависимостях смотрите здесь -  <a href="https://docs.djangoproject.com/en/1.10/ref/contrib/admin/">Django docs</a>) . В результате все, что необходимо сделать для того, чтобы добавить модели в приложение admin, это <em>зарегистрировать</em> их. В конце этой статьи мы представим краткую демонстрацию того, каким образом  можно дополнительно настроить админ-панель для лучшего отображения данные наших моделей.</p>
+
+<p>После регистрации моделей мы покажем как создать нового суперпользователя , войти на сайт от его имени и создать книги, авторов, экземпляры книг и жанры. Это будет полезным для тестирования представлений и шаблонов, которые мы начнем создавать в следующей части руководства.</p>
+
+<h2 id="Регистрация_моделей">Регистрация моделей </h2>
+
+<p>Вначале откройте файл <strong>admin.py </strong>в папке приложения (<strong>/locallibrary/catalog/admin.py</strong>). Пока он выглядит так (заметьте, что он уже содержит импорт  <code>django.contrib.admin)</code>:</p>
+
+<pre class="brush: python">from django.contrib import admin
+
+# Register your models here.
+</pre>
+
+<p>Зарегистрируйте модели путем вставки следующего текста в нижнюю часть этого файла. Этот код просто импортирует модели и затем вызывает  <code>admin.site.register</code> для регистрации каждой из них.</p>
+
+<pre class="brush: python">from .models import Author, Genre, Book, BookInstance
+
+admin.site.register(Book)
+admin.site.register(Author)
+admin.site.register(Genre)
+admin.site.register(BookInstance)
+</pre>
+
+<div class="note"><strong>Примечание</strong>: Если вы приняли участие в создании модели для представления естественного языка книги (<a href="/ru-RU/docs/Learn/Server-side/Django/Models">см. обучающую статью о моделях</a>), импортируйте и зарегистрируйте её тоже!</div>
+
+<p>Это самый простой способ регистрации модели или моделей. Админ-панель имеет множество настроек. Мы рассмотрим другие способы регистрации ваших моделей ниже.</p>
+
+<h2 id="Создание_суперпользователя">Создание суперпользователя</h2>
+
+<p>Для того, чтобы войти в админ-панель, нам необходимо иметь учетную запись пользователя со статусом <em>Staff (сотрудники). </em>Для просмотра и создания записей, пользователю также понадобится разрешение для управления всеми нашими объектами. Вы можете создать учетную запись  "superuser", которая дает полный доступ к сайту и все необходимые разрешения, используя <strong>manage.py</strong>.</p>
+
+<p>Для создания суперпользователя вызовите следующую команду из той же папки, где расположен <strong>manage.py</strong>. Вас попросят ввести имя пользователя, адрес электронной почты и надежный пароль. </p>
+
+<pre class="brush: bash">python3 manage.py createsuperuser
+</pre>
+
+<p>После выполнения этой команды новый суперпользователь будет добавлен в базу данных. Теперь перезапустите сервер, чтобы можно было протестировать вход на сайт:</p>
+
+<pre class="brush: bash">python3 manage.py runserver
+
+</pre>
+
+<h2 id="Вход_в_админ-панель_и_ее_использование">Вход в админ-панель и ее использование</h2>
+
+<p>Для входа в админ-панель откройте ссылку<em> /admin</em> (например  <a href="http://127.0.0.1:8000/admin/">http://127.0.0.1:8000/admin</a>) и введите логин и пароль вашего нового суперпользователя  (вас перенаправят на login-страницу и потом обратно на /admin после ввода всех деталей).</p>
+
+<p>В этой части сайта отображаются все наши модели, сгрупированные по установленному приложению. Вы можете кликнуть на названии модели, чтобы получить список всех связанных записей, далее можете кликнуть на этих записях, для их редактирования . Также можно непосредственно кликнуть на ссылку <strong>Add</strong>, расположенную рядом с каждой моделью, чтобы начать создание записи этого типа. </p>
+
+<p><img alt="Admin Site - Home page" src="https://mdn.mozillademos.org/files/13975/admin_home.png" style="display: block; height: 634px; margin: 0px auto; width: 998px;"></p>
+
+<p>Кликните на ссылке <strong>Add</strong> справа от <em>Books</em>, чтобы создать новую книгу (появится диалоговое окно как на картинке внизу). Заметьте, что заголовок каждого поля - это тип используемого виджета, и    <code>help_text</code> (если есть) совпадает со значением, которое вы указали в модели. </p>
+
+<p>Введите значение для полей. Вы можете создавать новых авторов или жанры, нажимая на значок "+ ", расположенный рядом с соответствующим полем (или выберите существующее значение из списков, если вы уже создали их). Когда вы закончили, нажмите на <strong>SAVE,</strong>  <strong>Save and add another</strong>, или <strong>Save and continue editing,</strong> чтобы сохранить записи.</p>
+
+<p><img alt="Admin Site - Book Add" src="https://mdn.mozillademos.org/files/13979/admin_book_add.png" style="border-style: solid; border-width: 1px; display: block; height: 780px; margin: 0px auto; width: 841px;"></p>
+
+<div class="note">
+<p><strong>Примечание</strong>: А сейчас, хотелось бы, чтобы вы добавили несколько книг, авторов и жанров (например,  Фэнтези) в ваше приложение. Удостоверьтесь, что каждый автор и жанр включает пару различных книг (позже, когда мы реализуем представления "list" и "detail", это сделает их более интересными).</p>
+</div>
+
+<p>После того, когда книги добавлены, для перехода на главную страницу админ-панели кликните на ссылке <strong>Home </strong>в верхней части страницы. Потом кликните на ссылке <strong>Books</strong> для отображения текущего списка книг (или на одной из других ссылок, чтобы увидеть список соответствующей модели). После добавления нескольких книг список может выглядеть наподобие скриншота ниже.  Отображается название каждой из книг. Его возвращает метод <code>__str__() </code>в модели Book, созданной в предыдущей статье.</p>
+
+<p><img alt="Admin Site - List of book objects" src="https://mdn.mozillademos.org/files/13935/admin_book_list.png" style="border-style: solid; border-width: 1px; display: block; height: 407px; margin: 0px auto; width: 1000px;"></p>
+
+<p>Для удаления книги из этого списка выберите чекбокс рядом с ней и действие <em>delete...</em>  из выпадающего списка <em>Action</em>, а затем нажмите кнопку <strong>Go</strong>. Также можно добавить новую книгу, нажав на кнопку <strong>ADD BOOK</strong>. </p>
+
+<p>Вы можете редактировать книгу, кликнув по ссылке с ее названием. Страница редактирования книги, приведенная ниже, практически идентична странице добавления новой книги. Основные отличия - это заголовок страницы (<em>Change book</em>) и наличие кнопок <strong>Delete</strong>, <strong>HISTORY</strong> и <strong>VIEW ON SITE.  </strong>Последняя присутствует, так как мы определили метод <code>get_absolute_url() </code>в нашей модели.</p>
+
+<p><img alt="Admin Site - Book Edit" src="https://mdn.mozillademos.org/files/13977/admin_book_modify.png" style="border-style: solid; border-width: 1px; display: block; height: 780px; margin: 0px auto; width: 841px;"></p>
+
+<p>Теперь перейдите назад на страницу <strong>Home </strong>(используя ссылку <em>Home</em> в навигационной цепочке вверху страницы) и просмотрите списки <strong>Author</strong> и <strong>Genre</strong>. В них уже должно быть несколько элементов, созданных при добавлении новых книг. Если хотите, добавьте еще.</p>
+
+<p>Однако у вас не будет ни одного экземпляра книги, потому что они не создаются из модели <code>Book </code>(хотя можно создать книгу из модели <code>BookInstance</code> — такова природа поля <code>ForeignKey</code>). Для отображения страницы <em>Add book instance </em>(см. рисунок ниже)<em> </em>вернитесь на страницу <em>Home</em>  и нажмите кнопку <strong>Add</strong>. Обратите внимание на длинный уникальный Id для идентификации конкретного экземпляра книги в библиотеке.</p>
+
+<p><img alt="Admin Site - BookInstance Add" src="https://mdn.mozillademos.org/files/13981/admin_bookinstance_add.png" style="border-style: solid; border-width: 1px; display: block; height: 514px; margin: 0px auto; width: 863px;"></p>
+
+<p>Создайте несколько экземпляров для каждой из ваших книг. Установите статус <em>Available (доступен) </em>для некоторых экземплров и <em>On loan (выдан)</em> для остальных. Если статус экземпляра <strong>not</strong> <em>Available (недоступен)</em>, то также установите дату возврата (<em>Due back)</em>.</p>
+
+<p>Вот и все!  Вы изучили как запустить и использовать админ-панель. Также были созданы записи для <code>Book</code>, <code>BookInstance</code>, <code>Genre</code> и <code>Author</code>, которые можно будет использовать после создания наших собственных представлений и шаблонов.</p>
+
+<h2 id="Продвинутая_конфигурация">"Продвинутая" конфигурация</h2>
+
+<p>Django выполняет неплохую работу по созданию базовой админ-панели используя информацию из зарегистрированых моделей:</p>
+
+<ul>
+ <li>каждая модель имеет список записей, каждая из которых идентифицируется строкой, создаваемой методом <code>__str__()</code> модели, и связана с представлением для ее редактирования. По умолчанию, в верхней части этого представления находится меню действий, которое может быть использовано для удаления нескольких записей за раз</li>
+ <li>Формы для редактирования и добавления записей содержат все поля модели, которые расположены вертикально в порядке их объявления в модели.  </li>
+</ul>
+
+<p>Можно настроить интерфейс пользователя для упрощения его использования. Некоторые доступные настройки:</p>
+
+<ul>
+ <li>List views:
+ <ul>
+ <li>добавление дополнительных отображаемых полей или информации для каждой записи. </li>
+ <li>добавление фильтров для отбора записей по разным критериям (например, статус выдачи книги).</li>
+ <li>добавление дополнительных вариантов выбора в меню действий и места расположения этого меню на форме.</li>
+ </ul>
+ </li>
+ <li>Detail views
+ <ul>
+ <li>выбор отображаемых полей, их порядка, группирования и т.д. </li>
+ <li>добавление связанных полей к записи  (например, возможности добавления и редактирования записей книг при создании записи автора).</li>
+ </ul>
+ </li>
+</ul>
+
+<p>В этом разделе рассмотрим некоторые изменения для совершенствования интерфейса пользователя нашей местной библиотеки, а именно: добавление дополнительной информации в списки моделей <code>Book</code> и <code>Author</code> ,  а также улучшение расположения элементов соответствующих представлений редактирования. Пользовательский интерфейс моделей <code>Language</code> and <code>Genre</code> изменять не будем, так как это не даст заметного улучшения, поскольку он содержит только по одному полю!</p>
+
+<p>Полное руководство по всем возможным вариантам настройки админ-панели можно найти в <a href="https://docs.djangoproject.com/en/1.10/ref/contrib/admin/">The Django Admin site</a> (документация Django).</p>
+
+<h3 id="Регистрация_класса_ModelAdmin">Регистрация класса ModelAdmin</h3>
+
+<p>Для измененения отображения модели в пользовательском интерфейсе админ-панели, необходимо определить класс <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#modeladmin-objects">ModelAdmin</a>  (он описывает расположение элементов интерфейса, где Model - наименование модели) и зарегистрировать его для использования с этой моделью.</p>
+
+<p>Давайте начнем с модели Author. Откройте файл <strong>admin.py</strong> в каталоге приложения (<strong>/locallibrary/catalog/admin.py</strong>). Закомментируйте исходную регистрацию (используя префикс #) этой модели:</p>
+
+<pre class="brush: js"># admin.site.register(Author)</pre>
+
+<p>Теперь добавьте новый класс <code>AuthorAdmin</code> и зарегистрируйте его как показано ниже:</p>
+
+<pre class="brush: python"># Define the admin class
+class AuthorAdmin(admin.ModelAdmin):
+ pass
+
+# Register the admin class with the associated model
+admin.site.register(Author, AuthorAdmin)
+</pre>
+
+<p>Сейчас мы добавим классы <code>ModelAdmin</code> для моделей <code>Book </code> <code>BookInstance</code>. Нам снова нужно закомментировать исходную регистрацию:</p>
+
+<pre class="brush: js">#admin.site.register(Book)
+#admin.site.register(BookInstance)</pre>
+
+<p>В этот раз для создания и регистрации новых моделей используем декоратор  <code>@register</code> (он делает то же самое, что и метод <code>admin.site.register()</code>):</p>
+
+<pre class="brush: 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
+</pre>
+
+<p>Пока что все наши admin-классы пустые (см. "<code>pass"</code>), поэтому ничего не изменится ! Добавим код для задания особенностей интерфейса моделей.</p>
+
+<h3 id="Настройка_отображения_списков">Настройка отображения списков</h3>
+
+<p>Сейчас приложение <em>LocalLibrary</em> отображает всех авторов, используя имя объекта, возвращаемое методом <code>__str__()</code> модели. Это приемлемо, когда есть только несколько авторов, но, если их количество значительно, возможны дубликаты. Чтобы различить их или просто отобразить более интересную информацию о каждом авторе, можно использовать <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display">list_display</a> (для добавления дополнительных полей). </p>
+
+<p>Замените класс <code>AuthorAdmin</code> кодом, приведенным ниже. Названия полей, которые будут отображаться в списке, перечислены в кортеже list_display в требуемом порядке  (это те же имена, что и в исходной модели).</p>
+
+<pre class="brush: python">class AuthorAdmin(admin.ModelAdmin):
+ list_display = ('last_name', 'first_name', 'date_of_birth', 'date_of_death')
+</pre>
+
+<p>Перезапустите сайт и перейдите к списку авторов. Указанные поля должны отображаться следующим образом:</p>
+
+<p><img alt="Admin Site - Improved Author List" src="https://mdn.mozillademos.org/files/14023/admin_improved_author_list.png" style="border-style: solid; border-width: 1px; display: block; height: 302px; margin: 0px auto; width: 941px;"></p>
+
+<p>Для нашей модели <code>Book</code> добавим отображение полей <code>author</code> и <code>genre</code>. Поле <code>author</code>  - это  внешний ключ (<code>ForeignKey</code> ) связи один к одному, поэтому оно будет представлено значением <code>__str()__</code>  для связанной записи. Замените класс <code>BookAdmin</code> на версию, приведенную ниже.</p>
+
+<pre class="brush: python">class BookAdmin(admin.ModelAdmin):
+ list_display = ('title', 'author', 'display_genre')
+</pre>
+
+<p>К сожалению, мы не можем напрямую поместить поле <font face="Consolas, Liberation Mono, Courier, monospace">genre в</font> <code>list_display</code>, так как оно является  <code>ManyToManyField</code> (Django не позволяет это из-за большой "стоимости" доступа к базе данных). Вместо этого мы определим функцию <code>display_genre</code> для получения строкового представления информации (вызов этой функции есть в <code>list_display</code>,  ее определение см. ниже).</p>
+
+<div class="note">
+<p><strong>Примечание</strong>: Получение здесь значения поля <code>genre</code> возможно не самая хорошая идея вследствие "стоимости" операции базы данных. Мы показываем это, потому что вызов функций в ваших моделях может быть очень полезен по другим причинам, например, для добавления ссылки  <em>Delete </em>рядом с каждым пунктом списка.</p>
+</div>
+
+<p>Добавьте следующий код в вашу модель <code>Book</code> (<strong>models.py</strong>). В нем создается строка из первых трех значений поля <code>genre</code> (если они существуют) и <code>short_description</code>,  которое может быть использовано в админ-панели.</p>
+
+<pre class="brush: 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'
+</pre>
+
+<p>После сохранения модели и обновления админ-панели, перезапустите ее и перейдите на страницу списка <em>Books</em>. Вы должны увидеть список книг, наподобие приведенного ниже:</p>
+
+<p><img alt="Admin Site - Improved Book List" src="https://mdn.mozillademos.org/files/14025/admin_improved_book_list.png" style="border-style: solid; border-width: 1px; display: block; height: 337px; margin: 0px auto; width: 947px;"></p>
+
+<p>Модель <code>Genre</code> (и модель <code>Language</code>, если вы ее определили) имеет единственное поле. Поэтому нет необходимости создания для них дополнительных моделей с целью отображения дополнительных полей.</p>
+
+<div class="note">
+<p><strong>Примечание</strong>: целесообразно, чтобы в списке модели <code>BookInstance</code> отображались хотя бы статус и ожидаемая дата возврата. Мы добавили это в качестве "испытания" в конце этой статьи!</p>
+</div>
+
+<h3 id="Добавление_фильтров_списка">Добавление фильтров списка</h3>
+
+<p>Если в вашем списке есть множество элементов, может быть полезной возможность фильтрации отображаемых пунктов. Это выполняется путем перечисления их в атрибуте <code>list_filter</code>. Замените класс <code style="font-style: normal; font-weight: normal;">BookInstanceAdmin</code> на следующий:</p>
+
+<pre class="brush: python">class BookInstanceAdmin(admin.ModelAdmin):
+<strong> list_filter = ('status', 'due_back')</strong>
+</pre>
+
+<p>Представление списка теперь будет содержать панель фильтрации справа. Обратите внимание, как выбирать даты и статус для фильтрации:</p>
+
+<p><img alt="Admin Site - BookInstance List Filters" src="https://mdn.mozillademos.org/files/14037/admin_improved_bookinstance_list_filters.png" style="height: 528px; width: 960px;"></p>
+
+<h3 id="Формирование_макета_с_подробным_представлением">Формирование макета с подробным представлением</h3>
+
+<p>По умолчанию в представлениях деталей отображаются все поля по вертикали в порядке их объявления в модели. Вы можете изменить порядок декларации, какие поля отображаются (или исключены), используются ли разделы для организации информации, отображаются ли поля горизонтально или вертикально, и даже какие виджеты редактирования используются в админ-формах.</p>
+
+<div class="note">
+<p><strong>Примечание:</strong> Модели LocalLibrary относительно просты, поэтому нам не нужно менять макет, но мы все равно внесем некоторые изменения, просто чтобы показать вам, как это сделать.</p>
+</div>
+
+<h4 id="Управление_отображаемыми_и_вложенными_полями">Управление отображаемыми и вложенными полями</h4>
+
+<p>Обновите ваш AuthorAdmin класс, чтобы добавить строку полей, как показано ниже (выделено полужирным шрифтом):</p>
+
+<pre class="brush: python">class AuthorAdmin(admin.ModelAdmin):
+ list_display = ('last_name', 'first_name', 'date_of_birth', 'date_of_death')
+<strong> fields = ['first_name', 'last_name', ('date_of_birth', 'date_of_death')]</strong>
+</pre>
+
+<p>Атрибут полей перечисляет только те поля, которые должны отображаться в форме, по порядку. Поля отображаются по вертикали по умолчанию, но будут отображаться горизонтально, если вы дополнительно группируете их в кортеже (как показано в полях «date» выше).</p>
+
+<p>Перезагрузите приложение и перейдите к подробному представлению автора - он должен теперь отображаться, как показано ниже:</p>
+
+<p><img alt="Admin Site - Improved Author Detail" src="https://mdn.mozillademos.org/files/14027/admin_improved_author_detail.png" style="border-style: solid; border-width: 1px; display: block; height: 282px; margin: 0px auto; width: 928px;"></p>
+
+<div class="note">
+<p><strong>Примечание</strong>: Так же, вы можете использовать <code>exclude</code> атрибут для объявления списка атрибутов, которые будут исключены из формы (все остальные атрибутыв модели, будут отображаться). </p>
+</div>
+
+<h4 id="Разделение_на_секцииВыделение_подробного_представления">Разделение на секции/Выделение подробного представления</h4>
+
+<p>Вы можете добавлять "разделы" (sections) для группировки связанной информации в модели в форме детализации, используя атрибут <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.fieldsets">fieldsets</a> .</p>
+
+<p>В модели <code>BookInstance</code> мы имеем информацию соответствия конкретной книги (т.е. <code>name</code>, <code>imprint</code>, and <code>id</code>) и датой когда она вновь станет доступной (<code>status</code>, <code>due_back</code>). Мы можем добавить их  в разные секции, добавив текст жирным шрифтом в наш <code>BookInstanceAdmin</code> класс. </p>
+
+<pre class="brush: python">@admin.register(BookInstance)
+class BookInstanceAdmin(admin.ModelAdmin):
+ list_filter = ('status', 'due_back')
+
+<strong> fieldsets = (
+ (None, {
+ 'fields': ('book','imprint', 'id')
+ }),
+ ('Availability', {
+ 'fields': ('status', 'due_back')
+ }),
+ )</strong></pre>
+
+<p>Каждая секция имеет свой заголовок (или <code>None</code>, если заголовок не нужен) и ассоциированный кортеж полей в словаре - формат сложный для описания, но относительно простой для понимания, если вы посмотрите на фрагмент кода, представленный выше.</p>
+
+<p>Перезапустите сайт и перейдите к списку экземпляров; форма должна отображаться следующим образом:</p>
+
+<p><img alt="Admin Site - Improved BookInstance Detail with sections" src="https://mdn.mozillademos.org/files/14029/admin_improved_bookinstance_detail_sections.png" style="border-style: solid; border-width: 1px; display: block; height: 580px; margin: 0px auto; width: 947px;"></p>
+
+<h3 id="Встроенное_редактирование_связанных_записей">Встроенное редактирование связанных записей</h3>
+
+<p>Иногда бывает полезно иметь возможность добавлять связанные записи одновременно. Например, имеет смысл иметь как информацию о книге, так и информацию о конкретных копиях, которые вы получили на той же странице подробностей. К примеру, вполне логично получить и информацию о книге, и информацию о конкретных копиях, зайдя на страницу детализации.</p>
+
+<p>Вы можете это сделать, объявив <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.inlines">inlines</a>, и указав тип <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.TabularInline">TabularInline</a> (горизонтальное расположение) или  <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.StackedInline">StackedInline</a> (вертикальное расположение, так же как и в модели по умолчанию). Вы можете добавить  <code>BookInstance</code> информацию в подробное описание  <code>Book</code> , добавив строки, представленные ниже и распологающиеся рядом с  <code>BookAdmin</code>: </p>
+
+<pre class="brush: python"><strong>class BooksInstanceInline(admin.TabularInline):
+    model = BookInstance</strong>
+
+@admin.register(Book)
+class BookAdmin(admin.ModelAdmin):
+    list_display = ('title', 'author', 'display_genre')
+<strong>    inlines = [BooksInstanceInline]</strong>
+</pre>
+
+<p>Попробуйте перезапустить приложение, а затем взгляните на представление книги — внизу вы должны увидеть экземпляры книги, относящиеся к этой книге:</p>
+
+<p><img alt="Admin Site - Book with Inlines" src="https://mdn.mozillademos.org/files/14033/admin_improved_book_detail_inlines.png" style="border-style: solid; border-width: 1px; display: block; height: 889px; margin: 0px auto; width: 937px;"></p>
+
+<p>В этом случае, всё, что мы сделали - объявили наш встроенный класс tablular, который просто добавляет все поля из <em>встроенной</em> модели. Вы можете указать все виды дополнительной информации для макета, включая отображаемые поля, их порядок, независимо от того, являются ли они только для чтения или нет, и т. д. (См. <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.TabularInline">TabularInline</a> для получения дополнительной информации). </p>
+
+<div class="note">
+<p><strong>Примечание</strong>: В этой функции есть некоторые неприятные ограничения! На скриншоте выше у нас есть три существующих экземпляра книги, за которыми следуют три поля для новых экземпляров книги (которые очень похожи!). Было бы лучше НЕ иметь лишних экземпляров книг по умолчанию и просто добавить их с помощью ссылки <strong>Add another Book instance</strong> или иметь возможность просто перечислять <code>BookInstance</code>s как нечитаемые здесь ссылки. Первый вариант можно сделать, установив <code>extra</code> атрибут в 0 в модели <code>BookInstanceInline</code>, попробуйте сами.</p>
+</div>
+
+<h2 id="Проверьте_себя">Проверьте себя</h2>
+
+<p>Мы многое изучили в этом разделе и теперь настало время вам самостоятельно попробовать несколько вещей:</p>
+
+<ol>
+ <li>Для представления списка <code>BookInstance</code> , добавьте код  для отображения книги, статуса, даты возврата, и id (вместо значения по умолчанию возвращаемого  <code>__str__()</code> ).</li>
+ <li>Добавьте встроенный список перечня <code>Book</code> в представление списка <code>Author</code> , используя тот же самый подход, который мы применили для <code>Book</code>/<code>BookInstance</code>.</li>
+</ol>
+
+<ul>
+</ul>
+
+<h2 id="Заключение">Заключение</h2>
+
+<p>Вот и всё! Теперь вы узнали, как настроить сайт администрирования как в самой простой, так и в улучшенной форме, о создании суперпользователя и о том, как перемещаться по сайту администратора, просматривать, удалять и обновлять записи. По пути вы создали множество книг, экземпляров, жанров и авторов, которые мы сможем перечислить и отобразить, как только мы создадим собственный вид и шаблоны.</p>
+
+<h2 id="Дополнительные_материалы">Дополнительные материалы</h2>
+
+<ul>
+ <li><a href="https://docs.djangoproject.com/en/1.10/intro/tutorial02/#introducing-the-django-admin">Writing your first Django app, part 2: Introducing the Django Admin</a>  (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/ref/contrib/admin/">The Django Admin site</a> (Django Docs)</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Django/Models", "Learn/Server-side/Django/Home_page", "Learn/Server-side/Django")}}</p>
diff --git a/files/ru/learn/server-side/django/development_environment/index.html b/files/ru/learn/server-side/django/development_environment/index.html
new file mode 100644
index 0000000000..6173f67714
--- /dev/null
+++ b/files/ru/learn/server-side/django/development_environment/index.html
@@ -0,0 +1,398 @@
+---
+title: Setting up a Django development environment
+slug: Learn/Server-side/Django/development_environment
+translation_of: Learn/Server-side/Django/development_environment
+---
+<p>{{LearnSidebar}}</p>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Django/Introduction", "Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django")}}</p>
+
+<p>Теперь, когда вы знаете, что такое Django, мы покажем вам, как настроить и протестировать среду разработки Django для Windows, Linux (Ubuntu) и Mac OS X - какую бы операционную систему вы не использовали, эта статья должна дать вам все, что необходимо для возможности начать разрабатывать приложения Django.</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Требования:</th>
+ <td>Знание как открыть терминал / командную строку, как устанавливать программные пакеты в операционной системе вашего компьютера.</td>
+ </tr>
+ <tr>
+ <th scope="row">Задача:</th>
+ <td>Создать среду разработки для Django (1.10) и запустить её на вашем компьютере.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Обзор_среды_разработки_Django">Обзор среды разработки Django</h2>
+
+<p>Django упрощает настройку собственного компьютера, чтобы вы могли начать разработку веб-приложений. В этом разделе объясняется, что входит в состав среды разработки, и дается обзор некоторых параметров настройки и конфигурации. В оставшейся части статьи объясняется рекомендуемый метод установки среды разработки Django на Ubuntu, Mac OS X и Windows, и как вы можете ее протестировать.</p>
+
+<h3 id="Что_такое_среда_разработки_Django">Что такое среда разработки Django?</h3>
+
+<p>Среда разработки - это установка Django на вашем локальном компьютере, которую вы можете использовать для разработки и тестирования приложений Django до их развертывания в производственной среде.<br>
+ <br>
+ Основными инструментами, которые предоставляет сам Django, является набор скриптов Python для создания и работы с проектами Django, а также простой веб-сервер <em>разработки</em>, который можно использовать для тестирования локальных (то есть на вашем компьютере, а не на внешнем веб-сервере) веб-приложений Django на веб-браузере вашего компьютера.<br>
+ <br>
+ Существуют и другие периферийные инструменты, являющиеся частью среды разработки, которые мы не будем освещать здесь. К ним относятся такие вещи, как текстовый редактор или IDE для редактирования кода, и инструмент управления исходным кодом, например Git, для безопасного управления различными версиями вашего кода. Мы предполагаем, что у вас уже установлен текстовый редактор.</p>
+
+<h3 id="Какие_есть_разновидности_установки_Django">Какие есть разновидности установки Django ?</h3>
+
+<p>Django очень гибок с точки зрения способа и места установки и настройки. Django может быть:</p>
+
+<ul>
+ <li>установлен на различных операционных системах,</li>
+ <li>установлен из исходного кода, из Python Package Index (PyPi) и во многих случаях из любого менеджера пакетов,</li>
+ <li>настроен на использование различных баз данных, которые должны быть установлены и настроены отдельно,</li>
+ <li>запущен в основной системе окружения Python или в отдельном виртуальном окружении Python.</li>
+</ul>
+
+<p>Каждый из этих вариантов требует немного разной настройки и установки. Следующие подразделы объяснят некоторые аспекты вашего выбора. Далее мы покажем вам, как установить Django на некоторые операционные системы, и эта установка будет предполагаться на всём протяжении данного модуля.</p>
+
+<div class="note">
+<p><strong>Замечание</strong>: Другие возможные способы установки можно найти в официальной документации Django. Мы ссылаемся на <a href="#furtherreading">соответствующие документы</a>.</p>
+</div>
+
+<h4 id="Какие_операционные_системы_поддерживаются">Какие операционные системы поддерживаются?</h4>
+
+<p>Веб-приложения Django можно запускать почти на любых машинах, которые поддерживают язык программирования Python 3, среди прочих: Windows, Mac OS X, Linux/Unix, Solaris. Почти любой компьютер имеет необходимую производительность для запуска Django во время разработки.</p>
+
+<p>В этой статье мы предоставляем инструкции для Windows, Mac OS X, and Linux/Unix.</p>
+
+<h4 id="Какую_версию_Python_стоит_использовать">Какую версию Python стоит использовать?</h4>
+
+<p>Мы рекомендуем использовать самую последнюю доступную версию - на момент написания статьи это Python 3.6.</p>
+
+<div class="note">
+<p><strong>Замечание</strong>: Python 2.7 не может быть использован вместе с Django 2.0 (последние поддерживаемые серии для Python 2.7 - Django 1.11.x).</p>
+</div>
+
+<h4 id="Откуда_можно_скачать_Django">Откуда можно скачать Django?</h4>
+
+<p>Для загрузки Django можно воспользоваться 3 источниками:</p>
+
+<ul>
+ <li>The Python Package Repository (PyPi), при помощи инструмента <em>pip</em>. Это лучший способ получения последней стабильной версии Django.</li>
+ <li>Использование версии из менеджера пакетов вашего компьютера. Такие дистрибутивы Django, собранные для конкретных операционных систем, предлагают знакомый механизм установки. Однако обратите внимание на то, что пакетные версии могут быть достаточно старыми и установлены только в системную среду Python (что может отличаться от ваших желаний).</li>
+ <li>Установка из исходного кода. Вы можете получить и установить последний выпуск Django из исходного кода. Этот способ не рекомендован для новичков, но необходим в случае, когда вы готовы начать вносить собственный вклад в проект Django.</li>
+</ul>
+
+<p>Данный материал описывает способ установки Django из PyPi с целью получения последней стабильной версии.</p>
+
+<h4 id="Какую_базу_данных_выбрать">Какую базу данных выбрать?</h4>
+
+<p>Django поддерживает 4 основных базы данных (PostgreSQL, MySQL, Oracle и SQLite), также есть публичные библиотеки, которые предоставляют разные уровни поддержки других SQL и NoSQL баз данных. Мы рекомендуем вам выбрать одинаковую БД для обеих рабочей и разрабатываемой сред (несмотря на  то, что Django нивелирует множество различий баз данных при помощи Object-Relational Mapper (ORM), все равно возможны потенциальные <a href="https://docs.djangoproject.com/en/2.0/ref/databases/">проблемы</a>, которых лучше избегать.</p>
+
+<p>Для данной статьи (и большей части модуля) мы будем использовать базу данных <em>SQLite</em>, которая сохраняет свои данные в файл. SQLite предназначен для использования в качестве облегченной базы данных и не может поддерживать высокий уровень параллелизма. Это, однако, отличный выбор для приложений, которые в основном предназначены только для чтения.</p>
+
+<div class="note">
+<p><strong>Замечание</strong>: Django сконфигурирован для использования SQLite по умолчанию, при создании вашего проекта с использованием стандартных инструментов (django-admin). Это отличный выбор для начала работы, потому что он не требует дополнительной настройки.</p>
+</div>
+
+<h4 id="Глобальная_установка_или_установка_в_виртуальную_среду_Python">Глобальная установка или установка в виртуальную среду Python?</h4>
+
+<p>Когда вы устанавливаете Python 3 на свой компьютер, вы получаете единую глобальную среду (набор установленных пакетов) для вашего кода Python, которая доступна любому коду на компьютере. Вы можете установить любые пакеты Python, необходимые вам в этой среде, но только одну конкретную версию конкретного пакета.</p>
+
+<div class="note">
+<p><strong>Замечание</strong>: Установленные в глобальную среду приложения Python потенциально могут конфликтовать друг с другом (т.е. если они зависят от разных версий одного и того же пакета).</p>
+</div>
+
+<p>Если вы устанавливаете Django в среду по умолчанию (глобальную), то будете способны сфокусироваться на одной версии Django на вашем компьютере. Это может быть проблемой в случае, если вы захотите создать новые вебсайты (при помощи новой версии Django) во время поддержки вебсайтов со старой версией.</p>
+
+<p>По этой причине опытные разработчики Python / Django часто предпочитают вместо этого запускать свои приложения Python в независимых <em>виртуальных средах Python</em>. Это позволяет разработчикам иметь несколько разных сред Django на одном компьютере. Команда разработчиков Django сама рекомендует использовать виртуальные среды Python!</p>
+
+<p>Этот модуль предполагает вашу установку Django в виртуальную среду, и мы покажем, как это сделать.</p>
+
+<h2 id="Установка_Python_3">Установка Python 3</h2>
+
+<p>Для использования Django вам необходимо установить <em>Python 3</em> на свою операционную систему. Вам также понадобится инструмент <a href="https://pypi.python.org/pypi">Python Package Index</a> — <em>pip3</em> — который используется для управления (установка, обновление и удаление) библиотек/пакетов Python, используемых Django и другими вашими приложениями Python.</p>
+
+<p>Этот раздел коротко описывает то, как вы можете проверить имеющиеся версии и при необходимости установить новые для Ubuntu Linux 16.04, Mac OS X, and Windows 10.</p>
+
+<div class="note">
+<p><strong>Замечание</strong>: В зависимости от платформы, вы можете иметь возможность установки Python/pip из собственного менеджера пакетов операционной системы или при помощи других инструментов. Для большинства платформ вы можете скачать необходимые установочные файлы из <a href="https://www.python.org/downloads/">https://www.python.org/downloads/</a> и установить их при помощи соответствующего специфичного для платформы метода.</p>
+</div>
+
+<h3 id="Ubuntu_16.04">Ubuntu 16.04</h3>
+
+<p>Ubuntu Linux включает в себя Python 3 по умолчанию. Вы можете удостовериться в этом, выполнив следующую команду в терминале:</p>
+
+<pre class="notranslate">python3 -V
+ Python 3.5.2</pre>
+
+<p>Однако, инструмент Python Package Index, при помощи которого вам нужно будет установаить пакеты для  Python 3 (включая Django), по умолчанию <strong>не установлен</strong>. Вы можете установить pip3 через терминал bash при помощи:</p>
+
+<pre class="notranslate">sudo apt-get install python3-pip
+</pre>
+
+<h3 id="Mac_OS_X">Mac OS X</h3>
+
+<p>Mac OS X "El Capitan" не включает Python 3. Вы можете удостовериться в этом, выполнив следующую команду в терминале:</p>
+
+<pre class="notranslate">python3 -V
+ -bash: python3: command not found</pre>
+
+<p>Вы можете легко установить Python 3 (вместе с инструментом <em>pip3</em>) с<a href="https://www.python.org/"> python.org</a>:</p>
+
+<ol>
+ <li>Скачайте нужный установочный файл:
+ <ol>
+ <li>Перейдите в <a href="https://www.python.org/downloads/">https://www.python.org/downloads/</a></li>
+ <li>Нажмите на кнопку <strong>Скачать Python 3.6.4</strong> (точная основная версия может отличаться).</li>
+ </ol>
+ </li>
+ <li>Найдите файл при помощи <em>Finder</em>, дважды кликните по нему и следуйте подсказкам по установке.</li>
+</ol>
+
+<p>Удостовериться в успешной установке вы можете проверкой на наличие  <em>Python 3</em>, как показано ниже:</p>
+
+<pre class="notranslate">python3 -V
+ Python 3.5.20
+</pre>
+
+<p>Подобным образом вы можете проверить установку <em>pip3</em>, отобразив список доступных пакетов:</p>
+
+<pre class="notranslate">pip3 list</pre>
+
+<h3 id="Windows_10">Windows 10</h3>
+
+<p>Windows не включает Python по умолчанию, но вы можете легко установить его (вместе с инструментом <em>pip</em>) с<a href="https://www.python.org/"> python.org</a>:</p>
+
+<ol>
+ <li>Скачайте нужный установочный файл:
+ <ol>
+ <li>Перейдите в <a href="https://www.python.org/downloads/">https://www.python.org/downloads/</a></li>
+ <li>Нажмите на кнопку <strong>Скачать Python 3.6.4</strong> (точная основная версия может отличаться).</li>
+ </ol>
+ </li>
+ <li>Установите Python, дважды кликнув на скачанный файл и следуя инструкциям по установке.</li>
+</ol>
+
+<p>После этого вы сможете подтвердить успешную установку Python путем выполнения следующего текста в командной строке:</p>
+
+<pre class="notranslate">py -3 -V
+ Python 3.5.2
+</pre>
+
+<p>Установщик Windows включает в себя <em>pip3</em> (менеджер пакетов Python) по умолчанию. Вы можете отобразить список установленных пакетов, как показано далее:</p>
+
+<pre class="notranslate">pip list
+</pre>
+
+<div class="note">
+<p><strong>Замечание</strong>: Установщик должен сделать все, что необходимо для корректной работы указанной команды. Однако, если вы видите сообщение о том, что Python не может быть найден, вам может потребоваться добавить его в системный путь.</p>
+</div>
+
+<h2 id="Использование_Django_внутри_виртуальной_среды_Python">Использование Django внутри виртуальной среды Python</h2>
+
+<p>Для создания виртуальных сред мы будем использовать библиотеки <a href="https://virtualenvwrapper.readthedocs.io/en/latest/index.html">virtualenvwrapper</a> (Linux и macOS X) и <a href="https://pypi.python.org/pypi/virtualenvwrapper-win">virtualenvwrapper-win</a> (Windows), которые в свою очередь обе используют инструмент <a href="https://developer.mozilla.org/en-US/docs/Python/Virtualenv">virtualenv</a>. Инструмент обертки предоставляет совместимый интерфейс для управления интерфейсами на всех платформах.</p>
+
+<h3 id="Установка_ПО_виртуальной_среды">Установка ПО виртуальной среды</h3>
+
+<h4 id="Установка_виртуальной_среды_для_Ubuntu">Установка виртуальной среды для Ubuntu</h4>
+
+<p>После установки Python и pip вы можете установить <em>virtualenvwrapper </em>(который включает в себя <em>virtualenv</em>). Вы можете либо воспользоваться официальной инструкций по установке <a href="http://virtualenvwrapper.readthedocs.io/en/latest/install.html">отсюда</a>, либо следовать следующим инструкциям:</p>
+
+<p>Установите инструмент при помощи pip3:</p>
+
+<pre class="notranslate"><code>sudo pip3 install virtualenvwrapper</code>
+</pre>
+
+<p>Затем добавьте следующие строки в конец файла загрузки программной оболочки (shell) (это скрытый файл в вашей домашней директории с именем <strong>.bashrc</strong>). Они устанавливают расположение виртуальных сред, расположение каталога разрабатываемого проекта и расположение установленного с этим пакетом скрипта.</p>
+
+<pre class="notranslate"><code>export WORKON_HOME=$HOME/.virtualenvs
+export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
+export VIRTUALENVWRAPPER_VIRTUALENV_ARGS=' -p /usr/bin/python3 '
+export PROJECT_HOME=$HOME/Devel
+source /usr/local/bin/virtualenvwrapper.sh</code>
+</pre>
+
+<p>Затем перезагрузите файл загрузки, выполнив в терминале следующую команду:</p>
+
+<pre class="notranslate"><code>source ~/.bashrc</code>
+</pre>
+
+<p>В этот момент вы должны увидеть запуск группы скриптов, как показано ниже:</p>
+
+<pre class="notranslate"><code>virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/premkproject
+virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/postmkproject
+...
+virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/preactivate
+virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/postactivate
+virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/get_env_details</code>
+</pre>
+
+<p>Теперь вы можете создать новую виртуальную среду при помощи команды <code>mkvirtualenv</code>.</p>
+
+<h4 id="Установка_виртуальной_среды_для_macOS_X">Установка виртуальной среды для macOS X</h4>
+
+<p>Установка <em>virtualenvwrapper </em>на macOS X почти идентична Ubuntu (и снова вы можете воспользоваться либо <a href="http://virtualenvwrapper.readthedocs.io/en/latest/install.html">официальными</a>, либо следующими инструкциями).</p>
+
+<p>Установите инструмент при помощи pip3:</p>
+
+<pre class="notranslate"><code>sudo pip3 install virtualenvwrapper</code>
+</pre>
+
+<p>Затем добавьте следующие строки в конец вашего файла загрузки программной оболочки:</p>
+
+<pre class="notranslate"><code>export WORKON_HOME=$HOME/.virtualenvs
+export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
+export PROJECT_HOME=$HOME/Devel
+source /usr/local/bin/virtualenvwrapper.sh</code>
+</pre>
+
+<div class="note">
+<p><strong>Замечание</strong>: Переменная <code>VIRTUALENVWRAPPER_PYTHON</code> указывает на обычное расположение Python3. Если virtualenv не работает во время тестирования, то вам следует проверить, находится ли интерпертатор Python в нужном расположении (и затем поменять его соответствующим образом в значении переменной).</p>
+</div>
+
+<p>Эти строки такие же, как в случае с Ubuntu, но файл загрузки в вашей домашней директории назван иначе - <strong>.bash_profile</strong>. </p>
+
+<div class="note">
+<p><strong>Замечание</strong>: Если вы не можете найти и изменить <strong>.bash_profile </strong>при помощи Finder, то можно также открыть его при помощи редактора терминала <em>nano</em>.</p>
+
+<p>Команды в этом случае выглядят примерно так:</p>
+
+
+
+<pre class="notranslate"><code>cd ~ # Navigate to my home directory
+ls -la #List the content of the directory. You should see .bash_profile
+nano .bash_profile # Open the file in the nano text editor, within the terminal
+# Scroll to the end of the file, and copy in the lines above
+# Use Ctrl+X to exit nano, Choose Y to save the file.</code>
+</pre>
+</div>
+
+<p>После этого перезагрузите файл загрузки путем выполнения следующей команды в терминале:</p>
+
+<pre class="notranslate"><code>source ~/.bash_profile</code>
+</pre>
+
+<p>В этот момент вы должны увидеть запуск группы скриптов (те же скрипты, что и в случае установки на Ubuntu).</p>
+
+<p>Теперь вы должны иметь возможность создания новой виртуальной среды при помощи команды <code>mkvirtualenv</code>.</p>
+
+<h4 id="Установка_виртуальной_среды_для_Windows_10">Установка виртуальной среды для Windows 10</h4>
+
+<p>Установка <a href="https://pypi.python.org/pypi/virtualenvwrapper-win">virtualenvwrapper-win</a> еще более проста, чем установка <em>virtualenvwrapper</em>, потому что вам не нужно настраивать расположения сохранения информации о виртаульной среде инструментом (эти значения заданы по умолчанию). Все, что вам нужно сделать, это запустить следующую команду в командной строке:</p>
+
+<pre class="notranslate"><code>pip3 install virtualenvwrapper-win</code></pre>
+
+<p>Теперь вы можете создать новую виртуальную среду при помощи команды <code>mkvirtualen</code>.</p>
+
+<h3 id="Создание_виртуальной_среды">Создание виртуальной среды</h3>
+
+<p>После установки <em>virtualenvwrapper</em> и <em>virtualenvwrapper-win</em> работа с виртуальными средами становится одинаковой для всех платформ.</p>
+
+<p>Теперь вы можете создать новую виртуальную среду при помощи команды <code>mkvirtualenv</code>. Во время запуска команды вы увидите установку виртуальной среды (конкретные результаты команды очень зависят от платформы). После выполнения команды активируется новая виртуальная среда — заметить это вы можете по тому, что началом ввода будет название виртуальной среды в круглых скобках (как показано ниже).</p>
+
+<pre class="notranslate"><code>$ mkvirtualenv my_django_environment
+Running virtualenv with interpreter /usr/bin/python3 ...
+virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/t_env7/bin/get_env_details
+(my_django_environment) ubuntu@ubuntu:~$</code></pre>
+
+<p>Теперь вы находитесь внутри виртуальной области и можете установить Django и начать разработку.</p>
+
+<div class="note">
+<p><strong>Замечание</strong>: С этого момента в этой статье (и всем модуле) пожалуйста учитывайте, что любые команды запускаются в виртуальной среде Python, как та, что мы показали выше.</p>
+</div>
+
+<h3 id="Использование_виртуальной_среды">Использование виртуальной среды</h3>
+
+<p>Есть еще несколько полезных команд, которые вам следует знать (в документации по инструменту их гораздо больше, но эти вы будете использовать регулярно):</p>
+
+<ul>
+ <li><code>deactivate</code> — Выход из текущей виртуальной среды Python</li>
+ <li><code>workon</code> — Список доступных виртуальных сред</li>
+ <li><code>workon name_of_environment</code> — Активация конкретной виртуальной среды Python</li>
+ <li><code>rmvirtualenv name_of_environment</code> — Удаление конкретной виртуальной среды.</li>
+</ul>
+
+<h2 id="Установка_Django">Установка Django</h2>
+
+<p>После создания виртуальной среды и вызова <code>workon</code> для входа в нее вы можете использовать <em>pip3 </em>для установки Django. </p>
+
+<pre class="notranslate">pip3 install django
+</pre>
+
+<p>Вы можете проверить установку Django, выполнив следующую команду (она просто проверяет, что Python может найти модуль Django):</p>
+
+<pre class="notranslate"># Linux/Mac OS X
+python3 -m django --version
+ 1.10.10
+
+# Windows
+py -3 -m django --version
+ 1.10.10
+</pre>
+
+<div class="note">
+<p><strong>Замечание</strong>: Для Windows вы запускаете скрипты <em>Python 3</em> с префиксом команды <code>py -3</code>, в то время как для Linux/Mac OSX префикс - <code>python3</code>.</p>
+</div>
+
+<div class="warning">
+<p><strong>Важно</strong>: В оставшейся части материала<strong> </strong>используется вариант команды <em>Linux</em> для вызова Python 3 (<code>python3</code>) . Если вы работаете в <em>Windows, </em>то просто замените этот префикс на: <code>py -3</code></p>
+</div>
+
+<h2 id="Проверка_вашей_установки">Проверка вашей установки</h2>
+
+<p>Указанная выше проверка работает, но не представляет особого интереса.Более интересная проверка заключается в создании шаблона проекта и проверки его работы. Для ее выполнения перейдите в командной строке/терминале в место, где планируете сохранять приложения Django. Создайте папку для теста и перейдите в нее.</p>
+
+<pre class="notranslate">mkdir django_test
+cd django_test
+</pre>
+
+<p>Затем вы можете создать шаблон сайта "<em>mytestsite</em>" при помощи инструмента <strong>django-admin</strong>. После создания сайта вы можете перейти в папку, где найдете основной скрипт для управления проектами с именем <strong>manage.py</strong>.</p>
+
+<pre class="notranslate">django-admin startproject mytestsite
+cd mytestsite</pre>
+
+<p>Мы можем запустить веб-сервер разработки из этой папки при помощи <strong>manage.py</strong> и команды <code>runserver</code>, как показано ниже.</p>
+
+<pre class="notranslate">$ <strong>python3 manage.py runserver </strong>
+Performing system checks...
+
+System check identified no issues (0 silenced).
+
+You have 13 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
+Run 'python manage.py migrate' to apply them.
+
+September 19, 2016 - 23:31:14
+Django version 1.10.1, using settings 'mysite.settings'
+Starting development server at http://127.0.0.1:8000/
+Quit the server with CONTROL-C.
+</pre>
+
+<div class="note">
+<p><strong>Замечание</strong>: Указанная команда демонстрирует выполнение для Linux/Mac OS X. В настоящий момент вы можете проигнорировать предупреждения о  "13 непримененных миграциях"!</p>
+</div>
+
+<p>Как только сервер запущен, вы можете посмотреть сайт, перейдя по следующему адресу в вашем браузере: <code>http://127.0.0.1:8000/</code>. Вы должны увидеть, что сайт выглядит следующим образом:</p>
+
+<p><img alt="Django Skeleton App Homepage" src="https://mdn.mozillademos.org/files/15728/Django_Skeleton_Website_Homepage.png"></p>
+
+<ul>
+</ul>
+
+<h2 id="Заключение">Заключение</h2>
+
+<p>Теперь у вас на компьютере установлена и запущена среда разработки Django.</p>
+
+<p>В разделе проверки вам коротко был показан способ создания нового сайта на Django при помощи <code>django-admin startproject</code> и его запуск в вашем браузере при помощи веб-сервера разработки (<code><strong>python3 manage.py runserver</strong></code>). В следующей статье мы подробнее рассмотрим этот процесс создания простого, но полноценного веб-приложения.</p>
+
+<h2 id="В_этом_модуле">В этом модуле</h2>
+
+<ul>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Introduction">Введение в Django</a></li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/development_environment">Установка среды разработки Django</a></li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Руководство Django: Сайт локальной библиотеки</a></li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/skeleton_website">Руководство Django Часть 2: Создание основы веб-сайта</a></li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Models">Руководство Django Часть 3: Использование моделей</a></li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Admin_site">Руководство Django Часть 4: Панель администрирования Django</a></li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Home_page">Руководство Django Часть 5: Создание домашней страницы</a></li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Generic_views">Руководство Django Часть 6: Основной список и детали представлений</a></li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Sessions">Руководство Django Часть  7: Фреймворк сеансов</a></li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Authentication">Руководство Django Часть 8: Авторизация пользователей и уровни доступа</a></li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Forms">Руководство Django Часть 9: Работа с формами</a></li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Testing">Руководство Django Часть 10: Тестирование веб-приложений Django</a></li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Deployment">Руководство Django Часть 11: Разавертывание Django в производство</a></li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/web_application_security">Безопасность веб-приложения Django</a></li>
+ <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Мини-блог на Django</a></li>
+</ul>
diff --git a/files/ru/learn/server-side/django/django_assessment_blog/index.html b/files/ru/learn/server-side/django/django_assessment_blog/index.html
new file mode 100644
index 0000000000..59a1d9e1d2
--- /dev/null
+++ b/files/ru/learn/server-side/django/django_assessment_blog/index.html
@@ -0,0 +1,320 @@
+---
+title: 'Задание: DIY Джанго мини блог'
+slug: Learn/Server-side/Django/django_assessment_blog
+tags:
+ - Аттестация
+ - Бэкэнд
+ - Бэкэнд программирование
+ - Джанго
+ - Изучение
+ - Начинающий
+ - блог
+ - скриптовый кодинг
+translation_of: Learn/Server-side/Django/django_assessment_blog
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenu("Learn/Server-side/Django/web_application_security", "Learn/Server-side/Django")}}</div>
+
+<p class="summary">В этом задании вы будете оценивать знания Django, которые вы приобрели в <a href="/en-US/docs/Learn/Server-side/Django">Django Web Framework (Python)</a>, чтобы создать очень простой блог.</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Предпосылки:</th>
+ <td>Перед этим заданием, вы должны были проработать все статьи этого модуля.</td>
+ </tr>
+ <tr>
+ <th scope="row">Задача:</th>
+ <td>Проверить понимание основ Django, включая конфигурации URL, модели, представления, формы и шаблоны.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Краткое_описание_проекта">Краткое описание проекта</h2>
+
+<p>Страницы, которые должны отображаться, их URL-адреса и другие требования, перечислены ниже:</p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">Page</th>
+ <th scope="col">URL</th>
+ <th scope="col">Requirements</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Home page</td>
+ <td><code>/</code> and <code>/blog/</code></td>
+ <td>Страница индекса, описывающая сайт.</td>
+ </tr>
+ <tr>
+ <td>List of all blog posts</td>
+ <td><code>/blog/blogs/</code></td>
+ <td>
+ <p>Список всех сообщений блога:</p>
+
+ <ul>
+ <li>Доступно для всех пользователей из боковой панели.</li>
+ <li>Список отсортирован по дате публикации (от самого нового до самого старого).</li>
+ <li>Список разбит на группы по 5 статьям.</li>
+ <li>Элементы списка отображают название блога, дату публикации и автора.</li>
+ <li>Названия сообщений блога связаны с страницами подробных сведений о блоге.</li>
+ <li>Blogger (имена авторов) связаны с страницами подробных сведений о блоге.</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td>Blog author (blogger) detail page</td>
+ <td><code>/blog/blogger/<em>&lt;author-id&gt;</em></code></td>
+ <td>
+ <p>Информация для указанного автора (по id) и список постов:</p>
+
+ <ul>
+ <li>Доступен для всех пользователей по ссылкам на автора в сообщениях в блогах и т. Д.</li>
+ <li>Содержит некоторые биографические данные в blogger/author.</li>
+ <li>Список отсортирован по дате добавления (от новых к старым).</li>
+ <li>Не разбит на страницы.</li>
+ <li>Элементы списка отображают только имя сообщения в блоге и дату публикации.</li>
+ <li>Названия блога связаны со страницей блога.</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td>Blog post detail page</td>
+ <td><code>/blog/<em>&lt;blog-id&gt;</em></code></td>
+ <td>
+ <p>Сведения о блоге.</p>
+
+ <ul>
+ <li>Доступно для всех пользователей из списков блога.</li>
+ <li>Страница содержит сообщение в блоге: имя, автор, дата публикации и содержание.</li>
+ <li>Комментарии к сообщению в блоге должны отображаться внизу.</li>
+ <li>Комментарии должны быть отсортированы по порядку: от старых до самых последних.</li>
+ <li>Содержит ссылку для добавления комментариев на конец для зарегистрированных пользователей (см. Страницу формы комментариев)</li>
+ <li>В блогах и комментариях должен отображаться только обычный текст. Нет необходимости поддерживать какую-либо разметку HTML (например, ссылки, изображения, полужирный / курсив и т. Д.).</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td>List of all bloggers</td>
+ <td><code>/blog/bloggers/</code></td>
+ <td>
+ <p>Список блоггеров в системе:</p>
+
+ <ul>
+ <li>Доступный для всех пользователей с боковой панели сайта</li>
+ <li>Имя блогера связано с блогом автора страницы.</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td>Comment form page</td>
+ <td><code>/blog/<em>&lt;blog-id&gt;</em>/create</code></td>
+ <td>
+ <p>Создать комментарий для публикации в блоге:</p>
+
+ <ul>
+ <li>Доступно только зарегистрированным пользователям (только) из ссылки внизу страницы с подробными сведениями блога.</li>
+ <li>Отображает форму с описанием для ввода комментариев (дата публикации и блог недоступны для редактирования).</li>
+ <li>После того, как комментарий будет опубликован, страница будет перенаправлена ​​на связанную страницу блога.</li>
+ <li>Пользователи не могут редактировать или удалять свои сообщения.</li>
+ <li>Вышедшие пользователи будут перенаправлены на страницу входа в систему, чтобы добавить комментарии. После входа в систему они будут перенаправлены на страницу блога, которую они хотели бы прокомментировать.</li>
+ <li>Страницы комментариев должны содержать имя / ссылку на комментарий блога.</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td>User authentication pages</td>
+ <td><code>/accounts/<em>&lt;standard urls&gt;</em></code></td>
+ <td>
+ <p>Стандартные страницы аутентификации Django для входа, выхода и установки пароля:</p>
+
+ <ul>
+ <li>Вход / выход должен быть доступен через ссылки боковой панели.</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td>Admin site</td>
+ <td><code>/admin/<em>&lt;standard urls&gt;</em></code></td>
+ <td>
+ <p>Админ-сайт должен быть включен, чтобы разрешить создание / редактирование / удаление сообщений в блогах, авторов блога и комментариев блога (это механизм для создания блоггеров в блогах):</p>
+
+ <ul>
+ <li>В админ панеле должен отображаться список комментариев в строке (внизу каждого сообщения в блоге).</li>
+ <li>Имена комментариев в админке создаются усеканием описания комментария до 75 знаков</li>
+ <li>Другие типы записей могут использовать базовую регистрацию.</li>
+ </ul>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<p>Кроме того, вы должны написать некоторые базовые тесты для проверки:</p>
+
+<ul>
+ <li>Все поля модели имеют правильную метку и длину.</li>
+ <li>Все модели имеют ожидаемое имя объекта (например,<code> __str__()</code>выдает ожидаемое значение).</li>
+ <li>Модели имеют ожидаемый URL для отдельных записей в блогах и комментариях (например,<code>get_absolute_url()</code> возвращает ожидаемый URL-адрес).</li>
+ <li>Страница BlogListView (страница на всех блогах) доступна в ожидаемом месте (например, /blog/blogs)</li>
+ <li>Страница BlogListView (страница на всех блогах) доступна на ожидаемом именованном URL-адресе (например, 'blogs')</li>
+ <li>Страница BlogListView (страница на всех блогах) использует ожидаемый шаблон (например, по умолчанию)</li>
+ <li>BlogListView разбивает записи на 5 (по крайней мере, на первой странице)</li>
+</ul>
+
+<div class="note">
+<p><strong>Заметка</strong>: Конечно, есть много других тестов, которые вы можете запустить. Используйте на свое усмотрение, но мы ожидаем, что вы сделаете хотя бы тесты выше.</p>
+</div>
+
+<p>В следующем разделе показаны <a href="#Screenshots">скриншоты</a> сайта, который выполняет перечисленные выше требования.</p>
+
+<h2 id="Скриншоты">Скриншоты</h2>
+
+<p>Следующий скриншот - пример того, что должна выводить готовая программа.</p>
+
+<h3 id="Список_всех_сообщений_в_блоге">Список всех сообщений в блоге</h3>
+
+<p>Это отображает список всех сообщений в блоге (доступны из ссылки "All blogs" на боковой панели). Что нужно отметить:</p>
+
+<ul>
+ <li>На боковой панели также списки вошедшего в систему пользователя.</li>
+ <li>Индивидуальные блоги и блогеры доступны в виде ссылок на странице.</li>
+ <li>Разбивка включена (в группах по 5)</li>
+ <li>Показ от новых к старым.</li>
+</ul>
+
+<p><img alt="List of all blogs" src="https://mdn.mozillademos.org/files/14319/diyblog_allblogs.png" style="border-style: solid; border-width: 1px; display: block; height: 363px; margin: 0px auto; width: 986px;"></p>
+
+<h3 id="Список_всех_блоггеров">Список всех блоггеров</h3>
+
+<p> </p>
+
+<p>Это ссылки на всех блоггеров в "All bloggers" по ссылке, которая на боковой панели. В этом случае мы можем увидеть на боковой панели, что ни один пользователь не вошел в систему.</p>
+
+<p><img alt="List of all bloggers" src="https://mdn.mozillademos.org/files/14321/diyblog_blog_allbloggers.png" style="border-style: solid; border-width: 1px; display: block; height: 256px; margin: 0px auto; width: 493px;"></p>
+
+<h3 id="Подробная_страница_блога">Подробная страница блога</h3>
+
+<p>Это показывает подробную страницу для конкретного блога.</p>
+
+<p><img alt="Blog detail with add comment link" src="https://mdn.mozillademos.org/files/14323/diyblog_blog_detail_add_comment.png" style="border-style: solid; border-width: 1px; display: block; height: 640px; margin: 0px auto; width: 986px;"></p>
+
+<p>Обратите внимание, что комментарии имеют дату <em>и</em> время, и расположены в порядке от самых старых до новейших (противоположно порядку ведения блога). В конце у нас есть ссылка для доступа к форме, чтобы добавить новый комментарий. Если пользователь не вошел в систему, мы бы увидели предложение войти в систему.</p>
+
+<p><img alt="Comment link when not logged in" src="https://mdn.mozillademos.org/files/14325/diyblog_blog_detail_not_logged_in.png" style="border-style: solid; border-width: 1px; display: block; height: 129px; margin: 0px auto; width: 646px;"></p>
+
+<h3 id="Добавить_форму_комментария">Добавить форму комментария</h3>
+
+<p>Это форма добавления комментариев. Обратите внимание, что мы вошли в систему. Когда это удастся, мы должны вернуться к связанной странице блога.</p>
+
+<p><img alt="Add comment form" src="https://mdn.mozillademos.org/files/14329/diyblog_comment_form.png" style="border-style: solid; border-width: 1px; display: block; height: 385px; margin: 0px auto; width: 778px;"></p>
+
+<h3 id="Об_авторе">Об авторе</h3>
+
+<p>Здесь отображается информация о блоггере вместе со списком его блогов.</p>
+
+<p><img alt="Blogger detail page" src="https://mdn.mozillademos.org/files/14327/diyblog_blogger_detail.png" style="border-style: solid; border-width: 1px; display: block; height: 379px; margin: 0px auto; width: 982px;"></p>
+
+<h2 id="Завершающие_шаги">Завершающие шаги</h2>
+
+<p>В следующих разделах описывается, что вам нужно делать.</p>
+
+<ol>
+ <li>Создайте скелет проекта и веб-приложение для сайта (как описано в  <a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a>). Вы можете использовать «diyblog» для имени проекта и «blog» для имени приложения.</li>
+ <li>Создавайте модели для записей в блогах, комментариев и любых других необходимых объектов.
+ <ul>
+ <li>Каждый комментарий будет иметь только один блог, но блог может иметь много комментариев.</li>
+ <li>Посты в блоге и комментарии должны быть отсортированы по дате поста.</li>
+ <li>Не каждый пользователь обязательно будет автором блога, хотя любой пользователь может быть комментатором.</li>
+ <li>Блог автора также должен включать информацию о себе.</li>
+ </ul>
+ </li>
+ <li>Запустите миграцию для новых моделей и создайте суперпользователя.</li>
+ <li>Используйте админ панель, чтобы создать какой-нибудь пример блога и комментарии в блогах.</li>
+ <li>Создайте представления, шаблоны, и URL-конфигурации для публикации блога и списка страниц блоггера.</li>
+ <li>Создайте представления, шаблоны, и URL-конфигурации для публикации блога и подробных страниц блоггера.</li>
+ <li>Создайте страницу с формой для добавления новых комментариев (не забудьте сделать это доступным только для зарегистрированных пользователей!)</li>
+</ol>
+
+<h2 id="Советы_и_подсказки">Советы и подсказки</h2>
+
+<p>Этот проект очень похож на  <a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> учебник. Вы сможете настроить скелет, поведение входа пользователя / выхода из системы, поддержку статических файлов, представлений, URL-адресов, форм, базовых шаблонов и конфигурации админ-панели, используя почти все те же подходы.</p>
+
+<p>Некоторые общие рекомендации:</p>
+
+<ol>
+ <li>Индексная страница (index page) может быть реализована в качестве основной функции представления и шаблона (как и для locallibrary).</li>
+ <li>Просмотр списка публикаций блога и блогеров, а также подробное представление для сообщений в блоге можно создать с помощью  <a href="/en-US/docs/Learn/Server-side/Django/Generic_views">generic list and detail views</a>.</li>
+ <li>Список постов в блоге конкретного автора может быть создан с помощью общего списка Blog list view и фильтрация для объекта блога, соответствующего указанному автору.
+ <ul>
+ <li>Вам придется реализовать  <code>get_queryset(self)</code> для фильтрации (как и в нашем классе библиотеки <code>LoanedBooksAllListView</code>) и получить информацию об авторе из URL-адреса.</li>
+ <li>Вам также необходимо передать имя автора на страницу в контексте. Чтобы сделать это в представлении на основе классов, вам необходимо реализовать  <code>get_context_data()</code> (обсуждается ниже).</li>
+ </ul>
+ </li>
+ <li>Форма <em>добавления комментариев</em> может быть создана с использованием функционального представления (и связанной модели и формы) или с использованием общего <code>CreateView</code>. Если вы используете <code>CreateView</code> (рекомендуется):
+ <ul>
+ <li>Вам также нужно будет передать имя блога на страницу комментариев в контексте (реализовать  <code>get_context_data()</code> как обсуждается ниже).</li>
+ <li>Форма должна отображать только комментарий «описание» для записи пользователя (дата и связанная с ними запись в блоге не должны редактироваться). Поскольку они не будут в форме, ваш код должен будет установить автора комментария в <code> form_valid()</code> функцию, поэтому он может быть сохранен в модели (<a href="https://docs.djangoproject.com/en/2.0/topics/class-based-views/generic-editing/#models-and-request-user">as described here</a> — Django docs). В этой же функции мы устанавливаем связанный блог. Возможная реализация показана ниже (<code>pk</code> это идентификатор блога, переданный из URL / URL конфигурации ).
+ <pre class="brush: python"> def form_valid(self, form):
+ """
+ Add author and associated blog to form data before setting it as valid (so it is saved to model)
+ """
+ #Add logged-in user as author of comment
+ form.instance.author = self.request.user
+ #Associate comment with blog based on passed id
+ form.instance.blog=get_object_or_404(Blog, pk = self.kwargs['pk'])
+ # Call super-class form validation behaviour
+ return super(BlogCommentCreate, self).form_valid(form)
+</pre>
+ </li>
+ <li> Для успешного перенаправления после проверки формы вам нужно будет указать URL-адрес;  это должен быть оригинальный блог. Для этого вам нужно будет переопределить  <code>get_success_url()</code> и «обратный» URL-адрес для исходного блога. Вы можете получить требуемый ID блога, используя <code>self.kwargs</code> атрибут, как показано в методе <code>form_valid()</code> выше.</li>
+ </ul>
+ </li>
+</ol>
+
+<p>Мы кратко говорили о передаче контекста шаблону в представлении на основе классов в теме  <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Generic_views#Overriding_methods_in_class-based_views">Django Tutorial Part 6: Generic list and detail views</a>. Для этого вам нужно переопределить <code>get_context_data()</code> (сначала получить существующий контекст, обновить его любыми дополнительными переменными, которые вы хотите передать шаблону, а затем вернуть обновленный контекст). Например, фрагмент кода ниже показывает, как вы можете добавить объект blogger в контекст на основе его <code>BlogAuthor</code> id.</p>
+
+<pre class="brush: python">class SomeView(generic.ListView):
+ ...
+
+ def get_context_data(self, **kwargs):
+        # Call the base implementation first to get a context
+        context = super(SomeView, self).get_context_data(**kwargs)
+        # Get the blogger object from the "pk" URL parameter and add it to the context
+        context['blogger'] = get_object_or_404(BlogAuthor, pk = self.kwargs['pk'])
+        return context
+</pre>
+
+<h2 id="Аттестация">Аттестация</h2>
+
+<p>Оценка этого задания <a href="https://github.com/mdn/django-diy-blog/blob/master/MarkingGuide.md">доступна здесь на Github</a>. Эта оценка в основном основана на том, насколько хорошо ваше приложение соответствует требованиям, перечисленным выше, хотя есть некоторые части оценки, которые проверяют ваш код на использование соответствующих моделей и что вы написали хотя бы некоторый тестовый код. Когда вы закончите, вы можете проверить по нашему <a href="https://github.com/mdn/django-diy-blog">готовому примеру</a> который соответствует "высокой оценке проекта".</p>
+
+<p>После того, как вы завершили этот модуль, вы также закончили весь контент MDN для изучения базового веб-сайта на сервере Django! Надеемся, вам понравится этот модуль и вы почувствуете, что у вас есть хорошее понимание основ!</p>
+
+<p>{{PreviousMenu("Learn/Server-side/Django/web_application_security", "Learn/Server-side/Django")}}</p>
+
+<p> </p>
+
+<h2 id="В_этом_модуле">В этом модуле</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li>
+</ul>
+
+<p> </p>
diff --git a/files/ru/learn/server-side/django/forms/index.html b/files/ru/learn/server-side/django/forms/index.html
new file mode 100644
index 0000000000..3b155495a9
--- /dev/null
+++ b/files/ru/learn/server-side/django/forms/index.html
@@ -0,0 +1,650 @@
+---
+title: 'Руководство часть 9: Работа с формами'
+slug: Learn/Server-side/Django/Forms
+tags:
+ - HTML
+ - django
+ - Для начинающих
+ - Руководство
+ - Серверная сторона
+ - Формы
+ - Формы Django
+translation_of: Learn/Server-side/Django/Forms
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Django/authentication_and_sessions", "Learn/Server-side/Django/Testing", "Learn/Server-side/Django")}}</div>
+
+<p class="summary">На этом уроке мы покажем вам процесс работы с HTML-формами в Django. В частности, продемонстрируем самый простой способ построения формы для создания, обновления и удаления экземпляров модели. При этом мы расширим сайт  <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">местной библиотеки</a>, чтобы библиотекари могли обновлять книги, создавать, обновлять и удалять авторов, используя наши собственные формы (а не возможности приложения администратора).</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Необходимые условия:</th>
+ <td>Завершите все предыдущие учебные темы, в том числе <a href="/en-US/docs/Learn/Server-side/Django/authentication_and_sessions">Django руководство часть 8: Аутентификация пользователя и права доступа</a>.</td>
+ </tr>
+ <tr>
+ <th scope="row">Цель:</th>
+ <td>Научиться понимать, как создавать формы, чтобы получать информацию от пользователей и обновлять базу данных. Узнать, как обобщенные классы отображения форм могут значительно упростить процесс создания форм при работе с одной моделью.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Обзор">Обзор</h2>
+
+<p><a href="/en-US/docs/Web/Guide/HTML/Forms">HTML форма </a>- это группа из одного или нескольких полей/виджетов на веб-странице, которая используется для сбора информации от пользователей для последующей отправки на сервер. Формы являются гибким механизмом сбора пользовательских данных, поскольку имеют целый набор виджетов для ввода различных типов данных, как то: текстовые поля, флажки, переключатели, установщики дат и т. д. Формы являются относительно безопасным способом взаимодействия пользовательского клиента и сервера, поскольку они позволяют отправлять данные в POST-запросах, применяя защиту от <a href="https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D0%B6%D1%81%D0%B0%D0%B9%D1%82%D0%BE%D0%B2%D0%B0%D1%8F_%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D0%BB%D0%BA%D0%B0_%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%B0">Межсайтовой подделки запроса</a> (<em><span lang="en">Сross Site Request Forgery - CSRF</span></em>)</p>
+
+<p>Пока что мы не создавали каких-либо форм в этом учебнике, но мы встречались с ними в административной панели Django —  например, снимок экрана ниже показывает форму для редактирования одной из наших моделей книг (<a href="/en-US/docs/Learn/Server-side/Django/Models">Book</a>), состоящую из нескольких списков выбора и текстовых редакторов. </p>
+
+<p><img alt="Admin Site - Book Add" src="https://mdn.mozillademos.org/files/13979/admin_book_add.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p>
+
+<p>Работа с формами может быть достаточно сложной! Разработчикам надо описать форму на HTML, проверить ее валидность, а также, на стороне сервера, проверять введенные пользователем данные (а возможно и на стороне клиента), далее, в случае возникновения ошибок необходимо опять показать пользователю форму и, при этом, указать на то, что пошло не так, в случае же успеха проделать с данными необходимые операции и каким-то образом проинформировать об этом пользователя. Django, при работе с формами, берет большую часть, описанной выше работы, на себя. Он предоставляет фреймворк, который позволяет вам определять форму и ее поля программно, а затем использовать эти объекты и для генерации непосредственно кода HTML-формы, и для контроля за процессом валидации и других пользовательский взаимодействий с формой.</p>
+
+<p>В данной части руководства мы покажем вам несколько способов создания и работы с формами и, в частности, как применение обобщенных классов работы с формой могут значительно уменьшить необходимый объем работы. Кроме того, мы расширим возможности нашего сайта <em>LocalLibrary,</em> путем добавления функционала для библиотекарей, который будет позволять им обновлять информацию - добавим страницы для создания, редактирования, удаления книг и авторов (воспроизведем и расширим стандартные возможности административной части сайта).</p>
+
+<h2 id="Формы_HTML">Формы HTML</h2>
+
+<p>Начнем мы с краткого обзора <a href="/en-US/docs/Web/Guide/HTML/Forms">Форм HTML</a>. Рассмотрим простую форму HTML, имеющую поле для ввода имени некоторой "команды" ("team"), и, связанную с данным полем, текстовой меткой:</p>
+
+<p><img alt="Simple name field example in HTML form" src="https://mdn.mozillademos.org/files/14117/form_example_name_field.png" style="border-style: solid; border-width: 1px; display: block; height: 44px; margin: 0px auto; width: 399px;"></p>
+
+<p>Форма описывается на языке HTML как набор элементов, расположенных внутри парных тэгов <code>&lt;form&gt;...&lt;/form&gt;</code>. Любая форма содержит как минимум одно поле-тэг <code>input</code> типа <code>type="submit"</code>.</p>
+
+<pre class="brush: html notranslate">&lt;form action="/team_name_url/" method="post"&gt;
+    &lt;label for="team_name"&gt;Enter name: &lt;/label&gt;
+    &lt;input id="team_name" type="text" name="name_field" value="Default name for team."&gt;
+    &lt;input type="submit" value="OK"&gt;
+&lt;/form&gt;</pre>
+
+<p>Здесь у нас только одно поле для ввода имени команды, но форма <em>может</em> иметь любое количество элементов ввода и, связанных с ними, текстовых меток. Атрибут элемента <code>type</code> определяет какого типа виджет будет показан в данной строке. Атрибуты <code>name</code> и  <code>id</code> используются для однозначной идентификации данного поля в JavaScript/CSS/HTML, в то время как <code>value</code> содержит значение для поля (когда оно показывается в первый раз). Текстовая метка добавляется при помощи тэга <code style="font-style: normal; font-weight: normal;">label</code> (смотрите "Enter name", в предыдущем фрагменте) и имеет атрибут <code style="font-style: normal; font-weight: normal;">for</code> со значением идентификатора <code style="font-style: normal; font-weight: normal;">id</code>, того поля, с которым данная текстовая метка связана.</p>
+
+<p>Элемент <code>input</code>  с  <code>type="submit"</code> будет показана как кнопка (по умолчанию), нажав на которую, пользователь отправляет введенные им данные на сервер (в данном случае только значение поля с идентификатором <code>team_name</code>). Атрибуты формы определяют каким методом будут отправлены данные на сервер (атрибут <code>method</code>) и куда  (атрибут <code>action</code>):</p>
+
+<ul>
+ <li><code>action</code>: Это ресурс/URL-адрес куда будут отправлены данные для обработки. Если значение не установлено (то есть, значением поля является пустая строка), тогда данные будут отправлены в отображение (функцию, или класс), которое сформировало текущую страницу.</li>
+ <li><code>method</code>: HTTP-метод, используемый для отправки данных: <em>post</em>, или <em>get</em>.
+ <ul>
+ <li>Метод <code>POST</code> должен всегда использоваться если отправка данных приведет к внесению изменений в базе данных на сервере. Применение данного метода должно повысить уровень защиты от CSRF.</li>
+ <li>Метод <code>GET</code> должен применяться только для форм, действия с которыми не приводят к изменению базы данных (например для поисковых запросов). Кроме того, данный метод рекомендуется применять для создания внешних ссылок на ресурсы сайта.</li>
+ </ul>
+ </li>
+</ul>
+
+<p>Ролью сервера в первую очередь является отрисовка начального состояния формы — либо содержащей пустые поля, либо с установленными начальными значениями. После того как пользователь нажмет на кнопку,  сервер получит все данные формы, а затем должен провести их валидацию. В том случае, если форма содержит неверные данные, сервер должен снова отрисовать форму, показав при этом поля с правильными данными, а также сообщения, описывающие "что именно пошло не так". В тот момент, когда сервер получит запрос с "правильными" данными он должен выполнить все необходимые действия (например, сохранение данных, возврат результата поиска, загрузка файла и тому подобное), а затем, в случае необходимости, проинформировать пользователя.</p>
+
+<p>Как вы видите, создание HTML-формы, валидация и возврат данных, переотрисовка введенных значений, при необходимости, а также выполнение желаемых действий с "правильными данными", в целом, может потребовать довольно больших усилий для того, чтобы все "заработало". Django делает этот процесс намного проще, беря на себя некоторые "тяжелые" и повторяющиеся участки кода!</p>
+
+<h2 id="Процесс_управления_формой_в_Django_2"><a id="Процесс_управления_формой_в_Django" name="Процесс_управления_формой_в_Django">Процесс управления формой в Django</a></h2>
+
+<p>Управление формами в Django использует те же самые техники, которые мы изучали в предыдущих частях руководства (при показе информации из наших моделей): отображение получает запрос, выполняет необходимые действия, включающие в себя чтение данных из моделей, генерацию и возврат страницы HTML (из шаблона, в который передается <em>контекст,</em> содержащий данные, которые и будут показаны). Что делает данный процесс более сложным, так это то, что серверной части надо дополнительно обработать данные, предоставленные пользователем и, в случае возникновения ошибок, снова перерисовать страницу.</p>
+
+<p>Диаграмма, представленная ниже, демонстрирует процесс работы с формой в Django, начиная с запроса страницы, содержащей форму (выделено зеленым цветом).</p>
+
+<p><img alt="Updated form handling process doc." src="https://mdn.mozillademos.org/files/14205/Form%20Handling%20-%20Standard.png" style="display: block; height: 569px; margin: 0px auto; width: 800px;"></p>
+
+<p>В соответствии с данной диаграммой, главными моментами, которые берут на себя формы Django являются:</p>
+
+<ol>
+ <li>Показ формы по умолчанию при первом запросе со стороны пользователя.
+ <ul>
+ <li>Форма может содержать пустые поля (например, если вы создаете новую запись в базе данных), или они (поля) могут иметь начальные значения (например, если вы изменяете запись, или хотите заполнить ее каким-либо начальным значением).</li>
+ <li>Форма в данный момент является <em>несвязанной</em>, потому что она не ассоциируется с какими-либо введенными пользователем данными (хотя и может иметь начальные значения).</li>
+ </ul>
+ </li>
+ <li>Получение данных из формы (из HTML-формы) со стороны клиента и связывание их с формой (классом формы) на стороне сервера.
+ <ul>
+ <li>Связывание данных с формой означает, что данные, введенные пользователем, а также возможные ошибки, при переотрисовке в дальнейшем, будут относиться именно к данной форме, а не к какой-либо еще.</li>
+ </ul>
+ </li>
+ <li>Очистка и валидация данных.
+ <ul>
+ <li>Очистка данных  - это их проверка на наличие возможных значений, или вставок в поля ввода (то есть очистка - это удаление неправильных символов, которые потенциально могут использоваться для отправки вредоносного содержимого на сервер), с последующей конвертацией очищеных данных в подходящие типы данных Python.</li>
+ <li>Валидация проверяет, значения полей (например, правильность введенных дат, их диапазон и так далее)</li>
+ </ul>
+ </li>
+ <li>Если какие-либо данные являются неверными, то выполнение перерисовки формы, но на этот раз, с уже введенными пользователем данными и сообщениями об ошибках, описывающих возникшие проблемы.</li>
+ <li>Если все данные верны, то исполнение необходимых действий (например, сохранение данных, отправка писем, возврат результата поиска, загрузка файла и так далее)</li>
+ <li>Когда все действия были успешно завершены, то перенаправление пользователя на другую страницу.</li>
+</ol>
+
+<p>Django предоставляет несколько инстументов и приемов, которые помогают вам во время выполнения задач, описанных выше. Наиболее фундаметальным из них является класс <code>Form</code>, который упрощает генерацию HTML-формы и очистку/валидацию ее данных. В следующем разделе мы опишем процесс работы с формами при помощи практического примера по созданию страницы, которая позволит библиотекарям обновлять информацию о книгах.</p>
+
+<div class="note">
+<p><strong>Примечание:</strong> Понимание того, как используется класс <code>Form</code> поможет вам когда мы будем рассматривать классы фреймворка Django, для работы с формами более "высокого уровня".</p>
+</div>
+
+<h2 id="HTML-форма_обновления_книги._Класс_Form_и_функция_отображения">HTML-форма обновления книги. Класс Form и функция отображения</h2>
+
+<p>Данная глава будет посвещена процессу создания страницы, которая позволит библиотекарям обновлять информацию о книгах (в частности, вводить дату возврата книги). Для того, чтобы сделать это мы создадим форму, которая позволит пользователям вводить значение дат. Мы проинициализируем поле датой, равной 3 неделям, начиная с текущего дня, и, для того, чтобы библотекарь не имел возможность ввести "неправильную" дату, мы добавим валидацию введенных значений, которая будет проверять, чтобы введенная дата не относилась к прошлому, или к слишком далекому будущему. Когда будет получена "правильная" дата мы запишем ее значение в поле  <code>BookInstance.due_back</code>.</p>
+
+<p>Данный пример будет использовать отображение на основе функции, а также продемонстрирует работу с классом <code>Form</code>. Следующие разделы покажут изменения, которые вам надо сделать, чтобы продемонстрировать работу форм в проекте <em>LocalLibrary</em>.</p>
+
+<h3 id="Класс_Form">Класс Form</h3>
+
+<p>Класс <code>Form</code> является сердцем системы Django при работе с формами. Он определяет поля формы, их расположение, показ виджетов, текстовых меток, начальных значений, валидацию значений и сообщения об ошибках для "неправильных" полей (если таковые имеются). Данный класс, кроме того, предоставляет методы для отрисовки самого себя в шаблоне при помощи предопределенных форматов (таблицы, списки и так далее), или для получения значения любого элемента (позволяя выполнять более точную отрисовку).</p>
+
+<h4 id="Объявление_класса_формы_Form">Объявление класса формы Form</h4>
+
+<p>Синтаксис объявления для класса формы <code>Form</code> очень похож на объявление класса модели <code>Model</code>, он даже использует те же типы полей (и некоторые похожие параметры). Это существенный момент, поскольку в обоих случаях нам надо убедиться, что каждое поле управляет правильным типом данных, соответствует нужному диапазону (или другому критерию) и имеет необходимое описание для показа/документации.</p>
+
+<p>Для того, чтобы создать класс с функционалом базового класса <code>Form</code> мы должны импорировать библиотеку <code>forms</code>, наследовать наш класс от класса <code>Form</code>, а затем объявить поля формы. Таким образом, самый простой класс формы в нашем случае будет иметь вид, показанный ниже:</p>
+
+<pre class="brush: python notranslate">from django import forms
+
+class RenewBookForm(forms.Form):
+    renewal_date = forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).")
+</pre>
+
+<h4 id="Поля_формы">Поля формы</h4>
+
+<p>В  нашем случае мы имеем одно поле типа <code><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#datefield">DateField</a></code>, которое служит для ввода обновленной даты возврата книги, которое будет отрендерено в HTML с пустым значением и текстовой меткой "<em>Renewal date:</em>", а также текстовым описанием: "<em>Enter a date between now and 4 weeks (default 3 weeks).</em>" Так как никаких дополнительных опций мы не определяем, то поле будет "получать" даты в следующем формате <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#django.forms.DateField.input_formats">input_formats</a>: YYYY-MM-DD (2016-11-06), MM/DD/YYYY (02/26/2016), MM/DD/YY (10/25/16), а для отрисовки по умолчанию, будет использовать <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#widget">виджет</a>: <a href="https://docs.djangoproject.com/en/1.10/ref/forms/widgets/#django.forms.DateInput">DateInput</a>.</p>
+
+<p>Существует множество других типов полей для класса формы, которые по своему функционалу подобны соответствующим им эквивалентам типов полей для классов моделей: <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#booleanfield"><code>BooleanField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#charfield"><code>CharField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#choicefield"><code>ChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#typedchoicefield"><code>TypedChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#datefield"><code>DateField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#datetimefield"><code>DateTimeField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#decimalfield"><code>DecimalField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#durationfield"><code>DurationField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#emailfield"><code>EmailField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#filefield"><code>FileField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#filepathfield"><code>FilePathField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#floatfield"><code>FloatField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#imagefield"><code>ImageField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#integerfield"><code>IntegerField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#genericipaddressfield"><code>GenericIPAddressField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#multiplechoicefield"><code>MultipleChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#typedmultiplechoicefield"><code>TypedMultipleChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#nullbooleanfield"><code>NullBooleanField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#regexfield"><code>RegexField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#slugfield"><code>SlugField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#timefield"><code>TimeField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#urlfield"><code>URLField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#uuidfield"><code>UUIDField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#combofield"><code>ComboField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#multivaluefield"><code>MultiValueField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#splitdatetimefield"><code>SplitDateTimeField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#modelmultiplechoicefield"><code>ModelMultipleChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#modelchoicefield"><code>ModelChoiceField</code></a>​​​​.</p>
+
+<p>Общие аргументы для большинства полей перечислены ниже:</p>
+
+<ul>
+ <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#required">required</a>: Если <code>True</code>, то данное поле не может быть пустым, или иметь значение<code>None</code>. Данное значение установлено по умолчанию.</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#label">label</a>: Тектовая метка, используемая для рендеринга поля в HTML-код. Если <a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#label">label</a> не определена, то Django попытается создать ее значение при помощи имени поля, переводя первый символ в верхний регистр, а также заменяя символы подчеркивания пробелами (например, для переменной с именем renewal_date, будет создан следующий текст метки: <em>Renewal date</em>).</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#label-suffix">label_suffix</a>: По умолчанию показывает двоеточие после текста метки (например, Renewal date<strong>:</strong>). Данный параметр позволяет вам указать любой суффикс по вашему желанию.</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#initial">initial</a>: Начальное значение для поля при показе формы.</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#widget">widget</a>: Применяемый виджет для поля.</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#help-text">help_text</a> (как показано в примере выше): Дополнительный текст, который может быть показан на форме, для описания того, как использовать поле.</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#error-messages">error_messages</a>: Список сообщений об ошибках для данного поля. Вы можете переопределить его своими сообщениями, при необходимости.</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#validators">validators</a>: Список функций, которые будут вызваны для валидации, введенного в поле значения.</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#localize">localize</a>: Позволяет осуществить локализацию данных поля формы (например, формат ввода числовых значений, или дат).</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/#disabled">disabled</a>: Если установлено в <code>True</code>, то поле показывается, но его значение изменить нельзя. По умолчанию равно <code>False</code>.</li>
+</ul>
+
+<h4 id="Валидация">Валидация</h4>
+
+<p>Django предоставляет несколько мест где вы можете осуществить валидацию ваших данных. Простейшим способом проверки значения одиночного поля является переопределение метода<code>clean_<strong>&lt;fieldname&gt;</strong>()</code> (здесь, <code><strong>&lt;fieldname&gt;</strong></code> это имя поля, которое вы хотите проверить). Например, мы хотим проверить, что введенное значение <code>renewal_date</code> находится между текущей датой и  4 неделями в будущем. Для этого мы создаем метод <code>clean_<strong>renewal_date</strong>()</code>, как показано ниже:</p>
+
+<pre class="brush: python notranslate">from django import forms
+
+<strong>from django.core.exceptions import ValidationError
+from django.utils.translation import ugettext_lazy as _
+import datetime #for checking renewal date range.
+</strong>
+class RenewBookForm(forms.Form):
+    renewal_date = forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).")
+
+<strong>    def clean_renewal_date(self):
+        data = self.cleaned_data['renewal_date']
+
+        #Проверка того, что дата не выходит за "нижнюю" границу (не в прошлом).
+        if data &lt; datetime.date.today():
+            raise ValidationError(_('Invalid date - renewal in past'))
+
+        #Проверка того, то дата не выходит за "верхнюю" границу (+4 недели).
+        if data &gt; datetime.date.today() + datetime.timedelta(weeks=4):
+            raise ValidationError(_('Invalid date - renewal more than 4 weeks ahead'))
+
+        # Помните, что всегда надо возвращать "очищенные" данные.
+        return data</strong></pre>
+
+<p>Необходимо отметить два важных момента. Первый это то, что мы получаем наши данные при помощи словаря <code>self.cleaned_data['renewal_date']</code>, а затем в конце возвращаем полученное значение, для проведения необходимых проверок. Данный шаг позволяет нам, при помощи валидаторов, получить "очищенные", проверенные, а затем, приведенные к стандартным типам, данные (в нашем случае к типу Python <code>datetime.datetime</code>).</p>
+
+<p>Второй момент касается того случая, когда наше значение "выпадает за рамки" и мы "выкидываем" исключение <code>ValidationError</code>, в котором указываем текст, который мы хотим показать на форме, для случая когда были введены неправильные данные. Пример, показанный выше, оборачивает данный текст при помощи <a href="https://docs.djangoproject.com/en/1.10/topics/i18n/translation/">функции перевода Django</a> <code>ugettext_lazy()</code> (импортирумую через <code>_()</code>), которая может вам пригодиться, если вы планируете перевести ваш сайт в будущем.</p>
+
+<div class="note">
+<p><strong>Примечание:</strong> Существует множество других методов и примеров валидации различных форм, которые можно найти в <a href="https://docs.djangoproject.com/en/1.10/ref/forms/validation/">Формы и валидация поля</a> (Django docs). Например, в случае, если у вас имеется много полей, которые зависят один от другого, вы можете переопределить функцию <a href="https://docs.djangoproject.com/en/1.10/ref/forms/api/#django.forms.Form.clean">Form.clean()</a> и, при необходимости, "выкинуть" <code>ValidationError</code>.</p>
+</div>
+
+<p>В целом, это все, что нам понадобится для создания формы в данном примере!</p>
+
+<h4 id="Копирование_класса_формы">Копирование класса формы</h4>
+
+<p>Создайте и откройте файл <strong>locallibrary/catalog/forms.py</strong>, а затем скопируйте в него весь код, указанный в предыдущем фрагменте.</p>
+
+<h3 id="Конфигурация_URL-адресов">Конфигурация URL-адресов</h3>
+
+<p>Перед созданием отображения давайте добавим соответствующую конфигурацию URL-адреса для страницы обновления книг. Скопируйте следующий фрагмент в нижнюю часть файла<strong> locallibrary/catalog/urls.py</strong>.</p>
+
+<pre class="brush: python notranslate">urlpatterns += [
+ url(r'^book/(?P&lt;pk&gt;[-\w]+)/renew/$', views.renew_book_librarian, name='renew-book-librarian'),
+]</pre>
+
+<p>Данная конфигурация перенаправит запросы с адресов формата <strong>/catalog/book/<em>&lt;bookinstance id&gt;</em>/renew/</strong> в функции с именем <code>renew_book_librarian()</code> в <strong>views.py</strong>, туда же передаст идентификатор id записи <code>BookInstance</code> в качестве параметра с именем <code>pk</code>. Шаблон соответствует только если <strong>pk </strong>это правильно отформатированный <strong>uiid.</strong></p>
+
+<div class="note">
+<p><strong>Примечание</strong>: Вместо имени "pk" мы можем использовать любое другое, по нашему желанию, потому что мы имеем полный контроль над функцией отображения (которого у нас нет в случае использования встроенного обобщенного класса отображения, который ожидает параметр с определенным именем). Тем не менее имя <code>pk</code> является понятным сокращением от "primary key", поэтому мы его тут и используем!</p>
+</div>
+
+<h3 id="Отображение">Отображение</h3>
+
+<p>Как было отмечено в разделе <a href="#Процесс_управления_формой_в_Django">Процесс управление формой в Django</a>, отображение должно отрендерить форму по умолчанию, когда она вызывается в первый раз и, затем, перерендерить ее, в том случае, если возникли какие-либо ошибки при работе с ее полями. В случае же успеха, после обработки "правильных" данных отображение перенаправляет пользователя на новую (другую) страницу. Для того чтобы выполнить все эти действия, отображение должно знать вызвано ли оно в первый раз для отрисовки формы по умолчанию, а если это не так, то провести валидацию полученных данных.</p>
+
+<p>Для форм, которые используют <code>POST</code>-запрос при отправке информации на сервер, наиболее общей схемой проверки данного факта является следующая строка кода <code>if request.method == 'POST':</code>. <code>GET</code>-запросу, а также первому запросу формы, в таком случае соответствует блок <code>else</code>. Если вы хотите отправлять свои данные в виде <code>GET</code>-запроса, то в таком случае приемом проверки того факта, что данный запрос первый (или последующий), является получение значения какого-либо поля формы (например, если значение скрытого поля формы пустое, то данный вызов является первым).</p>
+
+<p>Процесс обновления книги приводит к изменению информации в базе данных, таким образом, в соответствии с нашими соглашениями, в таком случае мы должны применять запрос типа <code>POST</code>. Фрагмент кода, представленный ниже, показывает (наиболее общую) схему работы для таких запросов. </p>
+
+<pre class="brush: python notranslate">from django.shortcuts import get_object_or_404
+from django.http import HttpResponseRedirect
+from django.urls import reverse
+import datetime
+
+from .forms import RenewBookForm
+
+def renew_book_librarian(request, pk):
+    book_inst = get_object_or_404(BookInstance, pk=pk)
+
+    # Если данный запрос типа POST, тогда
+<strong>    if request.method == 'POST':</strong>
+
+        # Создаем экземпляр формы и заполняем данными из запроса (связывание, binding):
+        form = RenewBookForm(request.POST)
+
+        # Проверка валидности данных формы:
+        <strong>if form.is_valid():</strong>
+            # Обработка данных из form.cleaned_data
+ #(здесь мы просто присваиваем их полю due_back)
+            book_inst.due_back = form.cleaned_data['renewal_date']
+            book_inst.save()
+
+            # Переход по адресу 'all-borrowed':
+            return HttpResponseRedirect(reverse('all-borrowed') )
+
+    # Если это GET (или какой-либо еще), создать форму по умолчанию.
+<strong>    else:</strong>
+        proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3)
+        form = RenewBookForm(initial={'renewal_date': proposed_renewal_date,})
+
+    return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst':book_inst})</pre>
+
+<p>В первую очередь мы импортируем наш класс формы (<code>RenewBookForm</code>), а также другие необходимые объекты и методы:</p>
+
+<ul>
+ <li><code><a href="https://docs.djangoproject.com/en/1.10/topics/http/shortcuts/#get-object-or-404">get_object_or_404()</a></code>: Возвращает определенный объект из модели в зависимости от значения его первичного ключа, или выбрасывает исключение <code>Http404</code>, если данной записи не существует. </li>
+ <li><code><a href="https://docs.djangoproject.com/en/1.10/ref/request-response/#django.http.HttpResponseRedirect">HttpResponseRedirect</a></code>: Данный класс перенаправляет на другой адрес (HTTP код статуса 302). </li>
+ <li><code><a href="https://docs.djangoproject.com/en/1.10/ref/urlresolvers/#django.urls.reverse">reverse()</a></code>: Данная функция генерирует URL-адрес при помощи соответствующего имени URL конфигурации/преобразования и дополнительных аргументов. Это эквивалент Python тэгу <code>url</code>, которые мы использовали в наших шаблонах.</li>
+ <li><code><a href="https://docs.python.org/3/library/datetime.html">datetime</a></code>: Библиотека Python для работы с датами и временим. </li>
+</ul>
+
+<p>В отображении аргумент <code>pk</code> мы используем в функции<code>get_object_or_404()</code> для получения текущего объекта типа <code>BookInstance</code> (если его не существует, то функция, а следом и наше отображение прервут свое выполнение, а на странице пользователя отобразится сообщение об ошибке: "объект не найден"). Если запрос вызова отображения <em>не является</em> <code>POST</code>-запросом, то мы переходим к условному блоку <code>else</code>, в котором мы создаем форму по умолчанию и передаем ей начальное значения<code>initial</code> для поля <code>renewal_date</code> (выделено жирным ниже, - 3 недели, начиная с текущей даты). </p>
+
+<pre class="brush: python notranslate"> book_inst = get_object_or_404(BookInstance, pk=pk)
+
+    # Если это GET (или другой метод), тогда создаем форму по умолчанию
+    <strong>else:</strong>
+        proposed_renewal_date = datetime.date.today() + datetime.timedelta(<strong>weeks=3</strong>)
+        <strong>form = RenewBookForm(initial={'</strong>renewal_date<strong>': </strong>proposed_renewal_date<strong>,})</strong>
+
+    return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst':book_inst})</pre>
+
+<p>После создания формы мы вызываем функцию <code>render()</code>, чтобы создать HTML страницу; передаем ей в качестве параметров шаблон и контекст, который содержит объект формы. Кроме того, контекст содержит объект типа <code>BookInstance</code>, который мы будем использовать в шаблоне, для получения информации об обновляемой книге.</p>
+
+<p>Если все таки у нас <code>POST</code>-запрос, тогда мы создаем объект с  именем <code>form</code> и заполняем его данными, полученными из запроса. Данный процесс называется связыванием (или, биндингом, от англ. "binding") и позволяет нам провести валидацию данных. Далее осуществляется валидация формы, при этом проверяются все поля формы — для этого используются как код обобщенного класса, так и пользовательских функций, в частности нашей функции проверки введенных дат <code>clean_renewal_date()</code>. </p>
+
+<pre class="brush: python notranslate">    book_inst = get_object_or_404(BookInstance, pk=pk)
+
+    # Если данный запрос типа POST, тогда
+    if request.method == 'POST':
+
+        # Создаем экземпляр формы и заполняем данными из запроса (связывание, binding):
+<strong>        form = RenewBookForm(request.POST)</strong>
+
+        # Проверка валидности формы:
+        if form.is_valid():
+            # process the data in form.cleaned_data as required (here we just write it to the model due_back field)
+            book_inst.due_back = form.cleaned_data['renewal_date']
+            book_inst.save()
+
+            # redirect to a new URL:
+            return HttpResponseRedirect(reverse('all-borrowed') )
+
+    return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst':book_inst})</pre>
+
+<p>Если формы не прошла валидацию, то мы снова вызываем функцию <code>render()</code>, но на этот раз форма будет содержать сообщения об ошибках. </p>
+
+<p>Если форма прошла валидацию, тогда мы можем начать использовать данные, получая их из атрибута формы <code>form.cleaned_data</code>  (то есть, <code>data = form.cleaned_data['renewal_date']</code>). Здесь мы просто сохраняем данные в поле <code>due_back</code> , соответствующего объекта<code> BookInstance</code>.</p>
+
+<div class="warning">
+<p><strong>Важно</strong>: Хотя вы также можете получить доступ к данным формы непосредственно через запрос (например <code>request.POST['renewal_date'],</code> или <code>request.GET['renewal_date']</code> (в случае GET-запроса), это НЕ рекомендуется. Очищенные данные проверены на вредоносность и преобразованы в типы, совместимые с Python.</p>
+</div>
+
+<p>Последним шагом в части обработки формы представления является перенаправление на другую страницу, обычно страницу «Успех». В нашем случае мы используем объект класса <code>HttpResponseRedirect</code> и функцию <code>reverse()</code> для перехода к отображению с именем <code>'all-borrowed'</code> (это было домашним заданием в <a href="/en-US/docs/Learn/Server-side/Django/authentication_and_sessions#Challenge_yourself">Руководство часть 8: Аутентификация и разграничение доступа</a>). Если вы не создали данную страницу, то просто укажите переход на домашнюю страницу сайта по адресу '/').</p>
+
+<p>Все это необходимо для управления формой как таковой, но нам нужно как-то ограничить доступ к отображению (открыть доступ только библиотекарям). Мы могли бы создать новое разрешение (permission) в классе <code>BookInstance</code> ("<code>can_renew</code>"), но мы пойдем простым путем и воспользуемся функцией-декоратором <code>@permission_required</code>  вместе с нашим существующим разрешением<code>can_mark_returned</code>.</p>
+
+<p>Окончательный вид отображения показан ниже. Пожалуйста, скопируйте данный текст в нижнюю часть файла <strong>locallibrary/catalog/views.py</strong>.</p>
+
+<pre class="notranslate"><strong>from django.contrib.auth.decorators import permission_required</strong>
+
+from django.shortcuts import get_object_or_404
+from django.http import HttpResponseRedirect
+from django.urls import reverse
+import datetime
+
+from .forms import RenewBookForm
+
+<strong>@permission_required('catalog.<code>can_mark_returned</code>')</strong>
+def renew_book_librarian(request, pk):
+    """
+    View function for renewing a specific BookInstance by librarian
+    """
+    book_inst = get_object_or_404(BookInstance, pk=pk)
+
+    # If this is a POST request then process the Form data
+    if request.method == 'POST':
+
+        # Create a form instance and populate it with data from the request (binding):
+        form = RenewBookForm(request.POST)
+
+        # Check if the form is valid:
+        if form.is_valid():
+            # process the data in form.cleaned_data as required (here we just write it to the model due_back field)
+            book_inst.due_back = form.cleaned_data['renewal_date']
+            book_inst.save()
+
+            # redirect to a new URL:
+            return HttpResponseRedirect(reverse('all-borrowed') )
+
+    # If this is a GET (or any other method) create the default form.
+    else:
+        proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3)
+        form = RenewBookForm(initial={'renewal_date': proposed_renewal_date,})
+
+    return render(request, 'catalog/book_renew_librarian.html', {'form': form, 'bookinst':book_inst})
+</pre>
+
+<h3 id="Шаблон">Шаблон</h3>
+
+<p>Создайте шаблон, на который ссылается наше отображение (<strong>/catalog/templates/catalog/book_renew_librarian.html</strong>) и скопируйте в него код, указаный ниже:</p>
+
+<pre class="brush: html notranslate">{% extends "base_generic.html" %}
+{% block content %}
+
+ &lt;h1&gt;Renew: \{{bookinst.book.title}}&lt;/h1&gt;
+ &lt;p&gt;Borrower: \{{bookinst.borrower}}&lt;/p&gt;
+ &lt;p{% if bookinst.is_overdue %} class="text-danger"{% endif %}&gt;Due date: \{{bookinst.due_back}}&lt;/p&gt;
+
+<strong> &lt;form action="" method="post"&gt;
+ {% csrf_token %}
+ &lt;table&gt;
+ \{{ form }}
+  &lt;/table&gt;
+ &lt;input type="submit" value="Submit" /&gt;
+ &lt;/form&gt;</strong>
+
+{% endblock %}</pre>
+
+<p>Большая его часть вам знакома из предыдущих частей руководства. Мы расширяем базовый шаблон, а затем замещаем блок содержимого <code>content</code>. У нас имеется возможность ссылаться на переменную <code>\{{bookinst}}</code> (и ее поля) поскольку мы передали ее в объект контекста при вызове функции <code>render()</code>. Здесь мы используем данный объект для вывода заголовка книги, дат ее получения и возврата.</p>
+
+<p>Код формы относительно прост. В первую очередь мы объявляем тэг<code>form</code>, затем определяем куда будут отправлены данные (<code>action</code>) и каким способом (<code>method</code>, в данном случае "HTTP POST") — если обратитесь к обзору раздела <a href="#HTML_forms">Формы HTML</a> в верхней части данной страницы, то найдете там замечение, что пустое значние атрибута <code>action</code>, означает, что данные из формы будут переданы обратно по текущему URL-адресу данной страницы  (чего мы и хотим!). Внутри тэга формы мы объявляем кнопку <code>submit</code> при помощи которой мы можем отправить наши данные. Блок <code>{% csrf_token %}</code>, добавленный первой строкой внутри блока формы, является частью фреймворка Django и служит для борьбы с CSRF.</p>
+
+<div class="note">
+<p><strong>Примечание:</strong> Добавляйте <code>{% csrf_token %}</code> в каждый шаблон Django, в котором вы создаете форму для отправки данных методом <code>POST</code>. Это поможет уменьшить вероятность взлома вашего сайта злоумышленниками.</p>
+</div>
+
+<p>Все что осталось, это указать переменную <code>\{{form}}</code>, которую мы передали в шаблон в словаре контекста. Возможно это вас не удивит, но таким образом мы предоставим возможность форме отрендерить свои поля с их метками, виджетами и дополнительными текстами, и в результате мы получим следующее:</p>
+
+<pre class="brush: html notranslate">&lt;tr&gt;
+  &lt;th&gt;&lt;label for="id_renewal_date"&gt;Renewal date:&lt;/label&gt;&lt;/th&gt;
+  &lt;td&gt;
+  &lt;input id="id_renewal_date" name="renewal_date" type="text" value="2016-11-08" required /&gt;
+  &lt;br /&gt;
+  &lt;span class="helptext"&gt;Enter date between now and 4 weeks (default 3 weeks).&lt;/span&gt;
+  &lt;/td&gt;
+&lt;/tr&gt;
+</pre>
+
+<div class="note">
+<p><strong>Примечание:</strong> Возможно это не очевидно, поскольку наша форма содержит только одно поле, но по умолчанию каждое поле формы помещается в ее собственную строку таблицы (поэтому переменная <code>\{{form}}</code> находится внутри тэга <code>table </code>.​​​​​​ Тот же результат можно получить, если воспользоваться следующим вызовом <code>\{{ form.as_table }}</code>.</p>
+</div>
+
+<p>Если вы ввели неправильную дату, то на странице вы должны получить список сообщений об ошибках (показано жирным ниже).</p>
+
+<pre class="brush: html notranslate">&lt;tr&gt;
+  &lt;th&gt;&lt;label for="id_renewal_date"&gt;Renewal date:&lt;/label&gt;&lt;/th&gt;
+  &lt;td&gt;
+<strong>  &lt;ul class="errorlist"&gt;
+  &lt;li&gt;Invalid date - renewal in past&lt;/li&gt;
+  &lt;/ul&gt;</strong>
+  &lt;input id="id_renewal_date" name="renewal_date" type="text" value="2015-11-08" required /&gt;
+  &lt;br /&gt;
+  &lt;span class="helptext"&gt;Enter date between now and 4 weeks (default 3 weeks).&lt;/span&gt;
+ &lt;/td&gt;
+&lt;/tr&gt;</pre>
+
+<h4 id="Другие_варианты_применения_переменной_шаблона_form">Другие варианты применения переменной шаблона form</h4>
+
+<p>В простом случае применения <code>\{{form}}</code> как показано выше, каждое поле рендерится  в виде отдельной строки таблицы. Кроме того, вы можете отрендерить каждое поле как список элементов (<code>\{{form.as_ul}}</code> ), или как параграф (<code>\{{form.as_p}}</code>).</p>
+
+<p>Что еще больше вдохновляет, так это то, что вы можете полностью контролировать процесс рендеринга любой части формы, используя для этого дот-нотацию (точку). Например, мы можем получить доступ к следующим полям поля формы <code>renewal_date</code>:</p>
+
+<ul>
+ <li><code>\{{form.renewal_date}}:</code> само поле.</li>
+ <li><code>\{{form.renewal_date.errors}}</code>: Список ошибок.</li>
+ <li><code>\{{form.renewal_date.id_for_label}}</code>: Идентификатор текстовой метки.</li>
+ <li><code>\{{form.renewal_date.help_text}}</code>: Дополнительный текст.</li>
+ <li>и так далее!</li>
+</ul>
+
+<p>Примеры того как вручную отрендерить формы в шаблонах, а также пробежать циклом по шаблонным полям, смотрите <a href="https://docs.djangoproject.com/en/1.10/topics/forms/#rendering-fields-manually">Работы с формами &gt; Ручная работа с формами</a> (Django docs).</p>
+
+<h3 id="Тестирование_страницы">Тестирование страницы</h3>
+
+<p>Если вы выполнили задание в <a href="/en-US/docs/Learn/Server-side/Django/authentication_and_sessions#Challenge_yourself">Django руководство часть 8: Аутентификация и разрешение доступа</a>, то у вас должна быть страница со списком всех книг в наличии библиотеки и данный список (страница) должен быть доступен только ее сотрудникам. На данной странице в каждом пункте (для каждой книги) мы можем добавить ссылку на нашу новую страницу обновления книги.</p>
+
+<pre class="brush: html notranslate">{% if perms.catalog.can_mark_returned %}- &lt;a href="{% url 'renew-book-librarian' bookinst.id %}"&gt;Renew&lt;/a&gt; {% endif %}</pre>
+
+<div class="note">
+<p><strong>Примечание</strong>: Помните что, для того чтобы перейти на страницу обновления книги, ваш тестовый логин должен иметь разрешение доступа типа "<code>catalog.can_mark_returned</code>"(возможно надо воспользоваться вашим аккаунтом для суперпользователя).</p>
+</div>
+
+<p>Вы можете попробовать вручную создать URL-адрес для тестирования, например — <a href="http://127.0.0.1:8000/catalog/book/&lt;bookinstance id>/renew/">http://127.0.0.1:8000/catalog/book/<em>&lt;bookinstance_id&gt;</em>/renew/</a> (правильный идентификатор записи id для bookinstance можно получить, если перейти на страницу детальной информации книги и скопировать поле <code>id</code>).</p>
+
+<h3 id="Как_теперь_все_это_выглядит">Как теперь все это выглядит?</h3>
+
+<p>Если все получилось как надо, то форма по умолчанию должна выглядеть следующим образом:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14209/forms_example_renew_default.png" style="border-style: solid; border-width: 1px; display: block; height: 292px; margin: 0px auto; width: 680px;"></p>
+
+<p>А такой наша форма будет в случае ввода неправильной даты:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14211/forms_example_renew_invalid.png" style="border-style: solid; border-width: 1px; display: block; height: 290px; margin: 0px auto; width: 658px;"></p>
+
+<p>Список всех книг с ссылками на странцу обновления данных:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14207/forms_example_renew_allbooks.png" style="border-style: solid; border-width: 1px; display: block; height: 256px; margin: 0px auto; width: 613px;"></p>
+
+<h2 id="Класс_ModelForm">Класс ModelForm</h2>
+
+<p>Создание класса формы <code>Form</code> при помощи примера, описанного выше, является довольно гибким способом, позволяющим вам создавать формы любой структуры которую вы пожелаете, в связке с любой моделью, или моделями.</p>
+
+<p>Тем не менее, если вам просто нужна форма для отображения полей одиночной модели, тогда эта самая модель уже содержит большую часть информации, которая вам нужна для построения формы: сами поля, текстовые метки, дополнительный текст и так далее. И чтобы не воспроизводить информацию из модели для вашей формы, проще воспользоваться классом <a href="https://docs.djangoproject.com/en/1.10/topics/forms/modelforms/">ModelForm</a>, который помогает созадавать формы непосредственно из модели. Класс <code>ModelForm</code> может применяться в ваших отображениях точно таким же образом как и "классический" класс формы <code>Form</code>.</p>
+
+<p>Базовая реализация <code>ModelForm</code> содержит тоже поле как и ваш предыдущий класс формы  <code>RenewBookForm</code>, что и показано ниже. Все что вам необходимо сделать, - внутри вашего нового класса добавить класс <code>Meta</code> и связать его с моделью <code>model</code> (<code>BookInstance</code>), а затем перечислить поля модели в поле <code>fields</code> которые должны быть включены в форму (вы можете включить все поля при помощи <code>fields = '__all__'</code>, или можно вопользоваться полем <code>exclude</code> (вместо <code>fields</code>), чтобы определить поля модели, которые <em>не</em> нужно включать).</p>
+
+<pre class="brush: python notranslate">from django.forms import ModelForm
+from .models import BookInstance
+
+class RenewBookModelForm(ModelForm):
+<strong> class Meta:
+ model = BookInstance
+ fields = ['due_back',]</strong>
+</pre>
+
+<div class="note">
+<p><strong>Примечание</strong>: Это не выглядит сильно проще, чем просто использовать класс <code>Form</code> (и это действительно так, поскольку мы используем только одно поле). Тем не менее, если вы хотите иметь много полей, то такой способ построения формы может значительно уменьшить количество кода и ускорить разработку!</p>
+</div>
+
+<p>Оставшаяся часть информации касается объявления полей модели (то есть, текстовых меток, виджетов, текстов, сообщений об ошибках). Если они недостаточно "правильные", то тогда мы можем переопределить их в нашем классе <code>Meta</code> при помощи словаря, содержащего поле, которое надо изменить и его новое значение. Например, в нашей форме мы могли бы поменять текст метки для поля "<em>Renewal date</em>" (вместо того, чтобы оставить текст по умолчанию: <em>Due date</em>), а кроме того мы хотим написать другой вспомогательный текст. Класс <code>Meta</code>, представленный ниже, показывает вам, как переопределить данные поля. Кроме того, при необходимости, вы можете установить значения для виджетов <code>widgets</code> и сообщений об ошибках <code>error_messages</code>.</p>
+
+<pre class="brush: python notranslate">class Meta:
+ model = BookInstance
+ fields = ['due_back',]
+<strong> labels = { 'due_back': _('Renewal date'), }
+ help_texts = { 'due_back': _('Enter a date between now and 4 weeks (default 3).'), } </strong>
+</pre>
+
+<p>Чтобы добавить валидацию, вы можете использовать тот же способ как и для класса <code>Form</code> — вы определяете функцию с именем  <code>clean_<em>field_name</em>()</code> из которой выбрасываете исключение <code>ValidationError</code>, если это необходимо. Единственным отличием от нашей оригинальной формы будет являться то, что поле модели имеет имя <code>due_back</code>, а не "<code>renewal_date</code>".</p>
+
+<pre class="brush: python notranslate">from django.forms import ModelForm
+from .models import BookInstance
+
+class RenewBookModelForm(ModelForm):
+<strong>    def clean_due_back(self):
+       data = self.cleaned_data['due_back']
+
+  #Проверка того, что дата не в прошлом
+       if data &lt; datetime.date.today():
+           raise ValidationError(_('Invalid date - renewal in past'))
+
+       #Check date is in range librarian allowed to change (+4 weeks)
+       if data &gt; datetime.date.today() + datetime.timedelta(weeks=4):
+           raise ValidationError(_('Invalid date - renewal more than 4 weeks ahead'))
+
+       # Не забывайте всегда возвращать очищенные данные
+       return data
+</strong>
+ class Meta:
+ model = BookInstance
+ fields = ['due_back',]
+ labels = { 'due_back': _('Renewal date'), }
+ help_texts = { 'due_back': _('Enter a date between now and 4 weeks (default 3).'), }
+</pre>
+
+<p>Теперь класс <code>RenewBookModelForm</code> является функциональным эквивалентом нашему предыдущему классу <code>RenewBookForm</code>. Вы можете импортировать и использовать его в тех же местах, где и <code>RenewBookForm</code>.</p>
+
+<h2 id="Обобщенные_классы_отображения_для_редактирования">Обобщенные классы отображения для редактирования</h2>
+
+<p>Алгоритм управления формой, который мы использовали в нашей функции отображения, является примером достаточно общего подхода к работе с формой. Django старается абстрагировать и упростить бульшую часть данной работы, путем широкого применения <a href="https://docs.djangoproject.com/en/1.10/ref/class-based-views/generic-editing/">обобщенных классов отображений</a>, которые служат для создания, редактирования и удаления отображений на основе моделей. Они не только управляют поведением отображения, но, кроме того, они из вашей модели автоматически создают класс формы  (<code>ModelForm</code>).</p>
+
+<div class="note">
+<p><strong>Примечание: </strong>В дополнение к отображениям для реактирования, описываемых здесь, существует также класс <a href="https://docs.djangoproject.com/en/1.10/ref/class-based-views/generic-editing/#formview">FormView</a>, который по своему предназначению находится где-то между "простой" функцией отображения и другими обобщенными отображенями, то есть в каком-то смысле, в диапазоне: "гибкость" против "усилия при программировании". Применяя <code>FormView,</code> вы все еще нуждаетесь в создании класса <code>Form</code>, но вам не нужно реализовавыть весь "стандартный" функционал работы с формой. Вместо этого, вы должны просто реализовать функцию, которая будет вызвана в тот момент, когда станет понятно, что получаемые из формы данные, "правильные" (валидны).</p>
+</div>
+
+<p>В данном разделе мы собираемся  использовать обобщенные классы для редактирования, для того, чтобы создать страницы, который добавляют функционал создания, редактирования и удаления записей типа <code>Author</code> из нашей библиотеки — предоставляя базовый функционал некоторых частей административной части сайта (это может быть полезно для случаев, когда вам нужно создать административную часть сайта, которая, в отличие от стандартной, была бы более гибкой).</p>
+
+<h3 id="Отображения">Отображения</h3>
+
+<p>Откройте файл отображений (<strong>locallibrary/catalog/views.py</strong>) и добавьте следующий код в его нижнюю часть:</p>
+
+<pre class="brush: python notranslate">from django.views.generic.edit import CreateView, UpdateView, DeleteView
+from django.urls import reverse_lazy
+from .models import Author
+
+class AuthorCreate(CreateView):
+ model = Author
+ fields = '__all__'
+ initial={'date_of_death':'12/10/2016',}
+
+class AuthorUpdate(UpdateView):
+ model = Author
+ fields = ['first_name','last_name','date_of_birth','date_of_death']
+
+class AuthorDelete(DeleteView):
+ model = Author
+ success_url = reverse_lazy('authors')</pre>
+
+<p>Как вы видите, для создания отображений вам надо наследоваться от следующих классов<code>CreateView</code>, <code>UpdateView</code> и <code>DeleteView</code> (соответственно), а затем связать их с соответствующей моделью.</p>
+
+<p>Для случаев "создать" и "обновить" вам также понадобится определить поля для показа на форме (применяя тот же синтаксис, что и для <code>ModelForm</code>). В этом случае мы демонстриурем синтаксис и для показаза "всех" полей, и перечисление их по отдельности. Также вы можете указать начальные значения для каждого поля, применяя словарь пар <em>имя_поля</em>/<em>значение</em> (в целях демонстрации, в нашем примере мы явно указываем дату смерти — если хотите, то вы можете удалить это поле). По умолчанию отображения перенаправляют пользователя на страницу "успеха", показывая только что созданные/отредатированные данные (записи в модели). В нашем случае это, созданная в предыдущей части руководства, подробная информация об авторе. Вы можете указать альтернативное перенаправление при помощи параметра <code>success_url</code> (как в примере с классом <code>AuthorDelete</code>).</p>
+
+<p>Классу <code>AuthorDelete</code> не нужно показывать каких либо полей, таким образом их не нужно и декларировать. Тем не менее, вам нужно указать <code>success_url</code>, потому что, в данном случае, для Django не очевидно что делать после успешного выполнения операции удаления записи. Мы используем функцию <code><a href="https://docs.djangoproject.com/en/1.10/ref/urlresolvers/#reverse-lazy">reverse_lazy()</a></code> для перехода на страницу списка авторов после удаления одного из них — <code>reverse_lazy()</code> это более "ленивая" версия <code>reverse().</code></p>
+
+<h3 id="Шаблоны">Шаблоны</h3>
+
+<p>Отображения  "создать" и "обновить" используют  шаблоны с именем <em>model_name</em><strong>_form.html,</strong> по умолчанию: (вы можете поменять суффикс на что-нибудь другое, при помощи поля <code>template_name_suffix</code> в вашем отображении, например, <code>template_name_suffix = '_other_suffix'</code>)</p>
+
+<p>Создайте файл шаблона <strong>locallibrary/catalog/templates/catalog/author_form.html</strong>  и скопируйте в него следующий текст.</p>
+
+<pre class="brush: html notranslate">{% extends "base_generic.html" %}
+
+{% block content %}
+
+&lt;form action="" method="post"&gt;
+ {% csrf_token %}
+ &lt;table&gt;
+ \{{ form.as_table }}
+ &lt;/table&gt;
+ &lt;input type="submit" value="Submit" /&gt;
+
+&lt;/form&gt;
+{% endblock %}</pre>
+
+<p>Это напоминает наши предыдущие формы и рендер полей при помощи таблицы. Заметьте, что мы снова используем<code>{% csrf_token %}</code>.</p>
+
+<p>Отображения "удалить" ожидает "найти" шаблон с именем формата <em>model_name</em><strong>_confirm_delete.html</strong> (и снова, вы можете изменить суффикс при помощи поля отображения<code>template_name_suffix</code>). Создайте файл шаблона <strong>locallibrary/catalog/templates/catalog/author_confirm_delete</strong><strong>.html</strong> и скопируйте в него текст, указанный ниже.</p>
+
+<pre class="brush: html notranslate">{% extends "base_generic.html" %}
+
+{% block content %}
+
+&lt;h1&gt;Delete Author&lt;/h1&gt;
+
+&lt;p&gt;Are you sure you want to delete the author: \{{ author }}?&lt;/p&gt;
+
+&lt;form action="" method="POST"&gt;
+ {% csrf_token %}
+ &lt;input type="submit" value="Yes, delete." /&gt;
+&lt;/form&gt;
+
+{% endblock %}
+</pre>
+
+<h3 id="Настройки_URL-адресов">Настройки URL-адресов</h3>
+
+<p>Откройте файл конфигураций URL-адресов (<strong>locallibrary/catalog/urls.py</strong>) и добавьте в его нижнюю часть следующие настройки:</p>
+
+<pre class="brush: python notranslate">urlpatterns += [
+ url(r'^author/create/$', views.AuthorCreate.as_view(), name='author_create'),
+ url(r'^author/(?P&lt;pk&gt;\d+)/update/$', views.AuthorUpdate.as_view(), name='author_update'),
+ url(r'^author/(?P&lt;pk&gt;\d+)/delete/$', views.AuthorDelete.as_view(), name='author_delete'),
+]</pre>
+
+<p>Здесь нет ничего нового! Как вы видите отображения являются классами и следовательно должны вызываться через метод <code>.as_view()</code>. Паттерны URL-адресов для каждого случая должны быть вам понятны. Мы обязаны использовать <code>pk</code> как имя для "захваченного" значения первичного ключа, так как параметр именно с таким именем ожидается классами отображения.</p>
+
+<p>Страницы создания, обновления и удаления автора теперь готовы к тестированию (мы не будем создавать на них ссылки в отдельном меню, но вы, если хотите, можете их сделать).</p>
+
+<div class="note">
+<p><strong>Примечание</strong>: Наблюдательные пользователи могли заметить, что мы ничего не делаем, чтобы предотвратить несанкционированный доступ к страницам! Мы оставили это в качестве упражнения для вас (подсказка: вы можете использовать <code>PermissionRequiredMixin</code> и, либо создать новое разрешение, или воспользоваться нашим прежним <code>can_mark_returned</code>).</p>
+</div>
+
+<h3 id="Тестирование_страницы_2">Тестирование страницы</h3>
+
+<p>Залогиньтесь на сайте с аккаунтом, который позволит вам получить доступ к страницам редактирования данных (и записей) автора.</p>
+
+<p>Затем перейдите на страницу создания новой записи автора: <a href="http://127.0.0.1:8000/catalog/author/create/">http://127.0.0.1:8000/catalog/author/create/</a>, которая должна быть похожей на следующий скриншот.</p>
+
+<p><img alt="Form Example: Create Author" src="https://mdn.mozillademos.org/files/14223/forms_example_create_author.png" style="border-style: solid; border-width: 1px; display: block; height: 184px; margin: 0px auto; width: 645px;"></p>
+
+<p>Введите в поля значения и нажмите на кнопку <strong>Submit</strong>, чтобы сохранить новую запись об авторе. После этого, вы должны были перейти на страницу редактирования только что созданного автора, имеющий адрес, похожий на следующий <em>http://127.0.0.1:8000/catalog/author/10</em>.</p>
+
+<p>У вас есть возможность редактирования записей при помощи добавления<em> /update/</em> в конец адреса подробной информации (то есть, <em>http://127.0.0.1:8000/catalog/author/10/update/</em>) — мы не показываем скриншот, потому что он выглядит в точности также как  страница "создать"!</p>
+
+<p>И последнее, мы можем удалить страницу, добавляя строку <em>/delete/</em> в конец адреса подробной информации автора (то есть, <em>http://127.0.0.1:8000/catalog/author/10/delete/</em>). Django должен показать страницу, которая похожа на представленную ниже. Нажмите <strong>Yes, delete.</strong>, чтобы удалить запись и перейти на страницу со списком авторов.</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14221/forms_example_delete_author.png" style="border-style: solid; border-width: 1px; display: block; height: 194px; margin: 0px auto; width: 561px;"></p>
+
+<h2 id="Проверьте_себя">Проверьте себя</h2>
+
+<p>Создайте несколько форм создания, редактирования и удаления записей в модели <code>Book</code>. При желании, вы можете использовать теже структуры как и в случае с моделью <code>Authors</code>. Если ваш шаблон <strong>book_form.html</strong> является просто копией шаблона <strong>author_form.html</strong>, тогда новая страница "create book" будет выглядеть как на следующем скриншоте:</p>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/14225/forms_example_create_book.png" style="border-style: solid; border-width: 1px; display: block; height: 521px; margin: 0px auto; width: 595px;"></p>
+
+<ul>
+</ul>
+
+<h2 id="Итоги">Итоги</h2>
+
+<p>Создание и управление формами может быть достаточно сложным! Django делает этот процесс намного проще, предоставляя прикладные механизмы объявления, рендеринга и проверки форм. Более того, Django предоставляет обобщенные классы  редактирования форм, которые могут выполнять <em>практически любую</em> работу по созданию, редактированию и удалению записей, связанных с одиночной моделью.</p>
+
+<p>Существует много чего еще, что можно делать с формами (ознакомьтесь со списком ниже), но теперь вы должны понимать как добавлять базовые формы и создавать код управления формой на вашем сайте.  </p>
+
+<h2 id="Смотрите_также">Смотрите также</h2>
+
+<ul>
+ <li><a href="https://docs.djangoproject.com/en/1.10/topics/forms/">Работа с формами</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/intro/tutorial04/#write-a-simple-form">Создание вашего первого приложения, часть 4 &gt; Создание простой формы </a>(Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/api/">Forms API</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/fields/">Поля класса Form</a> (Django docs) </li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/ref/forms/validation/">Класс Form и валидация поля</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/topics/class-based-views/generic-editing/">Управление классом Form из классов отображений</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/topics/forms/modelforms/">Создание форм из моделей</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/ref/class-based-views/generic-editing/">Обобщенные отображения для редактирования</a> (Django docs)</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Django/authentication_and_sessions", "Learn/Server-side/Django/Testing", "Learn/Server-side/Django")}}</p>
diff --git a/files/ru/learn/server-side/django/generic_views/index.html b/files/ru/learn/server-side/django/generic_views/index.html
new file mode 100644
index 0000000000..7b1bf6f08c
--- /dev/null
+++ b/files/ru/learn/server-side/django/generic_views/index.html
@@ -0,0 +1,605 @@
+---
+title: 'Руководство часть 6: Отображение списков и детальной информации'
+slug: Learn/Server-side/Django/Generic_views
+tags:
+ - django
+ - Для начинающих
+ - Отображения django
+ - Руководство
+ - Шаблоны django
+translation_of: Learn/Server-side/Django/Generic_views
+---
+<div>{{LearnSidebar}}<br>
+{{PreviousMenuNext("Learn/Server-side/Django/Home_page", "Learn/Server-side/Django/Sessions", "Learn/Server-side/Django")}}</div>
+
+<p class="summary">Данная часть расширяет наш сайт <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a>, добавляя в него списки и страницы, путем предоставления подробной информации о книгах и авторах. В текущей части мы подробно изучим обобщенные базовые классы отображения и покажем как они могут существенно сократить количество кода, который вы должны были бы написать в обычной ситуации. Кроме того, мы более подробно рассмотрим управление и настройки URL-адресов, показывая как выполнить простое сопоставление какой-либо строки паттерну регулярного выражения.</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Требования:</th>
+ <td>Завершить все предыдущие части руководства, включая <a href="/en-US/docs/Learn/Server-side/Django/Home_page">Руководство Django Часть 5: Создание домашней страницы</a>.</td>
+ </tr>
+ <tr>
+ <th scope="row">Цель:</th>
+ <td>Понимать где и как применять обобщенные базовые классы отображения, и как применять паттерны URL-адресов для передачи информации в отображения.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Обзор">Обзор</h2>
+
+<p>В данном руководстве мы завершим первую версию сайта <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a>, с помощью добавления страницы перечисления и подробной информации о книгах и авторах (или, если быть более точными, мы покажем как вам реализовать соответствующие страницы для книг, а для авторов вы сможете сделать их самостоятельно!)</p>
+
+<p>Данный процесс похож на создание главной страницы сайта, который мы показывали в предыдущей части руководства. Нам все также надо создать URL-преобразования, отображения и шаблоны страниц. Основным отличием будет то, что для страниц подробной информации перед нами встанет дополнительная задача получения информации из паттерна URL-адреса и передачи ее отображению. Для этих страниц мы собираемся продемонстрировать совершенно другой тип отображения, основанный на применении  обобщеных классов отображения списка и детальной информации о записи. Это может существенно сократить количество кода, необходимого для отображения и сделает его (код) более простым для написания и поддержки.</p>
+
+<p>Завершающая часть данного руководства будет посвещена демонстрации постраничного показа ваших данных (pagination) при применении обобщенного класса отображения списка.</p>
+
+<h2 id="Страница_со_списком_книг">Страница со списком книг</h2>
+
+<p>Страница со списком книг показывает все книги в наличии и будет доступна по адресу: <code>catalog/books/</code>. Эта страница для каждой записи выводит заголовок и автора, при этом каждый заголовок является гиперссылкой на соответствующую страницу подробной информации о книге. Данная страница будет иметь ту же структуру и навигацию как и все остальные страницы сайта, таким образом мы сможем расширить базовый шаблон сайта (<strong>base_generic.html</strong>), который мы создали в предыдущей части руководства.</p>
+
+<h3 id="Преобразования_URL-адресов">Преобразования URL-адресов</h3>
+
+<p>Откройте файл <strong>/catalog/urls.py</strong> и скопируйте в него строки, выделенные жирным внизу. Практически также как и для главной страницы сайта, данная функция <code>url()</code> определяет регулярное выражение (<strong>r'^books/$'</strong>), связывающее URL-адрес с функцией отображения (<code>views.BookListView.as_view()</code> ), которая будет вызвана, если URL-адрес будет соответствовать паттерну РВ. Кроме того, определяется имя для данного сопоставления.</p>
+
+<pre class="brush: python">from django.urls import path
+from . import views
+<strong>from django.conf.urls import url</strong>
+
+urlpatterns = [
+    url(r'^$', views.index, name='index'),
+<strong>    url(r'^books/$', views.BookListView.as_view(), name='books'),
+</strong>]</pre>
+
+<p>Данный паттерн РВ сопоставления URL-адреса полностью соответствует строке <code>books/</code> (<code>^</code> является маркером начала строки, а <code>$</code>  - маркер конца строки). Как было отмечено в предыдущей части руководства, URL-адрес уже должен содержать <code>/catalog</code>, таким образом полный адрес, на самом деле, имеет вид : <code>/catalog/books/</code>.</p>
+
+<p>Функция отображения имеет другой формат, чем ранее — это связано с тем, что данное отображение реализуется через класс. Мы будем наследоваться от существующей общей функции из <strong>view</strong>, которая уже делает большую часть того, что мы хотим, что нам и нужно, вместо того, чтобы писать свою собственную функцию во <strong>view</strong> с нуля.</p>
+
+<p>При использовании обобщенных классов отображения в Django мы получаем доступ к соответствующей функции отображения при помощи вызова метода  <code>as_view()</code>. Таким образом выполняется вся работа по созданию экземпляра класса и гарантируется вызов правильных методов для входящих HTTP-запросов.</p>
+
+<h3 id="Отображение_(на_основе_базового_класса)">Отображение (на основе базового класса)</h3>
+
+<p>Мы могли бы достаточно просто реализовать отображение списка книг при помощи обычной функции (также, как мы сделали это для главной страницы сайта), которая должны была бы выполнить запрос получения всех книг из базы данных, затем вызвать  функцию  <code>render()</code>, в которую передать данный список, в соответствующий шаблон страницы. Тем не менее, вместо это мы будем использовать обобщенный класс отображения списка — класс, который наследуется от существующего отображения (ListView). Поскольку обобщенный класс уже реализует большую часть того, что нам нужно, и следуя лучшим практикам Django, мы сможем создать более эффективный список при помощи меньшего количества кода, меньшего количества повторений и гораздо лучшей поддержкой.</p>
+
+<p>Откройте <strong>catalog/views.py</strong> и скопируйте следующий код, в нижнюю часть данного файла:</p>
+
+<pre class="brush: python">from django.views import generic
+
+class BookListView(generic.ListView):
+ model = Book</pre>
+
+<p>Это всё! Обобщенное отображение выполнит запрос к базе данных, получит все записи заданной модели (<code>Book</code>), затем отрендерит (отрисует) соответствующий шаблон, расположенный в <strong>/locallibrary/catalog/templates/catalog/book_list.html</strong> (который мы создадим позже). Внутри данного шаблона вы можете получить доступ к списку книг при помощи переменной шаблона <code>object_list</code> ИЛИ <code>book_list</code> (если обобщить, то "<code><em>the_model_name</em>_list</code>").</p>
+
+<div class="note">
+<p><strong>Примечание</strong>: Этот, выглядящий странно, путь к файлу шаблона не является опечаткой — обобщенное отображение ищет файл шаблона <code>/<em>application_name</em>/<em>the_model_name</em>_list.html</code> (<code>catalog/book_list.html</code>, в данном случае) внутри директории приложения <code>/<em>application_name</em>/templates/</code> (у нас - <code>/catalog/templates/)</code>.</p>
+</div>
+
+<p>Вы можете использовать атрибуты для того, чтобы изменить поведение по умолчанию. Например, вы могли бы указать другой файл шаблона, например, если в вашем распоряжении имеется несколько отображений, которые используют одну и ту же модель, или вам позарез захотелось бы использовать другое имя переменной шаблона, если <code>book_list</code> не является интуитивно понятным. Возможно, наиболее полезным вариантом является изменение/отфильтрование результата запроса к базе данных — таким образом, вместо перечисления всех книг вы могли бы показывать 5 наиболее популярных.</p>
+
+<pre class="brush: python">class BookListView(generic.ListView):
+ model = Book
+ context_object_name = 'my_book_list' # ваше собственное имя переменной контекста в шаблоне
+ queryset = Book.objects.filter(title__icontains='war')[:5] # Получение 5 книг, содержащих слово 'war' в заголовке
+ template_name = 'books/my_arbitrary_template_name_list.html' # Определение имени вашего шаблона и его расположения</pre>
+
+<h4 id="Переопределение_методов_в_классах_отображения">Переопределение методов в классах отображения</h4>
+
+<p>Пока что вам не приходилось этого делать, но у вас имеется возможность переопределять некоторые методы класса отображения.</p>
+
+<p>Например, мы можем переопределить метод получения списка всех записей <code>get_queryset()</code>. Данный подход является более гибким, чем использование атрибута <code>queryset</code>, как мы сделали в предыдущем фрагменте кода (хотя, в данном случае и нет никакой разницы):</p>
+
+<pre class="brush: python">class BookListView(generic.ListView):
+ model = Book
+
+    def get_queryset(self):
+        return Book.objects.filter(title__icontains='war')[:5] # Получить 5 книг, содержащих 'war' в заголовке
+</pre>
+
+<p>Мы также могли бы переопределить метод <code>get_context_data()</code> для того, чтобы в контексте (в переменной контекста) передавать шаблону дополнительные переменные (например, список книг передается по умолчанию). Фрагмент, представленный ниже, показывает как добавить переменную с именем "some_data" в контекст (затем она будет доступна как переменная шаблона).</p>
+
+<pre class="brush: python">class BookListView(generic.ListView):
+ model = Book
+
+    def get_context_data(self, **kwargs):
+        # В первую очередь получаем базовую реализацию контекста
+        context = super(BookListView, self).get_context_data(**kwargs)
+        # Добавляем новую переменную к контексту и иниуиализируем ее некоторым значением
+        context['some_data'] = 'This is just some data'
+        return context</pre>
+
+<p>В процессе выполнения всего этого важно придерживаться определенной последовательности действий:</p>
+
+<ul>
+ <li>В первую очередь - получить существующий контекст из нашего суперкласса.</li>
+ <li>Затем добавить в контекст новую информацию.</li>
+ <li>Затем вернуть новый (обновленный) контекст.</li>
+</ul>
+
+<div class="note">
+<p><strong>Примечание</strong>: Посмотрите <a href="https://docs.djangoproject.com/en/1.10/topics/class-based-views/generic-display/">Встроенные обобщенные классы отображения</a> (Django docs) для ознакомления с большим количеством примеров того, что вы могли бы сделать.</p>
+</div>
+
+<h3 id="Создание_шаблона_Отображения_Списка">Создание шаблона Отображения Списка</h3>
+
+<p>Создайте HTML-файл <strong>/locallibrary/catalog/templates/catalog/book_list.html</strong> и скопируйте в него текст, указанный ниже. Как было отмечено ранее, это файл шаблона по умолчанию, который будет "искать" обобщенный класс отображения списка (для модели с именем <code>Book</code> в приложении с именем <code>catalog</code>).</p>
+
+<p>Шаблоны для обобщенных отображений такие же как все остальные шаблоны (хотя, естественно, передаваемые в них контекст, или информация могут отличаться). Так же как и с нашим шаблоном для главной страницы, в первой строке мы расширяем наш базовый шаблон, а затем определяем и замещаем блок с именем <code>content</code>.</p>
+
+<pre class="brush: html">{% extends "base_generic.html" %}
+
+{% block content %}
+    &lt;h1&gt;Book List&lt;/h1&gt;
+
+    <strong>{% if book_list %}</strong>
+    &lt;ul&gt;
+
+      {% for book in book_list %}
+      &lt;li&gt;
+        &lt;a href="\{{ book.get_absolute_url }}"&gt;\{{ book.title }}&lt;/a&gt; (\{{book.author}})
+      &lt;/li&gt;
+      {% endfor %}
+
+    &lt;/ul&gt;
+    <strong>{% else %}</strong>
+      &lt;p&gt;There are no books in the library.&lt;/p&gt;
+    <strong>{% endif %} </strong>
+{% endblock %}</pre>
+
+<p>По умолчанию отображение передает контекст (список книг) как <code>object_list</code> и <code>book_list</code> (синонимы; оба варианта будут работать).</p>
+
+<h4 id="Условные_ветвления">Условные ветвления</h4>
+
+<p>Мы применяем теги шаблона <code><a href="https://docs.djangoproject.com/en/1.10/ref/templates/builtins/#if">if</a></code>, <code>else</code> и <code>endif</code> для того, чтобы проверить определена ли переменная <code>book_list</code> и содержит ли она данные. Если список НЕ пуст, тогда мы выполняем итерации по списку книг. Если список пуст (<code>else</code>-случай) тогда мы показываем текст, поясняющий, что в наличии нет книг.</p>
+
+<pre class="brush: html"><strong>{% if book_list %}</strong>
+ &lt;!-- здесь наш код "бежит" по списку книг --&gt;
+<strong>{% else %}</strong>
+ &lt;p&gt;В библиотеке книг нет.&lt;/p&gt;
+<strong>{% endif %}</strong>
+</pre>
+
+<p>В данном фрагменте проверяется только одно условие, но вы можете протестировать другие варианты при помощи тэга шаблона <code>elif</code> (например, <code>{% elif var2 %}</code> ). Для дополнительной информации по данной теме смотрите: <a href="https://docs.djangoproject.com/en/1.10/ref/templates/builtins/#if">if</a>, <a href="https://docs.djangoproject.com/en/1.10/ref/templates/builtins/#ifequal-and-ifnotequal">ifequal/ifnotequal</a> и <a href="https://docs.djangoproject.com/en/1.10/ref/templates/builtins/#ifchanged">ifchanged</a> в главе <a href="https://docs.djangoproject.com/en/1.10/ref/templates/builtins">Встроенные тэги и фильтры шаблона</a> (Django Docs).</p>
+
+<h4 id="Цикл_For">Цикл For</h4>
+
+<p>Шаблон использует тэги <a href="https://docs.djangoproject.com/en/1.10/ref/templates/builtins/#for">for</a> и <code>endfor</code> для того, чтобы "пробежаться" по списку книг, как показано ниже. На каждой итерации (каждом цикле) в переменную шаблона <code>book</code> передается информация текущего эелемента списка.</p>
+
+<pre class="brush: html">{% for <strong>book</strong> in book_list %}
+ &lt;li&gt; &lt;!-- здесь код, который использует информацию из каждого элемента <strong>book </strong>списка--&gt; &lt;/li&gt;
+{% endfor %}
+</pre>
+
+<p>Мы не применяем здесь, но внутри каждого цикла Django создает переменные, которые вы можете использовать при итерации. Например, вы можете проверять переменную <code>forloop.last</code> (указывает на последнюю итерацию в цикле) для выполнения каких-либо завершающих действий для данного цикла.</p>
+
+<h4 id="Доступ_к_переменным">Доступ к переменным</h4>
+
+<p>Код внутри цикла создает экземпляр для каждой книги из списка, при помощи которой показывается заголовок (как ссылка на "скоро-будет-сделано" подробное отображение) и автора книги.</p>
+
+<pre class="brush: html">&lt;a href="\{{ book.get_absolute_url }}"&gt;\{{ book.title }}&lt;/a&gt; (\{{book.author}})
+</pre>
+
+<p>Мы получаем доступ к <em>полям</em> соответствующей записи о книге при помощи "дот-нотации", то есть через точку (например, <code>book.title</code> и <code>book.author</code>), где текст, который идет после <code>book</code>, является именем поля (так, как определено в модели).</p>
+
+<p>Кроме того, внутри нашего шаблона, мы можем вызывать <em>функции</em> модели — в данном случае, мы вызываем <code>Book.get_absolute_url()</code> для получения URL-адреса, который мы используем для показа детальной информации о книге. Данный вызов работает только для функции у которой нет аргументов (в шаблоне не существует возможности передать аргументы в функцию!)</p>
+
+<div class="note">
+<p><strong>Примечание</strong>: Мы должны быть достаточно осмотрительными для того, чтобы избегать "сторонних эффектов" когда мы вызываем функции из шаблона. В данном случае мы просто получаем URL-адрес, но функции могут делать все что угодно — мы не хотели бы "убить" наша базу данных (например) просто отрендеривая наш шаблон!</p>
+</div>
+
+<h4 id="Обновление_базового_шаблона">Обновление базового шаблона</h4>
+
+<p>Откройте файл базового шаблона (<strong>/locallibrary/catalog/templates/<em>base_generic.html</em></strong>) и вставьте <strong>{% url 'books' %} </strong> в URL-ссылку для пункта <strong>All books</strong>, как показано ниже. Тем самым, мы создали "переход" на страницу с книгами (теперь мы можем смело это сделать, поскольку у нас имеется соответствующее "книжное" url-преобразование).</p>
+
+<pre class="brush: python">&lt;li&gt;&lt;a href="{% url 'index' %}"&gt;Home&lt;/a&gt;&lt;/li&gt;
+<strong>&lt;li&gt;&lt;a href="{% url 'books' %}"&gt;All books&lt;/a&gt;&lt;/li&gt;</strong>
+&lt;li&gt;&lt;a href=""&gt;All authors&lt;/a&gt;&lt;/li&gt;</pre>
+
+<h3 id="Как_же_теперь_все_это_выглядит">Как же теперь все это выглядит?</h3>
+
+<p>Пока что у вас нет возможности создать список книг, потому что мы не учли еще необходимые зависимости — преобразование URL-адреса для страниц с подробной информации о книге, которое необходимо для ссылок на отдельные книги. Мы покажем страницы со списком и подробной информацией о книге после следующего раздела.</p>
+
+<h2 id="Страница_с_подробной_информацией_о_книге">Страница с подробной информацией о книге</h2>
+
+<p>Доступ к странице с подробной информацией о книге осуществляется при помощи URL-адреса <code>catalog/book/<em>&lt;id&gt;</em></code> (где <code><em>&lt;id&gt;</em></code> является первичным ключом для данной книги). В дополнение к полям модели <code>Book</code>  (автор, краткое содержание, ISBN, язык и жанр), также мы перечислим детали доступных экземпляров книги (<code>BookInstances</code>) включая их статус, ожидаемую дату возврата, штамп (imprint) и id. Это должно позволить нашим читателям не просто узнать о книге, но также убедиться, имеется ли она в наличии и/или когда будет доступна.</p>
+
+<h3 id="URL-преобразования">URL-преобразования</h3>
+
+<p>Откройте <strong>/catalog/urls.py</strong> и добавьте '<strong>book-detail</strong>' URL-преобразование, отмеченное жирным в следующем фрагменте. Эта функция <code>url()</code> определяет паттерн, связанный с обобщенным классом отображения детальной информации, а также имя для данной связи.</p>
+
+<pre class="brush: python">from django.urls import path
+from . import views
+<strong>from django.conf.urls import url</strong>
+
+urlpatterns = [
+    url(r'^$', views.index, name='index'),
+    url(r'^books/$', views.BookListView.as_view(), name='books'),
+    <strong>url(r'^book/(?P&lt;pk&gt;\d+)$', views.BookDetailView.as_view(), name='book-detail'),</strong>
+]</pre>
+
+<p>В отличие от предыдущих преобразований, в данном случае мы применяем наше регулярное выражение (РВ) для сопоставления "настоящего паттерна", а не просто строки. Данное РВ сопоставляет любой URL-адрес, который начинается с <code>book/</code>, за которым до конца строки (до маркера конца строки - $) следуют одна, или более <em>цифр</em>. В процессе выполнения данного преобразования, оно "захватывает" цифры и передает их в функцию отображения как параметр с именем <code>pk</code>.</p>
+
+<div class="note">
+<p><strong>Примечание</strong>: как было отмечено ранее, наш преоразуемый URL-адрес в реальности выглядит вот так <code>catalog/book/&lt;digits&gt;</code> (потому что мы находимся в приложении <strong>catalog</strong>, то подразумевается каталог <code>/catalog/</code>).</p>
+</div>
+
+<div class="warning">
+<p><strong>Важно</strong>: Обобщенный класс отображения подробной информации ожидает получить параметр с именем pk. Если вы пишете свою собственную функцию отображения, то тогда вы можете использовать параметр с любым именем, который пожелаете, или вообще передавать информацию в безымянном аргументе.</p>
+</div>
+
+<h4 id="Отдельный_пример_с_регулярными_выражениями">Отдельный пример с регулярными выражениями</h4>
+
+<p>Паттерны <a href="https://docs.python.org/3/library/re.html">регулярного выражения</a> является невероятно мощным инструментом преобразования. Пока что, мы не очень много говорили о них, поскольку мы сопоставляли URL-адреса с простыми строками (а не паттернами), и потому что они не интуитивны и  пугающи для начинающих.</p>
+
+<div class="note">
+<p><strong>Примечание</strong>: Без паники! Мы будем рассматривать и использовать достаточно простые паттерны и при этом хорошо задокументированные!</p>
+</div>
+
+<p>В первую очередь вы должны знать что обычно регулярные выражения объявляются при помощи строкового литерала (то есть, они заключены в кавычки: <strong>r'&lt;ваше регулярное выражение&gt;'</strong>).</p>
+
+<p>Главными элементами синтаксиса объявления паттерна, который вы должны знать, являются:</p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">Символ</th>
+ <th scope="col">Значение</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>^</td>
+ <td>Соответствует началу строки</td>
+ </tr>
+ <tr>
+ <td>$</td>
+ <td>Соответствует концу строки</td>
+ </tr>
+ <tr>
+ <td>\d</td>
+ <td>Соответствует цифре (0, 1, 2, ... 9)</td>
+ </tr>
+ <tr>
+ <td>\w</td>
+ <td>Соответствует любому символу из алфавита в верхнем- или нижнем- регистре, цифре, или символу подчеркивания (_)</td>
+ </tr>
+ <tr>
+ <td>+</td>
+ <td>Соответствует <strong>одному, или более</strong> предыдущему символу. Например, для соответствия <strong>одной, или более</strong> цифре вы должны использовать <code>\d+</code>. Для <strong>одного и более</strong> символа "a", вы можете использовать <code>a+</code></td>
+ </tr>
+ <tr>
+ <td>*</td>
+ <td>Соответствует отсутствию вообще, или присутствию <strong>одного, или более</strong> предыдущему символу. Например, для соответствия "ничему", или слову (то есть, любому символу) вы можете использовать  <code>\w*</code></td>
+ </tr>
+ <tr>
+ <td>( )</td>
+ <td>Захват части паттерна внутри скобок. Любое захваченное значение будет передано отображению как безымянный параметр (если захватывается множество паттернов, то соответствующие параметры будут поставляться в порядке их объявления).</td>
+ </tr>
+ <tr>
+ <td>(?P&lt;name&gt;...)</td>
+ <td>Захват части паттерна (обозначеного через ...) как именованной переменной (в данном случае &lt;name&gt;). Захваченные значения передаются в отображение с определенным именем. Таким образом, ваше отображение должно объявить аргумент с тем же самым именем!</td>
+ </tr>
+ <tr>
+ <td>[  ]</td>
+ <td>Соответствует одному символу из множества. Например, [abc] будет соответствовать либо 'a', или 'b', или 'c'. [-\w] будет соответствовать либо символу '-' , или любому другому словарному символу.</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>Большинство других символов могут быть заданы буквально!</p>
+
+<p>Давайте рассмотрим несколько реальных примеров паттернов:</p>
+
+<table class="standard-table">
+ <thead>
+ <tr>
+ <th scope="col">Паттерн</th>
+ <th scope="col">Описание</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td><strong>r'^book/(?P&lt;pk&gt;\d+)$'</strong></td>
+ <td>
+ <p>Это РВ применяется в нашем url-преобразовании. Оно соответствует строке, которая начинается с <code>book/</code> (<strong>^book/</strong>), затем имеет одну, или более цифр (<code>\d+</code>), а затем завершается (цифрой и только цифрой).</p>
+
+ <p>Оно также захватывает все цифры <strong>(?P&lt;pk&gt;\d+)</strong> и передает их в отображение, в параметре с именем 'pk'. <strong>Захваченные значения всегда передаются как строка!</strong></p>
+
+ <p>Например, данному паттерну должна соответствовать следующая строка <code>book/1234</code> , которая отправляет переменную <code>pk='1234'</code> в отображение.</p>
+ </td>
+ </tr>
+ <tr>
+ <td><strong>r'^book/(\d+)$'</strong></td>
+ <td>Этот паттерн соответствует тем же самым URL-адресам как и в предыдущем случае. Захваченная информация будет отправлена в отображение как безымянный параметр.</td>
+ </tr>
+ <tr>
+ <td><strong>r'^book/(?P&lt;stub&gt;[-\w]+)$'</strong></td>
+ <td>
+ <p>Данный паттерн соответствует строке, которая начинается с <code>book/</code> (<strong>^book/</strong>), затем идут один, или более символов либо '-', или  словарные символы (<strong>[-\w]+</strong>), а затем завершается. Он также захватывает данное множество символов и передает их в отображение в параметре с именем 'stub'.</p>
+
+ <p>Это довольно типичный паттерн для "стаба". Стабы являются дружественными URL-адресами - первичными ключами для данных. Вы могли бы применить стаб,  если вы захотели бы, чтобы URL-адрес вашей книги был более информативным. Например, <code>/catalog/book/the-secret-garden</code>, выглядит немного лучше чем <code>/catalog/book/33</code>.</p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<p>Вы можете захватить (указать) несколько паттернов в одном преобразовании и, тем самым, закодировать много различной информации в URL-адресе.</p>
+
+<div class="note">
+<p><strong>Примечание</strong>: В качестве дополнительного задания, рассмотрите возможность того, как вы могли бы закодировать url на список всех книг, вышедших в определенный год, месяц, день и какое РВ (паттерн) должно соответствовать этому.</p>
+</div>
+
+<h4 id="Передача_дополнительных_настроек_в_ваши_преобразования_URL-адресов">Передача дополнительных настроек в ваши преобразования URL-адресов</h4>
+
+<p>Одной возможностью, которую мы не применяли здесь, но которая могла бы быть вам полезной, является то, что вы можете объявлять и передавать <a href="https://docs.djangoproject.com/en/1.10/topics/http/urls/#views-extra-options">дополнительные настройки</a> в отображения. Данные настройки объявляются как словарь, который вы передаете как третий безымянный аргумент функции <code>url()</code>. Этот способ может быть полезен, если вы хотите воспользоваться тем же самым отображением для нескольких ресурсов и передавать данные для изменения его поведения в каждом отдельном случае (ниже, мы передаем разные имена шаблонов).</p>
+
+<pre class="brush: python">url(r'^/url/$', views.my_reused_view, {'my_template_name': 'some_path'}, name='aurl'),
+url(r'^/anotherurl/$', views.my_reused_view, {'my_template_name': 'another_path'}, name='anotherurl'),
+
+</pre>
+
+<div class="note">
+<p><strong>Примечание:</strong> И дополнительные настройки, и именованные захваченные паттерны передаются в отображение как именованные параметры. Если вы используете одинаковое имя и для захваченного паттерна и для дополнительной настройки, то последняя будет отброшена, а в отображение будет передано значение захваченного паттерна. </p>
+</div>
+
+<h3 id="Отображение_(на_основе_класса)">Отображение (на основе класса)</h3>
+
+<p>Откройте <strong>catalog/views.py</strong>, и скопируйте следующий код в нижнюю часть файла:</p>
+
+<pre class="brush: python">class BookDetailView(generic.DetailView):
+    model = Book</pre>
+
+<p>Это всё! Все что вам надо теперь сделать это создать шаблон с именем <strong>/locallibrary/catalog/templates/catalog/book_detail.html</strong>, а отображение передаст ему информацию из базы данных для определенной записи <code>Book,</code>выделенной при помощи URL-преобразования. Внутри шаблона вы можете получить доступ к списку книг при помощи переменной с именем <code>object</code> или <code>book</code> (обобщённо "<code><em>the_model_name</em></code>").</p>
+
+<p>Если у вас имеется необходимость, то вы можете изменить текущий шаблон и/или имя объекта контекста, используемого для ссылки на книгу в шаблоне. Кроме того, вы можете переопределить методы, например, для добавления дополнительной информации к контексту.</p>
+
+<h4 id="Что_произойдет_если_записи_не_существует">Что произойдет,  если записи не существует?</h4>
+
+<p>Если запрашиваемой записи не существует, тогда обобщенный класс отображения подробной информации автоматически "выкинет" исключение Http404 — в продакшине это приведет к автоматическому отображению страницы с текстом "resource not found" ("ресурс не найден"), которую, конечно же, вы можете настроить по своему усмотрению.</p>
+
+<p>Просто для иллюстрации идеи как это могло бы работать, мы приведем фрагмент кода, демонстрирующего возможную реализацию отображения в виде функции, если по каким-либо причинам вы не используете отображение на основе обобщенного класса.</p>
+
+<pre class="brush: python">def book_detail_view(request,pk):
+ try:
+ book_id=Book.objects.get(pk=pk)
+ except Book.DoesNotExist:
+ raise Http404("Book does not exist")
+
+  #book_id=get_object_or_404(Book, pk=pk)
+
+ return render(
+ request,
+ 'catalog/book_detail.html',
+ context={'book':book_id,}
+ )
+</pre>
+
+<p>В первую очередь отображение пытается получить определенную запись о книге из модели. Если ей это не удается, то "выбрасывается" исключение <code>Http404</code>, которое сигнализирует, что данная книга не найдена "not found". Последним шагом является, как обычно, вызов функции <code>render()</code> с именем соответствующего шаблона и данных о книге, передаваемых в параметре с именем <code>context</code> (в виде словаря).</p>
+
+<div class="note">
+<p><strong>Примечание</strong>: Функция <code>get_object_or_404()</code> (показана закомментированной) является удобным "ярлыком" для генерации исключения <code>Http404</code> если запись не найдена.</p>
+</div>
+
+<h3 id="Создание_шаблона_детальной_информации">Создание шаблона детальной информации</h3>
+
+<p>Создайте HTML файл <strong>/locallibrary/catalog/templates/catalog/book_detail.html</strong> и скопируйте в него содержимое, представленное ниже. Как было указано ранее, это шаблон "по умолчанию" (имя шаблона), который "ожидается"обобщенным классом отображения детальной информации (для модели с именем <code>Book</code> в приложении с именем <code>catalog</code>).</p>
+
+<pre class="brush: html">{% extends "base_generic.html" %}
+
+{% block content %}
+ &lt;h1&gt;Title: \{{ book.title }}&lt;/h1&gt;
+
+ &lt;p&gt;&lt;strong&gt;Author:&lt;/strong&gt; &lt;a href=""&gt;\{{ book.author }}&lt;/a&gt;&lt;/p&gt; &lt;!-- author detail link not yet defined --&gt;
+ &lt;p&gt;&lt;strong&gt;Summary:&lt;/strong&gt; \{{ book.summary }}&lt;/p&gt;
+ &lt;p&gt;&lt;strong&gt;ISBN:&lt;/strong&gt; \{{ book.isbn }}&lt;/p&gt;
+ &lt;p&gt;&lt;strong&gt;Language:&lt;/strong&gt; \{{ book.language }}&lt;/p&gt;
+ &lt;p&gt;&lt;strong&gt;Genre:&lt;/strong&gt; {% for genre in book.genre.all %} \{{ genre }}{% if not forloop.last %}, {% endif %}{% endfor %}&lt;/p&gt;
+
+ &lt;div style="margin-left:20px;margin-top:20px"&gt;
+ &lt;h4&gt;Copies&lt;/h4&gt;
+
+ {% for copy in book.bookinstance_set.all %}
+ &lt;hr&gt;
+ &lt;p class="{% if copy.status == 'a' %}text-success{% elif copy.status == 'd' %}text-danger{% else %}text-warning{% endif %}"&gt;\{{ copy.get_status_display }}&lt;/p&gt;
+ {% if copy.status != 'a' %}&lt;p&gt;&lt;strong&gt;Due to be returned:&lt;/strong&gt; \{{copy.due_back}}&lt;/p&gt;{% endif %}
+ &lt;p&gt;&lt;strong&gt;Imprint:&lt;/strong&gt; \{{copy.imprint}}&lt;/p&gt;
+ &lt;p class="text-muted"&gt;&lt;strong&gt;Id:&lt;/strong&gt; \{{copy.id}}&lt;/p&gt;
+ {% endfor %}
+ &lt;/div&gt;
+{% endblock %}</pre>
+
+<ul>
+</ul>
+
+<div class="note">
+<p>Ссылка на автора в шаблоне содержит пустой URL-адрес, потому что мы еще не создали страницу детальной информации об авторе. Когда это произойдет, вы должны будете обновить данный URL-адрес как указано ниже:</p>
+
+<pre>&lt;a href="<strong>{% url 'author-detail' book.author.pk %}</strong>"&gt;\{{ book.author }}&lt;/a&gt;
+</pre>
+</div>
+
+<p>Хотя и несколько больше, но почти все в данном шаблоне нам уже встречалось ранее:</p>
+
+<ul>
+ <li>Мы расширяем наш базовый шаблон и переопределяем блок <code>content</code>.</li>
+ <li>Мы используем условие <code>if</code> для показа того, или иного содержимого.</li>
+ <li>Мы используем циклы <code>for</code> того, чтобы пробежаться по элементам (объектам) в соответствующих списках.</li>
+ <li>Мы получаем доступ к полям контекста при помощи "дот-нотации" (поскольку мы использовали обобщенный класс отображения детальной информации, то контекст имеет имя <code>book</code>; также можем использовать имя <code>object</code>)</li>
+</ul>
+
+<p>Одной интересной вещью, которую мы не видели ранее, является функция <code>book.bookinstance_set.all()</code>. Данный метод является "автомагически"-сконструированным Django для того, чтобы вернуть множество записей <code>BookInstance</code>, связанных с данной книгой <code>Book</code>.</p>
+
+<pre class="brush: python">{% for copy in book.bookinstance_set.all %}
+&lt;!-- итерации по каждой копии/экземпляру книги --&gt;
+{% endfor %}</pre>
+
+<p>Этот метод создан, потому что вы, на стороне "многим" данной связи, объявили поле <code>ForeignKey</code> (один-ко многим). Поскольку вы ничего не объявили на другой стороне ("один") данной модели (то есть, модель <code>Book</code> "ничего не знает" про модель <code>BookInstance</code>), то она не имеет никакой возможности (по умолчанию) для получения множества соответствующих записей. Для того, чтобы обойти эту проблему, Django конструирует соответствующую функцию "обратного просмотра" ("reverse lookup"), которой вы можете воспользоваться. Имя данной функции создается в нижнем регистре и состоит из имени модели, в которой был объявлен <code>ForeignKey</code> (то есть, <code>bookinstance</code>), за которым следует <code>_set</code> (то есть функция, созданная для <code>Book</code> будет иметь вид <code>bookinstance_set()</code>).</p>
+
+<div class="note">
+<p><strong>Примечание</strong>: Здесь мы используем  <code>all()</code> для получения всех записей (по умолчанию). Вы, наверное, могли бы использовать метод <code>filter()</code> для получения подмножетсва записей в коде, но, к сожалению, вы НЕ можете применить данный вызов в шаблоне, потому что вы не можете передать в нем (в шаблоне) аргументы в функцию.</p>
+
+<p>Обратите внимание, что если вы не определяете порядок выдачи данных (в вашем отображении, или в модели), то сервер разработки "выкинет" сообщения об ошибках, похожие на следующие:</p>
+
+<pre>[29/May/2017 18:37:53] "GET /catalog/books/?page=1 HTTP/1.1" 200 1637
+/foo/local_library/venv/lib/python3.5/site-packages/django/views/generic/list.py:99: UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list: &lt;QuerySet [&lt;Author: Ortiz, David&gt;, &lt;Author: H. McRaven, William&gt;, &lt;Author: Leigh, Melinda&gt;]&gt;
+ allow_empty_first_page=allow_empty_first_page, **kwargs)
+</pre>
+
+<p>Это случилось потому что, <a href="https://docs.djangoproject.com/en/1.10/topics/pagination/#paginator-objects">paginator object</a> (далее объект постраничного вывода) ожидает видеть некую упорядоченность ORDER BY при запросе к базе данных. Без этого, он не сможет гарантировать правильный вывод полученных данных!<strong> </strong></p>
+
+<p>Данное руководство пока не дошло до описания <strong>Pagination</strong> (пока, но скоро будет), и поскольку вы не можете использовать функцию <code>sort_by()</code> и передавать параметр (по той же причине, что и <code>filter()</code>) вы должны выбрать один из трех вариантов дальнейших действий:</p>
+
+<ol>
+ <li>Добавить атрибут <code>ordering</code> внутри <code>Meta-класса</code> объявленного в вашей модели.</li>
+ <li>Добавить атрибут <code>queryset</code> в вашей реализации класса отображения, определяющего <code>order_by()</code>.</li>
+ <li>Добавить метод <code>get_queryset</code> в вашу реализацию класса отображения и также определить метод <code>order_by()</code>.</li>
+</ol>
+
+<p>Если вы выбрали пункт номер один с <code>Meta-классом</code> для модели Author  (вероятно, не такой гибкий как вариант с настройкой класса отображения, но тем не менее, достаточно простой), вы должны прийти к чему-то похожему на следующее:</p>
+
+<pre>class Author(models.Model):
+ first_name = models.CharField(max_length=100)
+ last_name = models.CharField(max_length=100)
+ date_of_birth = models.DateField(null=True, blank=True)
+ date_of_death = models.DateField('Died', null=True, blank=True)
+
+ def get_absolute_url(self):
+ return reverse('author-detail', args=[str(self.id)])
+
+ def __str__(self):
+ return '%s, %s' % (self.last_name, self.first_name)
+
+<strong> class Meta:
+ ordering = ['last_name']</strong></pre>
+
+<p>Конечно же, поле не обязательно должно иметь имя <code>last_name</code>: оно может быть любым.</p>
+
+<p>И последнее, но не окончательное, вы должны сортировать по атрибуту/колонке, которая была проиндексирована (уникально, или нет) в вашей базе данных для того, чтобы избежать проблем с быстродействием. Конечно, это не является необходимым в данном примере (и мы, вероятно, забегаем далеко вперед), если у нас такое небольшое количество книг (и пользователей!),  но это необходимо помнить для будущих проектов.</p>
+</div>
+
+<h2 id="Как_это_теперь_выглядит">Как это теперь выглядит?</h2>
+
+<p>На данный момент мы должны были создать все необходимое для показа страниц со списком книг и детальной информацией. Запустите сервер (<code>python3 manage.py runserver</code>) и откройте ваш браузер <a href="http://127.0.0.1:8000/">http://127.0.0.1:8000/</a>.</p>
+
+<div class="warning">
+<p><strong>Предупреждение:</strong> Не кликайте на каком-либо авторе, - ссылки пока не заданы — это будет вашим дополнительным заданием!</p>
+</div>
+
+<p>Кликните ссылку <strong>All books</strong> для перехода на страницу со списком книг. </p>
+
+<p><img alt="Book List Page" src="https://mdn.mozillademos.org/files/14049/book_list_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; height: 216px; margin: 0px auto; width: 823px;"></p>
+
+<p>Затем кликните на ссылку одной из ваших книг. Если все настроено как надо, то вы должны увидеть то, что указано на картинке.</p>
+
+<p><img alt="Book Detail Page" src="https://mdn.mozillademos.org/files/14051/book_detail_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; height: 783px; margin: 0px auto; width: 926px;"></p>
+
+<h2 id="Постраничный_вывод_(Pagination)">Постраничный вывод (Pagination)</h2>
+
+<p>Если у вас всего лишь несколько записей в базе данных, то наша страница вывода списка книг будет выглядеть отлично. Тем не менее, когда у вас появятся десятки, или сотни записей ваша страница станет значительно дольше загружаться (и станет слишком длинной для комфортного просмотра). Решением данной проблемы является добавление постраничного вывода (Pagination) к вашему отображению списка, который будет выводить ограниченное количество элементов на каждой странице.</p>
+
+<p>Django имеет отличный встроенный механизм для постраничного вывода. Даже более того, он встроен в обобщенный класс отображения списков, следовательно вам не нужно проделывать большой объем работы, чтобы воспользоваться возможностями постраничного вывода!</p>
+
+<h3 id="Отображения">Отображения</h3>
+
+<p>Откройте <strong>catalog/views.py</strong> и добавьте поле <code>paginate_by</code> как показано жирным в следующем фрагменте.</p>
+
+<pre class="brush: python">class BookListView(generic.ListView):
+ model = Book
+ <strong>paginate_by = 10</strong></pre>
+
+<p>Как только у вас появится более 10 записей в базе данных отображение начнет формировать постраничный вывод данных, которые он передает шаблону. К различным страницам данного вывода можно получить доступ при помощи параметров GET-запроса — к странице 2 вы можете получить доступ, используя URL-адрес: <code>/catalog/books/<strong>?page=2</strong></code>.</p>
+
+<h3 id="Шаблоны">Шаблоны</h3>
+
+<p>Теперь, когда данные выводятся постранично, нам надо добавить функционал переключения между страницами в шаблона страницы. Поскольку мы хотели бы использовать данный механизм для всех списков на сайте, то мы пропишем его в базовом шаблоне сайта.</p>
+
+<p>Откройте <strong>/locallibrary/catalog/templates/<em>base_generic.html</em></strong> и, ниже блока <code>content</code>, вставьте блок (во фрагменте не выделен жирным), отвечающий за постраничный вывод. Данный код, в первую очередь, проверяет "включен" ли механизм постраничного вывода для данной страницы и если это так, то он добавляет ссылки <code>next</code> и <code>previous,</code>соответственно (а также, номер текущей страницы). </p>
+
+<pre class="brush: python"><strong>{% block content %}{% endblock %}</strong>
+
+{% block pagination %}
+ {% if is_paginated %}
+ &lt;div class="pagination"&gt;
+ &lt;span class="page-links"&gt;
+ {% if page_obj.has_previous %}
+ &lt;a href="\{{ request.path }}?page=\{{ page_obj.previous_page_number }}"&gt;previous&lt;/a&gt;
+ {% endif %}
+ &lt;span class="page-current"&gt;
+ Page \{{ page_obj.number }} of \{{ page_obj.paginator.num_pages }}.
+ &lt;/span&gt;
+ {% if page_obj.has_next %}
+ &lt;a href="\{{ request.path }}?page=\{{ page_obj.next_page_number }}"&gt;next&lt;/a&gt;
+ {% endif %}
+ &lt;/span&gt;
+ &lt;/div&gt;
+ {% endif %}
+{% endblock %} </pre>
+
+<p>Параметр <code>page_obj</code> является объектом типа <a href="https://docs.djangoproject.com/en/1.10/topics/pagination/#paginator-objects">Paginator</a>, который будет создаваться каждый раз, когда будет применяться постраничный вывод данных для текущей страницы. Он позволяет получить всю информацию о текущей странице, о предыдущих страницах, сколько всего страниц и так далее. </p>
+
+<p>Мы используем <code>\{{ request.path }}</code> для получения URL-адреса текущей страницы, для того, чтобы создать ссылки на соответствующие страницы, обратите внимание, что данный вызов не зависит от объекта <code>page_obj</code>и, таким образом, может использоваться отдельно.</p>
+
+<p>На этом все!</p>
+
+<h3 id="Как_это_выглядит">Как это выглядит?</h3>
+
+<p>Картинка ниже показывает как выглядит постраничный вывод — если вы не добавили более 10 записей в вашу базу данных, тогда вы можете проверить как это работает, просто уменьшив значение в <code>paginate_by,</code> в файле <strong>catalog/views.py</strong>. Для получения результата, соответствующего картинке ниже, мы изменили<code>paginate_by = 2</code>.</p>
+
+<p>Ссылки на страницы показаны в нижней части страницы. Показаны ссылки следующая/предыдущая в зависимости от того на какой странице вы в данный момент находитесь.</p>
+
+<p><img alt="Book List Page - paginated" src="https://mdn.mozillademos.org/files/14057/book_list_paginated.png" style="border-style: solid; border-width: 1px; display: block; height: 216px; margin: 0px auto; width: 924px;"></p>
+
+<h2 id="Проверьте_себя">Проверьте себя</h2>
+
+<p>Дополнительным задание в данной статье и для завершения данного этапа проекта будет создание отображений детальной информации об авторе и их списка. Эти отображения должны находиться по следующим адресам:</p>
+
+<ul>
+ <li><code>catalog/authors/</code> — Список авторов.</li>
+ <li><code>catalog/author/<em>&lt;id&gt;</em></code><em> </em>— Детальная информация об авторе со значением первичного ключа равным <em><code>&lt;id&gt;</code></em></li>
+</ul>
+
+<p>Соответствующий код для URL-преобразований и оторажений должен быть идентичным коду для списка книг и детальной информаци о книге <code>Book</code>, который мы создали ранее. Шаблоны будут отличаться, но будут иметь похожее поведение.</p>
+
+<div class="note">
+<p><strong>Примечание</strong>:</p>
+
+<ul>
+ <li>Когда вы создадите URL-преобразование для страницы списка авторов вам понадобится обновить ссылку <strong>All authors</strong> в базовом шаблоне. Следуйте <a href="#Update_the_base_template">тем же путем</a>, который мы проделали когда обновляли ссылку <strong>All books</strong>.</li>
+ <li>Когда вы создадите URL-преобразование для страницы с детальной информацией об авторе,  вы должны будете обновить <a href="#Creating_the_Detail_View_template">шаблон детальной информации о книге</a> (<strong>/locallibrary/catalog/templates/catalog/book_detail.html</strong>), таким образом, чтобы ссылка автора указывала на страницу с детальной информации о нем (а не быть пустой). Данная ссылка будет иметь вид как указано жирным во фрагменте ниже.
+ <pre class="brush: html">&lt;p&gt;&lt;strong&gt;Author:&lt;/strong&gt; &lt;a href="<strong>{% url 'author-detail' book.author.pk %}</strong>"&gt;\{{ book.author }}&lt;/a&gt;&lt;/p&gt;
+</pre>
+ </li>
+</ul>
+</div>
+
+<p>Когда вы закончите, ваши страницы должны будут выглядеть как на картинке.</p>
+
+<p><img alt="Author List Page" src="https://mdn.mozillademos.org/files/14053/author_list_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p>
+
+<ul>
+</ul>
+
+<p><img alt="Author Detail Page" src="https://mdn.mozillademos.org/files/14055/author_detail_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; height: 358px; margin: 0px auto; width: 825px;"></p>
+
+<ul>
+</ul>
+
+<h2 id="Итоги">Итоги</h2>
+
+<p>Поздравляем! Наш базовый функционал библиотеки готов! </p>
+
+<p>В данной статье мы изучили как применять обобщенные классы отображения списка и детальной информации, и использовать их для создания страниц отображения наших книг и авторов. Кроме того, мы многое узнали о паттернах преобразования, построенных на основе регулярных выражений, а также то, как вы можете передавать данные из URL-адреса в ваше отображение. Мы изучили несколько приемов применения шаблонов. В самом конце мы показали как осуществлять постраничный вывод списков, так, что наши списки управляются даже тогда, когда они содерждат много записей.</p>
+
+<p>В нашей следующей статье мы расширим нашу библиотеку, путем поддержки пользовательких аккаутов,  и так образом продемонстрируем аутетификацию, разграничение уровней доступа, сессии и  формы.</p>
+
+<h2 id="Дополнительная_информация">Дополнительная информация</h2>
+
+<ul>
+ <li><a href="https://docs.djangoproject.com/en/1.10/topics/class-based-views/generic-display/">Встроенные обобщенные классы отображения</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/ref/class-based-views/generic-display/">Обобщенный вид отображения</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/topics/class-based-views/intro/">Введение в отображения на основе классов</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/ref/templates/builtins">Встроенные теги шаблона и фильтры</a> (Django docs).</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/topics/pagination/">Постраничный вывод (Pagination)</a> (Django docs)</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Django/Home_page", "Learn/Server-side/Django/Sessions", "Learn/Server-side/Django")}}</p>
diff --git a/files/ru/learn/server-side/django/home_page/index.html b/files/ru/learn/server-side/django/home_page/index.html
new file mode 100644
index 0000000000..b573f3fdb6
--- /dev/null
+++ b/files/ru/learn/server-side/django/home_page/index.html
@@ -0,0 +1,359 @@
+---
+title: 'Руководство часть 5: Создание домашней страницы'
+slug: Learn/Server-side/Django/Home_page
+tags:
+ - django
+ - Для начинающих
+ - Изучение
+ - Кодирование
+ - Отображения
+ - Руководство
+ - Серверная сторона
+ - Статья
+ - Шаблоны
+translation_of: Learn/Server-side/Django/Home_page
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django")}}</div>
+
+<p class="summary">Теперь мы готовы создать код нашей первой страницы — домашняя страница сайта <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> будет показывать количество записей в каждой модели, кроме того, она будет выводить боковую навигационную панель с ссылками на другие страницы сайта. В результате мы приобретем практический навык написания простых URL-преобразований и отображений, получения записей из базы данных и применения шаблонов.</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Требования:</th>
+ <td>Прочитать <a href="/en-US/docs/Learn/Server-side/Django/Introduction">Введение в Django</a>. Завершить изучение предыдущех частей руководства (включая <a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Руководство часть 4: Django административный раздел сайта</a>).</td>
+ </tr>
+ <tr>
+ <th scope="row">Цель:</th>
+ <td>Понимать как создавать простые url-преобразования (которые не содержат никаких данных) и отображения, как получать данные из моделей и создавать шаблоны.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Обзор">Обзор</h2>
+
+<p>Теперь, когда мы определили наши модели и создали несколько записей в них, пришло время написать код, который будет показывать данную информацию пользователям. И первое, что нам необходимо сделать это определиться какую информацию мы бы хотели показывать на наших страницах,  а затем определить соответствующие URL-адреса для получения соответствующих ресурсов. Затем нам надо создать url-преобразования, отображения (функции, или классы), а затем шаблоны страницы. </p>
+
+<p>Диаграмма, представленная ниже,  демонстрирует главный поток данных и элементов, которые нужно реализовать для управления HTTP запросами и ответами. Поскольку мы уже создали модель, то нам остается создать следующее:</p>
+
+<ul>
+ <li>URL-преобразования для перехода по соответствующему URL-адресу (с учетом информации, передаваемой в данном адресе) к соответствующей функции отображения.</li>
+ <li>Функции отображения для запроса соответствующих данных из моделей, создание страниц HTML для показа этих данных и их отправку в клиент пользователя (в браузер).</li>
+ <li>Шаблоны, которые используются отображениями для рендеринга (отрисовки) данных.</li>
+</ul>
+
+<p><img alt="" src="https://mdn.mozillademos.org/files/13931/basic-django.png" style="display: block; margin: 0px auto;"></p>
+
+<p>Как вы увидите в следующем разделе, у нас будет 5 страниц, которые мы немного опишем в данной статье. Данная статья, большей частью, будет сконцентрирована на реализации всего-лишь одной, домашней страницы нашего сайта (к другим страницам мы перейдем в других частях руководства). Это должно дать вам хорошее базовое представление о работе с URL-преобразованиями (связывании), отображениями и моделями.</p>
+
+<h2 id="Определяем_URL-адреса_страниц">Определяем URL-адреса страниц</h2>
+
+<p>По сути, так как для конечных пользователей, данная версия сайта <em>LocalLibrary</em> является read-only (только для чтения), то нам надо создать домашнюю страницу и страницы, которые будут <em>показывать</em> списки авторов и книг, а также детальную информацию о них, соответственно. </p>
+
+<p>Перечислим URL-адреса, которые понадобятся для наших страниц:</p>
+
+<ul>
+ <li><code>catalog/</code> — Домашняя/индексная странца.</li>
+ <li><code>catalog/books/</code> — Список всех книг.</li>
+ <li><code>catalog/authors/</code> — Список всех авторов.</li>
+ <li><code>catalog/book/<em>&lt;id&gt;</em></code> — Детальная информация для определенной книги со значением первичного ключа равного <code><em>&lt;id&gt;</em></code>. Например, <code>/catalog/book/3</code>, для <code>id = 3</code>.</li>
+ <li><code>catalog/author/<em>&lt;id&gt;</em></code><em> </em>— Детальная информация для определенного автора со значением первичного ключа равного <em><code>&lt;id&gt;. </code></em>Например, <code>/catalog/author/11</code>, для автора с <code>id = 11</code>.</li>
+</ul>
+
+<p>Первые три URL-адреса используются для показа домашней страницы, а также списков книг и авторов. Они не кодируют никакой дополнительной информации и результат показа данных страниц будет полностью зависеть от того, что находится в базе данных  и, по сути, будет все время одним и тем же (при неизменной базе данных, конечно).</p>
+
+<p>Последние два URL-адреса применяются для показа детальной информации об определенной книге, или авторе — в себе они содержат соответствующее значение идентификатора (показан как <code><em>&lt;id&gt;</em></code>, выше). URL-преобразование получает данную информацию и передает ее в отображение, которое применяет ее для запроса к базе данных. Для кодирования и применения данной информации в вашем URL-адресе нам понадобится только одно url-преобразование, соответствующее отображение и шаблон страницы для показа любой книги (или автора). </p>
+
+<div class="note">
+<p><strong>Примечание</strong>: Django позволяет вам конструировать ваши URL-адреса любым, удобным для вас, способом — вы можете закодировать информацию в теле URL-адреса, как показано выше, или использовать URL-адрес типа <code>GET</code> (например, <code>/book/?id=6</code>). Независимо от ваших предпочтений, URL-адреса должны быть понятными, логичными и читабельными (<a href="https://www.w3.org/Provider/Style/URI">посмотрите совет W3C здесь</a>).<br>
+ <br>
+ Документация Django рекомендует кодировать информацию в теле URL-адреса, на практике это приводит к лучшей стркутуре сайта.</p>
+</div>
+
+<p>Как было отмечено ранее, оставшаяся часть данной статьи описывает как сделать главную страницу сайта.</p>
+
+<h2 id="Создание_главной_страницы_сайта">Создание главной страницы сайта</h2>
+
+<p>Первой страницей, которую мы создадим, будет главная страница сайта (<code>catalog/</code>). Она будет небольшой статической HTML-страницей, которая будет показывать вычисленные "количества" различных записей из базы данных. Для того, чтобы проделать данную работу мы вначале создадим URL-преобразование, затем отображение и шаблон. </p>
+
+<div class="note">
+<p><strong>Примечание</strong>: Лучше уделить больше внимания на данный раздел, поскольку информация, представленная здесь, применяется для создания всех страниц сайта.</p>
+</div>
+
+<h3 id="URL-преобразование">URL-преобразование</h3>
+
+<p>Когда мы создавали <a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">скелет сайта</a> мы обновили <strong>locallibrary/urls.py </strong>так что всякий раз, когда начинается URL-адрес наш catalog/ получен и URLConf catalog.urls подлючен для обработки оставшейся части строки.</p>
+
+<pre><code>urlpatterns += [
+ path('catalog/', include('catalog.urls')),
+]</code></pre>
+
+<p>Примечание: всякий раз, когда Django сталкивается c  <code><a href="https://docs.djangoproject.com/en/2.0/ref/urls/#django.urls.include" title="django.conf.urls.include">django.urls.include()</a></code>  он отбрасывает часть совпавшего URL , и отправляет оставшуюся строку в включенный URLconf для дальнейшей обработки.</p>
+
+<p>Внутри нашего каталога приложения откройте <strong>urls.py</strong> и поместите в него текст, отмеченный жирным, ниже. </p>
+
+<pre class="brush: python line-numbers language-python"><code class="language-python">urlpatterns = [
+<strong> path('', views.index, name='index'),</strong>
+]</code></pre>
+
+<p>Эта функция <code>path()</code> определяет URL-паттерн (в данном случае это пустая строка:<code>'' - </code>мы поговорим чуть более подробно о них далее в данном руководстве) и функцию отображения, которая будет вызвана, если введенный адрес будет соответствать данному паттерну (<code>views.index</code> — это функция с именем <code>index()</code> в <strong>views.py</strong>).</p>
+
+<p>Данная функция <code>path()</code>, кроме того, определяет параметр <code>name</code>, который уникально определяет <em>это </em>частное URL-преобразование. Вы можете использовать данное имя для "обратного" ("reverse") преобразования — то есть, для динамического создания URL-адреса, указывающего на ресурс, на которое указывает данное преобразование. Например, теперь, когда у нас имеется данное символическое имя, мы можем ссылаться на нашу домашнюю страницу при помощи создания следующей ссылки внутри какого-либо шаблона:</p>
+
+<pre class="brush: html">&lt;a href="<strong>{% url 'index' %}</strong>"&gt;Home&lt;/a&gt;.</pre>
+
+<div class="note">
+<p><strong>Примечание</strong>: Мы могли бы, конечно, жестко указать прямую ссылку (то есть, <code>&lt;a href="<strong>/catalog/</strong>"&gt;Home&lt;/a&gt;</code>), но тогда, если мы изменим адрес нашей домашней страницы (например на <code>/catalog/index</code>), то данные ссылки перестанут корректно работать. Применение "обратного" url-преобразования более гибкий и эффективный подход!</p>
+</div>
+
+<h3 id="Отображения_(на_основе_функций)">Отображения (на основе функций)</h3>
+
+<p>Отображение является функцией, которая обрабатывает HTTP-запрос, получает данные из базы данных (при необходимости), которые применяются для генерации страницы HTML. Затем функция отображения возвращает сгенерированную страницу пользователю в виде HTTP-ответа. В нашем случае, индексная функция демонстрирует этот процесс — она получает информацию о количестве записей <code>Book</code>, <code>BookInstance</code>, доступности <code>BookInstance</code>, а также записи <code>Author</code> из базы данных, затем передает эти записи в шаблон страницы, генерирует страницу и передает ее пользователю (клиенту пользователя, например браузеру).</p>
+
+<p>Откройте <strong>catalog/views.py</strong> и отметьте для себя, что данный файл уже импортирует функцию <a href="https://docs.djangoproject.com/en/1.10/topics/http/shortcuts/#django.shortcuts.render">render()</a> - функцию, которая генерирует HTML-файлы при помощи шаблонов страниц и соответствующих данных. </p>
+
+<pre class="brush: python">from django.shortcuts import render
+
+# Создайте ваше отображение здесь
+</pre>
+
+<p>Скопируйте следующий код в нижнюю часть файла. Первая строка импортирует классы модели, которые мы будем использовать для доступа к данным во всех наших функциях (позже и классах) отображения.</p>
+
+<pre class="brush: python">from .models import Book, Author, BookInstance, Genre
+
+def index(request):
+ """
+ Функция отображения для домашней страницы сайта.
+ """
+ # Генерация "количеств" некоторых главных объектов
+ num_books=Book.objects.all().count()
+ num_instances=BookInstance.objects.all().count()
+ # Доступные книги (статус = 'a')
+ num_instances_available=BookInstance.objects.filter(status__exact='a').count()
+ num_authors=Author.objects.count() # Метод 'all()' применен по умолчанию.
+
+ # Отрисовка HTML-шаблона index.html с данными внутри
+ # переменной контекста context
+ return render(
+ request,
+ 'index.html',
+ context={'num_books':num_books,'num_instances':num_instances,'num_instances_available':num_instances_available,'num_authors':num_authors},
+ )</pre>
+
+<p>Первая часть функции отображения получает количество записей при помощи вызова функции <code>objects.all()</code> у атрибута <code>objects</code>, доступного для всех классов моделей. Похожим образом мы получаем список объектов <code>BookInstance</code>, которые имеют статус 'a' (Доступно). Вы можете найти дополнительную инофрмацию о работе с моделями в предыдущей части руководства (<a href="/en-US/docs/Learn/Server-side/Django/Models#Searching_for_records">Руководство часть 3: Применение моделей &gt; Поиск записей</a>).</p>
+
+<p>В конце функции <code>index</code> вызывается функция  <code>render()</code>, которая, в качестве ответа, создает и возвращает страницу HTML  (эта функция "оборачивает" вызовы нескольких функций, тем самым существенно упрощая процесс разработки). В качестве параметров ей передаются объект <code>request</code>  (типа <code>HttpRequest</code>), шаблон HTML-страницы с метками (<code>placeholders</code>), которые будут замещены данными,  а также переменной <code>context</code> (словарь Python, который содержит данные, которые и будут замещать метки в шаблоне). </p>
+
+<p>В следующем разделе мы более подробно поговорим о шаблонах и переменной контекста. Давайте создадим наш шаблон, чтобы показать уже что-нибудь пользователю!</p>
+
+<h3 id="Шаблон">Шаблон</h3>
+
+<p>Шаблон это текстовый файл, который определяет структуру и расположение данных в файле, кроме того, в нем размещают специальные метки (placeholders), которые используются для показа реального содержимого, то есть данных. По умолчанию Django ищет файлы шаблонов в директории с именем '<strong>templates</strong>' внутри вашего приложения. Например, внутри индексной функции отображения, которую мы только что создали, вызов <code>render()</code> будет пытаться найти файл <strong>/locallibrary/catalog/templates/<em>index.html</em></strong> и в случае неудачи сгенерирует ошибку о том, что файл не найден. Вы можете увидеть данную ошибку, если вы сохраните предыдущие изменения, затем перейдете в браузер и наберете в адресной строке <code>127.0.0.1:8000</code>. В результате, в окно браузера будет выведено сообщение об ошибке "TemplateDoesNotExist at /catalog/" и некоторая другая информация.</p>
+
+<div class="note">
+<p><strong>Примечание</strong>: На самом деле, в зависимости от настроек проекта, Django просматривает несколько мест в поисках шаблона (поиск в директории приложения осуществляется по умолчанию!). Вы можете найти больше информации о шаблонах и форматах, которые они поддерживают, перейдя по ссылке <a href="https://docs.djangoproject.com/en/1.10/topics/templates/">Шаблоны</a> (Django docs).</p>
+</div>
+
+<h4 id="Расширение_шаблонов">Расширение шаблонов</h4>
+
+<p>Шаблон главной страницы нашего сайта должен соответствовать стандарту разметки HTML для разделов <code>head</code> и <code>body</code>, кроме того иметь разделы для навигации (на другие страницы, которые мы создадим позже) и показа некоторого вводного текста. Большая часть данной структуры будет одинаковой для всех страниц нашего сайта. Таким образом, чтобы избежать копирования одной и той же информации, язык создания шаблонов Django позволяет вам объявить базовый шаблон, а затем расширить его, замещая только те части, которые являются специфическими для каждой страницы. </p>
+
+<p>Например, базовый шаблон <strong>base_generic.html</strong> может выглядеть как показано ниже. Как вы видите, этот файл содержит некоторую "общую" структуру HTML, разделы для заголовка, панель навигации и содержимое, отмеченное тэгами шаблона <code>block</code> и <code>endblock</code> (показано жирным). Данные блоки могут быть пустыми, или иметь содержимое, которое будет использоваться "по умолчанию" всеми страницами-наследниками.</p>
+
+<div class="note">
+<p><strong>Примечание</strong>: <em>Тэги</em> шаблона подобны функциям, которые могут применяться для создания циклов по спискам, выполнять условные оперции и так далее. Кроме тэгов, язык шаблона позволяет использовать переменные (которые передаются в шаблон из отображения), а также <em>шаблонные фильтры</em>, которые переформатируют переменные (например, переводят строку в нижний регистр).</p>
+</div>
+
+<pre class="brush: html">&lt;!DOCTYPE html&gt;
+&lt;html lang="en"&gt;
+&lt;head&gt;
+ <strong>{% block title %}</strong>&lt;title&gt;Local Library&lt;/title&gt;<strong>{% endblock %}</strong>
+&lt;/head&gt;
+
+&lt;body&gt;
+ <strong>{% block sidebar %}</strong>&lt;!-- insert default navigation text for every page --&gt;<strong>{% endblock %}</strong>
+ <strong>{% block content %}</strong>&lt;!-- default content text (typically empty) --&gt;<strong>{% endblock %}</strong>
+&lt;/body&gt;
+&lt;/html&gt;
+</pre>
+
+<p>Когда мы определяем шаблон для конкретного отображения, то в первую очередь мы объявляем базовый шаблон (при помощи тэга <code>extends</code> — смотрите код в следующем фрагменте). Если имеются блоки в базовом шаблоне, которые мы хотим заместить, тогда в нашем текущем шаблоне мы объявляем <code>block</code>/<code>endblock</code> и указываем соответствующее имя блока. </p>
+
+<p>Например фрагмент кода, показанный ниже, демонстрирует применение тэга <code>extends</code> и переопределяет блок с именем <code>content</code>. Окончальный код HTML будет содержать все структуры базового файла шаблона (включая содержимое по умолчанию, которое мы указали в блоке <code>title</code>) и код блока <code>content</code>, который мы разместили в текущем файле шаблона.</p>
+
+<pre class="brush: html">{% extends "base_generic.html" %}
+
+{% block content %}
+&lt;h1&gt;Local Library Home&lt;/h1&gt;
+&lt;p&gt;Welcome to &lt;em&gt;LocalLibrary&lt;/em&gt;, a very basic Django website developed as a tutorial example on the Mozilla Developer Network.&lt;/p&gt;
+{% endblock %}</pre>
+
+<h4 id="Базовый_шаблон_сайта_LocalLibrary">Базовый шаблон сайта LocalLibrary</h4>
+
+<p>Базовый шаблон, который мы планируем использовать для сайта <em>LocalLibrary</em>, представлен ниже. Как вы видите, данный фрагмент содержит HTML код и объявляет следующие блоки <code>title</code>, <code>sidebar</code> и <code>content</code>. Мы добавили заголовок по умолчанию (который, возможно, мы захотим изменить), а также боковую панель навигации, содержащей ссылки на списки всех книг и авторов (панель навигации, мы, вероятно, не будем менять/замещать, но, тем не менее, добавив этот блок, мы оставим для себя такую возможность).</p>
+
+<div class="note">
+<p><strong>Примечание</strong>: Во фрагменте мы используем два дополнительных шаблонных тега: <code>url</code> и <code>load static</code>. Они будут описаны в следующих разделах.</p>
+</div>
+
+<p>Создайте новый файл — <strong>/locallibrary/catalog/templates/<em>base_generic.html</em></strong> — и добавьте в него следующее содержимое:</p>
+
+<pre class="brush: html">&lt;!DOCTYPE html&gt;
+&lt;html lang="en"&gt;
+&lt;head&gt;
+
+ {% block title %}&lt;title&gt;Local Library&lt;/title&gt;{% endblock %}
+ &lt;meta charset="utf-8"&gt;
+ &lt;meta name="viewport" content="width=device-width, initial-scale=1"&gt;
+ &lt;link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"&gt;
+ &lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"&gt;&lt;/script&gt;
+ &lt;script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"&gt;&lt;/script&gt;
+
+ &lt;!-- Добавление дополнительного статического CSS файла --&gt;
+ {% load static %}
+ &lt;link rel="stylesheet" href="{% static 'css/styles.css' %}"&gt;
+&lt;/head&gt;
+
+&lt;body&gt;
+
+ &lt;div class="container-fluid"&gt;
+
+ &lt;div class="row"&gt;
+ &lt;div class="col-sm-2"&gt;
+ {% block sidebar %}
+ &lt;ul class="sidebar-nav"&gt;
+ &lt;li&gt;&lt;a href="{% url 'index' %}"&gt;Home&lt;/a&gt;&lt;/li&gt;
+ &lt;li&gt;&lt;a href=""&gt;All books&lt;/a&gt;&lt;/li&gt;
+ &lt;li&gt;&lt;a href=""&gt;All authors&lt;/a&gt;&lt;/li&gt;
+ &lt;/ul&gt;
+ {% endblock %}
+ &lt;/div&gt;
+ &lt;div class="col-sm-10 "&gt;
+ {% block content %}{% endblock %}
+ &lt;/div&gt;
+ &lt;/div&gt;
+
+ &lt;/div&gt;
+&lt;/body&gt;
+&lt;/html&gt;</pre>
+
+<p>Шаблон использует (и включает в себя) JavaScript и CSS от <a href="http://getbootstrap.com/">Bootstrap</a> для лучшего размещения элементов и формирования внешнего вида HTML страницы. Применение Bootstrap, или любого другого фреймворка для клиентской части сайта, является довольно продуктивным способом повышения привлекательности страницы, в том числе, это учитывает возможность запроса и показа сайта с устройств, с различными разрешениями экрана, а кроме того, это позволяет нам повысить уровень взаимодействия с пользователем — мы направим большую часть своих усилий на серверную часть нашего сайта!</p>
+
+<p>Базовый шаблон ссылается на локальный файл css  (<strong>styles.css</strong>), который предоставляет дополнительные стили. Создайте <strong>/locallibrary/catalog/static/css/styles.css</strong> и добавьте в него следующее содержимое:</p>
+
+<pre class="brush: css">.sidebar-nav {
+ margin-top: 20px;
+ padding: 0;
+ list-style: none;
+}</pre>
+
+<h4 id="Индексный_шаблон_(шаблон_главной_страницы_сайта)">Индексный шаблон (шаблон главной страницы сайта)</h4>
+
+<p>Создайте файл HTML <strong>/locallibrary/catalog/templates/<em>index.html</em></strong> и скопируйте в него код, указанный ниже. Как вы наверное заметили, в первой строке мы расширяем наш базовый шаблон, а затем замещаем содержимое блока <code>content</code>, базового шаблона, новым содержимым текущего шаблона.</p>
+
+<pre class="brush: html">{% extends "base_generic.html" %}
+
+{% block content %}
+&lt;h1&gt;Local Library Home&lt;/h1&gt;
+
+ &lt;p&gt;Welcome to &lt;em&gt;LocalLibrary&lt;/em&gt;, a very basic Django website developed as a tutorial example on the Mozilla Developer Network.&lt;/p&gt;
+
+&lt;h2&gt;Dynamic content&lt;/h2&gt;
+
+ &lt;p&gt;The library has the following record counts:&lt;/p&gt;
+ &lt;ul&gt;
+ &lt;li&gt;&lt;strong&gt;Books:&lt;/strong&gt; <strong>\{{ num_books }}</strong>&lt;/li&gt;
+ &lt;li&gt;&lt;strong&gt;Copies:&lt;/strong&gt; <strong>\{{ num_instances }}</strong>&lt;/li&gt;
+ &lt;li&gt;&lt;strong&gt;Copies available:&lt;/strong&gt; <strong>\{{ num_instances_available }}</strong>&lt;/li&gt;
+ &lt;li&gt;&lt;strong&gt;Authors:&lt;/strong&gt; <strong>\{{ num_authors }}</strong>&lt;/li&gt;
+ &lt;/ul&gt;
+
+{% endblock %}</pre>
+
+<p>В данном фрагменте, в разделе <em>Динамическое содержимое, </em>мы объявили метки (<em>шаблонные переменные</em>) для информации, которую мы получаем из соответствующего отображения.  Данные переменные объявляются при помощи "двойных фигурных скобок" (в предыдущем фрагменте выделено жирным).</p>
+
+<div class="note">
+<p><strong>Примечание:</strong> Переменные шаблона заключаются в двойные фигурные скобки (<code>\{{ num_books }}</code>) , а тэги шаблона (функции шаблона), помещаются в одинарные фигурные скобки со знаками процента (<code>{% extends "base_generic.html" %}</code>).</p>
+</div>
+
+<p>Важно отметить, что данные переменные имеют имена, соответствующие именам передаваемых <em>ключей</em> из словаря переменной <code>context</code>, которая, в свою очередь, передается из отображения, во время вызова функции <code>render()</code> (смотри ниже). При отрисовке шаблона, вместо этих ключей будут подставлены, соответствующие им, <em>значения</em>.  </p>
+
+<pre class="brush: python">return render(
+ request,
+ 'index.html',
+ context={'<strong>num_books</strong>':num_books,'<strong>num_instances</strong>':num_instances,'<strong>num_instances_available</strong>':num_instances_available,'<strong>num_authors</strong>':num_authors},
+)</pre>
+
+<h4 id="Ссылка_на_статические_файлы_их_шаблонов">Ссылка на статические файлы их шаблонов</h4>
+
+<p>Любой ваш проект с большой вероятностью будет использовать статические ресурсы, включая JavaScript, CSS и изображения. В связи с тем, что расположение этих файлов может быть неизвестно (или может измениться), Django позволяет вам в шаблоне указать относительное расположение данных файлов при помощи глобального значения <code>STATIC_URL</code> (по умолчанию, значение параметра <code>STATIC_URL</code> установлено в '<code>/static/</code>',  но вы можете выбрать любое другое значение, указав, например, сетевой ресурс, или что-то еще).</p>
+
+<p>Внутри шаблона вы  вызываете функцию (тэг) <code>load</code>, которая загружает статическую библиотеку "static" (как показано ниже). После того как статическая библиотека загружена, вы можете использовать тэг шаблона <code>static</code>, который указывает относительный путь URL к интересующему вас файлу.</p>
+
+<pre class="brush: html"> &lt;!-- Добавляем дополнительный статический CSS-файл --&gt;
+{% load static %}
+&lt;link rel="stylesheet" href="{% static 'css/styles.css' %}"&gt;</pre>
+
+<p>Тем же способом вы можете загрузить нужное изображение. Например:</p>
+
+<pre class="brush: html">{% load static %}
+&lt;img src="{% static 'catalog/images/local_library_model_uml.png' %}" alt="My image" style="width:555px;height:540px;"/&gt;
+</pre>
+
+<div class="note">
+<p><strong>Примечание</strong>: Фрагменты выше указывают пути расположения файлов, но Django не использует их по умолчанию. В процессе разработки сервер использует значения, указанные в глобальном файле URL-преобразований (<strong>/locallibrary/locallibrary/urls.py</strong>), который мы создали в части <a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">создание скелета сайта</a>. В дальнейшем, в продакшине, вам нужно будет уточнить параметры расположения статических файлов. Мы вернемся к этому позже.</p>
+</div>
+
+<p>Для получения более подробной информации о работе со статическими файлами  обратитесь к документации по ссылке <a href="https://docs.djangoproject.com/en/1.10/howto/static-files/">Управление статическими файлами</a> (Django docs).</p>
+
+<h4 id="Построение_URL-адресов">Построение URL-адресов</h4>
+
+<p>Базовый шаблон, указанный выше, вводит тэг <code>url</code>.</p>
+
+<pre class="brush: python">&lt;li&gt;&lt;a href="{% url 'index' %}"&gt;Home&lt;/a&gt;&lt;/li&gt;
+</pre>
+
+<p>Данный тэг с именем <code>url()</code>, ищет в файле <strong>urls.py</strong> связанное значение переменной, указанной в качестве ее параметра <code>'index'</code>, а затем возвращает URL, который вы можете использовать для ссылки на соответствующие ресурсы.</p>
+
+<h2 id="Как_теперь_все_это_выглядит">Как теперь все это выглядит?</h2>
+
+<p>На данный момент мы должны были сделать все что необходимо, для того, чтобы показать главную страницу нашего сайта. Запустите сервер (<code>python3 manage.py runserver</code>) и введите в ваш браузер адрес <a href="http://127.0.0.1:8000/">http://127.0.0.1:8000/</a>. Если все настроено как надо, то ваш сайт должен выглядеть как показано на следующей картинке.</p>
+
+<p><img alt="Index page for LocalLibrary website" src="https://mdn.mozillademos.org/files/14045/index_page_ok.png" style="border-style: solid; border-width: 1px; display: block; height: 356px; margin: 0px auto; width: 874px;"></p>
+
+<div class="note">
+<p><strong>Примечание:</strong> На данном этапе вы не сможете воспользоваться ссылками на страницы <strong>All books</strong> и <strong>All authors</strong>, потому что url-адреса, отображения и шаблоны для данных страниц не созданы (мы просто объявили метки для соответствующих ссылок в базовом шаблоне<code> base_generic.html</code>).</p>
+</div>
+
+<h2 id="Проверьте_себя">Проверьте себя</h2>
+
+<p>А теперь парочка заданий, чтобы проверить, насколько вы усвоили работу с запросами к моделям базы данных, взаимодействия с отображениями и шаблонами. </p>
+
+<ol>
+ <li>В главном файле шаблона (<em>base_generic.html</em>) есть блок <code>title</code>. Переопределите этот блок в индексном шаблоне (<em>index.html</em>) и задейте новый заголовок для этой страницы.</li>
+ <li>Модифицируйте функцию отображения таким образом, чтобы получать из базы данных количество жанров и количество книг, которые содержат в своих заголовках какое-либо слово (без учета регистра), а затем передайте эти значения в шаблон.</li>
+</ol>
+
+<ul>
+</ul>
+
+<h2 id="Итог">Итог</h2>
+
+<p>Мы создали домашнюю страницу для нашего сайта — HTML страница, которая показывает количество некоторых записей из базы данных и содержит ссылки на другие "все-еще-будут-созданы" страницы. Кроме того, мы изучили большое количество базовой информации об url-преобразованиях, отображениях, запросах к базе данных, используя наши модели, передачу информации из отображений в шаблоны, кроме того, создание и расширение шаблонов.</p>
+
+<p>В  следующей части, при помощи наших новых знаний, мы  создадим еще четыре страницы.</p>
+
+<h2 id="Смотрите_также">Смотрите также</h2>
+
+<ul>
+ <li><a href="https://docs.djangoproject.com/en/1.10/intro/tutorial03/">Написание вашего первого приложения Django, часть 3: Отображения и Шаблоны</a>  (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/topics/http/urls/">URL-диспетчер</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/topics/http/views/">Функции отображения</a> (DJango docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/topics/templates/">Шаблоны</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/howto/static-files/">Управление статическими файлами</a> (Django docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/topics/http/shortcuts/#django.shortcuts.render">Удобные (встроенные) функции Django</a> (Django docs)</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django")}}</p>
diff --git a/files/ru/learn/server-side/django/index.html b/files/ru/learn/server-side/django/index.html
new file mode 100644
index 0000000000..7e167477b1
--- /dev/null
+++ b/files/ru/learn/server-side/django/index.html
@@ -0,0 +1,66 @@
+---
+title: Веб-фреймворк Django (Python)
+slug: Learn/Server-side/Django
+tags:
+ - back-end программирование
+ - Введение
+ - Джанго
+ - Изучать
+ - Начинающим
+translation_of: Learn/Server-side/Django
+---
+<div>{{LearnSidebar}}</div>
+
+<p>Django является чрезвычайно популярным и полнофункциональным серверным веб-фреймворком, написанным на Python. Данный модуль расскажет о том, почему Django один из самых популярных серверных веб-фреймворков, как установить среду разработки, и как начать использовать его для создания собственных веб-приложений.</p>
+
+<h2 id="Требования">Требования</h2>
+
+<p>Перед началом работы с этим модулем вам не обязательно уже быть знакомым с Django. Вам бы пригодилось общее понимание того, что такое серверное веб-программирование и веб-фреймворки, почерпнутое, в идеале, из топиков другого нашего модуля <a href="./First_steps">Первые шаги серверного программирования вебсайтов</a>.</p>
+
+<p>Рекомендуется базовое понимание концепций программирования и языка Python, но это не обязательно для освоения основных понятий.</p>
+
+<div class="note">
+<p><strong>Примечание</strong>: Python является одним из самых доступных в чтении и понимании для новичков языком программирования. Тем не менее, если вы захотите глубже понять этот модуль, в Интернете сейчас доступны многочисленные бесплатные книги и учебные пособия (новички в программирование возможно захотят посетить <a href="https://wiki.python.org/moin/BeginnersGuide/NonProgrammers">Python for Non Programmers</a> на вики-страницах python.org).</p>
+</div>
+
+<h2 id="Руководство">Руководство</h2>
+
+<dl>
+ <dt><a href="/ru/docs/Learn/Server-side/Django/Introduction">Введение в Django</a></dt>
+ <dd>В этой первой статье по Django мы ответим на вопрос "Что такое Django?" и сделаем обзор того, что делает этот веб-фреймворк особенным. Мы кратко рассмотрим основные особенности, включая некоторый продвинутый функционал, на котором у нас не будет возможности подробно остановиться в этом модуле. Мы также покажем вам некоторые из основных строительных блоков приложения Django, чтобы дать вам представление о том, что он может сделать, прежде чем вы перейдете к установке и начнете экспериментировать.</dd>
+ <dt><a href="/ru/docs/Learn/Server-side/Django/development_environment">Установка среды разработки Django</a></dt>
+ <dd>Теперь, когда вы знаете, что такое Django, мы покажем вам, как установить и протестировать среду разработки Django для Windows, Linux (Ubuntu) и Mac OS X — какую бы операционную систему вы не использовали, эта статья должна дать вам понимание того, что вам потребуется, чтобы начать разработку Django-приложений .</dd>
+ <dt><a href="/ru/docs/Learn/Server-side/Django/Tutorial_local_library_website">Учебник Django: Веб-сайт местной библиотеки</a></dt>
+ <dd>Первая статья в нашей серии практических уроков объясняет, что вы узнаете, и представит обзор веб-сайта «местной библиотеки», над которым мы будем работать и развиваться в последующих статьях.</dd>
+ <dt><a href="/ru/docs/Learn/Server-side/Django/skeleton_website">Учебник Django часть 2: Создание скелета веб-сайта</a></dt>
+ <dd>В этой статье показано, как вы можете создать проект  веб-сайта «каркас» в качестве основы, после чего вы сможете заполнить параметры сайта, urls, модели, представления и шаблоны.</dd>
+ <dt><a href="/ru/docs/Learn/Server-side/Django/Models">Учебник Django часть 3: Использование моделей</a></dt>
+ <dd>В этой статье показано, как определить модели для сайта местной библиотеки — модели представляют структуры данных, в которых мы хотим хранить данные нашего приложения, а также позволяют Django хранить данные в базе данных для нас (и модифицировать позже). Она раскрывает, что такое модель, как она объявляется и некоторые из основных типов полей. В ней также кратко показаны некоторые из основных способов доступа к данным модели.</dd>
+ <dt><a href="/ru/docs/Learn/Server-side/Django/Admin_site">Учебник Django часть 4: Django admin веб-сайта</a></dt>
+ <dd>Теперь, когда мы создали модели для сайта местной библиотеки, мы будем использовать Django Admin, чтобы добавить данные о книгах в библиотеке. Сначала мы покажем вам, как регистрировать и администрировать модели сайта а затем мы покажем вам, как входить в систему и создавать некоторые данные. В конце мы покажем некоторые способы дальнейшего улучшения представлений сайта.</dd>
+ <dt><a href="/ru/docs/Learn/Server-side/Django/Home_page">Учебник Django часть 5: Создание главной страницы </a></dt>
+ <dd>Теперь мы готовы добавить код для отображения нашей первой полной страницы — главной страницы сайта местной библиотеки, которая показывает, сколько записей у нас есть для каждого типа модели, и предоставляет ссылки на боковых панелях на другие наши страницы. По пути мы получим практический опыт написания основных карт и представлений URL, получения записей из базы данных и использования шаблонов.</dd>
+ <dt><a href="/ru/docs/Learn/Server-side/Django/Generic_views">Учебник Django часть 6: Общий список и подробные представления</a></dt>
+ <dd>Это руководство расширяет наш сайт местной библиотеки, добавляя список и подробные страницы для книг и авторов. Здесь мы узнаем об общих представлениях на основе классов и покажем, как они могут уменьшить количество кода, который вы должны писать для случаев общего использования. Мы также перейдем к обработке URL-адресов более подробно, покажем, как выполнить базовое сопоставление шаблонов.</dd>
+ <dt><a href="/ru/docs/Learn/Server-side/Django/Sessions">Учебник Django часть 7:  Структура сессий</a></dt>
+ <dd>Это руководство расширяет наш сайт местной библиотеки, добавляя счётчик посещений домашней страницы. Это относительно простой пример, но он показывает, как вы можете использовать структуру сессии, чтобы обеспечить постоянное поведение анонимных пользователей на ваших собственных сайтах.</dd>
+ <dt><a href="/ru/docs/Learn/Server-side/Django/Authentication">Учебник Django часть 8: Авторизация и права пользователей</a></dt>
+ <dd>В этом уроке мы покажем вам, как разрешить пользователям входить на ваш сайт со своими учетными записями и как управлять тем, что они могут делать и видеть на основе того, зарегистрированы ли они или нет, и их допусках. В рамках этой демонстрации мы расширим сайт местной библиотеки, добавив страницы входа и выхода, а также страницы пользователей и персональные страницы для просмотра книг, которые были взяты на руки.</dd>
+ <dt><a href="/ru/docs/Learn/Server-side/Django/Forms">Учебник Django часть 9: Работа с формами</a></dt>
+ <dd>В этом уроке мы покажем вам, как работать с <a href="/en-US/docs/Web/Guide/HTML/Forms">HTML Forms</a> в Django, и  в частности, самый простой способ писать формы для создания, обновления и удаления экземпляров модели. В рамках этой демонстрации мы расширим сайт местной библиотеки, чтобы библиотекари могли вносить новые книги, создавать, обновлять и удалять авторов, используя наши собственные формы (а не использовать приложение администратора).</dd>
+ <dt><a href="/ru/docs/Learn/Server-side/Django/Testing">Учебник Django часть10: Тестирование веб-приложения Django</a></dt>
+ <dd>По мере роста веб-сайтов становится сложнее проверять вручную — требуется больше проверок, поскольку взаимодействие между компонентами усложняется, небольшое изменение в одной области может потребовать дополнительные тесты для проверки его влияния на другие области. Один из способов смягчить эти проблемы - написать автоматизированные тесты, которые можно легко и надежно запускать каждый раз, когда вы вносите изменения. В этом руководстве показано, как автоматизировать модульное тестирование вашего сайта с помощью тестовой среды Django.</dd>
+ <dt><a href="/ru/docs/Learn/Server-side/Django/Deployment">Учебник Django часть 11: Деплой Django на продакшн</a></dt>
+ <dd>Теперь вы создали (и протестировали) удивительный сайт местной библиотеки, вам захочется установить его на общедоступный веб-сервер, чтобы к нему мог получить доступ персонал библиотеки и пользователи Интернета. В этой статье представлен обзор того, как вы можете найти хост для развертывания вашего веб-сайта и что вам нужно сделать, чтобы подготовить ваш сайт к выпуску.</dd>
+ <dt><a href="/ru/docs/Learn/Server-side/Django/web_application_security">Безопасность веб-приложений Django</a></dt>
+ <dd>Защита пользовательских данных является неотъемлемой частью любой разработки сайта. Ранее мы объяснили некоторые из наиболее распространенных угроз безопасности в статье <a href="https://developer.mozilla.org/ru/docs/Web/Security">Web security</a> — Эта статья дает практическую демонстрацию того, как встроенные средства защиты Django справляются с такими угрозами.</dd>
+</dl>
+
+<h2 id="Задания">Задания</h2>
+
+<p>Следующее задание проверит ваше понимание того, как создать сайт с помощью Django, как описано в руководствах, перечисленных выше.</p>
+
+<dl>
+ <dt><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django мини-блог</a></dt>
+ <dd>В этом задании вы будете использовать некоторые знания, которые вы узнали из этого модуля, чтобы создать свой собственный блог.</dd>
+</dl>
diff --git a/files/ru/learn/server-side/django/models/index.html b/files/ru/learn/server-side/django/models/index.html
new file mode 100644
index 0000000000..9ed7993e0b
--- /dev/null
+++ b/files/ru/learn/server-side/django/models/index.html
@@ -0,0 +1,448 @@
+---
+title: 'Django учебник Часть 3: Использование моделей'
+slug: Learn/Server-side/Django/Models
+tags:
+ - Джанго
+ - данные
+ - модель
+ - туториал
+translation_of: Learn/Server-side/Django/Models
+---
+<div>             {{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django")}}</div>
+
+<p class="summary">В этой статье показано, как определить модели для <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> сайта. Она объясняет, что такое модель, как она объявляется, и некоторые из основных типов полей. В ней также кратко показаны некоторые из основных способов доступа к данным модели.</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Предпосылки</th>
+ <td><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a>.</td>
+ </tr>
+ <tr>
+ <th scope="row">Задача:</th>
+ <td>Научиться проектировать и создавать свои собственные модели, выбирая подходящие поля.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Обзор">Обзор</h2>
+
+<p>Веб-приложения Django получают доступ и управляют данными через объекты Python, называемые моделями. Модели определяют структуру хранимых данных, включая типы полей и, возможно, их максимальный размер, значения по умолчанию, параметры списка выбора, текст справки для документации, текст меток для форм и т. д. Определение модели не зависит от основной базы данных - вы можете выбрать один из нескольких компонентов вашей настройки проекта. После того, как вы выбрали какую базу данных хотите использовать, вам не нужно напрямую работать с ней - вы просто пишете свою структуру модели и код, а Django делает всю грязную работу, связанную с базой данных за вас.</p>
+
+<p>В этом учебнике показано, как определить и получить доступ к моделям на примере <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary website</a>.</p>
+
+<h2 id="Проектирование_моделей_LocalLibrary">Проектирование моделей LocalLibrary</h2>
+
+<p>Перед тем, как вы начнёте программировать модели, стоит потратить несколько минут, чтобы подумать о том, какие данные нам нужно хранить, и о взаимоотношениях между разными объектами.</p>
+
+<p>Мы знаем, что нам нужно хранить информацию о книгах (название, резюме, автор, язык, на котором написана книга, категория, ISBN) и что у нас может быть несколько доступных экземпляров (с уникальным глобальным идентификатором, статусом доступности и т. Д.). Нам может потребоваться хранить больше информации об авторе, чем просто их имя, и могут быть несколько авторов с одинаковыми или похожими именами. Мы хотим иметь возможность сортировать информацию на основе названия книги, автора, письменного языка и категории.</p>
+
+<p>При проектировании ваших моделей имеет смысл иметь отдельные модели для каждого «объекта» (группа связанной информации). В этом случае очевидными объектами являются книги, экземпляры книг и авторы.</p>
+
+<p>Вы также можете использовать модели для представления параметров списка выбора (например, как выпадающий список вариантов), вместо жёсткого кодирования выбора на самом веб-сайте - это рекомендуется, когда все варианты неизвестны заранее или могут измениться. Очевидные кандидаты на модели в этом случае включают жанр книги (например, «Научная фантастика», «Французская поэзия» и т. д.) И язык (английский, французский, японский).</p>
+
+<p>Как только мы определились с нашими моделями и полями, нам нужно подумать об отношениях. Django позволяет вам определять отношения, как один к одному (<code>OneToOneField</code>), один ко многим (<code>ForeignKey</code>) и многие ко многим (<code>ManyToManyField</code>).</p>
+
+<p>Диаграмма ассоциации UML, приведённая ниже показывает модели, которые мы определили в этом случае (в виде блоков). Как и выше, мы создали модели для книги (общие сведения о книге), экземпляр книги (статус конкретных физических копий книги, доступных в системе) и автора.Мы также решили создать модель для жанра, чтобы можно было создавать / выбирать значения через интерфейс администратора. Мы решили не иметь модель для BookInstance: status - мы жестко закодировали значения (LOAN_STATUS), потому что мы не ожидаем их изменения. В каждом из полей вы можете увидеть имя модели, имена и типы полей, а также методы и их типы возврата.</p>
+
+<p>На диаграмме также показаны зависимости между моделями, включая их <em>множители</em>. Множители представляют собой числа на диаграмме, показывающие минимум и максимум единиц каждой модели, которые могут присутствовать в этой связи. Например, соединительная линия между ящиками показывает, что книга и жанр связаны между собой. Цифры, близкие к модели жанра, показывают, что у книги может быть один или несколько жанров (сколько угодно), а числа на другом конце строки рядом с моделью книги показывают, что у жанра может быть ноль или более связанных книг.</p>
+
+<p><img alt="LocalLibrary Model UML - v3" src="https://mdn.mozillademos.org/files/15646/local_library_model_uml.png" style="height: 660px; width: 977px;"></p>
+
+<div class="note">
+<p>Примечание. В следующем разделе приведен базовый пример, поясняющий, как модели определяются и используются. Когда вы его прочитаете, подумайте, как мы построим каждую из моделей на диаграмме выше.</p>
+</div>
+
+<h2 id="Модель_для_начинающих">Модель для начинающих</h2>
+
+<p>В этом разделе представлен краткий обзор того, как определяется модель, и некоторые из наиболее важных полей и аргументы поля.</p>
+
+<h3 id="Определение_модели">Определение модели</h3>
+
+<p>Модели обычно определяются в приложении <strong>models.py</strong>. Они реализуются как подклассы <code>django.db.models.Model</code>, и могут включать поля, методы и метаданные. В приведенном ниже фрагменте кода показана «типичная» модель, названная <code>MyModelName</code>:</p>
+
+<pre class="notranslate">from django.db import models
+
+class MyModelName(models.Model):
+    """
+    A typical class defining a model, derived from the Model class.
+    """
+
+  # Fields
+    my_field_name = models.CharField(max_length=20, help_text="Enter field documentation")
+  ...
+
+  # Metadata
+ class Meta:
+  ordering = ["-my_field_name"]
+
+  # Methods
+    def get_absolute_url(self):
+         """
+         Returns the url to access a particular instance of MyModelName.
+         """
+         return reverse('model-detail-view', args=[str(self.id)])
+
+    def __str__(self):
+        """
+        String for representing the MyModelName object (in Admin site etc.)
+        """
+        return self.field_name</pre>
+
+<p>В следующих разделах мы подробно рассмотрим каждый элемент внутри модели:</p>
+
+<h4 id="Поля">Поля</h4>
+
+<p>Модель может иметь произвольное количество полей любого типа - каждый представляет столбец данных, который мы хотим сохранить в одной из наших таблиц базы данных. Каждая запись (строка) базы данных будет состоять из одного значения каждого поля. Давайте рассмотрим приведенный выше пример:</p>
+
+<pre class="brush: js notranslate">my_field_name = models.CharField(max_length=20, help_text="Enter field documentation")</pre>
+
+<p>Наш вышеприведенный пример имеет одно поле, называемое my_<code>field_name</code>, типа <code>models.CharField</code> — что означает, что это поле будет содержать строки буквенно-цифровых символов. Типы полей назначаются с использованием определенных классов, которые определяют тип записи, которая используется для хранения данных в базе данных, а также критерии проверки, которые должны использоваться, когда значения получены из формы HTML (то есть, что составляет действительное значение). Типы полей также могут принимать аргументы, которые дополнительно определяют, как поле хранится или может использоваться. В этом случае мы даем нашему полю два аргумента:</p>
+
+<ul>
+ <li><code>max_length=20</code> — Указывает, что максимальная длина значения в этом поле составляет 20 символов.</li>
+ <li><code>help_text="Enter field documentation"</code> — предоставляет текстовую метку для отображения, чтобы помочь пользователям узнать, какое значение необходимо предоставить, когда это значение должно быть введено пользователем через HTML-форму.</li>
+</ul>
+
+<p>Имя поля используется для обращения к нему в запросах и шаблонах. В полях также есть метка, которая задается как аргумент (verbose_name), либо выводится путем заглавной буквы первой буквы имени переменной поля и замены любых символов подчеркивания пробелом (например, my_field_name будет иметь метку по умолчанию <em>My field name</em>).</p>
+
+<p>Порядок, в котором объявляются поля, будет влиять на их порядок по умолчанию, если модель отображается в форме (например, на сайте администратора), хотя это может быть переопределено.</p>
+
+<h5 id="Общие_аргументы_поля">Общие аргументы поля</h5>
+
+<p>Следующие общие аргументы могут использоваться при объявлении многих / разных типов полей:</p>
+
+<ul>
+ <li><a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#help-text">help_text</a>: Предоставляет текстовую метку для HTML-форм (например, на сайте администратора), как описано выше.</li>
+ <li><a href="https://docs.djangoproject.com/en/2.1/ref/models/fields/#verbose-name">verbose_name</a>: Удобо-читаемое имя для поля, используемого в поле метки. Если не указано, Django выведет по умолчанию подробное название от имени поля.</li>
+ <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#default">default</a>: Значение по умолчанию для поля. Это может быть значение или вызываемый объект, и в этом случае объект будет вызываться каждый раз, когда создается новая запись.</li>
+ <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#null">null</a>: Если True, Django будет хранить пустые значения как NULL в базе данных для полей, где это уместно (CharField вместо этого сохранит пустую строку). По умолчанию используется значение False.</li>
+ <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#blank">blank</a>: Если True, поле может быть пустым в ваших формах. По умолчанию используется значение False, что означает, что проверка формы Django заставит вас ввести значение. Это часто используется с null = True, потому что если вы хотите разрешить пустые значения, вы также хотите, чтобы база данных могла представлять их соответствующим образом.</li>
+ <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#choices">choices</a>: Группа вариантов для этого поля. Если это предусмотрено, по умолчанию соответствующий виджет формы будет полем выбора с этими вариантами вместо стандартного текстового поля.</li>
+ <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#primary-key">primary_key</a>: Если True, задает текущее поле в качестве первичного ключа для модели (первичный ключ - это специальный столбец базы данных, предназначенный для однозначной идентификации всех разных записей таблицы). Если в качестве первичного ключа не указано поле, Django автоматически добавит для этой цели поле.</li>
+</ul>
+
+<p>Есть много других вариантов - вы можете просмотреть <a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/">full list of field options here</a>.</p>
+
+<h5 id="Общие_типы_полей">Общие типы полей</h5>
+
+<p>Следующие общие аргументы могут использоваться при объявлении многих / разных типов полей:</p>
+
+<ul>
+ <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.CharField">CharField</a> Используется для определения строк фиксированной длины от короткой до средней. Вы должны указать max_length для хранения данных.</li>
+ <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.TextField">TextField</a> используется для больших строк произвольной длины. Вы можете указать <code>max_length</code> для поля, но это используется только тогда, когда поле отображается в формах (оно не применяется на уровне базы данных).</li>
+ <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.IntegerField" title="django.db.models.IntegerField">IntegerField</a> это поле для хранения значений (целого числа) и для проверки введенных значений в виде целых чисел в формах.</li>
+ <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.DateField">DateField</a> и <a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.DateTimeField">DateTimeField</a> используются для хранения / представления дат и информации о дате / времени (как Python datetime.date и datetime.datetime, соответственно). Эти поля могут дополнительно объявлять (взаимоисключающие) параметры <code>auto_now=True</code> (для установки поля на текущую дату каждый раз, когда модель сохраняется), auto_now_add (только для установки даты, когда модель была впервые создана) и по умолчанию (чтобы установить дату по умолчанию, которую пользователь может переустановить).</li>
+ <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.EmailField">EmailField</a> используется для хранения и проверки адресов электронной почты.</li>
+ <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.FileField">FileField</a> и <a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.ImageField">ImageField</a> используются для загрузки файлов и изображений соответственно ( <code>ImageField</code> просто добавляет дополнительную проверку, что загруженный файл является изображением). Они имеют параметры для определения того, как и где хранятся загруженные файлы.</li>
+ <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.AutoField">AutoField</a> - это особый тип IntegerField, который автоматически увеличивается. Первичный ключ этого типа автоматически добавляется в вашу модель, если вы явно не укажете его.</li>
+ <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.ForeignKey">ForeignKey</a> Используется для указания отношения «один ко многим» к другой модели базы данных (например, автомобиль имеет одного производителя, но производитель может делать много автомобилей). «Одна» сторона отношения - это модель, содержащая ключ.</li>
+ <li><a href="https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.ManyToManyField">ManyToManyField</a> используется для определения отношения «многие ко многим» (например, книга может иметь несколько жанров, и каждый жанр может содержать несколько книг). В нашем приложении для библиотек мы будем использовать их аналогично ForeignKeys, но их можно использовать более сложными способами для описания отношений между группами. Они имеют параметр on_delete, чтобы определить, что происходит, когда связанная запись удаляется (например, значение <code>models.SET_NULL</code> просто установило бы значение NULL)</li>
+</ul>
+
+<p>Существует много других типов полей, включая поля для разных типов чисел (большие целые числа, малые целые числа, дробные), логические значения, URL-адреса, slugs, уникальные идентификаторы и другие «связанные с временем» сведения (продолжительность, время и т. д.). Вы можете просмотреть <a href="https://docs.djangoproject.com/en/1.10/ref/models/fields/#field-types">full list here</a>.</p>
+
+<h4 id="Метаданные">Метаданные</h4>
+
+<p>Вы можете объявить метаданные на уровне модели для своей модели, объявив класс Meta, как показано на рисунке.</p>
+
+<pre class="brush: python notranslate">class Meta:
+ ordering = ["-my_field_name"]
+  ...</pre>
+
+<p>Одной из наиболее полезных функций этих метаданных является управление сотрировкой записей, возвращаемых при запросе типа модели. Вы можете сделать это, указав соответствия названия полей для сортировки, как показано выше. Порядок будет зависеть от типа поля (поля символов отсортированы в алфавитном порядке, а поля даты отсортированы в хронологическом порядке). Как показано выше, вы можете префикс имени поля минус-символом (-), чтобы изменить порядок сортировки.</p>
+
+<p>Например, если мы решили сортировать книги по умолчанию:</p>
+
+<pre class="brush: python notranslate">ordering = ["title", "-pubdate"]</pre>
+
+<p>Книги будут отсортированы по алфавиту по названию, от A-Z, а затем по дате публикации внутри каждого названия, от самого нового до самого старого.</p>
+
+<p>Другим распространенным атрибутом является verbose_name, подробное имя для класса в единственной и множественной форме:</p>
+
+<pre class="brush: python notranslate">verbose_name = "BetterName"</pre>
+
+<p>Другие полезные атрибуты позволяют создавать и применять новые «разрешения доступа» для модели (разрешения по умолчанию применяются автоматически), разрешить упорядочение на основе другого поля или объявить, что класс является «абстрактным» (базовый класс, для которого вы не можете создавать записи, и вместо этого будет создан для создания других моделей). Многие другие параметры метаданных управляют тем, какая база данных должна использоваться для модели и как хранятся данные (это действительно полезно, если вам нужно сопоставить модель с существующей базой данных). Полный список опций метаданных доступен здесь: <a href="https://docs.djangoproject.com/en/2.2/ref/models/options/#model-meta-options">Model metadata options</a> (Django документация).</p>
+
+<h4 id="Методы">Методы</h4>
+
+<p>Модель также может иметь методы. Минимально в каждой модели вы должны определить стандартный метод класса для Python __str __ (), чтобы вернуть удобочитаемую строку для каждого объекта. Эта строка используется для представления отдельных записей на сайте администрирования (и в любом другом месте, где вам нужно обратиться к экземпляру модели). Часто это возвращает поле названия или имени из модели.</p>
+
+<pre class="brush: python notranslate">def __str__(self):
+  return self.field_name</pre>
+
+<p>Другим распространенным методом включения в модели Django является get_absolute_url (), который возвращает URL-адрес для отображения отдельных записей модели на веб-сайте (если вы определяете этот метод, тогда Django автоматически добавит кнопку «Просмотр на сайте» на экранах редактирования записей модели на сайте администратора). Типичный шаблон для get_absolute_url () показан ниже.</p>
+
+<pre class="brush: python notranslate">def get_absolute_url(self):
+ """
+ Returns the url to access a particular instance of the model.
+ """
+ return reverse('model-detail-view', args=[str(self.id)])
+</pre>
+
+<div class="note">
+<p>Примечание. Предполагется, что вы будете использовать URL-адреса, например / myapplication / mymodelname / 2, для отображения отдельных записей для вашей модели (где «2» - это идентификатор для определенной записи), вам нужно будет создать URL-карту, чтобы передать ответ и идентификатор «Образцовое представление модели» (которое будет выполнять работу, необходимую для отображения записи). Вышеуказанная функция reverse () может «перевернуть» ваш URL-адрес (в приведенном выше примере с именем «model-detail-view»), чтобы создать URL-адрес правильного формата.</p>
+
+<p>Конечно, для выполнения этой работы вам все равно придется писать сопоставление URL-адрес, просмотр и шаблон!</p>
+</div>
+
+<p>Вы также можете определить любые другие методы, которые вам нравятся, и вызывать их из вашего кода или шаблонов (при условии, что они не принимают никаких параметров).</p>
+
+<h3 id="Управление_моделью">Управление моделью</h3>
+
+<p>После того, как вы определили свои классы моделей, вы можете использовать их для создания, обновления или удаления записей и для запуска запросов для получения всех записей или отдельных подмножеств записей. Мы покажем вам, как это сделать в учебнике, когда мы определяем наши представления, с кратким обзором.</p>
+
+<h4 id="Создание_и_изменение_записей">Создание и изменение записей</h4>
+
+<p>Чтобы создать запись, вы можете определить экземпляр модели, а затем вызвать метод save ().</p>
+
+<pre class="brush: python notranslate"># Create a new record using the model's constructor.
+a_record = MyModelName(my_field_name="Instance #1")
+
+# Save the object into the database.
+a_record.save()
+</pre>
+
+<div class="note">
+<p>Примечание. Если вы не указали какое-либо поле в качестве primary_key, новая запись будет выдаваться автоматически, с идентификатором имени поля. Вы можете запросить это поле после сохранения указанной выше записи, и оно будет иметь значение 1.</p>
+</div>
+
+<p>Вы можете получить доступ к полям в этой новой записи с использованием синтаксиса точек и изменить значения. Вы должны вызвать save (), чтобы сохранить измененные значения в базе данных.</p>
+
+<pre class="brush: python notranslate"># Access model field values using Python attributes.
+print(a_record.id) #should return 1 for the first record.
+print(a_record.my_field_name) # should print 'Instance #1'
+
+# Change record by modifying the fields, then calling save().
+a_record.my_field_name="New Instance Name"
+a_record.save()</pre>
+
+<h4 id="Поиск_записей">Поиск записей</h4>
+
+<p>Вы можете искать записи, соответствующие определенным критериям, используя атрибут объектов модели (предоставляемый базовым классом).</p>
+
+<div class="note">
+<p>Примечание. Объяснение того, как искать записи, используя «абстрактную» модель и имена полей, может быть немного запутанным. В приведенном ниже обсуждении мы будем ссылаться на модель книги с полями названия и жанра, где жанр также является моделью с единственным именем в поле.</p>
+</div>
+
+<p>Мы можем получить все записи для модели как объект QuerySet,  используя <code>objects.all()</code>. QuerySet - это итерируемый объект, означающий, что он содержит несколько объектов, которые мы можем перебирать / прокручивать.</p>
+
+<pre class="brush: python notranslate">all_books = Book.objects.all()
+</pre>
+
+<p>Метод <code>filter()</code> Django позволяет отфильтровать возвращаемый <code>QuerySet</code> для соответствия указанному текстовому или числовому полю по конкретным критериям. Например, чтобы отфильтровать книги, содержащие  слово «wild» («дикие») в заголовке, а затем подсчитать их, мы могли бы сделать следующее.</p>
+
+<pre class="brush: python notranslate">wild_books = Book.objects.filter(title__contains='wild')
+number_wild_books = Book.objects.filter(title__contains='wild').count()
+</pre>
+
+<p>Соответствующие поля и тип соответствия определяются в имени параметра фильтра, используя формат: <code>field_name__match_type </code>(обратите внимание на двойное подчеркивание между заголовком выше). Выше мы фильтруем заголовок с учетом регистра. Есть много других типов совпадений, которые вы можете сделать: <code>icontains</code> (без учета регистра), <code>iexact </code>(точное совпадение без учета регистра), <code>exact </code>(точное совпадение с учетом регистра ) и <code>in</code>, <code>gt </code>(больше), <code>startswith</code> и т. д <a href="https://docs.djangoproject.com/en/2.2/ref/models/querysets/#field-lookups">смотреть полный список </a>(Django Docs, [EN]).</p>
+
+<p>В некоторых случаях вам нужно будет фильтровать поле, которое определяет отношение «один ко многим» к другой модели (например, <code>ForeignKey</code>). В этом случае вы можете «индексировать» поля в связанной модели с дополнительными двойными подчеркиваниями. Так, например, чтобы фильтровать книги с определенным жанровым рисунком, вам нужно будет указывать имя в поле жанра, как показано ниже:</p>
+
+<pre class="brush: python notranslate">books_containing_genre = Book.objects.filter(genre<strong>__</strong>name<strong>__</strong>icontains='fiction') # Will match on: Fiction, Science fiction, non-fiction etc.
+</pre>
+
+<div class="note">
+<p><strong>Примечание:</strong> Вы можете использовать символы подчеркивания (__) для навигации по многим уровням отношений (ForeignKey / ManyToManyField) по своему усмотрению. Например, книга, имеющая разные типы, определяемая с использованием дополнительной связи «обложка», может иметь имя параметра: type__cover__name__exact = 'hard'.</p>
+</div>
+
+<p>Существует гораздо больше возможностей для запросов, включая обратные поиски от связанных моделей, цепочки фильтров, возврат меньшего набора значений и т. д. Для получения дополнительной информации см. <a href="https://docs.djangoproject.com/en/2.2/topics/db/queries/">Making queries</a> (Django Docs, [EN]).</p>
+
+<h2 id="Определение_моделей_LocalLibrary">Определение моделей LocalLibrary</h2>
+
+<p>В этом разделе мы начнем определять модели для библиотеки. Откройте <em>models.py (в / locallibrary / catalog /)</em>. Шаблон в верхней части страницы импортирует модуль моделей, который содержит базовый класс модели <code>models.Model</code>, от которого наследуются наши модели.</p>
+
+<pre class="brush: python notranslate">from django.db import models
+
+# Create your models here.</pre>
+
+<h3 id="Модель_жанра">Модель жанра</h3>
+
+<p>Скопируйте приведенный ниже код модели <code>Genre </code>и вставьте его в нижнюю часть вашего файла <code>models.py</code>. Эта модель используется для хранения информации о категории книг - например, будь то художественная или документальная, роман или военно-историческая и т. д. Как уже упоминалось выше, мы создали жанр как модель, а не как свободный текст или список выбора, чтобы возможные значения могли управляться через базу данных, а не были закодированными.</p>
+
+<pre class="brush: python notranslate">class Genre(models.Model):
+    """
+    Model representing a book genre (e.g. Science Fiction, Non Fiction).
+    """
+    name = models.CharField(max_length=200, help_text="Enter a book genre (e.g. Science Fiction, French Poetry etc.)")
+
+    def __str__(self):
+        """
+        String for representing the Model object (in Admin site etc.)
+        """
+        return self.name</pre>
+
+<p>Модель имеет один <code>CharField</code> field (имя), которое используется для описания жанра (оно ограничено 200 символами и имеет некоторый <code>help_text</code>. В конце модели мы объявляем метод <code>__str__()</code>, который просто возвращает имя жанра, определенного конкретной записью. Verbose name не был определен, поэтому поле будет называться <code>Name</code> в формах.</p>
+
+<h3 id="Модель_книги">Модель книги</h3>
+
+<p>Скопируйте модель книги ниже и снова вставьте ее в нижнюю часть файла. Модель книги представляет всю информацию о доступной книге в общем смысле, но не конкретный физический «экземпляр» или «копию» для временного использования. Модель использует CharField для представления названия книги и isbn (обратите внимание, как isbn указывает свой ярлык как «ISBN», используя первый неименованный параметр, поскольку в противном случае ярлык по умолчанию был бы «Isbn»). Модель использует TextField для summary, потому что этот текст, возможно, должен быть очень длинным.</p>
+
+<pre class="brush: python notranslate">from django.urls import reverse #Used to generate URLs by reversing the URL patterns
+
+class Book(models.Model):
+    """
+    Model representing a book (but not a specific copy of a book).
+    """
+    title = models.CharField(max_length=200)
+    author = models.ForeignKey('Author', on_delete=models.SET_NULL, null=True)
+    # Foreign Key used because book can only have one author, but authors can have multiple books
+    # Author as a string rather than object because it hasn't been declared yet in the file.
+    summary = models.TextField(max_length=1000, help_text="Enter a brief description of the book")
+    isbn = models.CharField('ISBN',max_length=13, help_text='13 Character &lt;a href="https://www.isbn-international.org/content/what-isbn"&gt;ISBN number&lt;/a&gt;')
+    genre = models.ManyToManyField(Genre, help_text="Select a genre for this book")
+    # ManyToManyField used because genre can contain many books. Books can cover many genres.
+    # Genre class has already been defined so we can specify the object above.
+
+    def __str__(self):
+        """
+        String for representing the Model object.
+        """
+        return self.title
+
+
+    def get_absolute_url(self):
+        """
+        Returns the url to access a particular book instance.
+        """
+        return reverse('book-detail', args=[str(self.id)])
+</pre>
+
+<p>Жанр представляет из себя ManyToManyField, так что книга может иметь несколько жанров, а жанр может иметь много книг. Автор объявляется через ForeignKey, поэтому в каждой книге будет только один автор, но у автора может быть много книг (на практике книга может иметь несколько авторов, но не в такой реализации!)</p>
+
+<p>В обоих типах полей соответствующий класс модели объявляется как первый неименованный параметр, используя либо класс модели, либо строку, содержащую имя соответствующей модели. Вы должны использовать имя модели как строку, если связанный класс еще не был определен в этом файле до того, как он будет указан! Другими параметрами, представляющими интерес для поля автора, являются <code>null=True</code>, которое позволяет базе данных хранить значение <code>Null</code> , если автор не выбран, и on_delete = models. <code>SET_NULL </code>установит значение автора в Null, если связанная с автором запись будет удалена.</p>
+
+<p>Модель также определяет __str __ (), используя поле заголовка книги для представления книги. Окончательный метод get_absolute_url () возвращает URL-адрес, который можно использовать для доступа к подробной записи для этой модели (для этого нам нужно будет определить сопоставление URL-адресов, в котором содержится подробная информация о книге, и определить связанное представление и шаблон ).</p>
+
+<h3 id="Модель_BookInstance">Модель BookInstance</h3>
+
+<p>Затем скопируйте модель BookInstance (показано ниже) под другие модели. BookInstance представляет собой определенную копию книги, которую кто-то может брать взаймы, и включает информацию о том, доступна ли копия или в какой день она ожидается, «отпечаток» или сведения о версии, а также уникальный идентификатор книги в библиотеке. Теперь некоторые из полей и методов будут знакомы. Модель использует</p>
+
+<ul>
+ <li>ForeignKey для идентификации связанной книги (в каждой книге может быть много копий, но в копии может быть только одна книга).</li>
+ <li>CharField, для представления данных (конкретного выпуска) о книге.</li>
+</ul>
+
+<pre class="brush: python notranslate">import uuid # Required for unique book instances
+
+class BookInstance(models.Model):
+ """
+ Model representing a specific copy of a book (i.e. that can be borrowed from the library).
+ """
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, help_text="Unique ID for this particular book across whole library")
+ book = models.ForeignKey('Book', on_delete=models.SET_NULL, null=True)
+ imprint = models.CharField(max_length=200)
+ due_back = models.DateField(null=True, blank=True)
+
+ LOAN_STATUS = (
+ ('m', 'Maintenance'),
+ ('o', 'On loan'),
+ ('a', 'Available'),
+ ('r', 'Reserved'),
+ )
+
+ status = models.CharField(max_length=1, choices=LOAN_STATUS, blank=True, default='m', help_text='Book availability')
+
+ class Meta:
+ ordering = ["due_back"]
+
+
+ def __str__(self):
+ """
+ String for representing the Model object
+ """
+ return '%s (%s)' % (self.id,self.book.title)</pre>
+
+<p>Мы дополнительно объявляем несколько новых типов полей:</p>
+
+<ul>
+ <li><code>UUIDField</code> используется для поля id, чтобы установить его как primary_key для этой модели. Этот тип поля выделяет глобальное уникальное значение для каждого экземпляра (по одному для каждой книги, которую вы можете найти в библиотеке).</li>
+ <li><code>DateField</code> используется для данных due_back (при которых ожидается, что книга появится после заимствования или обслуживания). Это значение может быть blank или null (необходимо, когда книга доступна). Метаданные модели (Class Meta) используют это поле для упорядочивания записей, когда они возвращаются в запросе.</li>
+ <li>status - это CharField, который определяет список choice/selection. Как вы можете видеть, мы определяем кортеж, содержащий кортежи пар ключ-значение и передаем его аргументу выбора. Значение в key/value паре - это отображаемое значение, которое пользователь может выбрать, а ключи - это значения, которые фактически сохраняются, если выбрана опция. Мы также установили значение по умолчанию «m» (техническое обслуживание), поскольку книги изначально будут созданы недоступными до того, как они будут храниться на полках.</li>
+</ul>
+
+<p>Модель __str __ () представляет объект BookInstance, используя комбинацию его уникального идентификатора и связанного с ним заголовка книги.</p>
+
+<div class="note">
+<p>Примечание. Немного Python'а:</p>
+
+<ul>
+ <li>Значение, возвращаемое __str __ (), является форматированной строкой. В строке мы используем % S для объявления 'placeholders'. После строки укажем %, а затем кортеж, содержащий значения, которые будут вставлены в заполнители. Если у вас просто один заполнитель, вы можете опустить кортеж - например, 'Мое значение:% S' % переменная.<br>
+ <br>
+ Обратите также внимание на то, что, хотя этот подход совершенно применим, но он более не является предпочтительным. Начиная с Python 3, вы должны использовать метод format, например. '{0} ({1})'.format (self.id, self.book.title). Вы можете узнать больше об этом  <a href="https://www.python.org/dev/peps/pep-3101/">здесь</a>.</li>
+</ul>
+</div>
+
+<h3 id="Модель_автора">Модель автора</h3>
+
+<p>Скопируйте модель автора (показано ниже) под существующим кодом в models.py.</p>
+
+<p>Теперь все поля/методы должны быть знакомы. Модель определяет автора как имя, фамилию, дату рождения и (необязательную) дату смерти. Он указывает, что по умолчанию __str __ () возвращает имя в фамилии, порядковый номер первого имени. Метод get_absolute_url () отменяет сопоставление URL-адреса автора с целью получения URL-адреса для отображения отдельного автора.</p>
+
+<pre class="brush: python notranslate">class Author(models.Model):
+    """
+    Model representing an author.
+    """
+    first_name = models.CharField(max_length=100)
+    last_name = models.CharField(max_length=100)
+    date_of_birth = models.DateField(null=True, blank=True)
+    date_of_death = models.DateField('Died', null=True, blank=True)
+
+    def get_absolute_url(self):
+        """
+        Returns the url to access a particular author instance.
+        """
+        return reverse('author-detail', args=[str(self.id)])
+
+
+    def __str__(self):
+        """
+        String for representing the Model object.
+        """
+        return '%s, %s' % (self.last_name, self.first_name)
+</pre>
+
+<h2 id="Повторно_выполнить_миграцию_базы_данных">Повторно выполнить миграцию базы данных</h2>
+
+<p>Теперь все ваши модели созданы. Теперь переустановите миграцию базы данных, чтобы добавить их в свою базу данных.</p>
+
+<pre class="notranslate"><code>python3 manage.py makemigrations
+python3 manage.py migrate</code></pre>
+
+<h2 id="Языковая_модель_-_вызов">Языковая модель - вызов</h2>
+
+<p>Представьте себе, что местный благотворитель жертвует ряд новых книг, написанных на другом языке (скажем, фарси). Задача состоит в том, чтобы определить, как они будут лучше всего представлены на нашем веб-сайте библиотеки, а затем добавить их в модели.</p>
+
+<p>Некоторые вещи, которые следует учитывать:</p>
+
+<ul>
+ <li>Должен ли «язык» ассоциироваться с Book, BookInstance или каким-либо другим объектом?</li>
+ <li>Должны ли быть представлены разные языки с использованием модели, свободного текстового поля или жестко запрограммированного списка выбора?</li>
+</ul>
+
+<p>После того, как вы решили, добавьте поле. Вы можете увидеть наше решение на Github <a href="https://github.com/mdn/django-locallibrary-tutorial/blob/master/catalog/models.py">here</a>.</p>
+
+<ul>
+</ul>
+
+<ul>
+</ul>
+
+<h2 id="Резюме">Резюме</h2>
+
+<p>В этой статье мы узнали, как определять модели, а затем использовать эту информацию в разработке и внедрении соответствующих моделей для сайта LocalLibrary.</p>
+
+<p>На этом этапе мы отвлечемся от создания сайта и проверим <em>Django Administration site</em>. Этот сайт позволит нам добавить некоторые данные в библиотеку, которые мы можем отобразить с помощью наших (еще не созданных) представлений и шаблонов.</p>
+
+<h2 id="Смотрите_также">Смотрите также</h2>
+
+<ul>
+ <li><a href="https://docs.djangoproject.com/en/1.10/intro/tutorial02/">Writing your first Django app, part 2</a> (Django Docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/topics/db/queries/">Making queries</a> (Django Docs)</li>
+ <li><a href="https://docs.djangoproject.com/en/1.10/ref/models/querysets/">QuerySet API Reference</a> (Django Docs)</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django")}}</p>
diff --git a/files/ru/learn/server-side/django/skeleton_website/index.html b/files/ru/learn/server-side/django/skeleton_website/index.html
new file mode 100644
index 0000000000..48dda2c3b8
--- /dev/null
+++ b/files/ru/learn/server-side/django/skeleton_website/index.html
@@ -0,0 +1,357 @@
+---
+title: 'Руководство по Django часть 2: создание скелета'
+slug: Learn/Server-side/Django/skeleton_website
+tags:
+ - django
+ - Введение
+ - Для новичков
+ - Программирование
+ - Руководство
+ - Статья
+translation_of: Learn/Server-side/Django/skeleton_website
+---
+<div>{{PreviousMenuNext("Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django/Models", "Learn/Server-side/Django")}}</div>
+
+<p class="summary">Это вторая статья из нашего <a href="/ru/docs/Learn/Server-side/Django/Tutorial_local_library_website">руководства по Django</a>, которая показывает, как можно создать "скелет" сайта, как фундамент, на котором можно строить всё остальное: настройки, ссылки, модели, контроллеры и представления.</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">Необходимо:</th>
+ <td>
+ <p><a href="/ru/docs/Learn/Server-side/Django/development_environment">Настройка окружения</a>. Прочитать первую статью <a href="/ru/docs/Learn/Server-side/Django/Tutorial_local_library_website">руководства по Django</a>.</p>
+ </td>
+ </tr>
+ <tr>
+ <th scope="row">Цель:</th>
+ <td>Научиться использовать инструменты Django для создания новых веб-сайтов.</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Обзор">Обзор</h2>
+
+<p>Эта статья показывает, как можно создать "скелет"(прототип) сайта, который затем можно расширить при помощи различных настроек, url адресов, моделей, представлений, и шаблонов (эти темы будут объясняться в последующих статьях).</p>
+
+<p>Алгоритм следующий:</p>
+
+<ol>
+ <li><span style="line-height: 1.5;">Использовать </span><code style="font-style: normal; font-weight: normal; line-height: 1.5;">django-admin</code><span style="line-height: 1.5;"> для создания папки проекта, шаблонов остальных файлов, и скрипта для управления проектом (</span><strong style="line-height: 1.5;">manage.py</strong><span style="line-height: 1.5;">).</span></li>
+ <li><span style="line-height: 1.5;">Использовать </span><strong style="line-height: 1.5;">manage.py</strong><span style="line-height: 1.5;"><em> </em>для создания одного или нескольких <em>приложений</em></span><span style="line-height: 1.5;">.</span>
+ <div class="note">
+ <p><strong>Заметка: </strong>Сайт может состоять из одной или нескольких различных частей, например: основная часть, блог, вики, раздел загрузок, и так далее. Философия Django подталкивает разработчиков создавать эти части, как разные <strong>приложения</strong>, которые, если понадобится, могут быть использованы повторно в других проектах. </p>
+ </div>
+ </li>
+ <li><span style="line-height: 1.5;">Зарегистрировать в настройках эти приложения, чтобы использовать их в проекте. </span></li>
+ <li><span style="line-height: 1.5;">Настроить маршруты url адресов для каждого из приложений.</span></li>
+</ol>
+
+<p>Для <a href="/ru/docs/Learn/Server-side/Django/Tutorial_local_library_website">Сайта местной библиотеки</a> папка сайта и проекта будет называться <em>locallibrary</em>, и у нас будет одно приложение с названием <em>catalog</em>. Верхняя структура проекта будет следующей:</p>
+
+<pre class="brush: bash"><em>locallibrary/ # Папка сайта</em>
+  <strong>manage.py </strong># Скрипт для управления проектов (создан manage.py)
+  <em>locallibrary/ # Папка сайта/проекта </em>(создана manage.py)
+ <em>catalog/ # Папка приложения </em>(также создана manage.py)
+</pre>
+
+<p><span style="line-height: 1.5;">Следующие разделы статьи разложат по полочкам этапы создания "скелета", и покажут вам, как можно проверить сделанные изменения. В конце статьи мы обсудим некоторые другие настройки сайта, которые можно назначить на этом этапе.</span></p>
+
+<h2 id="Создание_проекта">Создание проекта</h2>
+
+<p>Для начала откройте командную строку/терминал, перейдите в ту папку, куда вы хотите поместить проект<span style="line-height: 1.5;"> Django(лучше в папке профиля пользователя C:\Users\user_name, при запуске командной строки используется именно эта директория), и создайте папку для вашего нового сайта (в данном случае: </span><em>locallibrary</em>). Затем войдите в эту папку, используя команду cd:</p>
+
+<pre class="brush: bash">mkdir locallibrary
+cd locallibrary</pre>
+
+<p>Создайте новую папку, используя команду <code>django-admin startproject</code> как в примере ниже, и затем зайдите в созданную папку.</p>
+
+<pre class="brush: bash"> django-admin startproject locallibrary .
+cd locallibrary</pre>
+
+<p>Команда <code>django-admin</code> создаст файловую структуру, как в примере ниже:</p>
+
+<pre class="brush: bash"><em>locallibrary/</em>
+  <strong>manage.py</strong>
+  <em>locallibrary/</em>
+    settings.py
+    urls.py
+    wsgi.py</pre>
+
+<p>Подпапка проекта <em>locallibrary</em> это ключевая директория нашего проекта: </p>
+
+<ul>
+ <li><strong>settings.py</strong> содержит в себе все настройки проекта. Здесь мы регистрируем приложения, задаём размещение <em>статичных</em> файлов, настройки базы данных и так далее.  </li>
+ <li><strong>urls.py</strong> задаёт ассоциации url адресов с представлениями. Несмотря на то, что этот файл может содержать <em>все</em> настройки url<span style="line-height: 1.5;">, обычно его делят на части, по одной на приложение, как будет показано далее. </span></li>
+ <li><strong style="line-height: 1.5;">wsgi.py</strong><span style="line-height: 1.5;"> используется для налаживания связи между вашим Django приложением и веб-сервером. Вы можете воспринимать его, как утилиту.</span></li>
+</ul>
+
+<p>Скрипт <strong>manage.py</strong> используется для создания приложений, работы с базами данных и для запуска отладочного сервера. </p>
+
+<h2 id="Создание_приложения_Каталог">Создание приложения Каталог</h2>
+
+<p>Выполнив предыдущие шаги, запустите следующую команду для создания приложения <em>catalog</em>, который будет размещён внутри папки locallibrary (команду необходимо выполнять из папки, в которой находится <strong>manage.py</strong>):</p>
+
+<pre class="brush: bash">python3 manage.py startapp catalog</pre>
+
+<div class="note">
+<p><strong>Заметка</strong>: приведённая выше команда справедлива для GNU Linux/Mac OS. На Windows команда должна иметь вид: <code>py -3 manage.py startapp catalog</code></p>
+
+<p>Если вы работаете под Windows, заменяйте команду <code>python3</code> на <code>py -3</code> в этой и следующих статьях.</p>
+</div>
+
+<p>Эта команда создаст новую папку и наполнит её файлами различных частей приложения (выделенные <strong>полужирным </strong>ниже). Большинство файлов названы, исходя из их назначения (например контроллеры(views) должны находится во <strong>views.py</strong>, модели в <strong>models.py</strong>, тесты в <strong>tests.py</strong>, настройки административной части в <strong>admin.py</strong>, регистрация приложения в <strong>apps.py</strong>) и уже содержат некоторый шаблонный код для работы с вышеназванными объектами.</p>
+
+<p>Обновлённая директория должна выглядеть следующим образом:</p>
+
+<pre class="brush: bash"><em>locallibrary/</em>
+  manage.py
+  <em>locallibrary/
+</em><strong>  <em>catalog/</em>
+      admin.py
+      apps.py
+      models.py
+      tests.py
+      views.py
+      __init__.py
+  <em>migrations/</em></strong>
+</pre>
+
+<p>Кроме перечисленных выше файлов были созданы:</p>
+
+<ul>
+ <li>Папка <em>migrations</em> используется, чтобы хранить"миграции" — файлы, которые позволяют вам автоматически обновлять базу данных по мере изменения моделей. </li>
+ <li><strong>__init__.py</strong> — пустой файл для того, чтобы Django и Python распознавали папку как <a href="https://docs.python.org/3/tutorial/modules.html#packages">Python модуль </a>и позволяет нам использовать его объекты внутри других частей проекта.</li>
+</ul>
+
+<div class="note">
+<p><strong>Заметка</strong>: Заметили, что некоторых файлов не хватает? В то время, как там нашли себе место файлы для контроллеров(views) и моделей(models), файлов для настройки url соотносителя, шаблонов, и статичных файлов создано не было. Далее мы покажем, как их создать (они не обязательны для каждого сайта, но нужны в данном примере).</p>
+</div>
+
+<h2 id="Регистрация_папки_с_приложением">Регистрация папки с приложением</h2>
+
+<p>После создания приложения, нам нужно зарегистрировать его в проекте, чтобы различные утилиты затрагивали его своим действием (например при добавлении моделей в базу данных). Приложения регистрируются добавлением их названий в список <code>INSTALLED_APPS</code> в настройках проекта(который, как мы помним, называется <strong>settings.py</strong>). </p>
+
+<p>Откройте файл <strong>locallibrary/locallibrary/settings.py</strong> и найдите в нём список <code>INSTALLED_APPS</code> . Затем добавьте новую строку в конец списка, как показано <strong>полужирным </strong>ниже.</p>
+
+<pre class="brush: bash">INSTALLED_APPS = [
+ 'django.contrib.admin',
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+<strong> 'catalog.apps.CatalogConfig', </strong>
+]</pre>
+
+<p>Новая строка указывает на файл конфигурации приложения (<code>CatalogConfig</code>), который был создан в <strong>/locallibrary/catalog/apps.py</strong> , когда вы создали приложение.</p>
+
+<div class="note">
+<p><strong>Заметка</strong>: Легко заметить, что в <code>INSTALLED_APPS</code> уже подключено большое количество приложений (и объектов <code>MIDDLEWARE</code>, ниже в файле конфигурации). Они добавляют поддержку <a href="/ru/docs/Learn/Server-side/Django/Admin_site">админ-панели Django</a> и, как следствие, огромное количество функционала (включая сессии, аутентификацию и прочее).</p>
+</div>
+
+<h2 id="Настройка_базы_данных">