From 841aae260382e2bf5ebb44d765d8c7301d27caab Mon Sep 17 00:00:00 2001 From: Alexey Istomin Date: Sat, 20 Mar 2021 18:37:44 +0300 Subject: Restore "ё" letter in Russian translation (#239) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs(ru): restore ё letter * docs(ru): resolve conflicts * refactor(idea): remove ide folder --- .../apache_configuration_htaccess/index.html | 4 +- .../learn/server-side/django/admin_site/index.html | 32 +++---- .../server-side/django/authentication/index.html | 58 ++++++------- .../learn/server-side/django/deployment/index.html | 82 +++++++++--------- .../django/development_environment/index.html | 24 +++--- .../django/django_assessment_blog/index.html | 16 ++-- files/ru/learn/server-side/django/forms/index.html | 96 ++++++++++----------- .../server-side/django/generic_views/index.html | 98 +++++++++++----------- .../learn/server-side/django/home_page/index.html | 44 +++++----- files/ru/learn/server-side/django/index.html | 12 +-- .../server-side/django/introduction/index.html | 10 +-- .../ru/learn/server-side/django/models/index.html | 58 ++++++------- .../learn/server-side/django/sessions/index.html | 16 ++-- .../server-side/django/skeleton_website/index.html | 2 +- .../ru/learn/server-side/django/testing/index.html | 88 +++++++++---------- .../django/web_application_security/index.html | 20 ++--- .../development_environment/index.html | 30 +++---- .../displaying_data/author_list_page/index.html | 6 +- .../displaying_data/book_list_page/index.html | 6 +- .../bookinstance_list_page/index.html | 4 +- .../date_formatting_using_moment/index.html | 2 +- .../flow_control_using_async/index.html | 20 ++--- .../displaying_data/genre_detail_page/index.html | 2 +- .../displaying_data/home_page/index.html | 20 ++--- .../express_nodejs/displaying_data/index.html | 4 +- .../displaying_data/template_primer/index.html | 14 ++-- .../forms/create_bookinstance_form/index.html | 2 +- .../forms/delete_author_form/index.html | 10 +-- .../server-side/express_nodejs/forms/index.html | 26 +++--- .../forms/update_book_form/index.html | 4 +- .../ru/learn/server-side/express_nodejs/index.html | 8 +- .../express_nodejs/introduction/index.html | 62 +++++++------- .../server-side/express_nodejs/mongoose/index.html | 88 +++++++++---------- .../server-side/express_nodejs/routes/index.html | 40 ++++----- .../express_nodejs/skeleton_website/index.html | 30 +++---- .../tutorial_local_library_website/index.html | 2 +- files/ru/learn/server-side/first_steps/index.html | 6 +- .../first_steps/web_frameworks/index.html | 4 +- .../first_steps/website_security/index.html | 54 ++++++------ files/ru/learn/server-side/index.html | 6 +- .../node_server_without_framework/index.html | 4 +- 41 files changed, 557 insertions(+), 557 deletions(-) (limited to 'files/ru/learn/server-side') diff --git a/files/ru/learn/server-side/apache_configuration_htaccess/index.html b/files/ru/learn/server-side/apache_configuration_htaccess/index.html index 12ff630a4b..d4b3ecee56 100644 --- a/files/ru/learn/server-side/apache_configuration_htaccess/index.html +++ b/files/ru/learn/server-side/apache_configuration_htaccess/index.html @@ -15,7 +15,7 @@ translation_of: Learn/Server-side/Apache_Configuration_htaccess Redirect 302 / http://example.com/ # Временное перенаправление на example.com -

Блокирование: htaccess также может блокировать доступ с определенного IP адреса или диапазона IP адресов. Блокирование часто используется, чтобы запретить доступ к директории для различных ботов и поисковых пауков.

+

Блокирование: htaccess также может блокировать доступ с определённого IP адреса или диапазона IP адресов. Блокирование часто используется, чтобы запретить доступ к директории для различных ботов и поисковых пауков.

deny from 146.0.74.205                   # Блокирует все запросы с адреса 146.0.74.205
@@ -25,7 +25,7 @@ Redirect 302 / http://example.com/ # Временное перенапра php_value auto_append_file "/real/path/to/file/footer.php" # Подключит файл footer.html в конец документа -

Настройка страниц с ошибками: с помощью .htaccess можно перенаправлять пользователя на определенные страницы, при возникновении ошибок на сервере.

+

Настройка страниц с ошибками: с помощью .htaccess можно перенаправлять пользователя на определённые страницы, при возникновении ошибок на сервере.

ErrorDocument 404 /notfound.html # Перенаправит пользователя на страницу notfound.html , при возникновении ошибки с кодом 404
 ErrorDocument 500 /serverr.html  # Перенаправит пользователя на страницу serverr.html , при возникновении ошибки с кодом 500
diff --git a/files/ru/learn/server-side/django/admin_site/index.html b/files/ru/learn/server-side/django/admin_site/index.html
index 6cad300f10..9df48c1528 100644
--- a/files/ru/learn/server-side/django/admin_site/index.html
+++ b/files/ru/learn/server-side/django/admin_site/index.html
@@ -30,7 +30,7 @@ translation_of: Learn/Server-side/Django/Admin_site
 
 

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

-

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

+

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

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

@@ -41,7 +41,7 @@ translation_of: Learn/Server-side/Django/Admin_site # Register your models here.
-

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

+

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

from .models import Author, Genre, Book, BookInstance
 
@@ -57,9 +57,9 @@ admin.site.register(BookInstance)
 
 

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

-

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

+

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

-

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

+

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

python3 manage.py createsuperuser
 
@@ -70,7 +70,7 @@ admin.site.register(BookInstance)
-

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

+

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

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

@@ -94,7 +94,7 @@ admin.site.register(BookInstance)

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

-

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

+

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

Admin Site - Book Edit

@@ -113,7 +113,7 @@ admin.site.register(BookInstance)

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

@@ -143,7 +143,7 @@ admin.site.register(BookInstance)

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

-

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

+

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

# admin.site.register(Author)
@@ -183,7 +183,7 @@ class BookInstanceAdmin(admin.ModelAdmin):

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

-

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

+

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

class AuthorAdmin(admin.ModelAdmin):
     list_display = ('last_name', 'first_name', 'date_of_birth', 'date_of_death')
@@ -193,19 +193,19 @@ class BookInstanceAdmin(admin.ModelAdmin):
 
 

Admin Site - Improved Author List

-

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

+

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

class BookAdmin(admin.ModelAdmin):
     list_display = ('title', 'author', 'display_genre')
 
-

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

+

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

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

-

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

+

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

    def display_genre(self):
         """
@@ -215,11 +215,11 @@ class BookInstanceAdmin(admin.ModelAdmin):
     display_genre.short_description = 'Genre'
 
-

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

+

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

Admin Site - Improved Book List

-

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

+

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

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

@@ -227,7 +227,7 @@ class BookInstanceAdmin(admin.ModelAdmin):

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

-

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

+

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

class BookInstanceAdmin(admin.ModelAdmin):
     list_filter = ('status', 'due_back')
@@ -242,7 +242,7 @@ class BookInstanceAdmin(admin.ModelAdmin):
 

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

-

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

+

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

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

diff --git a/files/ru/learn/server-side/django/authentication/index.html b/files/ru/learn/server-side/django/authentication/index.html index 760cd8943c..636fc0e94b 100644 --- a/files/ru/learn/server-side/django/authentication/index.html +++ b/files/ru/learn/server-side/django/authentication/index.html @@ -39,7 +39,7 @@ original_slug: Learn/Server-side/Django/Аутентификация

Обзор

-

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

+

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

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

@@ -47,7 +47,7 @@ original_slug: Learn/Server-side/Django/Аутентификация

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

-

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

+

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

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

@@ -104,7 +104,7 @@ user.save()
  1. Нажмите на кнопку Add (Добавить) (рядом с Group) и создайте новую группу; для данной группы введите Name (Имя) "Library Members".Admin site - add group
  2. -
  3. Для данной группы не нужны какие-либо разрешения, поэтому мы просто нажимаем кнопку SAVE (Сохранить) (вы перейдете к списку групп).
  4. +
  5. Для данной группы не нужны какие-либо разрешения, поэтому мы просто нажимаем кнопку SAVE (Сохранить) (вы перейдёте к списку групп).

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

@@ -116,11 +116,11 @@ user.save()
  • Нажмите SAVE для завершения процесса создания пользователя.

    Административная часть сайта создаст нового пользователя и немедленно перенаправит вас на страницу Change user (Изменение параметров пользователя) где вы можете, соответственно, изменить ваш username, а кроме того добавить информацию для дополнительных полей модели User. Эти поля включают в себя имя пользователя, фамилию, адрес электронной почты, статус пользователя, а также соответствующие параметры доступа (может быть установлен только флаг  Active). Ниже вы можете определить группу для пользователя и необходимые параметры доступа, а кроме того, вы можете увидеть важные даты, относящиеся к пользователю (дату подключения к сайту и дату последнего входа).Admin site - add user pt2
  • -
  • В разделе Groups, из списка Доступные группы выберите группу Library Member, а затем переместите ее в блок "Выбранные группы" (нажмите стрелку-"направо", находящуюся между блоками).Admin site - add user to group
  • -
  • Больше нам не нужно здесь нечего делать, просто нажмите "Save"(Сохранить), и вы вернетесь к списку созданных пользователей.
  • +
  • В разделе Groups, из списка Доступные группы выберите группу Library Member, а затем переместите её в блок "Выбранные группы" (нажмите стрелку-"направо", находящуюся между блоками).Admin site - add user to group
  • +
  • Больше нам не нужно здесь нечего делать, просто нажмите "Save"(Сохранить), и вы вернётесь к списку созданных пользователей.
  • -

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

    +

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

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

    @@ -153,7 +153,7 @@ urlpatterns += [

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

    -

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

    +

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

    @@ -167,7 +167,7 @@ accounts/ reset/<uidb64>/<token>/ [name='password_reset_confirm'] accounts/ reset/done/ [name='password_reset_complete']
    -

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

    +

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

    Exception Type:    TemplateDoesNotExist
     Exception Value:    registration/login.html
    @@ -202,7 +202,7 @@ Exception Value: registration/login.html

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

    -

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

    +

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

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

    @@ -248,13 +248,13 @@ Exception Value: registration/login.html {% endblock %} -

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

    +

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

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

    Library login page v1

    -

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

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

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

    @@ -264,7 +264,7 @@ LOGIN_REDIRECT_URL = '/'

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

    -

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

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

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

    @@ -276,7 +276,7 @@ LOGIN_REDIRECT_URL = '/' <a href="{% url 'login'%}">Click here to login again.</a> {% endblock %} -

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

    +

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

    Library logout page v1

    @@ -357,7 +357,7 @@ LOGIN_REDIRECT_URL = '/' {% endblock %} -

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

    +

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

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

    @@ -371,7 +371,7 @@ LOGIN_REDIRECT_URL = '/'

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

    -

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

    +

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

    -

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

    +

    Ссылка на автора в шаблоне содержит пустой URL-адрес, потому что мы ещё не создали страницу детальной информации об авторе. Когда это произойдёт, вы должны будете обновить данный URL-адрес как указано ниже:

    <a href="{% url 'author-detail' book.author.pk %}">\{{ book.author }}</a>
     
    @@ -424,7 +424,7 @@ url(r'^/anotherurl/$', views.my_reused_view, {'my_template_name': 'another_path'
  • Мы расширяем наш базовый шаблон и переопределяем блок content.
  • Мы используем условие if для показа того, или иного содержимого.
  • Мы используем циклы for того, чтобы пробежаться по элементам (объектам) в соответствующих списках.
  • -
  • Мы получаем доступ к полям контекста при помощи "дот-нотации" (поскольку мы использовали обобщенный класс отображения детальной информации, то контекст имеет имя book; также можем использовать имя object)
  • +
  • Мы получаем доступ к полям контекста при помощи "дот-нотации" (поскольку мы использовали обобщённый класс отображения детальной информации, то контекст имеет имя book; также можем использовать имя object)
  • Одной интересной вещью, которую мы не видели ранее, является функция book.bookinstance_set.all(). Данный метод является "автомагически"-сконструированным Django для того, чтобы вернуть множество записей BookInstance, связанных с данной книгой Book.

    @@ -433,7 +433,7 @@ url(r'^/anotherurl/$', views.my_reused_view, {'my_template_name': 'another_path' <!-- итерации по каждой копии/экземпляру книги --> {% endfor %} -

    Этот метод создан, потому что вы, на стороне "многим" данной связи, объявили поле ForeignKey (один-ко многим). Поскольку вы ничего не объявили на другой стороне ("один") данной модели (то есть, модель Book "ничего не знает" про модель BookInstance), то она не имеет никакой возможности (по умолчанию) для получения множества соответствующих записей. Для того, чтобы обойти эту проблему, Django конструирует соответствующую функцию "обратного просмотра" ("reverse lookup"), которой вы можете воспользоваться. Имя данной функции создается в нижнем регистре и состоит из имени модели, в которой был объявлен ForeignKey (то есть, bookinstance), за которым следует _set (то есть функция, созданная для Book будет иметь вид bookinstance_set()).

    +

    Этот метод создан, потому что вы, на стороне "многим" данной связи, объявили поле ForeignKey (один-ко многим). Поскольку вы ничего не объявили на другой стороне ("один") данной модели (то есть, модель Book "ничего не знает" про модель BookInstance), то она не имеет никакой возможности (по умолчанию) для получения множества соответствующих записей. Для того, чтобы обойти эту проблему, Django конструирует соответствующую функцию "обратного просмотра" ("reverse lookup"), которой вы можете воспользоваться. Имя данной функции создаётся в нижнем регистре и состоит из имени модели, в которой был объявлен ForeignKey (то есть, bookinstance), за которым следует _set (то есть функция, созданная для Book будет иметь вид bookinstance_set()).

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

    @@ -447,7 +447,7 @@ url(r'^/anotherurl/$', views.my_reused_view, {'my_template_name': 'another_path'

    Это случилось потому что, paginator object (далее объект постраничного вывода) ожидает видеть некую упорядоченность ORDER BY при запросе к базе данных. Без этого, он не сможет гарантировать правильный вывод полученных данных!

    -

    Данное руководство пока не дошло до описания Pagination (пока, но скоро будет), и поскольку вы не можете использовать функцию sort_by() и передавать параметр (по той же причине, что и filter()) вы должны выбрать один из трех вариантов дальнейших действий:

    +

    Данное руководство пока не дошло до описания Pagination (пока, но скоро будет), и поскольку вы не можете использовать функцию sort_by() и передавать параметр (по той же причине, что и filter()) вы должны выбрать один из трёх вариантов дальнейших действий:

    1. Добавить атрибут ordering внутри Meta-класса объявленного в вашей модели.
    2. @@ -474,7 +474,7 @@ url(r'^/anotherurl/$', views.my_reused_view, {'my_template_name': 'another_path'

      Конечно же, поле не обязательно должно иметь имя last_name: оно может быть любым.

      -

      И последнее, но не окончательное, вы должны сортировать по атрибуту/колонке, которая была проиндексирована (уникально, или нет) в вашей базе данных для того, чтобы избежать проблем с быстродействием. Конечно, это не является необходимым в данном примере (и мы, вероятно, забегаем далеко вперед), если у нас такое небольшое количество книг (и пользователей!),  но это необходимо помнить для будущих проектов.

      +

      И последнее, но не окончательное, вы должны сортировать по атрибуту/колонке, которая была проиндексирована (уникально, или нет) в вашей базе данных для того, чтобы избежать проблем с быстродействием. Конечно, это не является необходимым в данном примере (и мы, вероятно, забегаем далеко вперёд), если у нас такое небольшое количество книг (и пользователей!),  но это необходимо помнить для будущих проектов.

    Как это теперь выглядит?

    @@ -497,7 +497,7 @@ url(r'^/anotherurl/$', views.my_reused_view, {'my_template_name': 'another_path'

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

    -

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

    +

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

    Отображения

    @@ -507,13 +507,13 @@ url(r'^/anotherurl/$', views.my_reused_view, {'my_template_name': 'another_path' model = Book paginate_by = 10 -

    Как только у вас появится более 10 записей в базе данных отображение начнет формировать постраничный вывод данных, которые он передает шаблону. К различным страницам данного вывода можно получить доступ при помощи параметров GET-запроса — к странице 2 вы можете получить доступ, используя URL-адрес: /catalog/books/?page=2.

    +

    Как только у вас появится более 10 записей в базе данных отображение начнёт формировать постраничный вывод данных, которые он передаёт шаблону. К различным страницам данного вывода можно получить доступ при помощи параметров GET-запроса — к странице 2 вы можете получить доступ, используя URL-адрес: /catalog/books/?page=2.

    Шаблоны

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

    -

    Откройте /locallibrary/catalog/templates/base_generic.html и, ниже блока content, вставьте блок (во фрагменте не выделен жирным), отвечающий за постраничный вывод. Данный код, в первую очередь, проверяет "включен" ли механизм постраничного вывода для данной страницы и если это так, то он добавляет ссылки next и previous,соответственно (а также, номер текущей страницы). 

    +

    Откройте /locallibrary/catalog/templates/base_generic.html и, ниже блока content, вставьте блок (во фрагменте не выделен жирным), отвечающий за постраничный вывод. Данный код, в первую очередь, проверяет "включён" ли механизм постраничного вывода для данной страницы и если это так, то он добавляет ссылки next и previous,соответственно (а также, номер текущей страницы). 

    {% block content %}{% endblock %}
     
    @@ -564,7 +564,7 @@ url(r'^/anotherurl/$', views.my_reused_view, {'my_template_name': 'another_path'
     

    Примечание:

      -
    • Когда вы создадите URL-преобразование для страницы списка авторов вам понадобится обновить ссылку All authors в базовом шаблоне. Следуйте тем же путем, который мы проделали когда обновляли ссылку All books.
    • +
    • Когда вы создадите URL-преобразование для страницы списка авторов вам понадобится обновить ссылку All authors в базовом шаблоне. Следуйте тем же путём, который мы проделали когда обновляли ссылку All books.
    • Когда вы создадите URL-преобразование для страницы с детальной информацией об авторе,  вы должны будете обновить шаблон детальной информации о книге (/locallibrary/catalog/templates/catalog/book_detail.html), таким образом, чтобы ссылка автора указывала на страницу с детальной информации о нем (а не быть пустой). Данная ссылка будет иметь вид как указано жирным во фрагменте ниже.
      <p><strong>Author:</strong> <a href="{% url 'author-detail' book.author.pk %}">\{{ book.author }}</a></p>
       
      @@ -588,15 +588,15 @@ url(r'^/anotherurl/$', views.my_reused_view, {'my_template_name': 'another_path'

      Поздравляем! Наш базовый функционал библиотеки готов! 

      -

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

      +

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

      -

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

      +

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

      Дополнительная информация

        -
      • Встроенные обобщенные классы отображения (Django docs)
      • -
      • Обобщенный вид отображения (Django docs)
      • +
      • Встроенные обобщённые классы отображения (Django docs)
      • +
      • Обобщённый вид отображения (Django docs)
      • Введение в отображения на основе классов (Django docs)
      • Встроенные теги шаблона и фильтры (Django docs).
      • Постраничный вывод (Pagination) (Django docs)
      • diff --git a/files/ru/learn/server-side/django/home_page/index.html b/files/ru/learn/server-side/django/home_page/index.html index df43a891ae..c5b6f2bbea 100644 --- a/files/ru/learn/server-side/django/home_page/index.html +++ b/files/ru/learn/server-side/django/home_page/index.html @@ -17,7 +17,7 @@ translation_of: Learn/Server-side/Django/Home_page
        {{PreviousMenuNext("Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django")}}
        -

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

        +

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

        @@ -36,17 +36,17 @@ translation_of: Learn/Server-side/Django/Home_page

        Теперь, когда мы определили наши модели и создали несколько записей в них, пришло время написать код, который будет показывать данную информацию пользователям. И первое, что нам необходимо сделать это определиться какую информацию мы бы хотели показывать на наших страницах,  а затем определить соответствующие URL-адреса для получения соответствующих ресурсов. Затем нам надо создать url-преобразования, отображения (функции, или классы), а затем шаблоны страницы. 

        -

        Диаграмма, представленная ниже,  демонстрирует главный поток данных и элементов, которые нужно реализовать для управления HTTP запросами и ответами. Поскольку мы уже создали модель, то нам остается создать следующее:

        +

        Диаграмма, представленная ниже,  демонстрирует главный поток данных и элементов, которые нужно реализовать для управления HTTP запросами и ответами. Поскольку мы уже создали модель, то нам остаётся создать следующее:

          -
        • URL-преобразования для перехода по соответствующему URL-адресу (с учетом информации, передаваемой в данном адресе) к соответствующей функции отображения.
        • +
        • URL-преобразования для перехода по соответствующему URL-адресу (с учётом информации, передаваемой в данном адресе) к соответствующей функции отображения.
        • Функции отображения для запроса соответствующих данных из моделей, создание страниц HTML для показа этих данных и их отправку в клиент пользователя (в браузер).
        • Шаблоны, которые используются отображениями для рендеринга (отрисовки) данных.

        -

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

        +

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

        Определяем URL-адреса страниц

        @@ -58,13 +58,13 @@ translation_of: Learn/Server-side/Django/Home_page
      • catalog/ — Домашняя/индексная страница.
      • catalog/books/ — Список всех книг.
      • catalog/authors/ — Список всех авторов.
      • -
      • catalog/book/<id> — Детальная информация для определенной книги со значением первичного ключа равного <id>. Например, /catalog/book/3, для id = 3.
      • -
      • catalog/author/<id> — Детальная информация для определенного автора со значением первичного ключа равного <id>. Например, /catalog/author/11, для автора с id = 11.
      • +
      • catalog/book/<id> — Детальная информация для определённой книги со значением первичного ключа равного <id>. Например, /catalog/book/3, для id = 3.
      • +
      • catalog/author/<id> — Детальная информация для определённого автора со значением первичного ключа равного <id>. Например, /catalog/author/11, для автора с id = 11.
      • Первые три URL-адреса используются для показа домашней страницы, а также списков книг и авторов. Они не кодируют никакой дополнительной информации и результат показа данных страниц будет полностью зависеть от того, что находится в базе данных  и, по сути, будет все время одним и тем же (при неизменной базе данных, конечно).

        -

        Последние два URL-адреса применяются для показа детальной информации об определенной книге, или авторе — в себе они содержат соответствующее значение идентификатора (показан как <id>, выше). URL-преобразование получает данную информацию и передает ее в отображение, которое применяет ее для запроса к базе данных. Для кодирования и применения данной информации в вашем URL-адресе нам понадобится только одно url-преобразование, соответствующее отображение и шаблон страницы для показа любой книги (или автора). 

        +

        Последние два URL-адреса применяются для показа детальной информации об определённой книге, или авторе — в себе они содержат соответствующее значение идентификатора (показан как <id>, выше). URL-преобразование получает данную информацию и передаёт её в отображение, которое применяет её для запроса к базе данных. Для кодирования и применения данной информации в вашем URL-адресе нам понадобится только одно url-преобразование, соответствующее отображение и шаблон страницы для показа любой книги (или автора). 

        Примечание: Django позволяет вам конструировать ваши URL-адреса любым, удобным для вас, способом — вы можете закодировать информацию в теле URL-адреса, как показано выше, или использовать URL-адрес типа GET (например, /book/?id=6). Независимо от ваших предпочтений, URL-адреса должны быть понятными, логичными и читабельными (посмотрите совет W3C здесь).
        @@ -84,13 +84,13 @@ translation_of: Learn/Server-side/Django/Home_page

        URL-преобразование

        -

        Когда мы создавали скелет сайта мы обновили locallibrary/urls.py так что всякий раз, когда начинается URL-адрес наш catalog/ получен и URLConf catalog.urls подключен для обработки оставшейся части строки.

        +

        Когда мы создавали скелет сайта мы обновили locallibrary/urls.py так что всякий раз, когда начинается URL-адрес наш catalog/ получен и URLConf catalog.urls подключён для обработки оставшейся части строки.

        urlpatterns += [
             path('catalog/', include('catalog.urls')),
         ]
        -

        Примечание: всякий раз, когда Django сталкивается c  django.urls.include()  он отбрасывает часть совпавшего URL , и отправляет оставшуюся строку в включенный URLconf для дальнейшей обработки.

        +

        Примечание: всякий раз, когда Django сталкивается c  django.urls.include()  он отбрасывает часть совпавшего URL , и отправляет оставшуюся строку в включённый URLconf для дальнейшей обработки.

        Внутри нашего каталога приложения откройте urls.py и поместите в него текст, отмеченный жирным, ниже. 

        @@ -98,19 +98,19 @@ translation_of: Learn/Server-side/Django/Home_page path('', views.index, name='index'), ] -

        Эта функция path() определяет URL-паттерн (в данном случае это пустая строка:'' - мы поговорим чуть более подробно о них далее в данном руководстве) и функцию отображения, которая будет вызвана, если введенный адрес будет соответствует данному паттерну (views.index — это функция с именем index() в views.py).

        +

        Эта функция path() определяет URL-паттерн (в данном случае это пустая строка:'' - мы поговорим чуть более подробно о них далее в данном руководстве) и функцию отображения, которая будет вызвана, если введённый адрес будет соответствует данному паттерну (views.index — это функция с именем index() в views.py).

        Данная функция path(), кроме того, определяет параметр name, который уникально определяет это частное URL-преобразование. Вы можете использовать данное имя для "обратного" ("reverse") преобразования — то есть, для динамического создания URL-адреса, указывающего на ресурс, на которое указывает данное преобразование. Например, теперь, когда у нас имеется данное символическое имя, мы можем ссылаться на нашу домашнюю страницу при помощи создания следующей ссылки внутри какого-либо шаблона:

        <a href="{% url 'index' %}">Home</a>.
        -

        Примечание: Мы могли бы, конечно, жестко указать прямую ссылку (то есть, <a href="/catalog/">Home</a>), но тогда, если мы изменим адрес нашей домашней страницы (например на /catalog/index), то данные ссылки перестанут корректно работать. Применение "обратного" url-преобразования более гибкий и эффективный подход!

        +

        Примечание: Мы могли бы, конечно, жёстко указать прямую ссылку (то есть, <a href="/catalog/">Home</a>), но тогда, если мы изменим адрес нашей домашней страницы (например на /catalog/index), то данные ссылки перестанут корректно работать. Применение "обратного" url-преобразования более гибкий и эффективный подход!

        Отображения (на основе функций)

        -

        Отображение является функцией, которая обрабатывает HTTP-запрос, получает данные из базы данных (при необходимости), которые применяются для генерации страницы HTML. Затем функция отображения возвращает сгенерированную страницу пользователю в виде HTTP-ответа. В нашем случае, индексная функция демонстрирует этот процесс — она получает информацию о количестве записей Book, BookInstance, доступности BookInstance, а также записи Author из базы данных, затем передает эти записи в шаблон страницы, генерирует страницу и передает ее пользователю (клиенту пользователя, например браузеру).

        +

        Отображение является функцией, которая обрабатывает HTTP-запрос, получает данные из базы данных (при необходимости), которые применяются для генерации страницы HTML. Затем функция отображения возвращает сгенерированную страницу пользователю в виде HTTP-ответа. В нашем случае, индексная функция демонстрирует этот процесс — она получает информацию о количестве записей Book, BookInstance, доступности BookInstance, а также записи Author из базы данных, затем передаёт эти записи в шаблон страницы, генерирует страницу и передаёт её пользователю (клиенту пользователя, например браузеру).

        Откройте catalog/views.py и отметьте для себя, что данный файл уже импортирует функцию render() - функцию, которая генерирует HTML-файлы при помощи шаблонов страниц и соответствующих данных. 

        @@ -132,7 +132,7 @@ def index(request): num_instances=BookInstance.objects.all().count() # Доступные книги (статус = 'a') num_instances_available=BookInstance.objects.filter(status__exact='a').count() - num_authors=Author.objects.count() # Метод 'all()' применен по умолчанию. + num_authors=Author.objects.count() # Метод 'all()' применён по умолчанию. # Отрисовка HTML-шаблона index.html с данными внутри # переменной контекста context @@ -144,13 +144,13 @@ def index(request):

        Первая часть функции отображения получает количество записей при помощи вызова функции objects.all() у атрибута objects, доступного для всех классов моделей. Похожим образом мы получаем список объектов BookInstance, которые имеют статус 'a' (Доступно). Вы можете найти дополнительную информацию о работе с моделями в предыдущей части руководства (Руководство часть 3: Применение моделей > Поиск записей).

        -

        В конце функции index вызывается функция  render(), которая, в качестве ответа, создает и возвращает страницу HTML  (эта функция "оборачивает" вызовы нескольких функций, тем самым существенно упрощая процесс разработки). В качестве параметров ей передаются объект request  (типа HttpRequest), шаблон HTML-страницы с метками (placeholders), которые будут замещены данными,  а также переменной context (словарь Python, который содержит данные, которые и будут замещать метки в шаблоне). 

        +

        В конце функции index вызывается функция  render(), которая, в качестве ответа, создаёт и возвращает страницу HTML  (эта функция "оборачивает" вызовы нескольких функций, тем самым существенно упрощая процесс разработки). В качестве параметров ей передаются объект request  (типа HttpRequest), шаблон HTML-страницы с метками (placeholders), которые будут замещены данными,  а также переменной context (словарь Python, который содержит данные, которые и будут замещать метки в шаблоне). 

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

        Шаблон

        -

        Шаблон это текстовый файл, который определяет структуру и расположение данных в файле, кроме того, в нем размещают специальные метки (placeholders), которые используются для показа реального содержимого, то есть данных. По умолчанию Django ищет файлы шаблонов в директории с именем 'templates' внутри вашего приложения. Например, внутри индексной функции отображения, которую мы только что создали, вызов render() будет пытаться найти файл /locallibrary/catalog/templates/index.html и в случае неудачи сгенерирует ошибку о том, что файл не найден. Вы можете увидеть данную ошибку, если вы сохраните предыдущие изменения, затем перейдете в браузер и наберете в адресной строке 127.0.0.1:8000. В результате, в окно браузера будет выведено сообщение об ошибке "TemplateDoesNotExist at /catalog/" и некоторая другая информация.

        +

        Шаблон это текстовый файл, который определяет структуру и расположение данных в файле, кроме того, в нем размещают специальные метки (placeholders), которые используются для показа реального содержимого, то есть данных. По умолчанию Django ищет файлы шаблонов в директории с именем 'templates' внутри вашего приложения. Например, внутри индексной функции отображения, которую мы только что создали, вызов render() будет пытаться найти файл /locallibrary/catalog/templates/index.html и в случае неудачи сгенерирует ошибку о том, что файл не найден. Вы можете увидеть данную ошибку, если вы сохраните предыдущие изменения, затем перейдёте в браузер и наберёте в адресной строке 127.0.0.1:8000. В результате, в окно браузера будет выведено сообщение об ошибке "TemplateDoesNotExist at /catalog/" и некоторая другая информация.

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

        @@ -278,7 +278,7 @@ def index(request):

        Примечание: Переменные шаблона заключаются в двойные фигурные скобки (\{{ num_books }}) , а тэги шаблона (функции шаблона), помещаются в одинарные фигурные скобки со знаками процента ({% extends "base_generic.html" %}).

        -

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

        +

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

        return render(
             request,
        @@ -288,7 +288,7 @@ def index(request):
         
         

        Ссылка на статические файлы их шаблонов

        -

        Любой ваш проект с большой вероятностью будет использовать статические ресурсы, включая JavaScript, CSS и изображения. В связи с тем, что расположение этих файлов может быть неизвестно (или может измениться), Django позволяет вам в шаблоне указать относительное расположение данных файлов при помощи глобального значения STATIC_URL (по умолчанию, значение параметра STATIC_URL установлено в '/static/',  но вы можете выбрать любое другое значение, указав, например, сетевой ресурс, или что-то еще).

        +

        Любой ваш проект с большой вероятностью будет использовать статические ресурсы, включая JavaScript, CSS и изображения. В связи с тем, что расположение этих файлов может быть неизвестно (или может измениться), Django позволяет вам в шаблоне указать относительное расположение данных файлов при помощи глобального значения STATIC_URL (по умолчанию, значение параметра STATIC_URL установлено в '/static/',  но вы можете выбрать любое другое значение, указав, например, сетевой ресурс, или что-то ещё).

        Внутри шаблона вы  вызываете функцию (тэг) load, которая загружает статическую библиотеку "static" (как показано ниже). После того как статическая библиотека загружена, вы можете использовать тэг шаблона static, который указывает относительный путь URL к интересующему вас файлу.

        @@ -303,7 +303,7 @@ def index(request):
        -

        Примечание: Фрагменты выше указывают пути расположения файлов, но Django не использует их по умолчанию. В процессе разработки сервер использует значения, указанные в глобальном файле URL-преобразований (/locallibrary/locallibrary/urls.py), который мы создали в части создание скелета сайта. В дальнейшем, в продакшене, вам нужно будет уточнить параметры расположения статических файлов. Мы вернемся к этому позже.

        +

        Примечание: Фрагменты выше указывают пути расположения файлов, но Django не использует их по умолчанию. В процессе разработки сервер использует значения, указанные в глобальном файле URL-преобразований (/locallibrary/locallibrary/urls.py), который мы создали в части создание скелета сайта. В дальнейшем, в продакшене, вам нужно будет уточнить параметры расположения статических файлов. Мы вернёмся к этому позже.

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

        @@ -315,7 +315,7 @@ def index(request):
        <li><a href="{% url 'index' %}">Home</a></li>
         
        -

        Данный тэг с именем url(), ищет в файле urls.py связанное значение переменной, указанной в качестве ее параметра 'index', а затем возвращает URL, который вы можете использовать для ссылки на соответствующие ресурсы.

        +

        Данный тэг с именем url(), ищет в файле urls.py связанное значение переменной, указанной в качестве её параметра 'index', а затем возвращает URL, который вы можете использовать для ссылки на соответствующие ресурсы.

        Как теперь все это выглядит?

        @@ -333,7 +333,7 @@ def index(request):
        1. В главном файле шаблона (base_generic.html) есть блок title. Переопределите этот блок в индексном шаблоне (index.html) и задайте новый заголовок для этой страницы.
        2. -
        3. Модифицируйте функцию отображения таким образом, чтобы получать из базы данных количество жанров и количество книг, которые содержат в своих заголовках какое-либо слово (без учета регистра), а затем передайте эти значения в шаблон.
        4. +
        5. Модифицируйте функцию отображения таким образом, чтобы получать из базы данных количество жанров и количество книг, которые содержат в своих заголовках какое-либо слово (без учёта регистра), а затем передайте эти значения в шаблон.
          @@ -341,9 +341,9 @@ def index(request):

          Итог

          -

          Мы создали домашнюю страницу для нашего сайта — HTML страница, которая показывает количество некоторых записей из базы данных и содержит ссылки на другие "все-еще-будут-созданы" страницы. Кроме того, мы изучили большое количество базовой информации об url-преобразованиях, отображениях, запросах к базе данных, используя наши модели, передачу информации из отображений в шаблоны, кроме того, создание и расширение шаблонов.

          +

          Мы создали домашнюю страницу для нашего сайта — HTML страница, которая показывает количество некоторых записей из базы данных и содержит ссылки на другие "все-ещё-будут-созданы" страницы. Кроме того, мы изучили большое количество базовой информации об url-преобразованиях, отображениях, запросах к базе данных, используя наши модели, передачу информации из отображений в шаблоны, кроме того, создание и расширение шаблонов.

          -

          В  следующей части, при помощи наших новых знаний, мы  создадим еще четыре страницы.

          +

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

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

          diff --git a/files/ru/learn/server-side/django/index.html b/files/ru/learn/server-side/django/index.html index 8993390384..76beccc18d 100644 --- a/files/ru/learn/server-side/django/index.html +++ b/files/ru/learn/server-side/django/index.html @@ -27,7 +27,7 @@ translation_of: Learn/Server-side/Django
          Введение в Django
          -
          В этой первой статье по Django мы ответим на вопрос "Что такое Django?" и сделаем обзор того, что делает этот веб-фреймворк особенным. Мы кратко рассмотрим основные особенности, включая некоторый продвинутый функционал, на котором у нас не будет возможности подробно остановиться в этом модуле. Мы также покажем вам некоторые из основных строительных блоков приложения Django, чтобы дать вам представление о том, что он может сделать, прежде чем вы перейдете к установке и начнете экспериментировать.
          +
          В этой первой статье по Django мы ответим на вопрос "Что такое Django?" и сделаем обзор того, что делает этот веб-фреймворк особенным. Мы кратко рассмотрим основные особенности, включая некоторый продвинутый функционал, на котором у нас не будет возможности подробно остановиться в этом модуле. Мы также покажем вам некоторые из основных строительных блоков приложения Django, чтобы дать вам представление о том, что он может сделать, прежде чем вы перейдёте к установке и начнёте экспериментировать.
          Установка среды разработки Django
          Теперь, когда вы знаете, что такое Django, мы покажем вам, как установить и протестировать среду разработки Django для Windows, Linux (Ubuntu) и Mac OS X — какую бы операционную систему вы не использовали, эта статья должна дать вам понимание того, что вам потребуется, чтобы начать разработку Django-приложений .
          Учебник Django: Веб-сайт местной библиотеки
          @@ -41,19 +41,19 @@ translation_of: Learn/Server-side/Django
          Учебник Django часть 5: Создание главной страницы 
          Теперь мы готовы добавить код для отображения нашей первой полной страницы — главной страницы сайта местной библиотеки, которая показывает, сколько записей у нас есть для каждого типа модели, и предоставляет ссылки на боковых панелях на другие наши страницы. По пути мы получим практический опыт написания основных карт и представлений URL, получения записей из базы данных и использования шаблонов.
          Учебник Django часть 6: Общий список и подробные представления
          -
          Это руководство расширяет наш сайт местной библиотеки, добавляя список и подробные страницы для книг и авторов. Здесь мы узнаем об общих представлениях на основе классов и покажем, как они могут уменьшить количество кода, который вы должны писать для случаев общего использования. Мы также перейдем к обработке URL-адресов более подробно, покажем, как выполнить базовое сопоставление шаблонов.
          +
          Это руководство расширяет наш сайт местной библиотеки, добавляя список и подробные страницы для книг и авторов. Здесь мы узнаем об общих представлениях на основе классов и покажем, как они могут уменьшить количество кода, который вы должны писать для случаев общего использования. Мы также перейдём к обработке URL-адресов более подробно, покажем, как выполнить базовое сопоставление шаблонов.
          Учебник Django часть 7:  Структура сессий
          Это руководство расширяет наш сайт местной библиотеки, добавляя счётчик посещений домашней страницы. Это относительно простой пример, но он показывает, как вы можете использовать структуру сессии, чтобы обеспечить постоянное поведение анонимных пользователей на ваших собственных сайтах.
          Учебник Django часть 8: Авторизация и права пользователей
          -
          В этом уроке мы покажем вам, как разрешить пользователям входить на ваш сайт со своими учетными записями и как управлять тем, что они могут делать и видеть на основе того, зарегистрированы ли они или нет, и их допусках. В рамках этой демонстрации мы расширим сайт местной библиотеки, добавив страницы входа и выхода, а также страницы пользователей и персональные страницы для просмотра книг, которые были взяты на руки.
          +
          В этом уроке мы покажем вам, как разрешить пользователям входить на ваш сайт со своими учётными записями и как управлять тем, что они могут делать и видеть на основе того, зарегистрированы ли они или нет, и их допусках. В рамках этой демонстрации мы расширим сайт местной библиотеки, добавив страницы входа и выхода, а также страницы пользователей и персональные страницы для просмотра книг, которые были взяты на руки.
          Учебник Django часть 9: Работа с формами
          В этом уроке мы покажем вам, как работать с HTML Forms в Django, и  в частности, самый простой способ писать формы для создания, обновления и удаления экземпляров модели. В рамках этой демонстрации мы расширим сайт местной библиотеки, чтобы библиотекари могли вносить новые книги, создавать, обновлять и удалять авторов, используя наши собственные формы (а не использовать приложение администратора).
          Учебник Django часть10: Тестирование веб-приложения Django
          -
          По мере роста веб-сайтов становится сложнее проверять вручную — требуется больше проверок, поскольку взаимодействие между компонентами усложняется, небольшое изменение в одной области может потребовать дополнительные тесты для проверки его влияния на другие области. Один из способов смягчить эти проблемы - написать автоматизированные тесты, которые можно легко и надежно запускать каждый раз, когда вы вносите изменения. В этом руководстве показано, как автоматизировать модульное тестирование вашего сайта с помощью тестовой среды Django.
          +
          По мере роста веб-сайтов становится сложнее проверять вручную — требуется больше проверок, поскольку взаимодействие между компонентами усложняется, небольшое изменение в одной области может потребовать дополнительные тесты для проверки его влияния на другие области. Один из способов смягчить эти проблемы - написать автоматизированные тесты, которые можно легко и надёжно запускать каждый раз, когда вы вносите изменения. В этом руководстве показано, как автоматизировать модульное тестирование вашего сайта с помощью тестовой среды Django.
          Учебник Django часть 11: Деплой Django на продакшн
          -
          Теперь вы создали (и протестировали) удивительный сайт местной библиотеки, вам захочется установить его на общедоступный веб-сервер, чтобы к нему мог получить доступ персонал библиотеки и пользователи Интернета. В этой статье представлен обзор того, как вы можете найти хост для развертывания вашего веб-сайта и что вам нужно сделать, чтобы подготовить ваш сайт к выпуску.
          +
          Теперь вы создали (и протестировали) удивительный сайт местной библиотеки, вам захочется установить его на общедоступный веб-сервер, чтобы к нему мог получить доступ персонал библиотеки и пользователи Интернета. В этой статье представлен обзор того, как вы можете найти хост для развёртывания вашего веб-сайта и что вам нужно сделать, чтобы подготовить ваш сайт к выпуску.
          Безопасность веб-приложений Django
          -
          Защита пользовательских данных является неотъемлемой частью любой разработки сайта. Ранее мы объяснили некоторые из наиболее распространенных угроз безопасности в статье Web security — Эта статья дает практическую демонстрацию того, как встроенные средства защиты Django справляются с такими угрозами.
          +
          Защита пользовательских данных является неотъемлемой частью любой разработки сайта. Ранее мы объяснили некоторые из наиболее распространённых угроз безопасности в статье Web security — Эта статья даёт практическую демонстрацию того, как встроенные средства защиты Django справляются с такими угрозами.

          Задания

          diff --git a/files/ru/learn/server-side/django/introduction/index.html b/files/ru/learn/server-side/django/introduction/index.html index 29f854b94c..5bb12b1323 100644 --- a/files/ru/learn/server-side/django/introduction/index.html +++ b/files/ru/learn/server-side/django/introduction/index.html @@ -78,9 +78,9 @@ original_slug: Learn/Server-side/Django/Введение

          Веб-фреймворки часто можно поделить на "гибкие" и "негибкие".

          -

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

          +

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

          -

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

          +

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

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

          @@ -192,7 +192,7 @@ class Team(models.Model):

          Модель Django предоставляет простой API запросов для поиска в базе данных. Поиск может осуществляться по нескольким полям одновременно, используя различные критерии (такие как exact («точный»), case-insensitive («без учёта регистра»), greater than («больше чем») и т. д.), и может поддерживать сложные выражения (например, вы можете указать поиск в командах U11, у которых есть имя команды, начинающееся с «Fr» или заканчивается на «al»).

          -

          Фрагмент кода показывает функцию view (обработчик ресурсов) для отображения всех команд U09. Выделенная жирным строка показывает, как мы можем использовать модель API-запросов для того, чтобы отфильтровать все записи, где поле team_level в точности содержит текст 'U09' (обратите внимание, как эти критерии передаются функции filter() в качестве аргумента с именем поля и типом соответствия, разделённым двойным подчеркиванием: team_level__exact). 

          +

          Фрагмент кода показывает функцию view (обработчик ресурсов) для отображения всех команд U09. Выделенная жирным строка показывает, как мы можем использовать модель API-запросов для того, чтобы отфильтровать все записи, где поле team_level в точности содержит текст 'U09' (обратите внимание, как эти критерии передаются функции filter() в качестве аргумента с именем поля и типом соответствия, разделённым двойным подчёркиванием: team_level__exact). 

          ## filename: views.py
           
          @@ -243,7 +243,7 @@ def index(request):
           
           
          • Формы: HTML-формы используются для сбора пользовательских данных для обработки на сервере. Django упрощает создание, проверку и обработку формы.
          • -
          • Аутентификация пользователя и разрешения: Django включает надежную систему аутентификации и авторизации пользователей, которая была построена с учетом безопасности.
          • +
          • Аутентификация пользователя и разрешения: Django включает надёжную систему аутентификации и авторизации пользователей, которая была построена с учётом безопасности.
          • Кэширование: Создание динамического контента намного более интенсивно (и медленнее), чем обслуживание статического содержимого. Django обеспечивает гибкое кэширование, чтобы вы могли хранить всю или часть отображаемой страницы, для того, чтобы она не вызывалась повторно, за исключением случаев, когда это необходимо.
          • Админ-панель: Административная панель в Django включена по умолчанию при создании приложения с использованием основного каркаса. Это упрощает управление админкой администраторам сайта для создания, редактирования и просмотра любых данных на вашем сайте.
          • Сериализация данных (преобразование в последовательную форму): Django упрощает сериализацию и обслуживание ваших данных в таких форматах как XML или JSON. Это может быть полезно при создании веб-сервисов (веб-сайтов, которые исключительно служат для использования данных другими приложениями или сайтами и сами ничего не отображают) или при создании веб-сайта, на котором клиентский код обрабатывает весь рендеринг данных.
          • @@ -251,7 +251,7 @@ def index(request):

            Резюме

            -

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

            +

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

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

            diff --git a/files/ru/learn/server-side/django/models/index.html b/files/ru/learn/server-side/django/models/index.html index 4aeb0d64bc..8fa353116b 100644 --- a/files/ru/learn/server-side/django/models/index.html +++ b/files/ru/learn/server-side/django/models/index.html @@ -45,14 +45,14 @@ translation_of: Learn/Server-side/Django/Models

            Как только мы определились с нашими моделями и полями, нам нужно подумать об отношениях. Django позволяет вам определять отношения, как один к одному (OneToOneField), один ко многим (ForeignKey) и многие ко многим (ManyToManyField).

            -

            Диаграмма ассоциации UML, приведённая ниже показывает модели, которые мы определили в этом случае (в виде блоков). Как и выше, мы создали модели для книги (общие сведения о книге), экземпляр книги (статус конкретных физических копий книги, доступных в системе) и автора.Мы также решили создать модель для жанра, чтобы можно было создавать / выбирать значения через интерфейс администратора. Мы решили не иметь модель для BookInstance: status - мы жестко закодировали значения (LOAN_STATUS), потому что мы не ожидаем их изменения. В каждом из полей вы можете увидеть имя модели, имена и типы полей, а также методы и их типы возврата.

            +

            Диаграмма ассоциации UML, приведённая ниже показывает модели, которые мы определили в этом случае (в виде блоков). Как и выше, мы создали модели для книги (общие сведения о книге), экземпляр книги (статус конкретных физических копий книги, доступных в системе) и автора.Мы также решили создать модель для жанра, чтобы можно было создавать / выбирать значения через интерфейс администратора. Мы решили не иметь модель для BookInstance: status - мы жёстко закодировали значения (LOAN_STATUS), потому что мы не ожидаем их изменения. В каждом из полей вы можете увидеть имя модели, имена и типы полей, а также методы и их типы возврата.

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

            LocalLibrary Model UML - v3

            -

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

            +

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

            Модель для начинающих

            @@ -61,7 +61,7 @@ translation_of: Learn/Server-side/Django/Models

            Определение модели

            -

            Модели обычно определяются в приложении models.py. Они реализуются как подклассы django.db.models.Model, и могут включать поля, методы и метаданные. В приведенном ниже фрагменте кода показана «типичная» модель, названная MyModelName:

            +

            Модели обычно определяются в приложении models.py. Они реализуются как подклассы django.db.models.Model, и могут включать поля, методы и метаданные. В приведённом ниже фрагменте кода показана «типичная» модель, названная MyModelName:

            from django.db import models
             
            @@ -95,18 +95,18 @@ class MyModelName(models.Model):
             
             

            Поля

            -

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

            +

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

            my_field_name = models.CharField(max_length=20, help_text="Enter field documentation")
            -

            Наш вышеприведенный пример имеет одно поле, называемое my_field_name, типа models.CharField — что означает, что это поле будет содержать строки буквенно-цифровых символов. Типы полей назначаются с использованием определенных классов, которые определяют тип записи, которая используется для хранения данных в базе данных, а также критерии проверки, которые должны использоваться, когда значения получены из формы HTML (то есть, что составляет действительное значение). Типы полей также могут принимать аргументы, которые дополнительно определяют, как поле хранится или может использоваться. В этом случае мы даем нашему полю два аргумента:

            +

            Наш вышеприведённый пример имеет одно поле, называемое my_field_name, типа models.CharField — что означает, что это поле будет содержать строки буквенно-цифровых символов. Типы полей назначаются с использованием определённых классов, которые определяют тип записи, которая используется для хранения данных в базе данных, а также критерии проверки, которые должны использоваться, когда значения получены из формы HTML (то есть, что составляет действительное значение). Типы полей также могут принимать аргументы, которые дополнительно определяют, как поле хранится или может использоваться. В этом случае мы даём нашему полю два аргумента:

            • max_length=20 — Указывает, что максимальная длина значения в этом поле составляет 20 символов.
            • help_text="Enter field documentation" — предоставляет текстовую метку для отображения, чтобы помочь пользователям узнать, какое значение необходимо предоставить, когда это значение должно быть введено пользователем через HTML-форму.
            -

            Имя поля используется для обращения к нему в запросах и шаблонах. В полях также есть метка, которая задается как аргумент (verbose_name), либо выводится путем заглавной буквы первой буквы имени переменной поля и замены любых символов подчеркивания пробелом (например, my_field_name будет иметь метку по умолчанию My field name).

            +

            Имя поля используется для обращения к нему в запросах и шаблонах. В полях также есть метка, которая задаётся как аргумент (verbose_name), либо выводится путём заглавной буквы первой буквы имени переменной поля и замены любых символов подчёркивания пробелом (например, my_field_name будет иметь метку по умолчанию My field name).

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

            @@ -117,11 +117,11 @@ class MyModelName(models.Model):
            • help_text: Предоставляет текстовую метку для HTML-форм (например, на сайте администратора), как описано выше.
            • verbose_name: Удобочитаемое имя для поля, используемого в поле метки. Если не указано, Django выведет по умолчанию подробное название от имени поля.
            • -
            • default: Значение по умолчанию для поля. Это может быть значение или вызываемый объект, и в этом случае объект будет вызываться каждый раз, когда создается новая запись.
            • +
            • default: Значение по умолчанию для поля. Это может быть значение или вызываемый объект, и в этом случае объект будет вызываться каждый раз, когда создаётся новая запись.
            • null: Если True, Django будет хранить пустые значения как NULL в базе данных для полей, где это уместно (CharField вместо этого сохранит пустую строку). По умолчанию используется значение False.
            • blank: Если True, поле может быть пустым в ваших формах. По умолчанию используется значение False, что означает, что проверка формы Django заставит вас ввести значение. Это часто используется с null = True, потому что если вы хотите разрешить пустые значения, вы также хотите, чтобы база данных могла представлять их соответствующим образом.
            • choices: Группа вариантов для этого поля. Если это предусмотрено, по умолчанию соответствующий виджет формы будет полем выбора с этими вариантами вместо стандартного текстового поля.
            • -
            • primary_key: Если True, задает текущее поле в качестве первичного ключа для модели (первичный ключ - это специальный столбец базы данных, предназначенный для однозначной идентификации всех разных записей таблицы). Если в качестве первичного ключа не указано поле, Django автоматически добавит для этой цели поле.
            • +
            • primary_key: Если True, задаёт текущее поле в качестве первичного ключа для модели (первичный ключ - это специальный столбец базы данных, предназначенный для однозначной идентификации всех разных записей таблицы). Если в качестве первичного ключа не указано поле, Django автоматически добавит для этой цели поле.

            Есть много других вариантов - вы можете просмотреть full list of field options here.

            @@ -133,7 +133,7 @@ class MyModelName(models.Model):
            • CharField Используется для определения строк фиксированной длины от короткой до средней. Вы должны указать max_length для хранения данных.
            • TextField используется для больших строк произвольной длины. Вы можете указать max_length для поля, но это используется только тогда, когда поле отображается в формах (оно не применяется на уровне базы данных).
            • -
            • IntegerField это поле для хранения значений (целого числа) и для проверки введенных значений в виде целых чисел в формах.
            • +
            • IntegerField это поле для хранения значений (целого числа) и для проверки введённых значений в виде целых чисел в формах.
            • DateField и DateTimeField используются для хранения / представления дат и информации о дате / времени (как Python datetime.date и datetime.datetime, соответственно). Эти поля могут дополнительно объявлять (взаимоисключающие) параметры auto_now=True (для установки поля на текущую дату каждый раз, когда модель сохраняется), auto_now_add (только для установки даты, когда модель была впервые создана) и по умолчанию (чтобы установить дату по умолчанию, которую пользователь может переустановить).
            • EmailField используется для хранения и проверки адресов электронной почты.
            • FileField и ImageField используются для загрузки файлов и изображений соответственно ( ImageField просто добавляет дополнительную проверку, что загруженный файл является изображением). Они имеют параметры для определения того, как и где хранятся загруженные файлы.
            • @@ -160,7 +160,7 @@ class MyModelName(models.Model):

              Книги будут отсортированы по алфавиту по названию, от A-Z, а затем по дате публикации внутри каждого названия, от самого нового до самого старого.

              -

              Другим распространенным атрибутом является verbose_name, подробное имя для класса в единственной и множественной форме:

              +

              Другим распространённым атрибутом является verbose_name, подробное имя для класса в единственной и множественной форме:

              verbose_name = "BetterName"
              @@ -173,7 +173,7 @@ class MyModelName(models.Model):
              def __str__(self):
                   return self.field_name
              -

              Другим распространенным методом включения в модели Django является get_absolute_url (), который возвращает URL-адрес для отображения отдельных записей модели на веб-сайте (если вы определяете этот метод, тогда Django автоматически добавит кнопку «Просмотр на сайте» на экранах редактирования записей модели на сайте администратора). Типичный шаблон для get_absolute_url () показан ниже.

              +

              Другим распространённым методом включения в модели Django является get_absolute_url (), который возвращает URL-адрес для отображения отдельных записей модели на веб-сайте (если вы определяете этот метод, тогда Django автоматически добавит кнопку «Просмотр на сайте» на экранах редактирования записей модели на сайте администратора). Типичный шаблон для get_absolute_url () показан ниже.

              def get_absolute_url(self):
                   """
              @@ -183,9 +183,9 @@ class MyModelName(models.Model):
               
              -

              Примечание. Предполагается, что вы будете использовать URL-адреса, например / myapplication / mymodelname / 2, для отображения отдельных записей для вашей модели (где «2» - это идентификатор для определенной записи), вам нужно будет создать URL-карту, чтобы передать ответ и идентификатор «Образцовое представление модели» (которое будет выполнять работу, необходимую для отображения записи). Вышеуказанная функция reverse () может «перевернуть» ваш URL-адрес (в приведенном выше примере с именем «model-detail-view»), чтобы создать URL-адрес правильного формата.

              +

              Примечание. Предполагается, что вы будете использовать URL-адреса, например / myapplication / mymodelname / 2, для отображения отдельных записей для вашей модели (где «2» - это идентификатор для определённой записи), вам нужно будет создать URL-карту, чтобы передать ответ и идентификатор «Образцовое представление модели» (которое будет выполнять работу, необходимую для отображения записи). Вышеуказанная функция reverse () может «перевернуть» ваш URL-адрес (в приведённом выше примере с именем «model-detail-view»), чтобы создать URL-адрес правильного формата.

              -

              Конечно, для выполнения этой работы вам все равно придется писать сопоставление URL-адрес, просмотр и шаблон!

              +

              Конечно, для выполнения этой работы вам все равно придётся писать сопоставление URL-адрес, просмотр и шаблон!

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

              @@ -209,7 +209,7 @@ a_record.save()

              Примечание. Если вы не указали какое-либо поле в качестве primary_key, новая запись будет выдаваться автоматически, с идентификатором имени поля. Вы можете запросить это поле после сохранения указанной выше записи, и оно будет иметь значение 1.

        -

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

        +

        Вы можете получить доступ к полям в этой новой записи с использованием синтаксиса точек и изменить значения. Вы должны вызвать save (), чтобы сохранить изменённые значения в базе данных.

        # Access model field values using Python attributes.
         print(a_record.id) #should return 1 for the first record.
        @@ -221,10 +221,10 @@ a_record.save()

        Поиск записей

        -

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

        +

        Вы можете искать записи, соответствующие определённым критериям, используя атрибут объектов модели (предоставляемый базовым классом).

        -

        Примечание. Объяснение того, как искать записи, используя «абстрактную» модель и имена полей, может быть немного запутанным. В приведенном ниже обсуждении мы будем ссылаться на модель книги с полями названия и жанра, где жанр также является моделью с единственным именем в поле.

        +

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

        Мы можем получить все записи для модели как объект QuerySet,  используя objects.all(). QuerySet - это итерируемый объект, означающий, что он содержит несколько объектов, которые мы можем перебирать / прокручивать.

        @@ -238,22 +238,22 @@ a_record.save() number_wild_books = Book.objects.filter(title__contains='wild').count() -

        Соответствующие поля и тип соответствия определяются в имени параметра фильтра, используя формат: field_name__match_type (обратите внимание на двойное подчеркивание между заголовком выше). Выше мы фильтруем заголовок с учетом регистра. Есть много других типов совпадений, которые вы можете сделать: icontains (без учета регистра), iexact (точное совпадение без учета регистра), exact (точное совпадение с учетом регистра ) и in, gt (больше), startswith и т. д смотреть полный список (Django Docs, [EN]).

        +

        Соответствующие поля и тип соответствия определяются в имени параметра фильтра, используя формат: field_name__match_type (обратите внимание на двойное подчёркивание между заголовком выше). Выше мы фильтруем заголовок с учётом регистра. Есть много других типов совпадений, которые вы можете сделать: icontains (без учёта регистра), iexact (точное совпадение без учёта регистра), exact (точное совпадение с учётом регистра ) и in, gt (больше), startswith и т. д смотреть полный список (Django Docs, [EN]).

        -

        В некоторых случаях вам нужно будет фильтровать поле, которое определяет отношение «один ко многим» к другой модели (например, ForeignKey). В этом случае вы можете «индексировать» поля в связанной модели с дополнительными двойными подчеркиваниями. Так, например, чтобы фильтровать книги с определенным жанровым рисунком, вам нужно будет указывать имя в поле жанра, как показано ниже:

        +

        В некоторых случаях вам нужно будет фильтровать поле, которое определяет отношение «один ко многим» к другой модели (например, ForeignKey). В этом случае вы можете «индексировать» поля в связанной модели с дополнительными двойными подчёркиваниями. Так, например, чтобы фильтровать книги с определённым жанровым рисунком, вам нужно будет указывать имя в поле жанра, как показано ниже:

        books_containing_genre = Book.objects.filter(genre__name__icontains='fiction')  # Will match on: Fiction, Science fiction, non-fiction etc.
         
        -

        Примечание: Вы можете использовать символы подчеркивания (__) для навигации по многим уровням отношений (ForeignKey / ManyToManyField) по своему усмотрению. Например, книга, имеющая разные типы, определяемая с использованием дополнительной связи «обложка», может иметь имя параметра: type__cover__name__exact = 'hard'.

        +

        Примечание: Вы можете использовать символы подчёркивания (__) для навигации по многим уровням отношений (ForeignKey / ManyToManyField) по своему усмотрению. Например, книга, имеющая разные типы, определяемая с использованием дополнительной связи «обложка», может иметь имя параметра: type__cover__name__exact = 'hard'.

        Существует гораздо больше возможностей для запросов, включая обратные поиски от связанных моделей, цепочки фильтров, возврат меньшего набора значений и т. д. Для получения дополнительной информации см. Making queries (Django Docs, [EN]).

        Определение моделей LocalLibrary

        -

        В этом разделе мы начнем определять модели для библиотеки. Откройте models.py (в / locallibrary / catalog /). Шаблон в верхней части страницы импортирует модуль моделей, который содержит базовый класс модели models.Model, от которого наследуются наши модели.

        +

        В этом разделе мы начнём определять модели для библиотеки. Откройте models.py (в / locallibrary / catalog /). Шаблон в верхней части страницы импортирует модуль моделей, который содержит базовый класс модели models.Model, от которого наследуются наши модели.

        from django.db import models
         
        @@ -261,7 +261,7 @@ number_wild_books = Book.objects.filter(title__contains='wild').count()
         
         

        Модель жанра

        -

        Скопируйте приведенный ниже код модели Genre и вставьте его в нижнюю часть вашего файла models.py. Эта модель используется для хранения информации о категории книг - например, будь то художественная или документальная, роман или военно-историческая и т. д. Как уже упоминалось выше, мы создали жанр как модель, а не как свободный текст или список выбора, чтобы возможные значения могли управляться через базу данных, а не были закодированными.

        +

        Скопируйте приведённый ниже код модели Genre и вставьте его в нижнюю часть вашего файла models.py. Эта модель используется для хранения информации о категории книг - например, будь то художественная или документальная, роман или военно-историческая и т. д. Как уже упоминалось выше, мы создали жанр как модель, а не как свободный текст или список выбора, чтобы возможные значения могли управляться через базу данных, а не были закодированными.

        class Genre(models.Model):
             """
        @@ -275,11 +275,11 @@ number_wild_books = Book.objects.filter(title__contains='wild').count()
                 """
                 return self.name
        -

        Модель имеет один CharField field (имя), которое используется для описания жанра (оно ограничено 200 символами и имеет некоторый help_text. В конце модели мы объявляем метод __str__(), который просто возвращает имя жанра, определенного конкретной записью. Verbose name не был определен, поэтому поле будет называться Name в формах.

        +

        Модель имеет один CharField field (имя), которое используется для описания жанра (оно ограничено 200 символами и имеет некоторый help_text. В конце модели мы объявляем метод __str__(), который просто возвращает имя жанра, определённого конкретной записью. Verbose name не был определён, поэтому поле будет называться Name в формах.

        Модель книги

        -

        Скопируйте модель книги ниже и снова вставьте ее в нижнюю часть файла. Модель книги представляет всю информацию о доступной книге в общем смысле, но не конкретный физический «экземпляр» или «копию» для временного использования. Модель использует CharField для представления названия книги и isbn (обратите внимание, как isbn указывает свой ярлык как «ISBN», используя первый неименованный параметр, поскольку в противном случае ярлык по умолчанию был бы «Isbn»). Модель использует TextField для summary, потому что этот текст, возможно, должен быть очень длинным.

        +

        Скопируйте модель книги ниже и снова вставьте её в нижнюю часть файла. Модель книги представляет всю информацию о доступной книге в общем смысле, но не конкретный физический «экземпляр» или «копию» для временного использования. Модель использует CharField для представления названия книги и isbn (обратите внимание, как isbn указывает свой ярлык как «ISBN», используя первый неименованный параметр, поскольку в противном случае ярлык по умолчанию был бы «Isbn»). Модель использует TextField для summary, потому что этот текст, возможно, должен быть очень длинным.

        from django.urls import reverse #Used to generate URLs by reversing the URL patterns
         
        @@ -313,13 +313,13 @@ class Book(models.Model):
         
         

        Жанр представляет из себя ManyToManyField, так что книга может иметь несколько жанров, а жанр может иметь много книг. Автор объявляется через ForeignKey, поэтому в каждой книге будет только один автор, но у автора может быть много книг (на практике книга может иметь несколько авторов, но не в такой реализации!)

        -

        В обоих типах полей соответствующий класс модели объявляется как первый неименованный параметр, используя либо класс модели, либо строку, содержащую имя соответствующей модели. Вы должны использовать имя модели как строку, если связанный класс еще не был определен в этом файле до того, как он будет указан! Другими параметрами, представляющими интерес для поля автора, являются null=True, которое позволяет базе данных хранить значение Null , если автор не выбран, и on_delete = models. SET_NULL установит значение автора в Null, если связанная с автором запись будет удалена.

        +

        В обоих типах полей соответствующий класс модели объявляется как первый неименованный параметр, используя либо класс модели, либо строку, содержащую имя соответствующей модели. Вы должны использовать имя модели как строку, если связанный класс ещё не был определён в этом файле до того, как он будет указан! Другими параметрами, представляющими интерес для поля автора, являются null=True, которое позволяет базе данных хранить значение Null , если автор не выбран, и on_delete = models. SET_NULL установит значение автора в Null, если связанная с автором запись будет удалена.

        Модель также определяет __str __ (), используя поле заголовка книги для представления книги. Окончательный метод get_absolute_url () возвращает URL-адрес, который можно использовать для доступа к подробной записи для этой модели (для этого нам нужно будет определить сопоставление URL-адресов, в котором содержится подробная информация о книге, и определить связанное представление и шаблон ).

        Модель BookInstance

        -

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

        +

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

        • ForeignKey для идентификации связанной книги (в каждой книге может быть много копий, но в копии может быть только одна книга).
        • @@ -361,7 +361,7 @@ class BookInstance(models.Model):
          • UUIDField используется для поля id, чтобы установить его как primary_key для этой модели. Этот тип поля выделяет глобальное уникальное значение для каждого экземпляра (по одному для каждой книги, которую вы можете найти в библиотеке).
          • DateField используется для данных due_back (при которых ожидается, что книга появится после заимствования или обслуживания). Это значение может быть blank или null (необходимо, когда книга доступна). Метаданные модели (Class Meta) используют это поле для упорядочивания записей, когда они возвращаются в запросе.
          • -
          • status - это CharField, который определяет список choice/selection. Как вы можете видеть, мы определяем кортеж, содержащий кортежи пар ключ-значение и передаем его аргументу выбора. Значение в key/value паре - это отображаемое значение, которое пользователь может выбрать, а ключи - это значения, которые фактически сохраняются, если выбрана опция. Мы также установили значение по умолчанию «m» (техническое обслуживание), поскольку книги изначально будут созданы недоступными до того, как они будут храниться на полках.
          • +
          • status - это CharField, который определяет список choice/selection. Как вы можете видеть, мы определяем кортеж, содержащий кортежи пар ключ-значение и передаём его аргументу выбора. Значение в key/value паре - это отображаемое значение, которое пользователь может выбрать, а ключи - это значения, которые фактически сохраняются, если выбрана опция. Мы также установили значение по умолчанию «m» (техническое обслуживание), поскольку книги изначально будут созданы недоступными до того, как они будут храниться на полках.

          Модель __str __ () представляет объект BookInstance, используя комбинацию его уникального идентификатора и связанного с ним заголовка книги.

          @@ -370,7 +370,7 @@ class BookInstance(models.Model):

          Примечание. Немного Python:

            -
          • Значение, возвращаемое __str __ (), является форматированной строкой. В строке мы используем % S для объявления 'placeholders'. После строки укажем %, а затем кортеж, содержащий значения, которые будут вставлены в заполнители. Если у вас просто один заполнитель, вы можете опустить кортеж - например, 'Мое значение:% S' % переменная.
            +
          • Значение, возвращаемое __str __ (), является форматированной строкой. В строке мы используем % S для объявления 'placeholders'. После строки укажем %, а затем кортеж, содержащий значения, которые будут вставлены в заполнители. Если у вас просто один заполнитель, вы можете опустить кортеж - например, 'Моё значение:% S' % переменная.

            Обратите также внимание на то, что, хотя этот подход совершенно применим, но он более не является предпочтительным. Начиная с Python 3, вы должны использовать метод format, например. '{0} ({1})'.format (self.id, self.book.title). Вы можете узнать больше об этом  здесь.
          @@ -420,7 +420,7 @@ python3 manage.py migrate
        • Должен ли «язык» ассоциироваться с Book, BookInstance или каким-либо другим объектом?
        • -
        • Должны ли быть представлены разные языки с использованием модели, свободного текстового поля или жестко запрограммированного списка выбора?
        • +
        • Должны ли быть представлены разные языки с использованием модели, свободного текстового поля или жёстко запрограммированного списка выбора?

        После того, как вы решили, добавьте поле. Вы можете увидеть наше решение на Github here.

        @@ -435,7 +435,7 @@ python3 manage.py migrate

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

        -

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

        +

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

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

        diff --git a/files/ru/learn/server-side/django/sessions/index.html b/files/ru/learn/server-side/django/sessions/index.html index cccdb20266..22b6248b35 100644 --- a/files/ru/learn/server-side/django/sessions/index.html +++ b/files/ru/learn/server-side/django/sessions/index.html @@ -19,13 +19,13 @@ original_slug: Learn/Server-side/Django/Сессии
        {{PreviousMenuNext("Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django/authentication_and_sessions", "Learn/Server-side/Django")}}
        -

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

        +

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

        - + @@ -44,7 +44,7 @@ original_slug: Learn/Server-side/Django/Сессии

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

        -

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

        +

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

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

        @@ -68,9 +68,9 @@ MIDDLEWARE = [

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

        -

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

        +

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

        -

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

        +

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

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

        @@ -83,7 +83,7 @@ MIDDLEWARE = [ my_car = request.session['my_car'] # Получение значения сессии. Если значения не существует, -# то вернется значение по умолчанию ('mini') +# то вернётся значение по умолчанию ('mini') my_car = request.session.get('my_car', 'mini') # Передача значения в сессию @@ -115,7 +115,7 @@ request.session['my_car']['wheels'] = 'alloy'
        -

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

        +

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

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

        @@ -141,7 +141,7 @@ request.session['my_car']['wheels'] = 'alloy' 'num_visits':num_visits}, # num_visits appended ) -

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

        +

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

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

        diff --git a/files/ru/learn/server-side/django/skeleton_website/index.html b/files/ru/learn/server-side/django/skeleton_website/index.html index 3a2dfa47b7..f5e25a0b9c 100644 --- a/files/ru/learn/server-side/django/skeleton_website/index.html +++ b/files/ru/learn/server-side/django/skeleton_website/index.html @@ -336,7 +336,7 @@ python3 manage.py migrate

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

        -

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

        +

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

        diff --git a/files/ru/learn/server-side/django/testing/index.html b/files/ru/learn/server-side/django/testing/index.html index 248141c498..7721c05dc1 100644 --- a/files/ru/learn/server-side/django/testing/index.html +++ b/files/ru/learn/server-side/django/testing/index.html @@ -18,7 +18,7 @@ translation_of: Learn/Server-side/Django/Testing
        {{PreviousMenuNext("Learn/Server-side/Django/Forms", "Learn/Server-side/Django/Deployment", "Learn/Server-side/Django")}}
        -

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

        +

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

        Требования:Завершить изучение всех предыдущих разделов, включая Django Руководство Часть 6: Обобщенные отображения списков и детальной информацииЗавершить изучение всех предыдущих разделов, включая Django Руководство Часть 6: Обобщённые отображения списков и детальной информации
        Цель:
        @@ -37,7 +37,7 @@ translation_of: Learn/Server-side/Django/Testing

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

        -

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

        +

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

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

        @@ -45,13 +45,13 @@ translation_of: Learn/Server-side/Django/Testing

        Типы тестирования

        -

        Существует несколько типов, уровней, классификаций тестов и тестовых приемов. Наиболее важными автоматическими тестами являются:

        +

        Существует несколько типов, уровней, классификаций тестов и тестовых приёмов. Наиболее важными автоматическими тестами являются:

        Юнит-тесты
        Проверяют функциональное поведение для отдельных компонентов, часто классов и функций.
        Регрессионное тестирование
        -
        Тесты которые воспроизводят исторические ошибки (баги). Каждый тест вначале запускается для проверки того, что баг был исправлен, а затем перезапускается для того, чтобы убедиться, что он не был внесен снова с появлением новых изменений в коде.
        +
        Тесты которые воспроизводят исторические ошибки (баги). Каждый тест вначале запускается для проверки того, что баг был исправлен, а затем перезапускается для того, чтобы убедиться, что он не был внесён снова с появлением новых изменений в коде.
        Интеграционные тесты
        Проверка совместной работы групп компонентов. Данные тесты отвечают за совместную работу между компонентами, не обращая внимания на внутренние процессы в компонентах. Они проводятся как для простых групп компонентов, так и для целых веб-сайтов.
        @@ -62,11 +62,11 @@ translation_of: Learn/Server-side/Django/Testing

        Что Django предоставляет для тестирования?

        -

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

        +

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

        Django предоставляет фреймворк для создания тестов, построенного на основе иерархии классов, которые, в свою очередь, зависят от стандартной библиотеки Python  unittest. Несмотря на название, данный фреймворк подходит и для юнит-, и для интеграционного тестирования. Фреймворк Django добавляет методы API и инструменты, которые помогают тестировать как веб так и, специфическое для Django, поведение. Это позволяет вам имитировать URL-запросы, добавление тестовых данных, а также проводить проверку выходных данных ваших приложений. Кроме того, Django предоставляет API (LiveServerTestCase) и инструменты для применения различных фреймворков тестирования, например вы можете подключить популярный фреймворк Selenium для имитации поведения пользователя в реальном браузере.

        -

        Для написания теста вы должны наследоваться от любого из классов тестирования Django (или юниттеста)  (SimpleTestCaseTransactionTestCaseTestCaseLiveServerTestCase), а затем реализовать отдельные методы проверки кода (тесты это функции-"утверждения", которые проверяют, что результатом выражения являются значения True или False, или что два значения равны и так далее). Когда вы запускаете тест, фреймворк выполняет соответствующие тестовые методы в вашем классе-наследнике. Методы тестирования запускаются независимо друг от друга, начиная с метода настроек и/или завершаясь методом разрушения (tear-down), определенном в классе, как показано ниже.

        +

        Для написания теста вы должны наследоваться от любого из классов тестирования Django (или юниттеста)  (SimpleTestCaseTransactionTestCaseTestCaseLiveServerTestCase), а затем реализовать отдельные методы проверки кода (тесты это функции-"утверждения", которые проверяют, что результатом выражения являются значения True или False, или что два значения равны и так далее). Когда вы запускаете тест, фреймворк выполняет соответствующие тестовые методы в вашем классе-наследнике. Методы тестирования запускаются независимо друг от друга, начиная с метода настроек и/или завершаясь методом разрушения (tear-down), определённом в классе, как показано ниже.

        class YourTestClass(TestCase):
         
        @@ -85,7 +85,7 @@ translation_of: Learn/Server-side/Django/Testing
                 self.assertTrue(False)
         
        -

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

        +

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

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

        @@ -95,7 +95,7 @@ translation_of: Learn/Server-side/Django/Testing

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

        -

        Например, рассмотрим модель Author, определенную ниже. Вам не нужно проверять тот факт, что first_name и last_name были сохранены в базу данных как CharField, потому что за это отвечает непосредственно Django (хотя конечно, на практике  в течение разработки вы косвенно будете проверять данную функциональность). Тоже касается и, например, проверки того, что поле date_of_birth является датой, поскольку это тоже часть реализации Django.

        +

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

        Вы должны проверить текст для меток (First name, Last_name, Date of birth, Died), и размер поля, выделенного для текста (100 символов), потому что они являются частью вашей разработки и чем-то, что может сломаться/измениться в будущем.

        @@ -117,11 +117,11 @@ translation_of: Learn/Server-side/Django/Testing

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

        -

        Ну что же, усвоив данную информацию, давайте перейдем к процессу определения и запуска тестов.

        +

        Ну что же, усвоив данную информацию, давайте перейдём к процессу определения и запуска тестов.

        Обзор структуры тестов

        -

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

        +

        Перед тем как мы перейдём к тому "что тестировать", давайте кратко взглянем на моменты где и как определяются тесты.

        Django использует юнит-тестовый модуль - встроенный "обнаружитель" тестов, который находит тесты в текущей рабочей директории, в любом файле с шаблонным именем test*.py. Предоставляя соответствующие имена файлов, вы можете работать с любой структурой которая вас устраивает. Мы рекомендуем создать пакет для вашего тестирующего кода и, следовательно, отделить файлы моделей, отображений, форм и любые другие, от кода который будет использоваться для тестов. Например:

        @@ -136,7 +136,7 @@ translation_of: Learn/Server-side/Django/Testing

        В проекте LocalLibrary создайте файловую структуру, указанную выше. Файл __init__.py должен быть пустым (так мы говорим Питону, что данная директория является пакетом). Вы можете создать три тестовых файла при помощи копирования и переименования файла-образца /catalog/tests.py.

        -

        Примечание: Скелет тестового файла /catalog/tests.py был создан автоматически когда мы выполняли построение скелета сайта Django. Является абсолютно "легальным" действием - поместить все ваши тесты в данный файл, тем не менее, если вы проводите тесты "правильно", то вы очень быстро придете к очень большому и неуправляемому файлу тестирования.

        +

        Примечание: Скелет тестового файла /catalog/tests.py был создан автоматически когда мы выполняли построение скелета сайта Django. Является абсолютно "легальным" действием - поместить все ваши тесты в данный файл, тем не менее, если вы проводите тесты "правильно", то вы очень быстро придёте к очень большому и неуправляемому файлу тестирования.

        Можете удалить данный файл, поскольку больше он нам не понадобится.

        @@ -148,7 +148,7 @@ translation_of: Learn/Server-side/Django/Testing # Поместите ваш код тестов здесь -

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

        +

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

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

        @@ -200,7 +200,7 @@ translation_of: Learn/Server-side/Django/Testing
        python3 manage.py test
        -

        Таким образом мы найдем в текущей директории все файлы с именем test*.py и запустим все тесты (у нас имеются несколько файлов для тестирования, но на данный момент, только /catalog/tests/test_models.py содержит какие-либо тесты). По умолчанию, тесты сообщат что-нибудь, только в случае провала.

        +

        Таким образом мы найдём в текущей директории все файлы с именем test*.py и запустим все тесты (у нас имеются несколько файлов для тестирования, но на данный момент, только /catalog/tests/test_models.py содержит какие-либо тесты). По умолчанию, тесты сообщат что-нибудь, только в случае провала.

        Запустите тесты из корневой папки сайта LocalLibrary. Вы должны увидеть вывод, который похож на следующий.

        @@ -239,7 +239,7 @@ Destroying test database for alias 'default'...

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

        -

        Еще больше тестовой информации

        +

        Ещё больше тестовой информации

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

        @@ -247,7 +247,7 @@ Destroying test database for alias 'default'...

        Доступными значениями для verbosity являются  0, 1 (значение по умолчанию), 2 и 3.

        -

        Запуск определенных тестов

        +

        Запуск определённых тестов

        Если вы хотите запустить подмножество тестов, тогда вам надо указать полный путь к вашему пакету, модулю/подмодулю, классу наследникуTestCase, или методу:

        @@ -262,14 +262,14 @@ python3 manage.py test catalog.tests.test_models.YourTestClass.test_one_plus_one

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

        -

        Примечание: Мы не будем расписывать все тесты, а просто покажем вам пример того, как они должны работать и что еще вы можете с ними сделать.

        +

        Примечание: Мы не будем расписывать все тесты, а просто покажем вам пример того, как они должны работать и что ещё вы можете с ними сделать.

        Модели

        Как было отмечено ранее, мы должны тестировать все то, что является частью нашего кода, а не библиотеки/код, которые уже были протестированы командами разработчиков Django, или Python.

        -

        Рассмотрим модель Author. Мы должны провести тесты текстовых меток всех полей, поскольку, даже несмотря на то, что не все они определены, у нас есть проект, в котором сказано, что все их значения должны быть заданы. Если мы не проведем их тестирование, тогда мы не будем знать, что данные метки действительно содержат необходимые значения. Мы уверены в том, что Django создаст поле заданной длины, таким образом наши тесты будут проверять нужный нам размер поля, а заодно и его содержимое.

        +

        Рассмотрим модель Author. Мы должны провести тесты текстовых меток всех полей, поскольку, даже несмотря на то, что не все они определены, у нас есть проект, в котором сказано, что все их значения должны быть заданы. Если мы не проведём их тестирование, тогда мы не будем знать, что данные метки действительно содержат необходимые значения. Мы уверены в том, что Django создаст поле заданной длины, таким образом наши тесты будут проверять нужный нам размер поля, а заодно и его содержимое.

        class Author(models.Model):
             first_name = models.CharField(max_length=100)
        @@ -283,9 +283,9 @@ python3 manage.py test catalog.tests.test_models.YourTestClass.test_one_plus_one
             def __str__(self):
                 return '%s, %s' % (self.last_name, self.first_name)
        -

        Откройте файл /catalog/tests/test_models.py и замените все его содержимое кодом, приведенном во фрагменте для тестирования модели Author (фрагмент представлен ниже).

        +

        Откройте файл /catalog/tests/test_models.py и замените все его содержимое кодом, приведённом во фрагменте для тестирования модели Author (фрагмент представлен ниже).

        -

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

        +

        В первой строке мы импортируем класс TestCase, а затем наследуемся от него, создавая класс с описательным именем (AuthorModelTest), оно поможет нам идентифицировать места провалов в тестах во время вывода информации на консоль. Затем мы создаём метод setUpTestData(), в котором создаём объект автора, который мы будем использовать в тестах, но нигде не будем изменять.

        from django.test import TestCase
         
        @@ -385,7 +385,7 @@ AssertionError: 'Died' != 'died'
         
         

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

        -

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

        +

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

        Рассмотрим форму для обновления книг. Она имеет только одно поле обновления даты, которое будет иметь текстовую метку и вспомогательный текст, который вам надо проверить.

        @@ -401,7 +401,7 @@ AssertionError: 'Died' != 'died' #Проверка, что дата не в прошлом. if data < datetime.date.today(): raise ValidationError(_('Invalid date - renewal in past')) - #Если дата в "далеком" будущем (+4 недели) + #Если дата в "далёком" будущем (+4 недели) if data > datetime.date.today() + datetime.timedelta(weeks=4): raise ValidationError(_('Invalid date - renewal more than 4 weeks ahead')) @@ -455,7 +455,7 @@ class RenewBookFormTest(TestCase):

        Первые две функции проверяют текст который должны содержать поля label и help_text. Доступ к полю мы получаем при помощи словаря (то есть, form.fields['renewal_date']). Отметим, что мы должны проверять содержит ли метка значение None, иначе в поле текста метки вы увидите "None".

        -

        Оставшиеся функции проверяют валидность дат, то есть их нахождение внутри определенного интервала, а также невалидность для значений, которые находятся вне заданного интервала. Для получения исходного значения мы использовали функцию получения текущей даты (datetime.date.today()), а также функцию datetime.timedelta() (которая принимает определенное число дней, или недель). Затем мы просто создали форму, передавая ей наши данные и проверяя ее на валидность.

        +

        Оставшиеся функции проверяют валидность дат, то есть их нахождение внутри определённого интервала, а также невалидность для значений, которые находятся вне заданного интервала. Для получения исходного значения мы использовали функцию получения текущей даты (datetime.date.today()), а также функцию datetime.timedelta() (которая принимает определённое число дней, или недель). Затем мы просто создали форму, передавая ей наши данные и проверяя её на валидность.

        Примечание: В данном примере мы не использовали ни базу данных, ни тестовый клиент. Рассмотрите модификацию этих тестов при помощи класса SimpleTestCase.

        @@ -463,22 +463,22 @@ class RenewBookFormTest(TestCase):

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

        -

        На этом с формами можно закончить; у нас имеются и другие тесты, но они были созданы обобщенными классами отображения для редактирования! Запустите тесты и убедитесь, что наш код все еще им соответствует!

        +

        На этом с формами можно закончить; у нас имеются и другие тесты, но они были созданы обобщёнными классами отображения для редактирования! Запустите тесты и убедитесь, что наш код все ещё им соответствует!

        Отображения

        -

        Для проверки поведения отображения мы используем тестовый клиент Django Client. Данный класс действует как упрощенный веб-браузер который мы применяем для имитации  GET и POST запросов и проверки ответов. Про ответы мы можем узнать почти все, начиная с низкоуровневого HTTP (итоговые заголовки и коды статусов) и вплоть до применяемых шаблонов, которые используются для HTML-рендера, а также контекста, который передается в соответствующий  шаблон. Кроме того, мы можем отследить последовательность перенаправлений (если имеются), проверить URL-адреса и коды статусов на каждом шаге. Все это позволит нам проверить, что каждое отображение выполняет то, что ожидается.

        +

        Для проверки поведения отображения мы используем тестовый клиент Django Client. Данный класс действует как упрощённый веб-браузер который мы применяем для имитации  GET и POST запросов и проверки ответов. Про ответы мы можем узнать почти все, начиная с низкоуровневого HTTP (итоговые заголовки и коды статусов) и вплоть до применяемых шаблонов, которые используются для HTML-рендера, а также контекста, который передаётся в соответствующий  шаблон. Кроме того, мы можем отследить последовательность перенаправлений (если имеются), проверить URL-адреса и коды статусов на каждом шаге. Все это позволит нам проверить, что каждое отображение выполняет то, что ожидается.

        -

        Давайте начнем с одного из простейших отображений которое возвращает список всех авторов. Вы можете его увидеть по URL-адресу /catalog/authors/ (данный URL-адрес можно найти в разделе приложения catalog,  в файле настроек urls.py по имени  'authors').

        +

        Давайте начнём с одного из простейших отображений которое возвращает список всех авторов. Вы можете его увидеть по URL-адресу /catalog/authors/ (данный URL-адрес можно найти в разделе приложения catalog,  в файле настроек urls.py по имени  'authors').

        class AuthorListView(generic.ListView):
             model = Author
             paginate_by = 10
         
        -

        Поскольку это обобщенное отображение списка, то почти все за нас делает Django. Если вы доверяете Django, то единственной вещью, которую вам нужно протестировать, является переход к данному отображению по указанному URL-адресу. Таким образом, если вы применяете методику TDD (test-driven development, разработка через тесты), то начните проект с написания тестов, которые будут проверять, что данное отображение выводит всех авторов и, к тому же, например, блоками по 10.

        +

        Поскольку это обобщённое отображение списка, то почти все за нас делает Django. Если вы доверяете Django, то единственной вещью, которую вам нужно протестировать, является переход к данному отображению по указанному URL-адресу. Таким образом, если вы применяете методику TDD (test-driven development, разработка через тесты), то начните проект с написания тестов, которые будут проверять, что данное отображение выводит всех авторов и, к тому же, например, блоками по 10.

        -

        Откройте файл /catalog/tests/test_views.py замените все его содержимое на следующий код теста для класса AuthorListView. Как и ранее, мы импортируем нашу модель и некоторые полезные классы. В методе setUpTestData() мы задаем число объектов класса Author которые мы тестируем при постраничном выводе.

        +

        Откройте файл /catalog/tests/test_views.py замените все его содержимое на следующий код теста для класса AuthorListView. Как и ранее, мы импортируем нашу модель и некоторые полезные классы. В методе setUpTestData() мы задаём число объектов класса Author которые мы тестируем при постраничном выводе.

        from django.test import TestCase
         
        @@ -525,15 +525,15 @@ class AuthorListViewTest(TestCase):
                 self.assertTrue(resp.context['is_paginated'] == True)
                 self.assertTrue( len(resp.context['author_list']) == 3)
        -

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

        +

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

        resp = self.client.get('/catalog/authors/')
         resp = self.client.get(reverse('authors'))
         
        -

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

        +

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

        -

        Наиболее интересной переменной является resp.context, которая является объектом контекста, который передается шаблону из отображения. Он (объект контекста) очень полезен для тестов, поскольку позволяет нам убедиться, что наш шаблон получает все данные которые ему необходимы. Другими словами мы можем проверить, что мы используем правильный шаблон с данными, которые проделывают долгий путь проверок чтобы соответствовать данному шаблону.

        +

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

        Отображения и регистрация пользователей

        @@ -543,7 +543,7 @@ resp = self.client.get(reverse('authors')) class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView): """ - Обобщенный класс отображения списка взятых книг текущим пользователем + Обобщённый класс отображения списка взятых книг текущим пользователем """ model = BookInstance template_name ='catalog/bookinstance_list_borrowed_user.html' @@ -555,7 +555,7 @@ class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView):

        Добавьте тестовый код следующего фрагмента в /catalog/tests/test_views.py. В нем, для создания нескольких аккаунтов и  объектов BookInstance которые будут использоваться в дальнейших тестах, мы используем метод SetUp() (вместе с соответствующими книгами и другими записями). Половина книг бронируется  тестовыми пользователями, но в начале для них всех мы устанавливаем статус "доступно". Использование метода SetUp() предпочтительнее чем setUpTestData(), поскольку в дальнейшем мы будем модифицировать некоторые объекты.

        -

        Примечание: Метод setUp() создает книгу с заданным языком Language, но ваш код может не включать в себя модель Language, поскольку это было домашним заданием. В таком случае просто закомментируйте соответствующие строки. Поступите также и в следующем разделе, посвященном RenewBookInstancesViewTest.

        +

        Примечание: Метод setUp() создаёт книгу с заданным языком Language, но ваш код может не включать в себя модель Language, поскольку это было домашним заданием. В таком случае просто закомментируйте соответствующие строки. Поступите также и в следующем разделе, посвящённом RenewBookInstancesViewTest.

        import datetime
        @@ -611,7 +611,7 @@ class LoanedBookInstancesByUserListViewTest(TestCase):
                 self.assertTemplateUsed(resp, 'catalog/bookinstance_list_borrowed_user.html')
         
        -

        Если пользователь не залогирован то, чтобы убедиться в том что отображение перейдет на страницу входа (логирования), мы используем метод assertRedirects, что продемонстрировано в методе test_redirect_if_not_logged_in(). Затем мы осуществляем вход для пользователя и проверяем что полученный статус status_code равен 200 (успешно). 

        +

        Если пользователь не залогирован то, чтобы убедиться в том что отображение перейдёт на страницу входа (логирования), мы используем метод assertRedirects, что продемонстрировано в методе test_redirect_if_not_logged_in(). Затем мы осуществляем вход для пользователя и проверяем что полученный статус status_code равен 200 (успешно). 

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

        @@ -678,7 +678,7 @@ class LoanedBookInstancesByUserListViewTest(TestCase):

        Тестирование форм и отображений

        -

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

        +

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

        В качестве демонстрации давайте напишем некоторые тесты для отображения, которые отвечают за обновление книг(renew_book_librarian()):

        @@ -694,7 +694,7 @@ def renew_book_librarian(request, pk):     # Если это POST-запрос, тогда обработать данные формы     if request.method == 'POST': -        # Создать объект формы и заполнить ее данными из запроса (связывание/биндинг): +        # Создать объект формы и заполнить её данными из запроса (связывание/биндинг):         form = RenewBookForm(request.POST)         # Проверка валидности формы: @@ -706,7 +706,7 @@ def renew_book_librarian(request, pk):             # переход по URL-адресу:             return HttpResponseRedirect(reverse('all-borrowed') ) -    # Если это GET-запрос (или что-то еще), то создаем форму по умолчанию +    # Если это GET-запрос (или что-то ещё), то создаём форму по умолчанию     else:         proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3)         form = RenewBookForm(initial={'renewal_date': proposed_renewal_date,}) @@ -715,7 +715,7 @@ def renew_book_librarian(request, pk):

        Нам надо проверить что к данному отображению имеют доступ только те пользователи, которые имеют разрешение типа can_mark_returned, а кроме того, что пользователи перенаправляются на страницу ошибки HTTP 404  если они пытаются обновить экземпляр книги  BookInstance, который не существует. Мы должны проверить что начальное значение формы соответствует дате через 3 недели в будущем, а также то, что если форма прошла валидацию, то мы переходим на страницу отображения книг "all-borrowed" (забронированных). Для тестов, отвечающих за проверку "провалов", мы также должны удостовериться что они отправляют соответствующие сообщения об ошибках.

        -

        В нижнюю часть файла /catalog/tests/test_views.py добавьте класс тестирования (показан во фрагменте, ниже). Он создает двух пользователей и два экземпляра книги, но только один пользователь получает необходимый доступ к соответствующему отображению. Код, который "присваивает" соответствующий доступ, выделен в коде жирным:

        +

        В нижнюю часть файла /catalog/tests/test_views.py добавьте класс тестирования (показан во фрагменте, ниже). Он создаёт двух пользователей и два экземпляра книги, но только один пользователь получает необходимый доступ к соответствующему отображению. Код, который "присваивает" соответствующий доступ, выделен в коде жирным:

        from django.contrib.auth.models import Permission # Required to grant the permission needed to set a book as returned.
         
        @@ -750,7 +750,7 @@ class RenewBookInstancesViewTest(TestCase):
                 return_date= datetime.date.today() + datetime.timedelta(days=5)
                 self.test_bookinstance2=BookInstance.objects.create(book=test_book,imprint='Unlikely Imprint, 2016', due_back=return_date, borrower=test_user2, status='o')
        -

        В нижнюю часть класса тестирования добавьте следующие методы (из следующего фрагмента). Они проверяют, что только пользователь с соответствующим доступом (testuser2) имеет доступ к отображению. Мы проверяем все случаи: когда пользователь не залогинился, когда залогинился, но не имеет соответствующего доступа, когда имеет доступ, но не является заемщиком книги (тест должен быть успешным), а также, что произойдет если попытаться получить доступ к книге BookInstance которой не существует. Кроме того, мы проверяем то, что используется правильный (необходимый) шаблон.

        +

        В нижнюю часть класса тестирования добавьте следующие методы (из следующего фрагмента). Они проверяют, что только пользователь с соответствующим доступом (testuser2) имеет доступ к отображению. Мы проверяем все случаи: когда пользователь не залогинился, когда залогинился, но не имеет соответствующего доступа, когда имеет доступ, но не является заёмщиком книги (тест должен быть успешным), а также, что произойдёт если попытаться получить доступ к книге BookInstance которой не существует. Кроме того, мы проверяем то, что используется правильный (необходимый) шаблон.

            def test_redirect_if_not_logged_in(self):
                 resp = self.client.get(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}) )
        @@ -796,7 +796,7 @@ class RenewBookInstancesViewTest(TestCase):
                 self.assertTemplateUsed(resp, 'catalog/book_renew_librarian.html')
         
        -

        Добавьте еще один тестовый метод, показанный ниже. Он проверяет что начальная дата равна трем неделям в будущем. Заметьте, что мы имеем возможность получить доступ к начальному значению из поля формы (выделено жирным).

        +

        Добавьте ещё один тестовый метод, показанный ниже. Он проверяет что начальная дата равна трём неделям в будущем. Заметьте, что мы имеем возможность получить доступ к начальному значению из поля формы (выделено жирным).

            def test_form_renewal_date_initially_has_date_three_weeks_in_future(self):
                 login = self.client.login(username='testuser2', password='12345')
        @@ -807,7 +807,7 @@ class RenewBookInstancesViewTest(TestCase):
                 self.assertEqual(resp.context['form'].initial['renewal_date'], date_3_weeks_in_future )
         
        -

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

        +

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

            def test_redirects_to_all_borrowed_book_list_on_success(self):
                 login = self.client.login(username='testuser2', password='12345')
        @@ -817,7 +817,7 @@ class RenewBookInstancesViewTest(TestCase):
         
        -

        Вместо перехода к отображению all-borrowed, добавленного в качестве домашнего задания, вы можете перенаправить пользователя на домашнюю страницу '/'. В таком случае, исправьте две последние строки тестового кода на код, показанный ниже. Присваивание follow=True, в запросе, гарантирует что запрос вернет окончательный URL-адрес пункта назначения (следовательно проверяется /catalog/, а не /).

        +

        Вместо перехода к отображению all-borrowed, добавленного в качестве домашнего задания, вы можете перенаправить пользователя на домашнюю страницу '/'. В таком случае, исправьте две последние строки тестового кода на код, показанный ниже. Присваивание follow=True, в запросе, гарантирует что запрос вернёт окончательный URL-адрес пункта назначения (следовательно проверяется /catalog/, а не /).

         resp = self.client.post(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}), {'renewal_date':valid_date_in_future},follow=True )
          self.assertRedirects(resp, '/catalog/')
        @@ -844,7 +844,7 @@ class RenewBookInstancesViewTest(TestCase):

        Шаблоны

        -

        Django предоставляет API для тестирования, которое проверяет что функции отображения вызывают правильные шаблоны, а также позволяют убедиться, что им передается соответствующая информация. Кроме того, в Django имеется возможность использовать сторонние API для проверок того, что ваш HTML показывает то, что надо.

        +

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

        Другие рекомендованные инструменты для тестирования

        @@ -853,7 +853,7 @@ class RenewBookInstancesViewTest(TestCase):

        Из всего множества сторонних инструментов тестирования, мы кратко опишем возможности двух:

          -
        • Coverage: Это инструмент Python, который формирует отчеты о том, какое количество кода выполняется во время проведения тестов. Это полезно для уточнения степени "покрытия" кода тестами.
        • +
        • Coverage: Это инструмент Python, который формирует отчёты о том, какое количество кода выполняется во время проведения тестов. Это полезно для уточнения степени "покрытия" кода тестами.
        • Selenium это фреймворк проведения автоматического тестирования в настоящем браузере. Он позволяет вам имитировать взаимодействие пользователя с вашим сайтом (что является следующим шагом в проведении интеграционных тестов).
        @@ -871,7 +871,7 @@ class RenewBookInstancesViewTest(TestCase):

        Итоги

        -

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

        +

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

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

        diff --git a/files/ru/learn/server-side/django/web_application_security/index.html b/files/ru/learn/server-side/django/web_application_security/index.html index 435982ac1f..9ceb8c74e2 100644 --- a/files/ru/learn/server-side/django/web_application_security/index.html +++ b/files/ru/learn/server-side/django/web_application_security/index.html @@ -7,7 +7,7 @@ translation_of: Learn/Server-side/Django/web_application_security
        {{PreviousMenuNext("Learn/Server-side/Django/Deployment", "Learn/Server-side/Django/django_assessment_blog", "Learn/Server-side/Django")}}
        -

        Защита пользовательских данных - важная часть проектирования любого веб-сайта.Ранее мы рассматривали некоторые наиболее распространенные угрозы безопасности в теме Веб безопасность. В данной статье будет представлена практическая демонстрация того, как встроенные механизмы защиты Django's обрабатывают подобные угрозы.

        +

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

        @@ -24,7 +24,7 @@ translation_of: Learn/Server-side/Django/web_application_security

        Обзор

        -

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

        +

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

        Важно: Наиболее важный урок, который вы должны усвоить, состоит в том - что никогда не стоит доверять переданным пользователем данным. Они включают в себя GET параметры в URL, тело POST запроса, HTTP заголовки, cookies, загруженные пользователем данные и т.д. Всегда проверяйте и обрабатывайте все входные данные. Всегда готовьтесь к худшему.

        @@ -32,15 +32,15 @@ translation_of: Learn/Server-side/Django/web_application_security

        Хорошей новостью для всех разработчиков, использующих Django, является то, что большинство известных атак обрабатывается фреймворком! Статья Безопасность в Django (Django docs) описывает методы обеспечения безопасности Django и стратегии защиты веб-приложения разработанного на данном фреймворке.

        -

        Распространенные угрозы/методы защиты

        +

        Распространённые угрозы/методы защиты

        Мы не будем дублировать документацию Django и в данной статье продемонстрируем некоторые основные методы обеспечения безопасности в контексте разрабатываемого в данном руководстве приложения LocalLibrary.

        Межсайтовый скриптинг (XSS)

        -

        XSS это термин, применяющийся для описания класса атак, позволяющего атакующему, через веб-сайт внедрить скрипты, которые будут выполнены на устройстве зашедшего на страницу пользователя. Часто это происходит через сохранение вредоносного кода в базе данных, откуда данный код будет возвращен и выполнен для запросившего некие данные пользователя (типичный пример - сохранение тега <script> с вредоносным кодом в комментарии, который может увидеть другой пользователь). Другой вектор атаки - в том чтобы сгенерировать определенную ссылку, при клике на которую пользователь запустит выполнение некоего замаскированного кода JavaScript в своем браузере.

        +

        XSS это термин, применяющийся для описания класса атак, позволяющего атакующему, через веб-сайт внедрить скрипты, которые будут выполнены на устройстве зашедшего на страницу пользователя. Часто это происходит через сохранение вредоносного кода в базе данных, откуда данный код будет возвращён и выполнен для запросившего некие данные пользователя (типичный пример - сохранение тега <script> с вредоносным кодом в комментарии, который может увидеть другой пользователь). Другой вектор атаки - в том чтобы сгенерировать определённую ссылку, при клике на которую пользователь запустит выполнение некоего замаскированного кода JavaScript в своём браузере.

        -

        Система шаблонов Django защищает от большинства XSS атак,  экранируя определенные символы, считающиеся "опасными" в HTML. Мы можем продемонстрировать это, попытавшись внедрить произвольный JavaScript код в наше приложение LocalLibrary через форму добавления автора, созданную в Руководство часть 9: Работа с формами.

        +

        Система шаблонов Django защищает от большинства XSS атак,  экранируя определённые символы, считающиеся "опасными" в HTML. Мы можем продемонстрировать это, попытавшись внедрить произвольный JavaScript код в наше приложение LocalLibrary через форму добавления автора, созданную в Руководство часть 9: Работа с формами.

        1. Запустите веб-сайт, используя сервер разработки (python3 manage.py runserver).
        2. @@ -54,7 +54,7 @@ translation_of: Learn/Server-side/Django/web_application_security
      • Нажмите Submit для сохранения записи.
      • -
      • После сохранения автора - он должен быть отображен, как показано ниже. Так как сработала защита от XSS - команда alert() не будет запущена. Вместо этого скрипт будет отображаться как обычный текст.Author detail view XSS test
      • +
      • После сохранения автора - он должен быть отображён, как показано ниже. Так как сработала защита от XSS - команда alert() не будет запущена. Вместо этого скрипт будет отображаться как обычный текст.Author detail view XSS test
      • Если вы посмотрите исходный HTML код, вы увидите, что "опасные" символы - например такие как скобки тегов - были заменены на их безопасные эквивалентные html сущности (к примеру > на &gt;)

        @@ -64,7 +64,7 @@ translation_of: Learn/Server-side/Django/web_application_security

        Использование шаблонов Django защищает вас от большинства XSS атак. Однако существует возможность отключения данной защиты, при котором экранирование не будет автоматически применятся ко всем полям, которые не должны будут заполнятся пользователем(к примеру, поле help_text обычно заполняется не пользователем, поэтому Django не будет экранировать его значение).

        -

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

        +

        Так же XSS атаки могут быть осуществлены через другие ненадёжные источники данных, такие как cookies, сторонние сервисы или загруженные файлы (и прочие источники, данные которых не были специально обработаны перед отображением на странице). Если вы отображаете данные из этих источников, вы должны добавить ваш собственный обработчик для фильтрации данных.

        Межсайтовая подделка запроса (CSRF)

        @@ -93,9 +93,9 @@ translation_of: Learn/Server-side/Django/web_application_security </html> -

        Запустите веб-сервер разработки и войдите в аккаунт супер-пользователя. Скопируйте приведенный выше текст в файл и затем откройте его в браузере. Вы должны получить CSRF ошибку, потому что у Django есть защита от атак данного вида!

        +

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

        -

        Механизм защиты заключается в том, что вы добавляете тег шаблона {% csrf_token %} в вашу форму. Этот токен будет отображен в вашем HTML как показано ниже, со значением, уникальным для каждого запрашивающего форму пользователя.

        +

        Механизм защиты заключается в том, что вы добавляете тег шаблона {% csrf_token %} в вашу форму. Этот токен будет отображён в вашем HTML как показано ниже, со значением, уникальным для каждого запрашивающего форму пользователя.

        <input type='hidden' name='csrfmiddlewaretoken' value='0QRWHnYVg776y2l66mcvZqp8alrv4lb8S8lZ4ZJUWGZFA5VHrVfL2mpH29YZ39PW' />
         
        @@ -138,7 +138,7 @@ translation_of: Learn/Server-side/Django/web_application_security

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

        -

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

        +

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

        Это было очень краткое погружение в вопрос веб-безопасности. Мы крайне рекомендуем вам прочитать Безопасность в Django для более глубокого понимания.

        diff --git a/files/ru/learn/server-side/express_nodejs/development_environment/index.html b/files/ru/learn/server-side/express_nodejs/development_environment/index.html index 50a624c3cb..c0c188f731 100644 --- a/files/ru/learn/server-side/express_nodejs/development_environment/index.html +++ b/files/ru/learn/server-side/express_nodejs/development_environment/index.html @@ -35,7 +35,7 @@ translation_of: Learn/Server-side/Express_Nodejs/development_environment NPM также можно использовать для (глобальной) установки Express Application Generator, удобного инструмента для создания каркасных веб-приложений Express, которые следуют шаблону MVC. Генератор приложений является необязательным, поскольку вам не нужно использовать этот инструмент для создания приложений, использующих Express, или для приложений для создан Express, имеющих одинаковую архитектурную разметку или зависимости. Мы будем использовать его, потому что это значительно облегчает начало работы и продвигает модульную структуру приложения.

        -

        Примечание: в отличие от некоторых других веб-сред, среда разработки не включает отдельный веб-сервер разработки. В Node / Express веб-приложение создает и запускает собственный веб-сервер!

        +

        Примечание: в отличие от некоторых других веб-сред, среда разработки не включает отдельный веб-сервер разработки. В Node / Express веб-приложение создаёт и запускает собственный веб-сервер!

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

        @@ -50,11 +50,11 @@ translation_of: Learn/Server-side/Express_Nodejs/development_environment

        Существует множество выпусков Node - более новые выпуски содержат исправления ошибок, поддержку более свежих версий стандартов ECMAScript (JavaScript) и улучшения API-интерфейсов Node.

        - Как правило, вы должны использовать самый последний выпуск LTS (с долгосрочной поддержкой), поскольку он будет более стабильным, чем «текущий» выпуск, при этом все еще имея относительно недавние функции (и все еще активно поддерживается). Вы должны использовать Текущий выпуск, если вам нужна функция, которой нет в версии LTS.
        + Как правило, вы должны использовать самый последний выпуск LTS (с долгосрочной поддержкой), поскольку он будет более стабильным, чем «текущий» выпуск, при этом все ещё имея относительно недавние функции (и все ещё активно поддерживается). Вы должны использовать Текущий выпуск, если вам нужна функция, которой нет в версии LTS.

        Для Express вы всегда должны использовать последнюю версию.

        -

        Как насчет баз данных и других зависимостей?

        +

        Как насчёт баз данных и других зависимостей?

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

        @@ -78,7 +78,7 @@ translation_of: Learn/Server-side/Express_Nodejs/development_environment
      • Нажмите кнопку, чтобы загрузить сборку LTS, которая «Рекомендуется для большинства пользователей».
      • -
      • Установите Node, дважды щелкнув по загруженному файлу и следуя инструкциям по установке.
      • +
      • Установите Node, дважды щёлкнув по загруженному файлу и следуя инструкциям по установке.
      • Ubuntu 16.04

        @@ -98,7 +98,7 @@ sudo apt-get install -y nodejs

        Проверка вашей установки Nodejs и NPM

        -

        Самый простой способ проверить, установлен ли этот узел, - это запустить команду «версия» в своем терминале / командной строке и проверить, что возвращается строка версии:

        +

        Самый простой способ проверить, установлен ли этот узел, - это запустить команду «версия» в своём терминале / командной строке и проверить, что возвращается строка версии:

        >node -v
         v8.11.3
        @@ -137,7 +137,7 @@ server.listen(port, hostname, () => {

        Код импортирует модуль «http» и использует его для создания сервера (createServer ()), который обрабатывает HTTP-запросы на порту 3000. Затем сценарий выводит на консоль сообщение о том, какой URL-адрес браузера можно использовать для тестирования сервера. Функция createServer () принимает в качестве аргумента колбэк-функцию, которая будет вызываться при получении HTTP-запроса - она просто возвращает ответ с кодом состояния HTTP 200 («ОК») и простым текстом «Hello World».

        -

        Замечание: не беспокойтесь, если вы еще не совсем понимаете, что делает этот код! Мы объясним наш код более подробно, как только мы начнем использовать Express!

        +

        Замечание: не беспокойтесь, если вы ещё не совсем понимаете, что делает этот код! Мы объясним наш код более подробно, как только мы начнём использовать Express!

      • Запустите сервер, перейдя в тот же каталог, что и ваш файл hellonode.js в командной строке, и вызвав узел вместе с именем скрипта, например так: @@ -153,7 +153,7 @@ Server running at http://127.0.0.1:3000/

        Помимо самого Node, NPM является наиболее важным инструментом для работы с приложениями Node. NPM используется для получения любых пакетов (библиотек JavaScript), которые необходимы приложению для разработки, тестирования и / или производства, а также может использоваться для запуска тестов и инструментов, используемых в процессе разработки.

        -

        Замечание:  С точки зрения Node, Express - это просто еще один пакет, который вам нужно установить с помощью NPM, а затем установить его в своем собственном коде.

        +

        Замечание:  С точки зрения Node, Express - это просто ещё один пакет, который вам нужно установить с помощью NPM, а затем установить его в своём собственном коде.

        Вы можете вручную использовать NPM для получения каждого необходимого пакета отдельно. Обычно мы вместо этого управляем зависимостями, используя простой текстовый файл с именем package.json. В этом файле перечислены все зависимости для конкретного «пакета» JavaScript, включая имя пакета, версию, описание, исходный файл для выполнения, производственные зависимости, зависимости разработки, версии Node, с которыми он может работать, и т. Д. Файл package.json должен содержать все, что нужно NPM для загрузки и запуска вашего приложения (если вы пишете библиотеку многократного использования, вы можете использовать это определение для загрузки пакета в репозиторий npm и сделать его доступным для других пользователей).

        @@ -163,7 +163,7 @@ Server running at http://127.0.0.1:3000/

        Следующие шаги показывают, как вы можете использовать NPM для загрузки пакета, сохранить его в зависимостях проекта, а затем потребовать его в приложении Node.

        -

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

        +

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

          @@ -225,7 +225,7 @@ app.listen(8000, () => { }); -

          Этот код показывает минимальное веб-приложение Express «HelloWorld». Это импортирует модуль «экспресс» и использует его для создания сервера (приложения), который обрабатывает HTTP-запросы на порту 8000 и выводит на консоль сообщение, объясняющее, какой URL-адрес браузера можно использовать для тестирования сервера. Функция app.get () отвечает только на запросы HTTP GET с указанным URL-путем ('/'), в этом случае вызывая функцию для отправки нашего Hello World! сообщение.
          +

          Этот код показывает минимальное веб-приложение Express «HelloWorld». Это импортирует модуль «экспресс» и использует его для создания сервера (приложения), который обрабатывает HTTP-запросы на порту 8000 и выводит на консоль сообщение, объясняющее, какой URL-адрес браузера можно использовать для тестирования сервера. Функция app.get () отвечает только на запросы HTTP GET с указанным URL-путём ('/'), в этом случае вызывая функцию для отправки нашего Hello World! сообщение.

          Создайте файл с именем index.js в корне каталога приложения «myapp» и передайте ему содержимое, показанное выше.

          @@ -239,7 +239,7 @@ Example app listening on port 8000

          Зависимости разработки

          -

          Если зависимость используется только во время разработки, вы должны вместо этого сохранить ее как «зависимость разработки» (чтобы пользователям вашего пакета не приходилось устанавливать ее в производстве). Например, чтобы использовать популярный инструмент JavaScript Linting eslint, вы должны вызвать NPM, как показано ниже:

          +

          Если зависимость используется только во время разработки, вы должны вместо этого сохранить её как «зависимость разработки» (чтобы пользователям вашего пакета не приходилось устанавливать её в производстве). Например, чтобы использовать популярный инструмент JavaScript Linting eslint, вы должны вызвать NPM, как показано ниже:

          npm install eslint --save-dev
          @@ -284,7 +284,7 @@ npm run lint

          Установка Express Application Generator

          -

          Инструмент Express Application Generator создает «скелет» приложения Express. Установите генератор, используя NPM, как показано (флаг -g устанавливает инструмент глобально, чтобы вы могли вызывать его из любого места):

          +

          Инструмент Express Application Generator создаёт «скелет» приложения Express. Установите генератор, используя NPM, как показано (флаг -g устанавливает инструмент глобально, чтобы вы могли вызывать его из любого места):

          npm install express-generator -g
          @@ -302,7 +302,7 @@ npm run lint

          NPM создаст новое приложение Express в подпапке вашего текущего местоположения, отображая процесс сборки на консоли. По завершении инструмент отобразит команды, которые необходимо ввести, чтобы установить зависимости Node и запустить приложение.

          -

          Новое приложение будет иметь файл package.json в своем корневом каталоге. Вы можете открыть это, чтобы увидеть, какие зависимости установлены, включая Express и библиотеку шаблонов Jade:

          +

          Новое приложение будет иметь файл package.json в своём корневом каталоге. Вы можете открыть это, чтобы увидеть, какие зависимости установлены, включая Express и библиотеку шаблонов Jade:

          {
             "name": "helloworld",
          @@ -341,7 +341,7 @@ SET DEBUG=helloworld:* | npm start
           DEBUG=helloworld:* npm start
           
          -

          Команда DEBUG создает полезное ведение журнала, что приводит к выводу, подобному показанному ниже.

          +

          Команда DEBUG создаёт полезное ведение журнала, что приводит к выводу, подобному показанному ниже.

          >SET DEBUG=helloworld:* & npm start
           
          @@ -354,7 +354,7 @@ DEBUG=helloworld:* npm start
           
           

          Express - Generated App Default Screen

          -

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

          +

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

          @@ -363,7 +363,7 @@ DEBUG=helloworld:* npm start

          Теперь на вашем компьютере установлена и запущена среда разработки Node, которую можно использовать для создания веб-приложений Express. Вы также увидели, как NPM можно использовать для импорта Express в приложение, а также как вы можете создавать приложения с помощью инструмента Express Application Generator и затем запускать их.

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

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

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

          diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/author_list_page/index.html b/files/ru/learn/server-side/express_nodejs/displaying_data/author_list_page/index.html index 15097717f0..219f5639b0 100644 --- a/files/ru/learn/server-side/express_nodejs/displaying_data/author_list_page/index.html +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/author_list_page/index.html @@ -3,7 +3,7 @@ title: Список авторов. Тест - список жанров slug: Learn/Server-side/Express_Nodejs/Displaying_data/Author_list_page translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Author_list_page --- -

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

          +

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

          Контроллер

          @@ -74,8 +74,8 @@ block content
        1. Отображающий шаблон должен быть назван genre_list.pug.
        2. -
        3. Шаблону для отображения должны быть переданы переменные title (строка 'Genre List') и genre_list (the list of список жанров, который вернет колбэк-функция Genre.find().
        4. -
        5. Представление должно соответствовать скриншоту, приведенному ранее (оно должно иметь структуру и формат, похожие на таковые в представлении списка авторов, за исключением, конечно, продолжительности жизни, так как для жанров даты не заданы).
        6. +
        7. Шаблону для отображения должны быть переданы переменные title (строка 'Genre List') и genre_list (the list of список жанров, который вернёт колбэк-функция Genre.find().
        8. +
        9. Представление должно соответствовать скриншоту, приведённому ранее (оно должно иметь структуру и формат, похожие на таковые в представлении списка авторов, за исключением, конечно, продолжительности жизни, так как для жанров даты не заданы).

        Далее

        diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/book_list_page/index.html b/files/ru/learn/server-side/express_nodejs/displaying_data/book_list_page/index.html index fbbf8c9622..6bbab5a709 100644 --- a/files/ru/learn/server-side/express_nodejs/displaying_data/book_list_page/index.html +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/book_list_page/index.html @@ -3,7 +3,7 @@ title: Страница списка книг slug: Learn/Server-side/Express_Nodejs/Displaying_data/Book_list_page translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Book_list_page --- -

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

        +

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

        Контроллер

        @@ -24,7 +24,7 @@ exports.book_list }; -

        Метод использует функцию моделиfind() для возврата всех объектов Book, выбрав для возврата только заголовок и автора, поскольку нам не нужны другие поля (он также вернет _id и виртуальные поля). Здесь мы также вызываем populate() on Book, указывая поле  author —это заменит сохраненный идентификатор автора книги полными сведениями об авторе.

        +

        Метод использует функцию моделиfind() для возврата всех объектов Book, выбрав для возврата только заголовок и автора, поскольку нам не нужны другие поля (он также вернёт _id и виртуальные поля). Здесь мы также вызываем populate() on Book, указывая поле  author —это заменит сохранённый идентификатор автора книги полными сведениями об авторе.

        При успешном выполнении, колбэк передаст запрос на отрисовку шаблона book_list(.pug), передаст title иbook_list (список книг с автором) в качестве переменных.

        @@ -46,7 +46,7 @@ block content else li There are no books. -

        View расширит базовый шаблон layout.pug и переопределит block с именем 'content'. Он отображает  title который мы передали из контроллера (с помощью метода render() ), а затем перебирает переменную book_list  используя синтаксис each-in-else . Для каждой книги создается элемент списка, отображающий название книги в виде ссылки на страницу сведений о книге, за которой следует имя автора. Если в  book_list нет книг,  то выполняется else, и  отображается текст "нет книг".'

        +

        View расширит базовый шаблон layout.pug и переопределит block с именем 'content'. Он отображает  title который мы передали из контроллера (с помощью метода render() ), а затем перебирает переменную book_list  используя синтаксис each-in-else . Для каждой книги создаётся элемент списка, отображающий название книги в виде ссылки на страницу сведений о книге, за которой следует имя автора. Если в  book_list нет книг,  то выполняется else, и  отображается текст "нет книг".'

        Заметка: Мы используем book.url  для предоставления ссылки на подробную запись для каждой книги (мы реализовали этот маршрут, но не страницу). Это виртуальное свойство модели Book , которая использует поле  _id для создания уникального URL.

        diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/bookinstance_list_page/index.html b/files/ru/learn/server-side/express_nodejs/displaying_data/bookinstance_list_page/index.html index 6a924829bf..20b7d94f6a 100644 --- a/files/ru/learn/server-side/express_nodejs/displaying_data/bookinstance_list_page/index.html +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/bookinstance_list_page/index.html @@ -9,7 +9,7 @@ translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/BookInstance_li

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

        -

        Откройте файл /controllers/bookinstanceController.js. Найдите экспортируемый метод bookinstance_list() контроллера и замените его следующим кодом (измененный код выделен жирным).

        +

        Откройте файл /controllers/bookinstanceController.js. Найдите экспортируемый метод bookinstance_list() контроллера и замените его следующим кодом (изменённый код выделен жирным).

        // Display list of all BookInstances.
         exports.bookinstance_list = function(req, res, next) {
        @@ -30,7 +30,7 @@ exports.bookinstance_list Представление
         
        -

        Создайте файл  /views/bookinstance_list.pug и скопируйте в него текст, приведенный ниже.

        +

        Создайте файл  /views/bookinstance_list.pug и скопируйте в него текст, приведённый ниже.

        extends layout
         
        diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/date_formatting_using_moment/index.html b/files/ru/learn/server-side/express_nodejs/displaying_data/date_formatting_using_moment/index.html
        index 2180be7c4b..84e9925d43 100644
        --- a/files/ru/learn/server-side/express_nodejs/displaying_data/date_formatting_using_moment/index.html
        +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/date_formatting_using_moment/index.html
        @@ -46,7 +46,7 @@ translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Date_formatting
                 //span  (Due: #{val.due_back} )
                 span  (Due: #{val.due_back_formatted} )       
        -

        Вот и все. Если вы перейдете к  All book-instances в боковом меню, вы должны увидеть все даты  в привлекательном формате!

        +

        Вот и все. Если вы перейдёте к  All book-instances в боковом меню, вы должны увидеть все даты  в привлекательном формате!

         

        diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/flow_control_using_async/index.html b/files/ru/learn/server-side/express_nodejs/displaying_data/flow_control_using_async/index.html index f951a355e5..c09963fb70 100644 --- a/files/ru/learn/server-side/express_nodejs/displaying_data/flow_control_using_async/index.html +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/flow_control_using_async/index.html @@ -6,7 +6,7 @@ tags: - Часть 5 translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/flow_control_using_async --- -

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

        +

        Код контроллера для некоторых страниц библиотеки будет зависеть от результатов многих асинхронных запросов, которые должны выполняться в определённом порядке или параллельно. Для того, чтобы управлять потоком выполнения, и выводить страницы, когда получена вся необходимая информация, будет использован async - известный модуль node.

        Note:  В JavaScript существует много других способов управления асинхронным поведением и потоком выполнения, включая такой относительно  новый элемент языка JacaScript как Promises (обещания, промисы).

        @@ -17,12 +17,12 @@ translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/flow_control_us
        • async.parallel() для осуществления любых операций, которые должны выполняться параллельно.
        • async.series() если нужно иметь уверенность, что асинхронные операции выполняются последовательно.
        • -
        • async.waterfall() для операций, которые должны выполняться последовательно, причем каждая операция зависит от результатов предыдущих операций.
        • +
        • async.waterfall() для операций, которые должны выполняться последовательно, причём каждая операция зависит от результатов предыдущих операций.

        Почему это необходимо?

        -

        Большинство методов, которые используются в  Express - асинхронные - вы определяете выполняемую операцию, передавая  колбэк-функцию. Метод завершается немедленно, а колбэк-функция вызывается тогда, когда завершилась запрошенная операция. По соглашению, принятому в Express, колбэк-функция передает значение ошибки error  как первый параметр (или null при успехе) и результат функции (если есть) как второй параметр.

        +

        Большинство методов, которые используются в  Express - асинхронные - вы определяете выполняемую операцию, передавая  колбэк-функцию. Метод завершается немедленно, а колбэк-функция вызывается тогда, когда завершилась запрошенная операция. По соглашению, принятому в Express, колбэк-функция передаёт значение ошибки error  как первый параметр (или null при успехе) и результат функции (если есть) как второй параметр.

        Если контроллер должен выполнить только одну асинхронную операцию, чтобы получить информацию для представления страницы, то реализация проста - мы просто представляем шаблон в колбэке. Фрагмент кода (ниже) демонстрирует это для функции, которая подсчитывает количество элементов модели SomeModel (применяя метод Mongoose count() ):

        @@ -37,9 +37,9 @@ translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/flow_control_us }
        -

        Однако что, если требуется сделать множественные асинхронные запросы, и результат нельзя представить, пока не завершились все операции? Наивная реализация могла бы использовать "венок" запросов, запуская последующие запросы в колбэках предыдущих, и представляя ответ в последнем колбэке. Проблема такого подхода состоит в том, что запросы должны выполняться последовательно, хотя, вероятно, было бы более эффективно выполнять их параллельно. Это также может привести к усложненному вложенному коду, что обычно называют адом колбэков ( callback hell ).

        +

        Однако что, если требуется сделать множественные асинхронные запросы, и результат нельзя представить, пока не завершились все операции? Наивная реализация могла бы использовать "венок" запросов, запуская последующие запросы в колбэках предыдущих, и представляя ответ в последнем колбэке. Проблема такого подхода состоит в том, что запросы должны выполняться последовательно, хотя, вероятно, было бы более эффективно выполнять их параллельно. Это также может привести к усложнённому вложенному коду, что обычно называют адом колбэков ( callback hell ).

        -

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

        +

        Намного лучше было бы выполнять все запросы параллельно, и иметь единственную колбэк-функцию, которая будет вызвана после того как все запросы выполнены. Именно такое выполнение операций модуль Async делает лёгким и простым!

        Параллельные асинхронные операции

        @@ -47,7 +47,7 @@ translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/flow_control_us

        Первый аргумент в async.parallel() - это коллекция асинхронных функций, которые требуется выполнить (массив, объект или другой итерируемый элемент). Каждая функция получает колбэк-функцию callback(err, result) , которую она должна вызвать при завершении, с ошибкой err (может быть null) и, возможно, со значением результата results.

        -

        Возможный второй аргумент для  async.parallel() - это callback -функция, которая должна быть вызвана после завершения всех функций, указанных в первом аргументе. Эта функция вызывается с аргументом ошибки и результатом - коллекцией результатов отдельных асинхронных операций. Тип коллекции - такой же, как и тип первого аргумента async.parallel (т.е. если передается массив асинхронных функций, итоговая колбэк-функция будет вызвана с массивом результатов). Если любая из параллельных функций сообщила об ошибке, сразу вызывается итоговая колбэк-функция, которая возвращает ошибку.

        +

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

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

        @@ -67,7 +67,7 @@ translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/flow_control_us

        Последовательные асинхронные операции

        -

        Для выполнения нескольких асинхронных операций последовательно используется метод async.series() , при этом последующие функции не зависят от результатов предыдущих функций. Метод определяется и ведет себя так же, как и async.parallel().

        +

        Для выполнения нескольких асинхронных операций последовательно используется метод async.series() , при этом последующие функции не зависят от результатов предыдущих функций. Метод определяется и ведёт себя так же, как и async.parallel().

        async.series({
           one: function(callback) { ... },
        @@ -82,7 +82,7 @@ translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/flow_control_us
         );
        -

        Заметка: Спецификация языка ECMAScript (JavaScript) устанавливает, что порядок  в перечислении объектов не определен, поэтому возможно, что функции не будут вызываться в том порядке, в котором вы их задали на всех платформах. Если порядок вызова действительно важен, вместо объекта следует передавать массив, как показано ниже.

        +

        Заметка: Спецификация языка ECMAScript (JavaScript) устанавливает, что порядок  в перечислении объектов не определён, поэтому возможно, что функции не будут вызываться в том порядке, в котором вы их задали на всех платформах. Если порядок вызова действительно важен, вместо объекта следует передавать массив, как показано ниже.

        async.series([
        @@ -105,7 +105,7 @@ translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/flow_control_us
         
         

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

        -

        Функции-callback, которая вызываются асинхронными функциями , содержит null как первый аргумент, и результаты в следующих аргументах. Каждая функция в последовательности (кроме первой) как аргументы использует результаты предыдущих функция, а колбэк-функция является последним аргументом. Когда  операции завершаются, вызывается финальная колбэк-функция, аргументы которой - объект err и результат последней операции. Как это работает, станет более ясным после рассмотрения примера - фрагмента кода, приведенного ниже ( пример взят из документации async):

        +

        Функции-callback, которая вызываются асинхронными функциями , содержит null как первый аргумент, и результаты в следующих аргументах. Каждая функция в последовательности (кроме первой) как аргументы использует результаты предыдущих функция, а колбэк-функция является последним аргументом. Когда  операции завершаются, вызывается финальная колбэк-функция, аргументы которой - объект err и результат последней операции. Как это работает, станет более ясным после рассмотрения примера - фрагмента кода, приведённого ниже ( пример взят из документации async):

        async.waterfall([
           function(callback) {//первая функция в цепочке
        @@ -126,7 +126,7 @@ translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/flow_control_us
         
         

        Установка async

        -

        Установим модуль async при помощи менеджера пакетов NPM, чтобы использовать его в своем коде. Это делается обычным способом - откроем окно команд в корне проекта LocalLibrary и введем команду:

        +

        Установим модуль async при помощи менеджера пакетов NPM, чтобы использовать его в своём коде. Это делается обычным способом - откроем окно команд в корне проекта LocalLibrary и введём команду:

        npm install async
        diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/genre_detail_page/index.html b/files/ru/learn/server-side/express_nodejs/displaying_data/genre_detail_page/index.html index b3e40ff7a9..c62d6f9364 100644 --- a/files/ru/learn/server-side/express_nodejs/displaying_data/genre_detail_page/index.html +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/genre_detail_page/index.html @@ -43,7 +43,7 @@ exports.genre_detail = function(req, res, next) { };
        -

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

        +

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

        The ID of the required genre record is encoded at the end of the URL and extracted automatically based on the route definition (/genre/:id). The ID is accessed within the controller via the request parameters: req.params.id. It is used in Genre.findById() to get the current genre. It is also used to get all Book objects that have the genre ID in their genre field: Book.find({ 'genre': req.params.id }).

        diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/home_page/index.html b/files/ru/learn/server-side/express_nodejs/displaying_data/home_page/index.html index 2458131cd1..05b2dc3976 100644 --- a/files/ru/learn/server-side/express_nodejs/displaying_data/home_page/index.html +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/home_page/index.html @@ -14,20 +14,20 @@ translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Home_page
        // GET catalog home page.
         router.get('/', book_controller.index);  //This actually maps to /catalog/ because we import the route with a /catalog prefix
        -

        Параметр колбэк-функции определен в /controllers/bookController.js:

        +

        Параметр колбэк-функции определён в /controllers/bookController.js:

        exports.index = function(req, res, next) {
             res.send('NOT IMPLEMENTED: Site Home Page');
         }
        -

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

        +

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

        Контроллер

        -

        Функция контроллера индекса должна получать информацию о том, сколько книг (Book), экземпляров книг (BookInstance), сколько из них доступно, сколько авторов (Author), жанров (Genre) имеется в БД, должна поместить эту информацию в шаблон, чтобы создать  HTML-страницу, после чего вернуть ее в  HTTP-ответе.

        +

        Функция контроллера индекса должна получать информацию о том, сколько книг (Book), экземпляров книг (BookInstance), сколько из них доступно, сколько авторов (Author), жанров (Genre) имеется в БД, должна поместить эту информацию в шаблон, чтобы создать  HTML-страницу, после чего вернуть её в  HTTP-ответе.

        -

        Заметка: Количество экземпляров в каждой модели вычисляется при помощи метода countDocuments() . Он вызывается для модели с возможным набором условий, необходимых для проверки соответствия первому аргументу и колбэк-функции второго аргумента (обсуждалось ранее в "Использование базы данных с Mongoose" Using a Database (with Mongoose)), причем можно вернуть также запрос Query, а затем выполнить его позже при помощи callback. Эта  колбэк-функция будет выполняться, когда БД вернет количество записей.  Значение ошибки (or null) будет первым параметром, а количество записей (или null, если была ошибка) -  вторым параметром.

        +

        Заметка: Количество экземпляров в каждой модели вычисляется при помощи метода countDocuments() . Он вызывается для модели с возможным набором условий, необходимых для проверки соответствия первому аргументу и колбэк-функции второго аргумента (обсуждалось ранее в "Использование базы данных с Mongoose" Using a Database (with Mongoose)), причём можно вернуть также запрос Query, а затем выполнить его позже при помощи callback. Эта  колбэк-функция будет выполняться, когда БД вернёт количество записей.  Значение ошибки (or null) будет первым параметром, а количество записей (или null, если была ошибка) -  вторым параметром.

        SomeModel.countDocuments({ a_model_field: 'match_value' }, function (err, count) {
          // ... do something if there is an err
        @@ -43,7 +43,7 @@ exports.index = function(req, res, next) {
          res.send('NOT IMPLEMENTED: Site Home Page');
         }
        -

        Замените весь код, показанный выше, на следующий фрагмент кода. Первое, что он делает - импортирует (require())  все модели (выделено жирным).  Это требуется, поскольку они нужны для подсчета числа записей. Затем импортируется модуль async .

        +

        Замените весь код, показанный выше, на следующий фрагмент кода. Первое, что он делает - импортирует (require())  все модели (выделено жирным).  Это требуется, поскольку они нужны для подсчёта числа записей. Затем импортируется модуль async .

        var Book = require('../models/book');
         var Author = require('../models/author');
        @@ -76,7 +76,7 @@ exports.index = function(req, res) {
             });
         };
        -

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

        +

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

        При успешном завершении колбэк-функции она вызывает res.render(), у которой в качестве параметров - представление (шаблон)  'index' и объект, содержащий данные, которые следует поместить в шаблон (среди них - количества элементов в моделях). Данные представлены как пары ключ-значение, и могут быть получены в шаблоне по ключу.

        @@ -86,7 +86,7 @@ exports.index = function(req, res) {

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

        -

        Откройте файл  /views/index.pug и замените его содержимое текстом, приведенным ниже

        +

        Откройте файл  /views/index.pug и замените его содержимое текстом, приведённым ниже

        extends layout
         
        @@ -108,7 +108,7 @@ block content
               li #[strong Authors:] !{data.author_count}
               li #[strong Genres:] !{data.genre_count}
        -

        Представление несложное. Мы расширили базовый шаблон  layout.pug, переопределив блок (block) с именем 'content'. Первый заголовок h1 будет экранированным текстом - значением переменной title ,variable that  которая передается в функцию render() —заметьте, что применение 'h1='  говорит, что следующий текст рассматривается как выражение JavaScript. Затем расположен параграф, знакомящий с  LocalLibrary.

        +

        Представление несложное. Мы расширили базовый шаблон  layout.pug, переопределив блок (block) с именем 'content'. Первый заголовок h1 будет экранированным текстом - значением переменной title ,variable that  которая передаётся в функцию render() —заметьте, что применение 'h1='  говорит, что следующий текст рассматривается как выражение JavaScript. Затем расположен параграф, знакомящий с  LocalLibrary.

        Под заголовком Dynamic content  мы проверяем, определена ли переданная из функции render() переменная error. Если да, отмечаем ошибку. Если нет, выводим ( как список) количества копий каждой модели, которые хранятся в переменной data.

        @@ -118,12 +118,12 @@ block content

        Как это выглядит?

        -

        Сейчас у нас есть все для того, чтобы показать страницу index. Запустите приложение и откройте браузер с адресом http://localhost:3000/. Если все задано правильно, ваш сайт должен иметь примерно такой вид, как на приведенном снимке экрана.

        +

        Сейчас у нас есть все для того, чтобы показать страницу index. Запустите приложение и откройте браузер с адресом http://localhost:3000/. Если все задано правильно, ваш сайт должен иметь примерно такой вид, как на приведённом снимке экрана.

        Home page - Express Local Library site

        -

        Заметка:  Элементы бокового меню использовать еще нельзя, так как адреса, представления и шаблоны для этих страниц еще не определены. Если вы попытаетесь их использовать, будет выведено сообщение об ошибке, например,  вида "NOT IMPLEMENTED: Book list" (НЕ РЕАЛИЗОВАНО: список книг), в зависимости от выбранного элемента меню.  Эти строковые литералы (которые будут замещены действительными данными) были заданы в различных файлах контроллеров в каталоге "controllers".

        +

        Заметка:  Элементы бокового меню использовать ещё нельзя, так как адреса, представления и шаблоны для этих страниц ещё не определены. Если вы попытаетесь их использовать, будет выведено сообщение об ошибке, например,  вида "NOT IMPLEMENTED: Book list" (НЕ РЕАЛИЗОВАНО: список книг), в зависимости от выбранного элемента меню.  Эти строковые литералы (которые будут замещены действительными данными) были заданы в различных файлах контроллеров в каталоге "controllers".

        Next steps

        diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/index.html b/files/ru/learn/server-side/express_nodejs/displaying_data/index.html index bbe11606e8..4082c32f4a 100644 --- a/files/ru/learn/server-side/express_nodejs/displaying_data/index.html +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/index.html @@ -7,7 +7,7 @@ translation_of: Learn/Server-side/Express_Nodejs/Displaying_data
        {{PreviousMenuNext("Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs/forms", "Learn/Server-side/Express_Nodejs")}}
        -

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

        +

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

      • @@ -28,7 +28,7 @@ translation_of: Learn/Server-side/Express_Nodejs/Displaying_data

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

        -

        Мы начнем с обзорных / основных тем, объясняющих, как управлять асинхронными операциями в функциях контроллера и как писать шаблоны с помощью Pug. Затем мы предоставим реализации для каждой из наших основных страниц" только для чтения " с кратким объяснением любых специальных или новых функций, которые они используют.

        +

        Мы начнём с обзорных / основных тем, объясняющих, как управлять асинхронными операциями в функциях контроллера и как писать шаблоны с помощью Pug. Затем мы предоставим реализации для каждой из наших основных страниц" только для чтения " с кратким объяснением любых специальных или новых функций, которые они используют.

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

        diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/template_primer/index.html b/files/ru/learn/server-side/express_nodejs/displaying_data/template_primer/index.html index 449d197c96..7eeebc6e2a 100644 --- a/files/ru/learn/server-side/express_nodejs/displaying_data/template_primer/index.html +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/template_primer/index.html @@ -17,7 +17,7 @@ translation_of: Learn/Server-side/Express_Nodejs/Displaying_data/Template_primer

        Конфигурация шаблона

        -

        Когда создавался каркас (the skeleton website) веб-сайта LocalLibrary, он был настроен  на использование Pug . Можно было заметить, что модуль pug включен в зависимости в файле package.json, и установлен (app.set(...)) как движок представлений в файле app.js. Эта установка показывает,, что движок представлений -  pug, и что  Express должен искать шаблоны в подкаталоге /views.

        +

        Когда создавался каркас (the skeleton website) веб-сайта LocalLibrary, он был настроен  на использование Pug . Можно было заметить, что модуль pug включён в зависимости в файле package.json, и установлен (app.set(...)) как движок представлений в файле app.js. Эта установка показывает,, что движок представлений -  pug, и что  Express должен искать шаблоны в подкаталоге /views.

        // View engine setup.
         app.set('views', path.join(__dirname, 'views'));
        @@ -36,7 +36,7 @@ app.setПример файла шаблона (ниже) демонстрирует многие наиболее полезные черты  Pug.

        -

        Сначала отметим, что файл отражает структуру типового HTML-файла, причем первое слов в (почти) каждой строке является элементом HTML, а отступы используются, чтобы показать вложенные элементы. Так, например, элемент body находится внутри элемента html, а элементы p  (параграфы) - внутри элемента body, и так далее. Невложенные элементы (т.е. индивидуальные параграфы) располагаются в отдельных строках.

        +

        Сначала отметим, что файл отражает структуру типового HTML-файла, причём первое слов в (почти) каждой строке является элементом HTML, а отступы используются, чтобы показать вложенные элементы. Так, например, элемент body находится внутри элемента html, а элементы p  (параграфы) - внутри элемента body, и так далее. Невложенные элементы (т.е. индивидуальные параграфы) располагаются в отдельных строках.

        doctype html
         html(lang="en")
        @@ -74,7 +74,7 @@ html(lang="en")
               each val in [1, 2, 3, 4, 5]
                 li= val
        -

        Атрибуты элементов определены в скобках после соответствующих элементов. В скобках располагается список пар имя атрибута=значение,причем элементы списка разделяются запятой или пробелом. Например:

        +

        Атрибуты элементов определены в скобках после соответствующих элементов. В скобках располагается список пар имя атрибута=значение,причём элементы списка разделяются запятой или пробелом. Например:

        • script(type='text/javascript'), link(rel='stylesheet', href='/stylesheets/style.css')
        • @@ -83,7 +83,7 @@ html(lang="en")

          Значения всех атрибутов экранируются (т.е. такие символы как ">" заменяются эквивалентными кодами HTML как "&gt;") , чтобы предотвратить JavaScript инъекции и межсайтовые атаки.

          -

          Если после тэга стоит знак = , следующий текст рассматривается как выражение JavaScript. Например, ниже в первой строке, содержимое тэга h1 будет переменной  title (которая определена в файле или передана в шаблон из Express). Во второй строке содержимое параграфа - это текстовая строка, соединенная с переменной  title . В каждом из случаев поведение по умолчанию - экранировать строки.

          +

          Если после тэга стоит знак = , следующий текст рассматривается как выражение JavaScript. Например, ниже в первой строке, содержимое тэга h1 будет переменной  title (которая определена в файле или передана в шаблон из Express). Во второй строке содержимое параграфа - это текстовая строка, соединённая с переменной  title . В каждом из случаев поведение по умолчанию - экранировать строки.

          h1= title
           p= 'Evaluated and <em>escaped expression</em>:' + title
          @@ -97,12 +97,12 @@ p This line has an un-escaped string: !{'plain text"). Например, дополнительный текст, приведенный ниже, будет показан в той же строке, что и предыдущий, но не будет относиться к ссылке.

          +

          Можно использовать символ конвейера ('|') в начале строки, чтобы отметить простой текст ("plain text"). Например, дополнительный текст, приведённый ниже, будет показан в той же строке, что и предыдущий, но не будет относиться к ссылке.

          a(href='http://someurl/') Link text
           | Plain text
          -

          Pug позволяет выполнять условные операции if, else , else if и unless— пример приведен ниже:

          +

          Pug позволяет выполнять условные операции if, else , else if и unless— пример приведён ниже:

          if title
             p Переменная с именем "title" существует
          @@ -131,7 +131,7 @@ html
             body
               block content
          -

          Тэг  block применен для отметки разделов контента, которые могут быть заменены в производных шаблона (если блок не переопределяется, будет использования его реализация в базовом классе).

          +

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

          Умолчание для  index.pug (созданный для каркаса проекта) показывает, как можно заменить базовый шаблон. Тэг extends идентифицирует базовый шаблон, который следует использовать, а затем мы используем  block section_name, чтобы отметить новый контент раздела, который мы заменяем.

          diff --git a/files/ru/learn/server-side/express_nodejs/forms/create_bookinstance_form/index.html b/files/ru/learn/server-side/express_nodejs/forms/create_bookinstance_form/index.html index 13f409ea3c..f5b742715d 100644 --- a/files/ru/learn/server-side/express_nodejs/forms/create_bookinstance_form/index.html +++ b/files/ru/learn/server-side/express_nodejs/forms/create_bookinstance_form/index.html @@ -139,7 +139,7 @@ block content

          Как это выглядит?

          -

          Запустите приложение и откройте в браузере  http://localhost:3000/. Затем выберите ссылку Create new book instance (copy). Если все настроено правильно, ваш сайт должен выглядеть примерно так, как показано на скриншоте. После того, как вы отправите валидный BookInstance, он должен быть сохранен, и вы попадете на страницу сведений.

          +

          Запустите приложение и откройте в браузере  http://localhost:3000/. Затем выберите ссылку Create new book instance (copy). Если все настроено правильно, ваш сайт должен выглядеть примерно так, как показано на скриншоте. После того, как вы отправите валидный BookInstance, он должен быть сохранён, и вы попадёте на страницу сведений.

          diff --git a/files/ru/learn/server-side/express_nodejs/forms/delete_author_form/index.html b/files/ru/learn/server-side/express_nodejs/forms/delete_author_form/index.html index a92d787ec6..f03565426b 100644 --- a/files/ru/learn/server-side/express_nodejs/forms/delete_author_form/index.html +++ b/files/ru/learn/server-side/express_nodejs/forms/delete_author_form/index.html @@ -5,7 +5,7 @@ translation_of: Learn/Server-side/Express_Nodejs/forms/Delete_author_form ---

          В этой статье показано, как определить страницу для удаления объектов Author.

          -

          Как описано в разделе  form design,  наша стратегия будет заключаться в том, чтобы разрешить удаление только объектов, на которые не ссылаются другие объекты(в этом случае это означает, что мы не позволим Author быть удаленным, если на него ссылается  Book). С точки зрения реализации это означает, что форма должна подтвердить, что нет никаких связанных книг, прежде чем автор будет удален. Если есть связанные книги, то они должны отображаться и быть удалены до того, как будет удален объект Author.

          +

          Как описано в разделе  form design,  наша стратегия будет заключаться в том, чтобы разрешить удаление только объектов, на которые не ссылаются другие объекты(в этом случае это означает, что мы не позволим Author быть удалённым, если на него ссылается  Book). С точки зрения реализации это означает, что форма должна подтвердить, что нет никаких связанных книг, прежде чем автор будет удалён. Если есть связанные книги, то они должны отображаться и быть удалены до того, как будет удалён объект Author.

          Controller—get route

          @@ -32,7 +32,7 @@ exports.author_delete_get = function(req, res, next) { };
        -

        Контроллер получает id экземпляра Author для удаления из параметра URL  (req.params.id). Он использует метод  async.parallel() , чтобы получить запись автора и параллельно вс связанные книги. Когда оба параметра авершины, он рендерит страницу  author_delete.pug, передает значения для title, author, и author_books.

        +

        Контроллер получает id экземпляра Author для удаления из параметра URL  (req.params.id). Он использует метод  async.parallel() , чтобы получить запись автора и параллельно вс связанные книги. Когда оба параметра авершины, он рендерит страницу  author_delete.pug, передаёт значения для title, author, и author_books.

        Заметка: Если findById() не возвращает результатов, то автор отсутствует в базе данных. В этом случае удалять нечего, поэтому сразу выводим список всех авторов.

        @@ -77,10 +77,10 @@ exports.author_delete_post = function(req, res, next) { }); };
        -

        Сначала мы проверяем, что был предоставлен id (он отправляется через параметры тела формы, а не через версию в URL). Затем мы получаем автора и связанные с ним книги так же, как и для маршрута GET. Если книг нет, то удаляем объект автора и перенаправляем в список всех авторов. Если есть еще книги, то мы просто перерисовываем форму, передавая автора и список книг, которые нужно удалить.

        +

        Сначала мы проверяем, что был предоставлен id (он отправляется через параметры тела формы, а не через версию в URL). Затем мы получаем автора и связанные с ним книги так же, как и для маршрута GET. Если книг нет, то удаляем объект автора и перенаправляем в список всех авторов. Если есть ещё книги, то мы просто перерисовываем форму, передавая автора и список книг, которые нужно удалить.

        -

        Заметка: Мы можем проверить, возвращает ли вызов findbyid () какой-либо результат, и если нет, немедленно отобразить список всех авторов.Для краткости мы оставили код как есть выше (он все равно вернет список авторов, если id не будет найден, но это произойдет после findByIdAndRemove()).

        +

        Заметка: Мы можем проверить, возвращает ли вызов findbyid () какой-либо результат, и если нет, немедленно отобразить список всех авторов.Для краткости мы оставили код как есть выше (он все равно вернёт список авторов, если id не будет найден, но это произойдёт после findByIdAndRemove()).

        View

        @@ -128,7 +128,7 @@ block content

        Затем мы добавим элемент управления Delete в представление сведений об авторе (страница сведений-хорошее место для удаления записи).

        -

        Note: В полном объеме контроль будет доступен только авторизованным пользователям. Однако на данный момент у нас нет системы авторизации!

        +

        Note: В полном объёме контроль будет доступен только авторизованным пользователям. Однако на данный момент у нас нет системы авторизации!

        Откройте author_detail.pug и добавьте следующие строки внизу.

        diff --git a/files/ru/learn/server-side/express_nodejs/forms/index.html b/files/ru/learn/server-side/express_nodejs/forms/index.html index 6042d57b17..8048ad020b 100644 --- a/files/ru/learn/server-side/express_nodejs/forms/index.html +++ b/files/ru/learn/server-side/express_nodejs/forms/index.html @@ -30,12 +30,12 @@ translation_of: Learn/Server-side/Express_Nodejs/forms

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

        -

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

        +

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

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

        -

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

        +

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

        HTML Forms

        @@ -44,7 +44,7 @@ translation_of: Learn/Server-side/Express_Nodejs/forms

        Simple name field example in HTML form

        -

        Определенные в  HTML формы собираются внутри тэга <form>...</form>, содержащего хотя ы один элемент input с type="submit".

        +

        Определённые в  HTML формы собираются внутри тэга <form>...</form>, содержащего хотя ы один элемент input с type="submit".

        <form action="/team_name_url/" method="post">
             <label for="team_name">Enter name: </label>
        @@ -52,7 +52,7 @@ translation_of: Learn/Server-side/Express_Nodejs/forms
             <input type="submit" value="OK">
         </form>
        -

        Хотя здесь мы включили только одно (текстовое) поле для ввода имени команды, форма может содержать любое количество других элементов ввода и связанных с ними меток. Атрибут type определяет какой из виджетов будет выбран для отображения поля. Атрибуты name и id идентифицируют поле в JavaScript/CSS/HTML, а value определяет его первоначальное значение. Связанная с полем метка, задается с помощью тега label (располагается строкой выше и содержит в себе подпись "Enter name"). Связь метки и поля ввода устанавливается при помощи атрибута for, в котором указывается значение идентификатора поля (input id).

        +

        Хотя здесь мы включили только одно (текстовое) поле для ввода имени команды, форма может содержать любое количество других элементов ввода и связанных с ними меток. Атрибут type определяет какой из виджетов будет выбран для отображения поля. Атрибуты name и id идентифицируют поле в JavaScript/CSS/HTML, а value определяет его первоначальное значение. Связанная с полем метка, задаётся с помощью тега label (располагается строкой выше и содержит в себе подпись "Enter name"). Связь метки и поля ввода устанавливается при помощи атрибута for, в котором указывается значение идентификатора поля (input id).

        Input submit будет отображаться в виде кнопки (по умолчанию) - он может быть нажат пользователем, чтобы загрузить данные, содержащиеся в других входных элементов на сервер (в данном случае, только team_name). Атрибуты формы определяют метод HTTP, используемый для отправки данных, и назначение данных на сервере (action):

        @@ -70,7 +70,7 @@ translation_of: Learn/Server-side/Express_Nodejs/forms

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

        -

        Блок-схема процесса обработки запросов формы показана ниже, начиная с запроса страницы, содержащей форму (показана зеленым цветом):

        +

        Блок-схема процесса обработки запросов формы показана ниже, начиная с запроса страницы, содержащей форму (показана зелёным цветом):

        @@ -79,7 +79,7 @@ translation_of: Learn/Server-side/Express_Nodejs/forms
        1. Отображение формы по умолчанию при первом запросе пользователем.
            -
          • Форма может содержать пустые поля (например, если вы создаете новую запись), или она может быть предварительно заполнена начальными значениями (например, если вы изменяете запись или имеете полезные начальные значения по умолчанию).
          • +
          • Форма может содержать пустые поля (например, если вы создаёте новую запись), или она может быть предварительно заполнена начальными значениями (например, если вы изменяете запись или имеете полезные начальные значения по умолчанию).
        2. Получение данных, отправленных пользователем, обычно в запросе HTTP POST.
        3. @@ -98,7 +98,7 @@ translation_of: Learn/Server-side/Express_Nodejs/forms

          Перед сохранением данных формы их необходимо проверить и очистить:

            -
          • Проверка проверяет, что введенные значения являются подходящими для каждого поля (расположены в правильном диапазоне, формат и т. д.) и что значения были предоставлены для всех обязательных полей.
          • +
          • Проверка проверяет, что введённые значения являются подходящими для каждого поля (расположены в правильном диапазоне, формат и т. д.) и что значения были предоставлены для всех обязательных полей.
          • Очистка удаляет / заменяет символы в данных, которые потенциально могут использоваться для отправки вредоносного содержимого на сервер.
          @@ -128,7 +128,7 @@ const { sanitizeBody } = require('express-validator/filter');

          Функции определяются следующим образом:

            -
          • body(fields[, message]): Задает набор полей в теле запроса (параметр POST) для проверки, а также необязательное сообщение об ошибке, которое может отображаться в случае сбоя тестов. Критерии проверки последовательно связаны с методом body(). Например, первая проверка ниже проверяет, что поле" имя "не пустое и задает сообщение об ошибке" пустое имя", если оно не пустое. Второй тест проверяет, что поле age является допустимой датой, и с помощью optional() указывает, что пустые и пустые строки не пройдут проверку. +
          • body(fields[, message]): Задаёт набор полей в теле запроса (параметр POST) для проверки, а также необязательное сообщение об ошибке, которое может отображаться в случае сбоя тестов. Критерии проверки последовательно связаны с методом body(). Например, первая проверка ниже проверяет, что поле" имя "не пустое и задаёт сообщение об ошибке" пустое имя", если оно не пустое. Второй тест проверяет, что поле age является допустимой датой, и с помощью optional() указывает, что пустые и пустые строки не пройдут проверку.
            body('name', 'Empty name').isLength({ min: 1 }),
             body('age', 'Invalid age').optional({ checkFalsy: true }).isISO8601(),
            @@ -143,7 +143,7 @@ body('age', 'Invalid age').optional({ checkFalsy: true }).isISO8601(),
               

            Note: Вы также можете добавить встроенные средства очистки, такие как trim(), как показано выше. Однако средства очистки, применяемые здесь, применяются только к шагу проверки. Если требуется очистить конечный результат, необходимо использовать отдельный метод очистки, как показано ниже.

        -
      • sanitizeBody(fields): Задает поле тела для очистки. затем операции очистки последовательно соединяются с этим методом. Например, операция очистки escape(), описанная ниже, удаляет символы HTML из переменной name, которые могут использоваться в атаках сценариев между сайтами JavaScript. +
      • sanitizeBody(fields): Задаёт поле тела для очистки. затем операции очистки последовательно соединяются с этим методом. Например, операция очистки escape(), описанная ниже, удаляет символы HTML из переменной name, которые могут использоваться в атаках сценариев между сайтами JavaScript.
        sanitizeBody('name').trim().escape(),
         sanitizeBody('date').toDate(),
      • @@ -172,8 +172,8 @@ sanitizeBody('date').toDate(),

        Многие модели в библиотеке связаны / зависимы—например, книга требует автора, а также может иметь один или несколько жанров. Это поднимает вопрос о том, как мы должны обрабатывать случай, когда пользователь хочет:

          -
        • Создайте объект, если связанные с ним объекты еще не существуют (например, книга, в которой не определен объект автора).
        • -
        • Удаление объекта, который все еще используется другим объектом (например, удаление жанра, который все еще используется книгой).
        • +
        • Создайте объект, если связанные с ним объекты ещё не существуют (например, книга, в которой не определён объект автора).
        • +
        • Удаление объекта, который все ещё используется другим объектом (например, удаление жанра, который все ещё используется книгой).

        Для этого проекта мы упростили реализацию, объявив, что форма может быть только:

        @@ -184,12 +184,12 @@ sanitizeBody('date').toDate(),
        -

        Note: Более" надежная " реализация может позволить создавать зависимые объекты при создании нового объекта и удалять любой объект в любое время (например, путем удаления зависимых объектов или путем удаления ссылок на удаленный объект из базы данных).

        +

        Note: Более" надёжная " реализация может позволить создавать зависимые объекты при создании нового объекта и удалять любой объект в любое время (например, путём удаления зависимых объектов или путём удаления ссылок на удалённый объект из базы данных).

        Маршруты

        -

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

        +

        Чтобы реализовать наш код обработки форм, нам понадобятся два маршрута с одинаковым шаблоном URL. Первый (GET) маршрут используется для отображения новой пустой формы создания объекта. Второй маршрут (POST) используется для проверки введённых пользователем данных, а затем сохранения информации и перенаправления на страницу сведений (если данные верны) или повторного отображения формы с ошибками (если данные неверны).

        Мы уже создали маршруты для всех страниц создания нашей модели в  /routes/catalog.js (in a previous tutorial).  Например, жанровые маршруты показаны ниже:

        diff --git a/files/ru/learn/server-side/express_nodejs/forms/update_book_form/index.html b/files/ru/learn/server-side/express_nodejs/forms/update_book_form/index.html index ba6d79d71d..374c4a2590 100644 --- a/files/ru/learn/server-side/express_nodejs/forms/update_book_form/index.html +++ b/files/ru/learn/server-side/express_nodejs/forms/update_book_form/index.html @@ -44,7 +44,7 @@ exports.book_update_get };
        -

        Контроллер получит id Book книги для обновления из параметра URL (req.params.id). Он использует метод async.parallel()чтобы получить указанную запись Book (заполнение полей жанра и автора) и список всех объектов Author и Genre. Когда все операции завершены, он помечает выбранные жанры как отмеченные, а затем отображает их в book_form.pug, передает переменные itle, book, всех authors, и всеgenres.

        +

        Контроллер получит id Book книги для обновления из параметра URL (req.params.id). Он использует метод async.parallel()чтобы получить указанную запись Book (заполнение полей жанра и автора) и список всех объектов Author и Genre. Когда все операции завершены, он помечает выбранные жанры как отмеченные, а затем отображает их в book_form.pug, передаёт переменные itle, book, всех authors, и всеgenres.

        Controller—post route

        @@ -128,7 +128,7 @@ exports.book_update_post } ]; -

        Это очень похоже на маршрут записи, используемый при создании Book. Сперва мы проверяем и очищаем данные книги  и используем их для создание нового объекта Book(устанавливая его значение _id в идентификатор объекта для обновления). Если есть ошибки, когда мы проверяем данные, то мы повторно представляем форму, дополнительно отображая данные, введенные пользователем, ошибки, а также списки жанров и авторов. Если ошибок нет, то мы вызываем Book.findByIdAndUpdate() для обновления документа Book, а затем перенаправить на страницу сведений.

        +

        Это очень похоже на маршрут записи, используемый при создании Book. Сперва мы проверяем и очищаем данные книги  и используем их для создание нового объекта Book(устанавливая его значение _id в идентификатор объекта для обновления). Если есть ошибки, когда мы проверяем данные, то мы повторно представляем форму, дополнительно отображая данные, введённые пользователем, ошибки, а также списки жанров и авторов. Если ошибок нет, то мы вызываем Book.findByIdAndUpdate() для обновления документа Book, а затем перенаправить на страницу сведений.

        View

        diff --git a/files/ru/learn/server-side/express_nodejs/index.html b/files/ru/learn/server-side/express_nodejs/index.html index 48a631f4c3..21c9909faa 100644 --- a/files/ru/learn/server-side/express_nodejs/index.html +++ b/files/ru/learn/server-side/express_nodejs/index.html @@ -28,7 +28,7 @@ translation_of: Learn/Server-side/Express_Nodejs
        Введение в Express/Node
        -
        В первой статье об Express мы ответим на вопросы "Что такое Node?" и "Что такое Express?" и дадим вам представление о том, что делает веб-фреймворк Express особенным. Мы расскажем об основных функциях и покажем вам некоторые из основных строительных блоков приложений Express (хотя на данный момент у вас еще нет среды разработки, в которой можно ее протестировать).
        +
        В первой статье об Express мы ответим на вопросы "Что такое Node?" и "Что такое Express?" и дадим вам представление о том, что делает веб-фреймворк Express особенным. Мы расскажем об основных функциях и покажем вам некоторые из основных строительных блоков приложений Express (хотя на данный момент у вас ещё нет среды разработки, в которой можно её протестировать).
        Настройка среды разработки Node (Express)
        Теперь, когда вы знаете, что такое Express, мы покажем вам, как настроить и протестировать среду разработки Node/Express в Windows, Linux (Ubuntu) и Mac OS X. Независимо от того, какую популярную операционную систему вы используете, эта статья даст вам то, что вам нужно, чтобы начать разработку приложений Express.
        @@ -46,18 +46,18 @@ translation_of: Learn/Server-side/Express_Nodejs
        Учебник Express часть 4: Маршруты и контроллеры
        В этом уроке мы создадим маршруты (код обработки URL) с "фиктивным" обработчиком функций для всех конечных точек ресурсов, которые нам в конечном итоге понадобятся для сайта LocalLibrary. По завершении мы будем иметь модульную структуру нашего кода обработки маршрута, который мы можем расширить с помощью функций реального обработчика в следующих статьях. Мы также будем очень хорошо понимать, как создавать модульные маршруты, используя Express.
        Учебник Express часть 5: Отображение данных библиотеки
        -
        Теперь мы готовы добавить страницы, на которых будут отображаться книги веб-сайта LocalLibrary и другие данные. Страницы будут включать главную страницу, которая показывает сколько записей определенного типа мы имеем и отдельную страницу для детального просмотра записи. По пути мы получим практический опыт в получении записей из баз данных и использовании шаблонов.
        +
        Теперь мы готовы добавить страницы, на которых будут отображаться книги веб-сайта LocalLibrary и другие данные. Страницы будут включать главную страницу, которая показывает сколько записей определённого типа мы имеем и отдельную страницу для детального просмотра записи. По пути мы получим практический опыт в получении записей из баз данных и использовании шаблонов.
        Учебник Express часть 6: Работы с формами
        В этой части мы покажем вам, как работать с HTML формами в Express, используя Pug, и в частности, как создавать, обновлять и удалять документы из базы данных.
        Учебник Express часть 7: Выкладка в production
        -
        Теперь когда вы создали восхитительный сайт LocalLibrary, вы захотите установить его на общедоступном сервере, чтобы он мог дать доступ персоналу библиотеки и пользователям в Интернет. В этой статье представлен обзор того, как вы можете найти хост для развертывания вашего сайта и что вам нужно сделать, чтобы подготовить ваш сайт к публикации.
        +
        Теперь когда вы создали восхитительный сайт LocalLibrary, вы захотите установить его на общедоступном сервере, чтобы он мог дать доступ персоналу библиотеки и пользователям в Интернет. В этой статье представлен обзор того, как вы можете найти хост для развёртывания вашего сайта и что вам нужно сделать, чтобы подготовить ваш сайт к публикации.

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

        Установка LocalLibrary на PWS/Cloud Foundry
        -
        В этой статье представлена практическая демонстрация того, как установить LocalLibrary на облаке Pivotal Web Services PaaS — это полнофункциональная альтернатива с открытым исходным кодом для Heroku, облачного сервиса PaaS  используемого в части 7 этого учебника, представленного выше. PWS/Cloud Foundry определенно стоит попробовать, если вы ищете альтернативу Heroku (или другому PaaS облачному сервису), или просто хотите попробовать что-то другое.
        +
        В этой статье представлена практическая демонстрация того, как установить LocalLibrary на облаке Pivotal Web Services PaaS — это полнофункциональная альтернатива с открытым исходным кодом для Heroku, облачного сервиса PaaS  используемого в части 7 этого учебника, представленного выше. PWS/Cloud Foundry определённо стоит попробовать, если вы ищете альтернативу Heroku (или другому PaaS облачному сервису), или просто хотите попробовать что-то другое.

        Изучите другие учебники

        diff --git a/files/ru/learn/server-side/express_nodejs/introduction/index.html b/files/ru/learn/server-side/express_nodejs/introduction/index.html index 96f5db6121..36bf2f9eb9 100644 --- a/files/ru/learn/server-side/express_nodejs/introduction/index.html +++ b/files/ru/learn/server-side/express_nodejs/introduction/index.html @@ -5,7 +5,7 @@ translation_of: Learn/Server-side/Express_Nodejs/Introduction ---
        {{NextMenu("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs")}}
        -

        В этой первой статье по Express мы ответим на вопросы "Что такое Node?" и "Что такое Express?", и сделаем обзор того, что делает веб-фреймворк Express таким особенным. Мы расскажем об основных функциях и покажем вам некоторые из основных строительных блоков приложения Express (хотя на данный момент у вас еще нет среды разработки, в которой можно ее протестировать).

        +

        В этой первой статье по Express мы ответим на вопросы "Что такое Node?" и "Что такое Express?", и сделаем обзор того, что делает веб-фреймворк Express таким особенным. Мы расскажем об основных функциях и покажем вам некоторые из основных строительных блоков приложения Express (хотя на данный момент у вас ещё нет среды разработки, в которой можно её протестировать).

        @@ -27,10 +27,10 @@ translation_of: Learn/Server-side/Express_Nodejs/Introduction

        С точки зрения веб-серверной разработки Node имеет ряд преимуществ:

          -
        • Отличная производительность! Node был разработан для оптимизации пропускной способности и масштабируемости в веб-приложениях и очень хорошо справляется со многими распространенными проблемами веб-разработки (например, веб-приложения реального времени).
        • +
        • Отличная производительность! Node был разработан для оптимизации пропускной способности и масштабируемости в веб-приложениях и очень хорошо справляется со многими распространёнными проблемами веб-разработки (например, веб-приложения реального времени).
        • Код написан на «обычном старом JavaScript», а это означает, что затрачивается меньше времени при написании кода для браузера и веб-сервера связанное с  «переключением технологий» между языками.
        • JavaScript является относительно новым языком программирования и имеет преимущества от улучшения дизайна языка по сравнению с другими традиционными языками для веб-серверов (например, Python, PHP, и т.д.). Многие другие новые и популярные языки компилируются/конвертируются в JavaScript, поэтому вы можете также использовать CoffeeScript, ClosureScript, Scala, LiveScript, etc.
        • -
        • Менеджер пакетов Node (NPM) обеспечивает доступ к сотням тысяч многоразовых пакетов. Он также имеет лучшее в своем классе разрешение зависимостей и может также использоваться для автоматизации большинства инструментов построения.
        • +
        • Менеджер пакетов Node (NPM) обеспечивает доступ к сотням тысяч многоразовых пакетов. Он также имеет лучшее в своём классе разрешение зависимостей и может также использоваться для автоматизации большинства инструментов построения.
        • Он портативен, имеет версии для  Microsoft Windows, OS X, Linux, Solaris, FreeBSD, OpenBSD, WebOS, и NonStop OS. Кроме того, он имеет хорошую поддержку среди многих хостинг-провайдеров, которые часто предоставляют конкретную инфраструктуру и документацию для размещения сайтов, работающих на Node.
        • Он имеет очень активную стороннюю экосистему и сообщество разработчиков, которые всегда готовы помочь.
        @@ -43,7 +43,7 @@ translation_of: Learn/Server-side/Express_Nodejs/Introduction
        1. Откройте терминал (в Windows окно командной строки)
        2. -
        3. Создайте папку, куда вы хотите сохранить программу, к примеру test-node и перейдите в нее с помощью следующей команды:
        4. +
        5. Создайте папку, куда вы хотите сохранить программу, к примеру test-node и перейдите в неё с помощью следующей команды:
        cd test-node
        @@ -58,7 +58,7 @@ const http = require("http"); const hostname = "127.0.0.1"; const port = 8000; -// Создаем HTTP-сервер +// Создаём HTTP-сервер const server = http.createServer((req, res) => { // Устанавливаем HTTP-заголовок ответа с HTTP статусом и Content type @@ -114,7 +114,7 @@ server.listen(port, hostname, () => {

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

        -

        Не существует какого-либо доступного и точного измерения популярности серверных фреймворков (хотя сайты, такие как Hot Frameworks, пытаются оценить популярность, используя такие механизмы, как подсчет количества проектов на GitHub и вопросов на StackOverflow для каждой платформы). Лучший вопрос заключается в том, достаточно ли популярны Node и Express, чтобы избежать проблем с непопулярными платформами. Они продолжают развиваться? Можете ли вы получить помощь, если вам это нужно? Есть ли у вас возможность получить оплачиваемую работу, если вы изучаете Express?

        +

        Не существует какого-либо доступного и точного измерения популярности серверных фреймворков (хотя сайты, такие как Hot Frameworks, пытаются оценить популярность, используя такие механизмы, как подсчёт количества проектов на GitHub и вопросов на StackOverflow для каждой платформы). Лучший вопрос заключается в том, достаточно ли популярны Node и Express, чтобы избежать проблем с непопулярными платформами. Они продолжают развиваться? Можете ли вы получить помощь, если вам это нужно? Есть ли у вас возможность получить оплачиваемую работу, если вы изучаете Express?

        Как только мы посмотрим на список широкоизвестных компаний пользующихся Express, количество разработчиков участвующих в разработке Express, и громадному числу людей, которые занимаются поддержкой Express, то мы с уверенностью скажем -  Express поистине популярный фреймворк!

        @@ -122,7 +122,7 @@ server.listen(port, hostname, () => {

        Web-фреймворки часто принято делить на "ограничивающие" и "не ограничивающие".

        -

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

        +

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

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

        @@ -130,7 +130,7 @@ server.listen(port, hostname, () => {

        Как выглядит код Express?

        -

        В традиционных динамических веб-сайтах, веб-приложение ожидает HTTP-запроса от веб-браузера (или другого клиента). Когда запрос получен, приложение определяет, какое действие необходимо выполнить на основе URL шаблона и, возможно, связанной информации, содержащейся в данных POST или GET. В зависимости от того, что требуется, Express может затем читать или записывать данные из/в базы данных или выполнять другие задачи, в соответствии с полученным запросом. Затем приложение возвращает ответ в веб-браузер, зачастую динамически создавая HTML страницу для отображения браузером, вставляя извлеченные данные в заполнители HTML шаблона.

        +

        В традиционных динамических веб-сайтах, веб-приложение ожидает HTTP-запроса от веб-браузера (или другого клиента). Когда запрос получен, приложение определяет, какое действие необходимо выполнить на основе URL шаблона и, возможно, связанной информации, содержащейся в данных POST или GET. В зависимости от того, что требуется, Express может затем читать или записывать данные из/в базы данных или выполнять другие задачи, в соответствии с полученным запросом. Затем приложение возвращает ответ в веб-браузер, зачастую динамически создавая HTML страницу для отображения браузером, вставляя извлечённые данные в заполнители HTML шаблона.

        Express предоставляет методы позволяющие указать, какая функция вызывается для конкретного HTTP запроса (GET, POST, SET, etc.), и URL шаблон ("Route"), а также методы позволяющие указать, какой механизм шаблона ("view") используется, где находятся шаблоны файлов и какой шаблон использовать для вывода ответа. Вы можете использовать Express middleware для добавления поддержки файлов cookies, сеансов, и пользователей, получения POST/GET параметров, и т.д. Вы можете использовать любой механизм базы данных, поддерживаемый Node (Express не определяет поведение, связанное с базой данных).

        @@ -158,15 +158,15 @@ app.listen(3000, function() {

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

        -

        Средняя часть кода (три строки, начинающиеся с app.get) показывает определение маршрута. Метод app.get () указывает колбэк-функцию, которая будет вызываться всякий раз, когда есть HTTP-запрос GET с путем ('/') относительно корня сайта. Колбэк-функция принимает запрос и объект ответа в качестве аргументов и просто вызывает send () для ответа, чтобы вернуть строку «Hello World!»

        +

        Средняя часть кода (три строки, начинающиеся с app.get) показывает определение маршрута. Метод app.get () указывает колбэк-функцию, которая будет вызываться всякий раз, когда есть HTTP-запрос GET с путём ('/') относительно корня сайта. Колбэк-функция принимает запрос и объект ответа в качестве аргументов и просто вызывает send () для ответа, чтобы вернуть строку «Hello World!»

        -

        Последний блок запускает сервер через порт «3000» и печатает комментарий журнала в консоль. Когда сервер работает, вы можете перейти к localhost: 3000 в вашем браузере, чтобы увидеть возвращенный пример ответа.

        +

        Последний блок запускает сервер через порт «3000» и печатает комментарий журнала в консоль. Когда сервер работает, вы можете перейти к localhost: 3000 в вашем браузере, чтобы увидеть возвращённый пример ответа.

        Импорт и создание модулей

        Модуль - это библиотека / файл JavaScript, который вы можете импортировать в другой код с помощью функции require () Node. Express сам по себе является модулем, как и промежуточное программное обеспечение и библиотеки баз данных, которые мы используем в наших приложениях Express.

        - Приведенный ниже код показывает, как мы импортируем модуль по имени, используя в качестве примера платформу Express. Сначала мы вызываем функцию require (), определяя имя модуля в виде строки («express») и вызывая возвращенный объект для создания приложения Express. Затем мы можем получить доступ к свойствам и функциям объекта приложения.

        + Приведённый ниже код показывает, как мы импортируем модуль по имени, используя в качестве примера платформу Express. Сначала мы вызываем функцию require (), определяя имя модуля в виде строки («express») и вызывая возвращённый объект для создания приложения Express. Затем мы можем получить доступ к свойствам и функциям объекта приложения.

        var express = require('express');
         var app = express();
        @@ -175,7 +175,7 @@ var app = express();
         

        Вы также можете создавать свои собственные модули, которые можно импортировать таким же образом.

        -

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

        +

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

        Чтобы сделать объекты доступными вне модуля, вам просто нужно назначить их объекту экспорта. Например, модуль square.js ниже представляет собой файл, который экспортирует методы area () и perimeter ():

        @@ -216,7 +216,7 @@ console.log('The area of a square with a width of 4 is ' + square.area(4));
        -

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

        +

        В отличие от этого, асинхронный API - это тот, в котором API начнёт операцию и сразу же вернётся (до завершения операции). После завершения операции API будет использовать некоторый механизм для выполнения дополнительных операций. Например, приведённый ниже код выведет «Second, First», потому что хотя метод setTimeout () вызывается первым и возвращается немедленно, операция не завершается в течение нескольких секунд.

        setTimeout(function() {
            console.log('First');
        @@ -224,9 +224,9 @@ console.log('Second');
         console.log('Second');
         
        -

        Использование неблокирующих асинхронных API-интерфейсов еще более важно в Node, чем в браузере, поскольку Node - это однопоточная среда выполнения, управляемая событиями. «Однопоточный» означает, что все запросы к серверу выполняются в одном потоке (а не порождаются в отдельных процессах). Эта модель чрезвычайно эффективна с точки зрения скорости и ресурсов сервера, но это означает, что если любая из ваших функций вызывает синхронные методы, выполнение которых занимает много времени, они будут блокировать не только текущий запрос, но и любой другой запрос, обрабатываемый ваше веб-приложение.
        +

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

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

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

        Совет: Использование колбэков может быть довольно «грязным», если у вас есть последовательность зависимых асинхронных операций, которые должны выполняться по порядку, потому что это приводит к нескольким уровням вложенных колбэков. Эта проблема широко известна как «ад колбэков». Эту проблему можно решить с помощью хороших методов кодирования (см. Http://callbackhell.com/), использования такого модуля, как async, или даже перехода к функциям ES6, таким как Promises.

        @@ -253,16 +253,16 @@ console.log('Second');

        Объект приложения Express также предоставляет методы для определения обработчиков маршрутов для всех других HTTP-глаголов, которые в основном используются одинаково: post (), put (), delete (), options (), trace (), copy ( ), lock (), mkcol (), move (), purge (), propfind (), proppatch (), unlock (), report (), mkactivity (), checkout (), merge ( ), m-search (), notify (), subscribe (), unsubscribe (), patch (), search () и connect ().

        -

        Существует специальный метод маршрутизации app.all (), который будет вызываться в ответ на любой метод HTTP. Это используется для загрузки функций промежуточного программного обеспечения по определенному пути для всех методов запроса. В следующем примере (из документации Express) показан обработчик, который будет выполняться для запросов к / secret независимо от используемого глагола HTTP (при условии, что он поддерживается модулем http).

        +

        Существует специальный метод маршрутизации app.all (), который будет вызываться в ответ на любой метод HTTP. Это используется для загрузки функций промежуточного программного обеспечения по определённому пути для всех методов запроса. В следующем примере (из документации Express) показан обработчик, который будет выполняться для запросов к / secret независимо от используемого глагола HTTP (при условии, что он поддерживается модулем http).

        app.all('/secret', function(req, res, next) {
           console.log('Accessing the secret section ...');
           next(); // pass control to the next handler
         });
        -

        Маршруты позволяют сопоставлять определенные шаблоны символов в URL-адресе, извлекать некоторые значения из URL-адреса и передавать их в качестве параметров обработчику маршрута (в качестве атрибутов объекта запроса, передаваемого в качестве параметра).
        +

        Маршруты позволяют сопоставлять определённые шаблоны символов в URL-адресе, извлекать некоторые значения из URL-адреса и передавать их в качестве параметров обработчику маршрута (в качестве атрибутов объекта запроса, передаваемого в качестве параметра).

        - Часто полезно группировать обработчики маршрутов для определенной части сайта и получать к ним доступ с помощью общего префикса маршрута (например, сайт с вики может иметь все связанные с вики маршруты в одном файле и иметь к ним доступ с префиксом маршрута из / вики /). В Express это достигается с помощью объекта express.Router. Например, мы можем создать наш вики-маршрут в модуле с именем wiki.js, а затем экспортировать объект Router, как показано ниже:

        + Часто полезно группировать обработчики маршрутов для определённой части сайта и получать к ним доступ с помощью общего префикса маршрута (например, сайт с вики может иметь все связанные с вики маршруты в одном файле и иметь к ним доступ с префиксом маршрута из / вики /). В Express это достигается с помощью объекта express.Router. Например, мы можем создать наш вики-маршрут в модуле с именем wiki.js, а затем экспортировать объект Router, как показано ниже:

        // wiki.js - Wiki route module
         
        @@ -304,7 +304,7 @@ app.use('/wiki', wiki);

        Большинство приложений используют стороннее промежуточное программное обеспечение для упрощения общих задач веб-разработки, таких как работа с файлами cookie, сессиями, аутентификацией пользователя, доступом к данным запросов POST и JSON, ведение журнала и т. д. Список пакетов промежуточного программного обеспечения, поддерживаемых командой Express, можно найти. (который также включает в себя другие популярные сторонние пакеты). Другие экспресс-пакеты доступны в диспетчере пакетов NPM.

        - Для использования стороннего промежуточного программного обеспечения сначала необходимо установить его в свое приложение с помощью NPM. Например, чтобы установить промежуточное программное обеспечение средства регистрации HTTP-запросов morgan, вы должны сделать следующее:

        + Для использования стороннего промежуточного программного обеспечения сначала необходимо установить его в своё приложение с помощью NPM. Например, чтобы установить промежуточное программное обеспечение средства регистрации HTTP-запросов morgan, вы должны сделать следующее:

        $ npm install morgan
         
        @@ -321,11 +321,11 @@ var app = express();

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

        -

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

        +

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

        -

        Вы можете добавить функцию промежуточного программного обеспечения в цепочку обработки с помощью app.use () или app.add (), в зависимости от того, хотите ли вы применить промежуточное программное обеспечение ко всем ответам или к ответам с определенным глаголом HTTP (GET, POST и т. д.). ). Маршруты задаются одинаково в обоих случаях, хотя маршрут необязателен при вызове app.use ().
        +

        Вы можете добавить функцию промежуточного программного обеспечения в цепочку обработки с помощью app.use () или app.add (), в зависимости от того, хотите ли вы применить промежуточное программное обеспечение ко всем ответам или к ответам с определённым глаголом HTTP (GET, POST и т. д.). ). Маршруты задаются одинаково в обоих случаях, хотя маршрут необязателен при вызове app.use ().

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

        + В приведённом ниже примере показано, как можно добавить функцию промежуточного программного обеспечения, используя оба метода, а также с / без маршрута.

        var express = require('express');
         var app = express();
        @@ -348,7 +348,7 @@ app.get('/', a_middleware_function);
         app.listen(3000);
        -

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

        +

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

        Документация по Express содержит намного больше отличной информации по использованию и написанию промежуточного программного обеспечения Express.

        @@ -360,7 +360,7 @@ app.listen(3000);
        app.use(express.static('public'));
         
        -

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

        +

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

        http://localhost:3000/images/dog.jpg
         http://localhost:3000/css/style.css
        @@ -390,7 +390,7 @@ http://localhost:3000/media/cry.mp3
         
         

        Обработка ошибок

        -

        Ошибки обрабатываются одной или несколькими специальными функциями промежуточного программного обеспечения, которые имеют четыре аргумента вместо обычных трех: (err, req, res, next). Например:

        +

        Ошибки обрабатываются одной или несколькими специальными функциями промежуточного программного обеспечения, которые имеют четыре аргумента вместо обычных трёх: (err, req, res, next). Например:

        app.use(function(err, req, res, next) {
           console.error(err.stack);
        @@ -400,7 +400,7 @@ http://localhost:3000/media/cry.mp3
         
         

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

        - Express поставляется со встроенным обработчиком ошибок, который заботится обо всех оставшихся ошибках, которые могут возникнуть в приложении. Эта промежуточная функция обработки ошибок по умолчанию добавляется в конец стека функций промежуточного программного обеспечения. Если вы передаете ошибку в next () и не обрабатываете ее в обработчике ошибок, она будет обработана встроенным обработчиком ошибок; ошибка будет записана клиенту с трассировкой стека.

        + Express поставляется со встроенным обработчиком ошибок, который заботится обо всех оставшихся ошибках, которые могут возникнуть в приложении. Эта промежуточная функция обработки ошибок по умолчанию добавляется в конец стека функций промежуточного программного обеспечения. Если вы передаёте ошибку в next () и не обрабатываете её в обработчике ошибок, она будет обработана встроенным обработчиком ошибок; ошибка будет записана клиенту с трассировкой стека.

        Примечание. Трассировка стека не включена в производственную среду. Чтобы запустить его в производственном режиме, необходимо установить переменную среды NODE_ENV в «производство».

        @@ -443,7 +443,7 @@ MongoClient.connect('mongodb://localhost:27017/animals', function(err, db) {

        Механизмы шаблонов (в Express называемые «механизмами просмотра») позволяют указывать структуру выходного документа в шаблоне, используя заполнители для данных, которые будут заполняться при создании страницы. Шаблоны часто используются для создания HTML, но могут также создавать другие типы документов. В Express есть поддержка ряда шаблонных движков, и здесь есть полезное сравнение более популярных движков: Сравнение шаблонизаторов JavaScript: Jade, Mustache, Dust и More.

        - В своем коде настроек приложения вы задаете механизм шаблонов для использования и место, где Express должен искать шаблоны, используя настройки «views» и «engine», как показано ниже (вам также нужно будет установить пакет, содержащий вашу библиотеку шаблонов). !)

        + В своём коде настроек приложения вы задаёте механизм шаблонов для использования и место, где Express должен искать шаблоны, используя настройки «views» и «engine», как показано ниже (вам также нужно будет установить пакет, содержащий вашу библиотеку шаблонов). !)

        var express = require('express');
         var app = express();
        @@ -465,18 +465,18 @@ app.set('view engine', 'some_template_engine_name');
         
         

        Файловая структура

        -

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

        +

        Express не делает никаких предположений относительно структуры или компонентов, которые вы используете. Маршруты, представления, статические файлы и другая логика конкретного приложения могут находиться в любом количестве файлов с любой структурой каталогов. Хотя вполне возможно иметь все приложения Express в одном файле, обычно имеет смысл разделить ваше приложение на файлы на основе функций (например, управление учётными записями, блоги, доски обсуждений) и проблемной области архитектуры (например, модель, представление или контроллер, если вы случайно используете MVC architecture).

        -

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

        +

        В более поздней теме мы будем использовать Express Application Generator, который создаёт модульный каркас приложения, который мы можем легко расширить для создания веб-приложений.

        Резюме

        -

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

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

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

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

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

        diff --git a/files/ru/learn/server-side/express_nodejs/mongoose/index.html b/files/ru/learn/server-side/express_nodejs/mongoose/index.html index a761872f99..7bbcc23eb4 100644 --- a/files/ru/learn/server-side/express_nodejs/mongoose/index.html +++ b/files/ru/learn/server-side/express_nodejs/mongoose/index.html @@ -7,7 +7,7 @@ translation_of: Learn/Server-side/Express_Nodejs/mongoose
        {{PreviousMenuNext("Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs")}}
        -

        В этой статье дается краткое введение в базы данных, и методика их использования в приложениях Node/Express. Затем мы покажем, как можно использовать Mongoose для доступа к базе данных веб-сайта  LocalLibrary. Мы объясним, как объявляются схемы и модели объектов, укажем основные типы полей, и методику базовой валидации. В статье также кратко показаны  основные методы доступа к данным модели.

        +

        В этой статье даётся краткое введение в базы данных, и методика их использования в приложениях Node/Express. Затем мы покажем, как можно использовать Mongoose для доступа к базе данных веб-сайта  LocalLibrary. Мы объясним, как объявляются схемы и модели объектов, укажем основные типы полей, и методику базовой валидации. В статье также кратко показаны  основные методы доступа к данным модели.

        @@ -24,7 +24,7 @@ translation_of: Learn/Server-side/Express_Nodejs/mongoose

        Обзор

        -

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

        +

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

        Express-приложения могут использовать различные базы данных, и есть несколько подходов, которые можно использовать для выполнения операций Create, Read, Update and Delete (CRUD) (создать, прочесть, обновить, удалить). В руководстве дан краткий обзор некоторых доступных опций, и детально рассмотрены некоторые механизмы работы.

        @@ -42,7 +42,7 @@ translation_of: Learn/Server-side/Express_Nodejs/mongoose
        • Использование родного языка запросов баз данных (т.е. SQL)
        • -
        • Использование объектной модели данных (ODM) или объектно-реляционной модели (ORM).  ODM / ORM представляют данные веб-сайта как объекты JavaScript, которые затем отображаются на поддерживающую базу данных. Некоторые ORM  привязаны к определенной базе данных, тогда как другие не зависят от конкретной базы данных.
        • +
        • Использование объектной модели данных (ODM) или объектно-реляционной модели (ORM).  ODM / ORM представляют данные веб-сайта как объекты JavaScript, которые затем отображаются на поддерживающую базу данных. Некоторые ORM  привязаны к определённой базе данных, тогда как другие не зависят от конкретной базы данных.

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

        @@ -50,7 +50,7 @@ translation_of: Learn/Server-side/Express_Nodejs/mongoose

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

        -

        Совет:  Применение ODM / ORMs часто приводит к снижению затрат на разработку и обслуживание! Если Вы не очень хорошо знакомы с родным языком запросов или если производительность имеет первостепенное значение, следует серьезно рассмотреть возможность применения ODM.

        +

        Совет:  Применение ODM / ORMs часто приводит к снижению затрат на разработку и обслуживание! Если Вы не очень хорошо знакомы с родным языком запросов или если производительность имеет первостепенное значение, следует серьёзно рассмотреть возможность применения ODM.

        Какую модель ORM/ODM следует использовать?

        @@ -63,8 +63,8 @@ translation_of: Learn/Server-side/Express_Nodejs/mongoose
      • Mongoose: -- это средство моделирование объектов базы данных MongoDB,  предназначенное для асинхронной работы.
      • Waterline: ORM  фреймворка Sails (основан на Express) . Она предоставляет единый API для доступа к множеству баз данных, в том числе Redis, mySQL, LDAP, MongoDB, и Postgres.
      • Bookshelf: поддерживает как promise- так и традиционные callback- интерфейсы, поддержка транзакций, eager/nested-eager relation loading, полиморфные ассоциации, и поддержка, один к одному, один ко многим, и многие ко многим. Работает с PostgreSQL, MySQL, и SQLite3.
      • -
      • Objection: Делает настолько легким, насколько возможно, использование всей мощи SQL и движка базы данных ( поддерживает  SQLite3, Postgres, и MySQL).
      • -
      • Sequelize: Основанная на промисах ORM для Node.js и io.js. Поддерживает диалекты PostgreSQL, MySQL, MariaDB, SQLite и MSSQL, обладает надежной поддержкой транзакций, отношений, чтения копий и т.д.
      • +
      • Objection: Делает настолько лёгким, насколько возможно, использование всей мощи SQL и движка базы данных ( поддерживает  SQLite3, Postgres, и MySQL).
      • +
      • Sequelize: Основанная на промисах ORM для Node.js и io.js. Поддерживает диалекты PostgreSQL, MySQL, MariaDB, SQLite и MSSQL, обладает надёжной поддержкой транзакций, отношений, чтения копий и т.д.
      • Node ORM2 -- это OR менеджер для NodeJS. Поддерживает MySQL, SQLite и Progress, помогает работать с БД, используя объектный подход.

      • @@ -73,7 +73,7 @@ translation_of: Learn/Server-side/Express_Nodejs/mongoose -

        Как правило, при выборе решения следует учитывать как предоставляемые функции, так и  "деятельность сообщества" ( загрузки, вклад, отчеты об ошибках, качество документации, и т.д. ) . На момент написания статьи Mongoose являлась очень популярной ORM, и разумно, если вы выбрали MongoDB.

        +

        Как правило, при выборе решения следует учитывать как предоставляемые функции, так и  "деятельность сообщества" ( загрузки, вклад, отчёты об ошибках, качество документации, и т.д. ) . На момент написания статьи Mongoose являлась очень популярной ORM, и разумно, если вы выбрали MongoDB.

        Применение Mongoose и MongoDb для LocalLibrary

        @@ -97,11 +97,11 @@ translation_of: Learn/Server-side/Express_Nodejs/mongoose

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

        -

        Можно также использовать модели для представления параметров списка выбора (например, как выпадающий список вариантов), вместо жесткого кодирования выбора на самом веб-сайте -  рекомендуется, когда не все параметры известны или могут быть изменены. Явный кандидат для модели такого типа -- это жанр книги (например, «Научная фантастика», «Французская поэзия» и т.д.),

        +

        Можно также использовать модели для представления параметров списка выбора (например, как выпадающий список вариантов), вместо жёсткого кодирования выбора на самом веб-сайте -  рекомендуется, когда не все параметры известны или могут быть изменены. Явный кандидат для модели такого типа -- это жанр книги (например, «Научная фантастика», «Французская поэзия» и т.д.),

        Как только мы определились с моделями и полями, следует подумать об отношениях между ними.

        -

        С учетом сказанного, UML-диаграмма связей (см. ниже) показывает модели, которые представлены как прямоугольники. Мы решили, что создадим модели для книги (общие сведения о книге), для экземпляра книги (состояние отдельных физических копий книги, доступных в системе) и для автора. Кроме того, у нас будет модель для жанра, чтобы эти значения можно было создавать динамически. Решено не создавать модель для  BookInstance:status — мы пропишем в коде необходимые значения, потому что не ожидаем их изменения. На элементах диаграммы показаны имя модели, имена и типы полей, имена методов и типы их результатов .

        +

        С учётом сказанного, UML-диаграмма связей (см. ниже) показывает модели, которые представлены как прямоугольники. Мы решили, что создадим модели для книги (общие сведения о книге), для экземпляра книги (состояние отдельных физических копий книги, доступных в системе) и для автора. Кроме того, у нас будет модель для жанра, чтобы эти значения можно было создавать динамически. Решено не создавать модель для  BookInstance:status — мы пропишем в коде необходимые значения, потому что не ожидаем их изменения. На элементах диаграммы показаны имя модели, имена и типы полей, имена методов и типы их результатов .

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

        @@ -112,7 +112,7 @@ translation_of: Learn/Server-side/Express_Nodejs/mongoose

        Mongoose Library Model  with correct cardinality

        -

        Заметка: В следующем разделе дан базовый пример, в котором объясняется, как задавать и как использовать модели. При чтении обратите внимание, как будут создаваться модели, приведенные на диаграмме.

        +

        Заметка: В следующем разделе дан базовый пример, в котором объясняется, как задавать и как использовать модели. При чтении обратите внимание, как будут создаваться модели, приведённые на диаграмме.

        Mongoose Справочник

        @@ -158,14 +158,14 @@ db.on('error', console.error.bind(console, 'MongoDB connection error:'));

        При помощи mongoose.connection можно получить стандартный объект Connection. После подключения в экземпляре Connection возникает событие open (открыт).

        -

        Tip: Если необходимо создать дополнительные подключения, можно использовать mongoose.createConnection(). При этом будут применены те же БД URI (хост, БД, порт, опции и т.д.), что и в connect() и будет возвращен объект Connection.

        +

        Tip: Если необходимо создать дополнительные подключения, можно использовать mongoose.createConnection(). При этом будут применены те же БД URI (хост, БД, порт, опции и т.д.), что и в connect() и будет возвращён объект Connection.

        Определение и создание моделей

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

        -

        Схемы "компилируются "  в окончательную модель методом  mongoose.model(). После создания модели ее можно использовать для поиска, создания, обновления и удаления объектов данного типа.

        +

        Схемы "компилируются "  в окончательную модель методом  mongoose.model(). После создания модели её можно использовать для поиска, создания, обновления и удаления объектов данного типа.

        Заметка: Каждой модели соответствует коллекция документов в ДБ MongoDB. Документы будут содержать поля тех типов, которые заданы в модели Schema.

        @@ -173,7 +173,7 @@ db.on('error', console.error.bind(console, 'MongoDB connection error:'));

        Определение схем данных

        -

        Код ниже показывает, как можно задать простую схему. Сначала при помощи require() создается объект mongoose, затем конструктор Schema создает новый экземпляр схемы, при этом различные поля задаются как параметры конструктора.

        +

        Код ниже показывает, как можно задать простую схему. Сначала при помощи require() создаётся объект mongoose, затем конструктор Schema создаёт новый экземпляр схемы, при этом различные поля задаются как параметры конструктора.

        //Требуется Mongoose
         var mongoose = require('mongoose');
        @@ -212,7 +212,7 @@ var SomeModel = mongoose.model('SomeModel', SomeModelSchema );

        Типы схемы (поля)

        -

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

        +

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

        var schema = new Schema(
         {
        @@ -228,12 +228,12 @@ var SomeModel = mongoose.model('SomeModel', SomeModelSchema );
        nested: { stuff: { type: String, lowercase: true, trim: true } } }) -

        Большинство типов в SchemaTypes (указаны после “type:” или после имен полей) достаточно очевидны. Исключения:

        +

        Большинство типов в SchemaTypes (указаны после “type:” или после имён полей) достаточно очевидны. Исключения:

        • ObjectId: Представляет отдельный экземпляр модели в БД. Например, book может ссылаться на объект- автора. Поле будет содержать уникальный идентификатор (_id) отдельного объекта. При необходимости использования этой информации применяют метод populate().
        • Mixed: Произвольный тип в схеме.
        • -
        • []: Массив элементов. В таких моделях можно выполнять JavaScript-операции для массивов (push, pop, unshift, etc.).  Выше показан пример массивы объектов неопределенного типа и массив строк, но можно использовать массив объектов любого типа.
        • +
        • []: Массив элементов. В таких моделях можно выполнять JavaScript-операции для массивов (push, pop, unshift, etc.).  Выше показан пример массивы объектов неопределённого типа и массив строк, но можно использовать массив объектов любого типа.

        Код содержит также два способа объявления полей:

        @@ -325,7 +325,7 @@ awesome_instance.save(function (err) {

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

        -

        Можно использовать метод create() для создании экземпляра модели при его сохранении. Тогда колбэк-функция вернет ошибку (или null) как первый аргумент и только что созданный экземпляр как второй аргумент.

        +

        Можно использовать метод create() для создании экземпляра модели при его сохранении. Тогда колбэк-функция вернёт ошибку (или null) как первый аргумент и только что созданный экземпляр как второй аргумент.

        SomeModel.create({ name: 'also_awesome' }, function (err, awesome_instance) {
           if (err) return handleError(err);
        @@ -348,7 +348,7 @@ console.log(awesome_instance.name); //вывод в консоль
         
         

        Поиск записей

        -

        При поиске записей методами запросов, условия поиска следует задавать как документ JSON. Приведенный фрагмент кода (ниже) показывает, как в БД найти имена (name) и возраст (age) всех спортсменов-теннисистов. Соответствие будет определяться по одному полю (sport), но можно добавить критерии поиска, задав, например, регулярное выражение, или удалить все критерии, чтобы получить список всех спортсменов.

        +

        При поиске записей методами запросов, условия поиска следует задавать как документ JSON. Приведённый фрагмент кода (ниже) показывает, как в БД найти имена (name) и возраст (age) всех спортсменов-теннисистов. Соответствие будет определяться по одному полю (sport), но можно добавить критерии поиска, задав, например, регулярное выражение, или удалить все критерии, чтобы получить список всех спортсменов.

        var Athlete = mongoose.model('Athlete', yourSchema);
         
        @@ -364,7 +364,7 @@ Athlete.find({ 'sport': 'Tennis' }, 'name age', function (err, athletes) {
         

        Заметка: Все колбэк-функции в Mongoose используют образец callback(error, result). Если при выполнении запроса возникает ошибка, параметр error будет содержать объект error, а result будет null. При успешном запросе параметр error будет null, а result будет содержать результат запроса.

        -

        Если не задать колбэк-функцию, API вернет переменную типа Query. Можно использовать объект запроса, чтобы создать и выполнить свой запрос (с колбэк-функцией) позже, при помощи метода exec().

        +

        Если не задать колбэк-функцию, API вернёт переменную типа Query. Можно использовать объект запроса, чтобы создать и выполнить свой запрос (с колбэк-функцией) позже, при помощи метода exec().

        // найти всех теннисистов
         var query = Athlete.find({ 'sport': 'Tennis' });
        @@ -404,7 +404,7 @@ query.exec(function (err, athletes) {
         
         
         
        -

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

        +

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

        Запросы полезны и во многих других случаях. Дополнительная информация - в Queries (документация Mongoose).

        @@ -431,17 +431,17 @@ var storySchema = Schema({ var Story = mongoose.model('Story', storySchema); var Author = mongoose.model('Author', authorSchema);
        -

        Можно сохранить ссылки в связанном документе, используя значение идентификатора _id. Ниже создается автор, затем   рассказ, и значение идентификатора id автора сохраняется в поле "author" рассказа.

        +

        Можно сохранить ссылки в связанном документе, используя значение идентификатора _id. Ниже создаётся автор, затем   рассказ, и значение идентификатора id автора сохраняется в поле "author" рассказа.

        var bob = new Author({ name: 'Bob Smith' });
         
         bob.save(function (err) {
           if (err) return handleError(err);
         
        -  //автор Bob создан, создаем рассказ
        +  //автор Bob создан, создаём рассказ
           var story = new Story({
             title: "Bob goes sledding",
        -    author: bob._id    // присваиваем полю значение идентификатора Боба. Идентификатор создается по умолчанию!
        +    author: bob._id    // присваиваем полю значение идентификатора Боба. Идентификатор создаётся по умолчанию!
           });
         
           story.save(function (err) {
        @@ -479,7 +479,7 @@ bob.save(function (err) {
         
         

        Одна схема (модель) - один файл

        -

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

        +

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

        // Файл: ./models/somemodel.js
         
        @@ -499,7 +499,7 @@ module.exports = mongoose.model('SomeModel', SomeModelSchema );<
         
         

        You can then require and use the model immediately in other files. Below we show how you might use it to get all instances of the model.

        -
        //Создаем модель SomeModel просто вызовом модуля из файла
        +
        //Создаём модель SomeModel просто вызовом модуля из файла
         var SomeModel = require('../models/somemodel')
         
         // Используем объект SomeModel (модель) для поиска всех записей в SomeModel
        @@ -509,7 +509,7 @@ SomeModel.find(callback_function);

        Мы уже немного понимаем,  что может делать Mongoose и как следует проектировать  модели. Теперь самое время начать работу над сайтом  LocalLibrary. Самое первое, что мы должны сделать - установить базу данных MongoDb, в которой будут храниться данные нашей   библиотеки.

        -

        В этом руководстве мы будем использовать базу данных в "песочнице" ("sandbox") - бесплатный облачный сервис, предоставляемый  mLab. Такая база не очень подходит для промышленных веб-сайтов, поскольку не имеет избыточности, но она очень удобна для разработки и прототипирования. Мы используем ее, так как она бесплатна, ее легко установить, и потому что mLab - популярный поставщик  базы данных как сервиса, и это может быть разумным выбором для промышленной базы данных (на данный момент другие известные возможности включают Compose, ScaleGrid и MongoDB Atlas).

        +

        В этом руководстве мы будем использовать базу данных в "песочнице" ("sandbox") - бесплатный облачный сервис, предоставляемый  mLab. Такая база не очень подходит для промышленных веб-сайтов, поскольку не имеет избыточности, но она очень удобна для разработки и прототипирования. Мы используем её, так как она бесплатна, её легко установить, и потому что mLab - популярный поставщик  базы данных как сервиса, и это может быть разумным выбором для промышленной базы данных (на данный момент другие известные возможности включают Compose, ScaleGrid и MongoDB Atlas).

        Заметка: При желании можно установить БД  MongoDb локально, загрузив и установив подходящие для вашей системы двоичные файлы. В этом случае приводимые ниже инструкции не изменятся, за исключением URL базы данных, который нужно будет задать для установки соединения.

        @@ -520,14 +520,14 @@ SomeModel.find(callback_function);

        После входа в систему вы увидите главную страницу home:

          -
        1. Щелкните Create New в разделе MongoDB Deployments для создания новой БД.
        2. +
        3. Щёлкните Create New в разделе MongoDB Deployments для создания новой БД.
        4. Откроется экран Cloud Provider Selection -  раздела провайдера облака.
          MLab - screen for new deployment
          • Выберите план SANDBOX (Free) из раздела Plan Type (тип плана). 
          • Выберите любого провайдера в разделе Cloud Provider (провайдер облака). Разные провайдеры обслуживают разные регионы (показаны под выбранным типом плана).
          • -
          • Щелкните кнопку Continue.
          • +
          • Щёлкните кнопку Continue.
        5. Откроется экран выбора региона Select Region. @@ -535,7 +535,7 @@ SomeModel.find(callback_function);
        • -

          Выберите ближайший к Вам регион и щелкните кнопку Continue.

          +

          Выберите ближайший к Вам регион и щёлкните кнопку Continue.

        @@ -554,17 +554,17 @@ SomeModel.find(callback_function);
        • -

          Щелкните Submit Order (подтвердить заказ), чтобы создать БД.

          +

          Щёлкните Submit Order (подтвердить заказ), чтобы создать БД.

      • -

        Вы вернетесь на главный (home) экран. Щелкните по вновь созданной базе, чтобы открыть экран с детальной информацией. Как видно, в БД нет коллекций (данных).
        +

        Вы вернётесь на главный (home) экран. Щёлкните по вновь созданной базе, чтобы открыть экран с детальной информацией. Как видно, в БД нет коллекций (данных).
        mLab - Database details screen
         
        - На форме выше обведен URL для соединения с вашей БДthat you need to use to access your database is displayed on the form above (shown for this database circled above). Чтобы его использовать, необходимо создать пользователя БД, который позже введет этот URL.

        + На форме выше обведён URL для соединения с вашей БДthat you need to use to access your database is displayed on the form above (shown for this database circled above). Чтобы его использовать, необходимо создать пользователя БД, который позже введёт этот URL.

      • -
      • Щелкните по вкладке Users и выберите кнопку Add database user (добавить пользователя БД).
      • +
      • Щёлкните по вкладке Users и выберите кнопку Add database user (добавить пользователя БД).
      • Введите имя пользователя и пароль (дважды), затем нажмите Create (создать). Не отмечайте Make read only (только для чтения)!
      • @@ -573,14 +573,14 @@ SomeModel.find(callback_function);

        Установка Mongoose

        -

        Откройте окно команд и перейдите в каталог, в котором создан  каркас веб-сайта Local Library. Введите команду install, чтобы установить Mongoose (и ее зависимости), а также добавьте ее в файл package.json, если вы еще не сделали этого ранее, при чтении примера Mongoose Primer.

        +

        Откройте окно команд и перейдите в каталог, в котором создан  каркас веб-сайта Local Library. Введите команду install, чтобы установить Mongoose (и её зависимости), а также добавьте её в файл package.json, если вы ещё не сделали этого ранее, при чтении примера Mongoose Primer.

        npm install mongoose
         

        Подключение к MongoDB

        -

        Откройте /app.js (в корне проекта) и скопируйте приведенный ниже текст, в котором  объявляется объект приложения Express (после строки var app = express();). Замените строку url БД ('insert_your_database_url_here') тем URL, который представляет вашу БД  (т.е. используйте информацию, полученную от mLab).

        +

        Откройте /app.js (в корне проекта) и скопируйте приведённый ниже текст, в котором  объявляется объект приложения Express (после строки var app = express();). Замените строку url БД ('insert_your_database_url_here') тем URL, который представляет вашу БД  (т.е. используйте информацию, полученную от mLab).

        //Устанавливаем соединение с mongoose
         var mongoose = require('mongoose');
        @@ -590,11 +590,11 @@ mongoose.Promise = global.Promise;
         var db = mongoose.connection;
         db.on('error', console.error.bind(console, 'MongoDB connection error:'));
        -

        Как указано ранее в примере Mongoose primer, этот код задает соединение по умолчанию с привязкой события ошибки error (так что ошибки будут выведены в консоль). 

        +

        Как указано ранее в примере Mongoose primer, этот код задаёт соединение по умолчанию с привязкой события ошибки error (так что ошибки будут выведены в консоль). 

        Определение схемы LocalLibrary

        -

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

        +

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

        /express-locallibrary-tutorial  //the project root
           /models
        @@ -606,7 +606,7 @@ db.on('error', console.error.bind(console, 'MongoDB connection error:'));

        Модель автора Author

        -

        Скопируйте код схемы автора Author (приведен ниже) в файл ./models/author.js . В схеме определено, что у автора есть обязательные поля имени и фамилии типа String  длиной не более 100 символов, и поля типа Date дата рождения и дата смерти.

        +

        Скопируйте код схемы автора Author (приведён ниже) в файл ./models/author.js . В схеме определено, что у автора есть обязательные поля имени и фамилии типа String  длиной не более 100 символов, и поля типа Date дата рождения и дата смерти.

        var mongoose = require('mongoose');
         
        @@ -644,14 +644,14 @@ module.exports = mongoose.model('Author', AuthorSchema);
         
         

        Заметка: Объявить  в схеме URL как виртуальные свойства - хорошая идея,  т.к. URL отдельного элемента при необходимости изменения требует коррекции только в одном месте.
        - Сейчас связь при помощи этого URL еще не работает, так как у нас еще нет кода, поддерживающего маршруты для экземпляров модели.  Мы построим его в следующей статье!

        + Сейчас связь при помощи этого URL ещё не работает, так как у нас ещё нет кода, поддерживающего маршруты для экземпляров модели.  Мы построим его в следующей статье!

        В конце модуля экспортируется модель.

        Модель книги Book

        -

        Скопируйте код схемы Book (приведен ниже) в файл ./models/book.js. Большая часть кода подобна коду для модели автора — объявляется схема с рядом строковых полей, с виртуальным свойством URL для получения  URL конкретных книг, затем модель экспортируется.

        +

        Скопируйте код схемы Book (приведён ниже) в файл ./models/book.js. Большая часть кода подобна коду для модели автора — объявляется схема с рядом строковых полей, с виртуальным свойством URL для получения  URL конкретных книг, затем модель экспортируется.

        var mongoose = require('mongoose');
         
        @@ -682,12 +682,12 @@ module.exports = mongoose.model('Book', BookSchema);
         
         
        • author - это ссылка на единственный объект модели Author , обязательный элемент.
        • -
        • genre (жанр) - ссылка на массив объектов модели Genre. Эта модель еще не объявлена!
        • +
        • genre (жанр) - ссылка на массив объектов модели Genre. Эта модель ещё не объявлена!

        Модель экземпляра книги BookInstance

        -

        Наконец, скопируйте код схемы BookInstance (приведен ниже) в файл ./models/bookinstance.js. Схема BookInstance представляет конкретный экземпляр книги, которую можно одолжить на время, и содержит информацию о доступности экземпляров книги, о дате возврата одолженной книги, о деталях версии или печатного экземпляра.

        +

        Наконец, скопируйте код схемы BookInstance (приведён ниже) в файл ./models/bookinstance.js. Схема BookInstance представляет конкретный экземпляр книги, которую можно одолжить на время, и содержит информацию о доступности экземпляров книги, о дате возврата одолженной книги, о деталях версии или печатного экземпляра.

        var mongoose = require('mongoose');
         
        @@ -734,7 +734,7 @@ module.exports = mongoose.model('BookInstance', BookInstanceSchema);
      • Экспортируйте модель.
      • -

        Тестирование — создаем элементы БД

        +

        Тестирование — создаём элементы БД

        Вот так. У нас теперь есть все модели для создания сайта!

        @@ -764,7 +764,7 @@ module.exports = mongoose.model('BookInstance', BookInstanceSchema);

        В этой статье мы познакомились с БД и ОРМ (объектно-реляционными моделями) в системе Node/Express, узнали, как определяются схемы и модели Mongoose. Мы применили эти знания при проектировании и реализации моделей Book, BookInstance, Author и Genre для веб-сайта LocalLibrary.

        -

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

        +

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

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

        diff --git a/files/ru/learn/server-side/express_nodejs/routes/index.html b/files/ru/learn/server-side/express_nodejs/routes/index.html index 14d65e989c..65169cf637 100644 --- a/files/ru/learn/server-side/express_nodejs/routes/index.html +++ b/files/ru/learn/server-side/express_nodejs/routes/index.html @@ -34,7 +34,7 @@ translation_of: Learn/Server-side/Express_Nodejs/routes

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

        -

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

        +

        Приведённая ниже диаграмма напоминает об основном потоке данных и об элементах, которые необходимо реализовать при обработке HTTP-запроса/ответа. Кроме представлений и маршрутов на диаграмме показаны "контроллеры" - функции, которые отделяют код для маршрутизации запросов от кода, который фактически обрабатывает запросы.

        Поскольку модели уже созданы, основные элементы, которые следует создать, таковы:

        @@ -48,13 +48,13 @@ translation_of: Learn/Server-side/Express_Nodejs/routes

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

        -

        В первом разделе ниже приведен краткие основы того, как использовать промежуточное средство (middleware)  Express Router. Эти знания будут использованы в следующих разделах при настройке  маршрутов для LocalLibrary.

        +

        В первом разделе ниже приведён краткие основы того, как использовать промежуточное средство (middleware)  Express Router. Эти знания будут использованы в следующих разделах при настройке  маршрутов для LocalLibrary.

        Маршруты - основы

        Маршруты - это часть кода Express, связывающая HTTP действия (GET, POST, PUT, DELETE, etc.), URL пути (шаблона), и функцию, которая обрабатывает этот шаблон.

        -

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

        +

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

        Заметка: Маршруты приложения Express уже кратко рассматривались в Express Introduction > Creating route handlers (Введение -> Создание обработчиков маршрутов).  Применение Router обеспечивает лучшую поддержку модульности (как обсуждается в первой подсекции ниже), а в остальном очень похоже на определение маршрутов непосредственно в объекте приложения Express.

        @@ -97,11 +97,11 @@ module.exports = router; // ... app.use('/wiki', wiki);
        -

        После этого два маршрута, определенные в нашем модуле маршрутов wiki, станут доступны из /wiki/ и /wiki/about/.

        +

        После этого два маршрута, определённые в нашем модуле маршрутов wiki, станут доступны из /wiki/ и /wiki/about/.

        Функции Route

        -

        В модуле выше определена пара типовых функций маршрута. Маршрут "about" (еще раз показан ниже) определен при помощи метода Router.get(), который отвечает только на  HTTP GET-запросы. Первый аргумент метода - URL-путь, а второй -  колбэк-функция, которая будет вызвана, если получен HTTP GET-запрос с указанным путем.

        +

        В модуле выше определена пара типовых функций маршрута. Маршрут "about" (ещё раз показан ниже) определён при помощи метода Router.get(), который отвечает только на  HTTP GET-запросы. Первый аргумент метода - URL-путь, а второй -  колбэк-функция, которая будет вызвана, если получен HTTP GET-запрос с указанным путем.

        router.get('/about', function (req, res) {
           res.send('About this wiki');
        @@ -117,7 +117,7 @@ app.use('/wiki', wiki);

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

        -

        Здесь, когда приходит GET-запрос с путем ('/about') колбэк-функция при ответе вызывает send() , возвращая строку "About this wiki". Существует  ряд других методов ответа , завершающих цикл запрос-ответ. Например, можно вызвать res.json() , чтобы послать ответ JSON, или res.sendFile(), чтобы послать файл. Метод ответа, который будет использован чаще всего при построении нашей библиотеки - это  render(), создающий, на основе шаблонов и данных, и возвращающий  HTML-файлы —мы поговорим об этом подробнее в следующей статье!

        +

        Здесь, когда приходит GET-запрос с путём ('/about') колбэк-функция при ответе вызывает send() , возвращая строку "About this wiki". Существует  ряд других методов ответа , завершающих цикл запрос-ответ. Например, можно вызвать res.json() , чтобы послать ответ JSON, или res.sendFile(), чтобы послать файл. Метод ответа, который будет использован чаще всего при построении нашей библиотеки - это  render(), создающий, на основе шаблонов и данных, и возвращающий  HTML-файлы —мы поговорим об этом подробнее в следующей статье!

        HTTP глаголы (действия)

        @@ -125,7 +125,7 @@ app.use('/wiki', wiki);

        Кроме того, Router обеспечивает также методы маршрутизации для других HTTP глаголов, которые обычно используются точно таким же способом: post(), put(), delete(), options(), trace(), copy(), lock(), mkcol(), move(), purge(), propfind(), proppatch(), unlock(), report(), ​​​​​​ mkactivity(), checkout(), merge(), m-search(), notify(), subscribe(), unsubscribe(), patch(), search(), и connect().

        -

        Например, код ниже делает то же, что и предыдущий, с путем /about, но отвечает на  HTTP POST-запросы.

        +

        Например, код ниже делает то же, что и предыдущий, с путём /about, но отвечает на  HTTP POST-запросы.

        router.post('/about', function (req, res) {
           res.send('About this wiki');
        @@ -156,7 +156,7 @@ app.use('/wiki', wiki);

        Параметры маршрутов

        -

        Параметры маршрутов - это именованные сегменты URL , которые используются для выбора значений из указанной позиции  URL. Именованные сегменты начинаются двоеточием, после которого следует имя (например, /:your_parameter_name/.  Выбранные значения сохраняются в объекте req.params, причем имя параметра  используется как ключ (т.е. req.params.your_parameter_name).

        +

        Параметры маршрутов - это именованные сегменты URL , которые используются для выбора значений из указанной позиции  URL. Именованные сегменты начинаются двоеточием, после которого следует имя (например, /:your_parameter_name/.  Выбранные значения сохраняются в объекте req.params, причём имя параметра  используется как ключ (т.е. req.params.your_parameter_name).

        Предположим, например, что URL содержит информацию о пользователях и книгах:  http://localhost:3000/users/34/books/8989. Можно извлечь эту информацию (см. ниже) в параметры userId и bookId пути:

        @@ -170,14 +170,14 @@ app.use('/wiki', wiki);

        Имена параметров пути должны состоять из “символов слова” (A-Z, a-z, 0-9, и _).

        -

        Заметка: URL /book/create будет соответствовать маршрутам вида /book/:bookId (и 'create' станет значением "bookId"). Будет использован первый маршрут, соответствующий введенному  URL, поэтому, если необходимо обрабатывать URL вида /book/create отдельно, обработчик этого маршрута должен быть расположен до маршрута /book/:bookId .

        +

        Заметка: URL /book/create будет соответствовать маршрутам вида /book/:bookId (и 'create' станет значением "bookId"). Будет использован первый маршрут, соответствующий введённому  URL, поэтому, если необходимо обрабатывать URL вида /book/create отдельно, обработчик этого маршрута должен быть расположен до маршрута /book/:bookId .

        Для начала этих сведений достаточно - если потребуется, можно найти дополнительную информацию в документации  Express: Basic routing (основы маршрутизации) и Routing guide (руководство по маршрутизации).  В следующем разделе показано, как задать маршруты и контроллеры для нашей библиотеки LocalLibrary.

        Маршруты, необходимые для библиотеки LocalLibrary

        -

        Те URL, которые в итоге будут нужны для наших страниц, показаны ниже.  Слово object должно быть заменено на имя каждой из наших моделей (book, bookinstance, genre, author),  слово objects - множественное число для object, а id - уникальное значение для поля(_id), которое Mongoose создает по умолчанию для каждого экземпляра модели.

        +

        Те URL, которые в итоге будут нужны для наших страниц, показаны ниже.  Слово object должно быть заменено на имя каждой из наших моделей (book, bookinstance, genre, author),  слово objects - множественное число для object, а id - уникальное значение для поля(_id), которое Mongoose создаёт по умолчанию для каждого экземпляра модели.

        • catalog/ — Домашняя страница home/index.
        • @@ -190,7 +190,7 @@ app.use('/wiki', wiki);

          Первая домашняя страница и страницы со списками не кодируют никакой дополнительной информации. Хотя результаты, возвращаемые запросами, будут зависеть от типа модели и от содержимого БД, запросы для получения этой информации всегда будут одинаковы (подобно тому, как код для создания объектов всегда будет одним и тем же). 

          -

          В противоположность этому, другие URL используются для работы с  определенными экземплярами документов и моделей— индивидуальность элементов кодируется в  URL (как <id> выше). Параметры путей используются для извлечения информации и передачи ее в обработчик пути (и в следующей статье мы применим этот прием для того, чтобы динамически определять, какую информацию следует получить из БД). By encoding the information in our URL we only need one route for every resource of a particular type (e.g. one route to handle the display of every single book item).

          +

          В противоположность этому, другие URL используются для работы с  определёнными экземплярами документов и моделей— индивидуальность элементов кодируется в  URL (как <id> выше). Параметры путей используются для извлечения информации и передачи её в обработчик пути (и в следующей статье мы применим этот приём для того, чтобы динамически определять, какую информацию следует получить из БД). By encoding the information in our URL we only need one route for every resource of a particular type (e.g. one route to handle the display of every single book item).

          Заметка: Express позволяет строить URL любым способом, который вам нравится — можно кодировать информацию в теле  URL как показано выше или использовать URL GET -запрос с параметрами (например, /book/?id=6). Какой бы подход вы не применяли, URL должны быть ясными, логичными и читаемыми (ознакомьтесь с советами W3C).

          @@ -198,11 +198,11 @@ app.use('/wiki', wiki);

          Далее мы создадим колбэк-функции обработчиков маршрутов и код маршрутов для всех указанных выше URL.

          -

          Создаем колбэк-функции обработчиков маршрутов

          +

          Создаём колбэк-функции обработчиков маршрутов

          Перед определением маршрутов сначала создадим фиктивные (каркасные) колбэк-функции, которые они будут вызывать. Эти функции будут храниться в отдельных модулях -"контроллерах" для моделей Book, BookInstance, Genre, и Author (можно использовать любую структуру моделей и файлов, но кажется, что выбранная обеспечивает приемлемую модульность нашего проекта).

          -

          Начнем с создания каталога для контроллеров в корне проекта (/controllers), а затем создадим отдельные файлы (модули) контроллеров для работы с моделями:

          +

          Начнём с создания каталога для контроллеров в корне проекта (/controllers), а затем создадим отдельные файлы (модули) контроллеров для работы с моделями:

          /express-locallibrary-tutorial  //корень проекта
             /controllers
          @@ -260,7 +260,7 @@ exports.author_update_post = function(req, res) {
           
           

          В модуле сначала подключается (requires) модель, которая далее будет использована для получения данных и их обновления. Далее экспортируются функции для каждого URL, который мы хотим обрабатывать (операции create-создать, update-обновить и delete-удалить используют формы, следовательно, должны быть дополнительные методы для обработки post-запросов от форм - эти методы обсуждаются далее, в статье "forms article" ("формы")).

          -

          Все функции имеют стандартную форму функций среднего слоя Express , с аргументами для запроса, ответа и следующей (next) функции, которая должна быть вызвана, если метод не завершил цикл запроса (во всех приведенных в коде случаях - завершает!). Методы просто возвращают строку, информирующую о том, что соответствующая страница еще не создана. Если функция контроллера должна получить параметры маршрута, эти параметры будут выведены в строке сообщения (смотри выше req.params.id ).

          +

          Все функции имеют стандартную форму функций среднего слоя Express , с аргументами для запроса, ответа и следующей (next) функции, которая должна быть вызвана, если метод не завершил цикл запроса (во всех приведённых в коде случаях - завершает!). Методы просто возвращают строку, информирующую о том, что соответствующая страница ещё не создана. Если функция контроллера должна получить параметры маршрута, эти параметры будут выведены в строке сообщения (смотри выше req.params.id ).

          BookInstance controller

          @@ -358,7 +358,7 @@ exports.genre_update_post = function(req, res) {

          Контроллер книги

          -

          Скопируйте следующий код в файл /controllers/bookController.js. Он построен по образцу других модулей контроллеров, но еще содержит функцию index() для вывода странички с приветствием:

          +

          Скопируйте следующий код в файл /controllers/bookController.js. Он построен по образцу других модулей контроллеров, но ещё содержит функцию index() для вывода странички с приветствием:

          var Book = require('../models/book');
           
          @@ -409,9 +409,9 @@ exports.book_update_post = function(req, res) {
           
           

          Создание модуля для маршрута catalog

          -

          Далее мы создадим маршруты для всех URL, необходимых веб-сайту LocalLibrary, которые будут вызывать функции контроллеров, определенные в предыдущем разделе.

          +

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

          -

          Каркас приложения уже содержит каталог ./routes, в котором есть маршруты для index и users. Внутри этого каталога создадим еще один файл маршрутов — catalog.js ( см. ниже).

          +

          Каркас приложения уже содержит каталог ./routes, в котором есть маршруты для index и users. Внутри этого каталога создадим ещё один файл маршрутов — catalog.js ( см. ниже).

          /express-locallibrary-tutorial //the project root
             /routes
          @@ -419,7 +419,7 @@ exports.book_update_post = function(req, res) {
               users.js
               catalog.js
          -

          Скопируйте приведенный ниже код в файл /routes/catalog.js :

          +

          Скопируйте приведённый ниже код в файл /routes/catalog.js :

          var express = require('express');
           var router = express.Router();
          @@ -554,7 +554,7 @@ router.get('/bookinstances', book_instance_controller.bookinstance_list);
           
           

          Все новые маршруты заданы, а маршрут на начальную страницу остался без изменения. Давайте перенаправим его на новую страницу "index", которая создана в каталоге  '/catalog'.

          -

          Откройте /routes/index.js и замените существующий маршрут приведенную ниже.

          +

          Откройте /routes/index.js и замените существующий маршрут приведённую ниже.

          // GET home page.
           router.get('/', function(req, res) {
          @@ -582,7 +582,7 @@ app.use('/users', usersRouter);
           app.use('/catalog', catalogRouter);  // Add catalog routes to middleware chain.
          -

          Заметка: Мы добавили модуль каталога в путь'/catalog'.  Этот путь будет предшествовать всем путям, определенным в модуле каталога. Например, для доступа к списку книг URL будет таким: /catalog/books/.

          +

          Заметка: Мы добавили модуль каталога в путь'/catalog'.  Этот путь будет предшествовать всем путям, определённым в модуле каталога. Например, для доступа к списку книг URL будет таким: /catalog/books/.

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

          diff --git a/files/ru/learn/server-side/express_nodejs/skeleton_website/index.html b/files/ru/learn/server-side/express_nodejs/skeleton_website/index.html index 1ed22246de..7f01cbf62e 100644 --- a/files/ru/learn/server-side/express_nodejs/skeleton_website/index.html +++ b/files/ru/learn/server-side/express_nodejs/skeleton_website/index.html @@ -73,7 +73,7 @@ translation_of: Learn/Server-side/Express_Nodejs/skeleton_website

          Какой движок представлений следует использовать?

          -

          Express-generator дает возможность сконфигурировать несколько популярных движков, включая EJS, Hbs, Pug (Jade), Twig, и Vash, но по умолчанию  выбран Jade. Экспресс сразу после установки может поддерживать большое количество и других шаблонизаторов.

          +

          Express-generator даёт возможность сконфигурировать несколько популярных движков, включая EJS, Hbs, Pug (Jade), Twig, и Vash, но по умолчанию  выбран Jade. Экспресс сразу после установки может поддерживать большое количество и других шаблонизаторов.

          Заметка: При желании использовать шаблонизатор, который не поддерживается генератором,  просмотрите  документацию Using template engines with Express  и документацию для нужного шаблонизатора.

          @@ -86,7 +86,7 @@ translation_of: Learn/Server-side/Express_Nodejs/skeleton_website
        • Популярность и активность — проверьте популярность движка, возможно, у него есть активное сообщество. Очень важно иметь поддержку для движка, если у вас возникнут проблемы в течении жизни веб-сайта.
        • Стиль — некоторые шаблонизаторы используют особую разметку для отображения вставленного контента внутри "обычного" HTML, а другие строят  HTML, используя специальный синтаксис (например, используя отступы или блочные имена).
        • Производительность и время интерпретации.
        • -
        • Особенности — следует выбирать движок  с учетом таких особенностей: +
        • Особенности — следует выбирать движок  с учётом таких особенностей:
          • Наследование макета: позволяет определить базовый шаблон и затем наследовать только те части, которые отличаются для конкретной страницы. Это, как правило, лучший подход, чем создание шаблонов путём включения нескольких необходимых компонентов или создания шаблона с нуля каждый раз.
          • Поддержка «Include»: позволяет создавать шаблоны, включая другие шаблоны.
          • @@ -207,7 +207,7 @@ GET /favicon.ico 404 34.134 ms - 1335
        • Обеспечиваем
          перезапуск сервера при изменении файлов

          -

          Любые изменения, внесенные на веб-сайт Express, не будут отображаться до перезапуска сервера. Остановка (Ctrl-C) и перезапуск сервера каждый раз после внесения изменений быстро становится раздражающей, поэтому стоит автоматизировать перезапуск.

          +

          Любые изменения, внесённые на веб-сайт Express, не будут отображаться до перезапуска сервера. Остановка (Ctrl-C) и перезапуск сервера каждый раз после внесения изменений быстро становится раздражающей, поэтому стоит автоматизировать перезапуск.

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

          @@ -254,7 +254,7 @@ GET /favicon.ico 404 34.134 ms - 1335
          DEBUG=express-locallibrary-tutorial:* npm run devstart
          -

          Заметка: Сейчас после изменения любого файла проекта сервер будет перезапускаться (или можно самостоятельно перезапустить его, введя rs в командной строке). Вам все равно придется обновить страницу в браузере .

          +

          Заметка: Сейчас после изменения любого файла проекта сервер будет перезапускаться (или можно самостоятельно перезапустить его, введя rs в командной строке). Вам все равно придётся обновить страницу в браузере .

          Теперь мы должны выполнять команду "npm run <scriptname>" а не просто  npm start, поскольку "start", это, по сути, команда NPM, сопоставленная сценарию в файле package.json. Можно заменить команду в сценарии "start", но, так как мы хотим использовать nodemon только во время разработки, разумно создать новую команду сценария.

          @@ -265,7 +265,7 @@ GET /favicon.ico 404 34.134 ms - 1335

          Структура каталогов

          -

          После установки зависимостей проект имеет такую структуру файлов (файлы - это элементы без префикса"/"). Файл package.json определяет имя файла с приложением, сценарии запуска, зависимости и др.  Сценарий запуска задает точку входа приложения, у нас -- файл JavaScript /bin/www. Этот файл настраивает некоторые обработчики ошибок приложения, а затем загружает  app.js для выполнения остальной работы. Пути приложения хранятся в отдельных модулях каталога routes/.  Шаблоны хранятся в каталоге /views.

          +

          После установки зависимостей проект имеет такую структуру файлов (файлы - это элементы без префикса"/"). Файл package.json определяет имя файла с приложением, сценарии запуска, зависимости и др.  Сценарий запуска задаёт точку входа приложения, у нас -- файл JavaScript /bin/www. Этот файл настраивает некоторые обработчики ошибок приложения, а затем загружает  app.js для выполнения остальной работы. Пути приложения хранятся в отдельных модулях каталога routes/.  Шаблоны хранятся в каталоге /views.

          /express-locallibrary-tutorial
               app.js
          @@ -321,7 +321,7 @@ GET /favicon.ico 404 34.134 ms - 1335
          • body-parser: -- анализирует часть тела входящего запроса HTTP и облегчает извлечение из него различных частей. Например, мы можно читать POST-параметры.
          • -
          • cookie-parser: разбирает заголовок и заполняет req.cookies (по сути, дает удобный метод для доступа к информации cookie).
          • +
          • cookie-parser: разбирает заголовок и заполняет req.cookies (по сути, даёт удобный метод для доступа к информации cookie).
          • debug: небольшой отладчик, работающий по образцу методики отладки ядра node.
          • morgan: средство логирования запросов HTTP для node.
          • serve-favicon: средство обработки favicon (значка, используемого для представления сайта на вкладках браузера, закладках и т. д).
          • @@ -336,7 +336,7 @@ GET /favicon.ico 404 34.134 ms - 1335

            Файл www

            -

            Файл /bin/www – это входная точка приложения. Сначала в файле создается объект основного приложения, расположенного в app.js — выполняется app=require(./app).

            +

            Файл /bin/www – это входная точка приложения. Сначала в файле создаётся объект основного приложения, расположенного в app.js — выполняется app=require(./app).

            #!/usr/bin/env node
             
            @@ -351,11 +351,11 @@ GET /favicon.ico 404 34.134 ms - 1335

            Заметка: require() -- это глобальная функция node  для импорта модулей в текущий файл.  Для модуля app.js указан относительный путь, а расширение файла по умолчанию (.js) опущено.

          -

          Оставшаяся часть кода настраивает порт сервера node для HTTP (определен в переменной среды или 3000, если не определен), и начинает обработку и протоколирование соединений и ошибок сервера. Сейчас вам не требуется дополнительных сведений о коде (все в этом файле шаблонно), но, при желании, его можно посмотреть.

          +

          Оставшаяся часть кода настраивает порт сервера node для HTTP (определён в переменной среды или 3000, если не определён), и начинает обработку и протоколирование соединений и ошибок сервера. Сейчас вам не требуется дополнительных сведений о коде (все в этом файле шаблонно), но, при желании, его можно посмотреть.

          Файл app.js

          -

          Этот файл создает объект приложения  express (с именемapp, по соглашению), настраивает приложение и промежуточное ПО, а затем экспортирует приложение из модуля. В приведенном ниже коде показаны только те части файла, которые создают и экспортируют объект приложения:

          +

          Этот файл создаёт объект приложения  express (с именемapp, по соглашению), настраивает приложение и промежуточное ПО, а затем экспортирует приложение из модуля. В приведённом ниже коде показаны только те части файла, которые создают и экспортируют объект приложения:

          var express = require('express');
           var app = express();
          @@ -382,10 +382,10 @@ var users = require('./routes/users');
           
          -

          Заметка: Здесь мы только импортируем модули. В действительности эти пути еще не используются — это произойдет в файле несколько позже.

          +

          Заметка: Здесь мы только импортируем модули. В действительности эти пути ещё не используются — это произойдёт в файле несколько позже.

          -

          Далее, импортированные модули express применяются для создания объекта app, который потом устанавливает движки-шаблоны представления. Установка движков состоит их двух частей. В первой мы задаем значение 'view', указывая папку, в которой будут размещаться шаблоны (у нас это /views). Во второй мы задаем значение движка 'view engine', указывая на библиотеку шаблона (у нас — "pug").

          +

          Далее, импортированные модули express применяются для создания объекта app, который потом устанавливает движки-шаблоны представления. Установка движков состоит их двух частей. В первой мы задаём значение 'view', указывая папку, в которой будут размещаться шаблоны (у нас это /views). Во второй мы задаём значение движка 'view engine', указывая на библиотеку шаблона (у нас — "pug").

          var app = express();
           
          @@ -412,7 +412,7 @@ app.use('/users', users);
           
          -

          Заметка: . пути, указанные выше ('/' и '/users') рассматриваются как префиксы путей, определенных в импортированных файлах. Так, например, если импортированный модуль users определяет путь для /profile, для доступа следует указать /users/profile.  Мы поговорим подробнее о путях в последующей статье.

          +

          Заметка: . пути, указанные выше ('/' и '/users') рассматриваются как префиксы путей, определённых в импортированных файлах. Так, например, если импортированный модуль users определяет путь для /profile, для доступа следует указать /users/profile.  Мы поговорим подробнее о путях в последующей статье.

          Последняя в файле промежуточная библиотека добавляет методы обработки ошибок и ответов 404 от HTTP.

          @@ -442,7 +442,7 @@ app.use(function(err, req, res, next) {

          Пути (Routes)

          -

          Файл путей /routes/users.js приведен ниже (файлы путей имеют сходную структуру, поэтому нет необходимости приводить также index.js). Сначала загружается модуль Express, затем он используется для получения объекта express.Router. После этого для этого объекта задается путь, и, наконец, объект-роутер экспортируется из модуля (именно это позволяет импортировать файл в app.js):.

          +

          Файл путей /routes/users.js приведён ниже (файлы путей имеют сходную структуру, поэтому нет необходимости приводить также index.js). Сначала загружается модуль Express, затем он используется для получения объекта express.Router. После этого для этого объекта задаётся путь, и, наконец, объект-роутер экспортируется из модуля (именно это позволяет импортировать файл в app.js):.

          var express = require('express');
           var router = express.Router();
          @@ -455,7 +455,7 @@ var router = express.Router();
           module.exports = router;
           
          -

          Путь определяет колбэк-функцию, которая будет вызвана, когда обнаружится HTTP GET-запрос корректного вида. Образец для сопоставления пути задается при импорте модуля -- ('/users') плюс что-то, определяемое в этом файле ('/'). Иными словами, этот путь будет использован, когда получен URL-запрос /users/.

          +

          Путь определяет колбэк-функцию, которая будет вызвана, когда обнаружится HTTP GET-запрос корректного вида. Образец для сопоставления пути задаётся при импорте модуля -- ('/users') плюс что-то, определяемое в этом файле ('/'). Иными словами, этот путь будет использован, когда получен URL-запрос /users/.

          Совет: запустите сервер и задайте в браузере URL http://localhost:3000/users/. Вы должны увидеть сообщение: 'respond with a resource'.

          @@ -473,7 +473,7 @@ router.get('/', function(req, res) { }); -

          Шаблон для пути '/' приведен ниже (файл index.pug). О синтаксисе мы поговорим позже. Сейчас важно знать, что переменная title со значением 'Express' помещена в определенное место шаблона.

          +

          Шаблон для пути '/' приведён ниже (файл index.pug). О синтаксисе мы поговорим позже. Сейчас важно знать, что переменная title со значением 'Express' помещена в определённое место шаблона.

          extends layout
           
          diff --git a/files/ru/learn/server-side/express_nodejs/tutorial_local_library_website/index.html b/files/ru/learn/server-side/express_nodejs/tutorial_local_library_website/index.html
          index 6a816405e4..57b1bcc18a 100644
          --- a/files/ru/learn/server-side/express_nodejs/tutorial_local_library_website/index.html
          +++ b/files/ru/learn/server-side/express_nodejs/tutorial_local_library_website/index.html
          @@ -43,7 +43,7 @@ original_slug: Learn/Server-side/Express_Nodejs/Учебник_сайт_local_li
            
        • Использовать базу данных для хранения данных вашего приложения.
        • Создавать маршруты для запросов различной информации и шаблонов ("представлений") для рендеринга данных в виде HTML для отображения в браузере.
        • Работать с формами.
        • -
        • Развертывать ваше приложение в производство.
        • +
        • Развёртывать ваше приложение в производство.

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

        diff --git a/files/ru/learn/server-side/first_steps/index.html b/files/ru/learn/server-side/first_steps/index.html index 4f6b0b78f6..7e1c323a9e 100644 --- a/files/ru/learn/server-side/first_steps/index.html +++ b/files/ru/learn/server-side/first_steps/index.html @@ -15,7 +15,7 @@ translation_of: Learn/Server-side/First_steps ---
        {{LearnSidebar}}
        -

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

        +

        В этом модуле, посвящённом программированию на стороне сервера, мы ответим на несколько фундаментальных вопросов о программировании серверной части: «что это такое?», «чем оно отличается от программирования клиентской части?» и «почему оно так полезно?». Затем последует обзор некоторых самых популярных веб-фреймворков для серверной части и руководство по выбору наиболее подходящего фреймворка для создания вашего первого сайта. Наконец, мы завершим этот модуль вводной статьёй о безопасности веб-сервера.

        Прежде чем начать

        @@ -41,9 +41,9 @@ translation_of: Learn/Server-side/First_steps
        Фреймворки серверной части
        Последняя статья рассказывает о том, что нужно делать веб-приложению серверной стороны для ответа на запросы от веб-браузера. Мы покажем здесь, как веб-фреймворки могут упростить эти задачи и поможем вам подобрать подходящий фреймворк для вашего первого серверного веб-приложения.
        Безопасность веб-сайта
        -
        Безопасность веб-сайта требует бдительности на всех этапах проектирования сайта и его использования. Эта вводная статья не сделает из вас гуру безопасности сайтов, но поможет узнать, какие первые важные шаги вы можете предпринять для повышения устойчивости вашего веб-приложения против наиболее распространенных угроз.
        +
        Безопасность веб-сайта требует бдительности на всех этапах проектирования сайта и его использования. Эта вводная статья не сделает из вас гуру безопасности сайтов, но поможет узнать, какие первые важные шаги вы можете предпринять для повышения устойчивости вашего веб-приложения против наиболее распространённых угроз.

        Аттестация

        -

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

        +

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

        diff --git a/files/ru/learn/server-side/first_steps/web_frameworks/index.html b/files/ru/learn/server-side/first_steps/web_frameworks/index.html index 29f5d6330c..25b9ec408e 100644 --- a/files/ru/learn/server-side/first_steps/web_frameworks/index.html +++ b/files/ru/learn/server-side/first_steps/web_frameworks/index.html @@ -235,7 +235,7 @@ def youngest(request):

        Flask это микрофреймворк для Python.

        - И хотя Flask минималистичен, он может создавать серьезные веб-сайты из коробки. Он содержит сервер разработки и отладчик, а также поддерживает шаблоны Jinja2, безопасные файлы cookie, модульное тестирование и диспетчеризацию запросов RESTful. У него хорошая документация и активное сообщество.

        + И хотя Flask минималистичен, он может создавать серьёзные веб-сайты из коробки. Он содержит сервер разработки и отладчик, а также поддерживает шаблоны Jinja2, безопасные файлы cookie, модульное тестирование и диспетчеризацию запросов RESTful. У него хорошая документация и активное сообщество.

        Flask стал чрезвычайно популярным, особенно для разработчиков, которым необходимо предоставлять веб-сервисы в небольших системах с ограниченными ресурсами (например, запуск веб-сервера на Raspberry Pi, контроллеры Drone и т. п.).

        @@ -243,7 +243,7 @@ def youngest(request):

        Express — быстрый, непринуждённый, гибкий и минималистский веб-фреймворк для Node.js (node — это серверная среда для запуска JavaScript). Он обеспечивает надёжный набор функций для веб и мобильных приложений и предоставляет полезные HTTP-утилиты и middleware (промежуточные интерфейсы).

        -

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

        +

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

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

        diff --git a/files/ru/learn/server-side/first_steps/website_security/index.html b/files/ru/learn/server-side/first_steps/website_security/index.html index 514d7490a5..1f976dd741 100644 --- a/files/ru/learn/server-side/first_steps/website_security/index.html +++ b/files/ru/learn/server-side/first_steps/website_security/index.html @@ -8,7 +8,7 @@ original_slug: Learn/Server-side/First_steps/Веб_Безопасность
        {{PreviousMenu("Learn/Server-side/First_steps/Web_frameworks", "Learn/Server-side/First_steps")}}
        -

        Безопасность сайта требует бдительности во всех аспектах дизайна и использования сайта. Эта вводная статья не сделает из вас гуру безопасности веб-сайта, но она поможет вам понять, откуда приходят угрозы, и что вы можете сделать, чтобы укрепить свое веб-приложение против наиболее распространенных атак.

        +

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

        @@ -18,20 +18,20 @@ original_slug: Learn/Server-side/First_steps/Веб_Безопасность - +
        Цель:Понять самые распространенные угрозы безопасности веб-приложений. И что вы можете сделать, чтобы уменьшить риск взлома вашего сайта.Понять самые распространённые угрозы безопасности веб-приложений. И что вы можете сделать, чтобы уменьшить риск взлома вашего сайта.

        Что такое безопасность сайта?

        -

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

        +

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

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

        -

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

        +

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

        -

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

        +

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

        Примечание: Это вводная статья, призванная помочь вам задуматься о безопасности веб-сайта, но она не является исчерпывающей.

        @@ -39,25 +39,25 @@ original_slug: Learn/Server-side/First_steps/Веб_Безопасность

        Угрозы безопасности сайта

        -

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

        +

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

        Межсайтовый скриптинг (XSS)

        -

        XSS (Cross-Site Scripting - Межсайтовый скриптинг) это термин, используемый для описания типа атак, которые позволяют злоумышленнику внедрять вредоносный код через веб-сайт в браузеры других пользователей. Поскольку внедренный код поступает в браузер с сайта, он является доверенным и может выполнять такие действия, как отправка авторизационного файла cookieпользователя злоумышленнику. Когда у злоумышленника есть файл cookie, он может войти на сайт, как если бы он был пользователем, и сделать все, что может пользователь, например, получить доступ к данным кредитной карты, просмотреть контактные данные или изменить пароли.

        +

        XSS (Cross-Site Scripting - Межсайтовый скриптинг) это термин, используемый для описания типа атак, которые позволяют злоумышленнику внедрять вредоносный код через веб-сайт в браузеры других пользователей. Поскольку внедрённый код поступает в браузер с сайта, он является доверенным и может выполнять такие действия, как отправка авторизационного файла cookieпользователя злоумышленнику. Когда у злоумышленника есть файл cookie, он может войти на сайт, как если бы он был пользователем, и сделать все, что может пользователь, например, получить доступ к данным кредитной карты, просмотреть контактные данные или изменить пароли.

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

        -

        Уязвимости XSS делятся на отраженные и хранимые, в зависимости от того, как сайт возвращает внедренный код в браузер.

        +

        Уязвимости XSS делятся на отражённые и хранимые, в зависимости от того, как сайт возвращает внедрённый код в браузер.

          -
        • Отраженная XSS-уязвимость возникает, когда пользовательский контент, который передается на сервер, немедленно и без изменений возвращается для отображения в браузере. Любой скрипт в исходном пользовательском контенте запустится при загрузке новой страницы. Например, рассмотрим строку поиска по сайту, в которой поисковые слова закодированы как параметры URL, и эти слова отображаются вместе с результатами. Злоумышленник может создать поисковую ссылку, которая будет содержать вредоносный скрипт в качестве параметра (например: http://mysite.com?q=beer<script%20src="http://evilsite.com/tricky.js"></script>) и переслать его другому пользователю по электронной почте. Если целевой пользователь кликнет по этой «интересной ссылке», то скрипт выполнится при отображении результатов поиска. Как мы уже говорили, злоумышленник  таким образом получает всю информацию, необходимую ему для входа на сайт в качестве целевого пользователя, потенциального совершения покупок от имени пользователя или получения его контактной информации.
        • +
        • Отражённая XSS-уязвимость возникает, когда пользовательский контент, который передаётся на сервер, немедленно и без изменений возвращается для отображения в браузере. Любой скрипт в исходном пользовательском контенте запустится при загрузке новой страницы. Например, рассмотрим строку поиска по сайту, в которой поисковые слова закодированы как параметры URL, и эти слова отображаются вместе с результатами. Злоумышленник может создать поисковую ссылку, которая будет содержать вредоносный скрипт в качестве параметра (например: http://mysite.com?q=beer<script%20src="http://evilsite.com/tricky.js"></script>) и переслать его другому пользователю по электронной почте. Если целевой пользователь кликнет по этой «интересной ссылке», то скрипт выполнится при отображении результатов поиска. Как мы уже говорили, злоумышленник  таким образом получает всю информацию, необходимую ему для входа на сайт в качестве целевого пользователя, потенциального совершения покупок от имени пользователя или получения его контактной информации.
        • Постоянная уязвимость XSS возникает, когда вредоносный скрипт хранится на веб-сайте, а затем снова отображается без изменений, чтобы другие пользователи могли выполнять его невольно.
          - Например, доска обсуждений, которая принимает комментарии, содержащие неизмененный HTML, может хранить вредоносный скрипт от злоумышленника. Когда комментарии отображаются, скрипт выполняется и может отправить злоумышленнику информацию, необходимую для доступа к учетной записи пользователя. Атака такого рода чрезвычайно популярна и мощна, потому что злоумышленник может даже не иметь прямого отношения к жертвам.
          + Например, доска обсуждений, которая принимает комментарии, содержащие неизмененный HTML, может хранить вредоносный скрипт от злоумышленника. Когда комментарии отображаются, скрипт выполняется и может отправить злоумышленнику информацию, необходимую для доступа к учётной записи пользователя. Атака такого рода чрезвычайно популярна и мощна, потому что злоумышленник может даже не иметь прямого отношения к жертвам.

          - Хотя данные из запросов POST или GET являются наиболее распространенным источником уязвимостей XSS, любые данные из браузера потенциально уязвимы, такие как данные cookie, отображаемые браузером, или пользовательские файлы, которые загружаются и отображаются.
          + Хотя данные из запросов POST или GET являются наиболее распространённым источником уязвимостей XSS, любые данные из браузера потенциально уязвимы, такие как данные cookie, отображаемые браузером, или пользовательские файлы, которые загружаются и отображаются.

          Наилучшей защитой от уязвимостей XSS является удаление или отключение любой разметки, которая потенциально может содержать инструкции по запуску кода. Для HTML это включает такие элементы, как <script>, <object>, <embed> и <link>.

          @@ -71,7 +71,7 @@ original_slug: Learn/Server-side/First_steps/Веб_Безопасность
          Типы внедрения SQL включают внедрение SQL на основе ошибок, внедрение SQL на основе логических ошибок и внедрение SQL на основе времени.

          - Эта уязвимость присутствует, если пользовательский ввод, который передается в базовый оператор SQL, может изменить смысл оператора. Например, следующий код предназначен для перечисления всех пользователей с определенным именем (userName), которое было предоставлено из формы HTML:

          + Эта уязвимость присутствует, если пользовательский ввод, который передаётся в базовый оператор SQL, может изменить смысл оператора. Например, следующий код предназначен для перечисления всех пользователей с определённым именем (userName), которое было предоставлено из формы HTML:

          statement = "SELECT * FROM users WHERE name = '" + userName + "';"
          @@ -80,7 +80,7 @@ original_slug: Learn/Server-side/First_steps/Веб_Безопасность
          SELECT * FROM users WHERE name = 'a';DROP TABLE users; SELECT * FROM userinfo WHERE 't' = 't';
           
          -

          Модифицированный оператор создает действительный оператор SQL, который удаляет таблицу пользователей и выбирает все данные из таблицы userinfo (которая раскрывает информацию о каждом пользователе). Это работает, потому что первая часть введенного текста (a ';) завершает исходное утверждение.
          +

          Модифицированный оператор создаёт действительный оператор SQL, который удаляет таблицу пользователей и выбирает все данные из таблицы userinfo (которая раскрывает информацию о каждом пользователе). Это работает, потому что первая часть введённого текста (a ';) завершает исходное утверждение.

          Чтобы избежать такого рода атак, вы должны убедиться, что любые пользовательские данные, которые передаются в запрос SQL, не могут изменить природу запроса. Один из способов сделать это - экранировать все символы пользовательского ввода, которые имеют особое значение в SQL.

          @@ -102,16 +102,16 @@ original_slug: Learn/Server-side/First_steps/Веб_Безопасность

          Подделка межсайтовых запросов (CSRF)

          -

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

          +

          CSRF-атаки позволяют злоумышленнику выполнять действия, используя учётные данные другого пользователя, без его ведома или согласия.

          -

          Этот тип атаки лучше всего пояснить на примере. Джон - злоумышленник, который знает, что определенный сайт позволяет пользователям, вошедшим в систему, отправлять деньги на указанную учетную запись, используя HTTP-запрос POST, который включает имя учетной записи и сумму денег. Джон создает форму, которая включает в себя его банковские реквизиты и сумму денег в виде скрытых полей, и отправляет ее по электронной почте другим пользователям сайта (с кнопкой «Отправить», замаскированной под ссылку на сайт «быстрого обогащения»).

          +

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

          -

          Если пользователь нажимает кнопку отправки, на сервер будет отправлен HTTP-запрос POST, содержащий сведения о транзакции и любые файлы cookie на стороне клиента, которые браузер связал с сайтом (добавление связанных файлов cookie сайта в запросы является нормальным поведением браузера). Сервер проверит файлы cookie и использует их, чтобы определить, вошел ли пользователь в систему и имеет ли разрешение на совершение транзакции.

          +

          Если пользователь нажимает кнопку отправки, на сервер будет отправлен HTTP-запрос POST, содержащий сведения о транзакции и любые файлы cookie на стороне клиента, которые браузер связал с сайтом (добавление связанных файлов cookie сайта в запросы является нормальным поведением браузера). Сервер проверит файлы cookie и использует их, чтобы определить, вошёл ли пользователь в систему и имеет ли разрешение на совершение транзакции.

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

          -

          Примечание: Уловка здесь в том, что Джону не нужен доступ к файлам cookie пользователя (или учетным данным). Браузер пользователя сохраняет эту информацию и автоматически включает ее во все запросы к соответствующему серверу.

          +

          Примечание: Уловка здесь в том, что Джону не нужен доступ к файлам cookie пользователя (или учётным данным). Браузер пользователя сохраняет эту информацию и автоматически включает её во все запросы к соответствующему серверу.

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

          @@ -120,11 +120,11 @@ original_slug: Learn/Server-side/First_steps/Веб_Безопасность

          Прочие угрозы

          -

          Другие распространенные атаки / уязвимости включают:

          +

          Другие распространённые атаки / уязвимости включают:

            -
          • Clickjacking. В этой атаке злоумышленник перехватывает клики, предназначенные для видимого сайта верхнего уровня, и направляет их на скрытую ниже страницу. Этот метод можно использовать, например, для отображения законного сайта банка, но захвата учетных данных для входа в невидимый {{htmlelement("iframe")}} , контролируемый злоумышленником. Clickjacking также можно использовать для того, чтобы заставить пользователя нажать кнопку на видимом сайте, но при этом на самом деле невольно нажимать совершенно другую кнопку. В качестве защиты ваш сайт может предотвратить встраивание себя в iframe на другом сайте, установив соответствующие заголовки HTTP.
          • -
          • Denial of Service (DoS). DoS обычно достигается за счет наводнения целевого сайта поддельными запросами, так что доступ к сайту нарушается для законных пользователей. Запросы могут быть просто многочисленными или по отдельности потреблять большие объемы ресурсов (например, медленное чтение или загрузка больших файлов). Защита от DoS обычно работает, выявляя и блокируя «плохой» трафик, пропуская при этом легитимные сообщения. Эти средства защиты обычно расположены перед веб-сервером или на нем (они не являются частью самого веб-приложения).
          • +
          • Clickjacking. В этой атаке злоумышленник перехватывает клики, предназначенные для видимого сайта верхнего уровня, и направляет их на скрытую ниже страницу. Этот метод можно использовать, например, для отображения законного сайта банка, но захвата учётных данных для входа в невидимый {{htmlelement("iframe")}} , контролируемый злоумышленником. Clickjacking также можно использовать для того, чтобы заставить пользователя нажать кнопку на видимом сайте, но при этом на самом деле невольно нажимать совершенно другую кнопку. В качестве защиты ваш сайт может предотвратить встраивание себя в iframe на другом сайте, установив соответствующие заголовки HTTP.
          • +
          • Denial of Service (DoS). DoS обычно достигается за счёт наводнения целевого сайта поддельными запросами, так что доступ к сайту нарушается для законных пользователей. Запросы могут быть просто многочисленными или по отдельности потреблять большие объёмы ресурсов (например, медленное чтение или загрузка больших файлов). Защита от DoS обычно работает, выявляя и блокируя «плохой» трафик, пропуская при этом легитимные сообщения. Эти средства защиты обычно расположены перед веб-сервером или на нем (они не являются частью самого веб-приложения).
          • Directory Traversal (Файл и раскрытие). В этой атаке злоумышленник пытается получить доступ к частям файловой системы веб-сервера, к которым у него не должно быть доступа. Эта уязвимость возникает, когда пользователь может передавать имена файлов, содержащие символы навигации файловой системы (например, ../../). Решение состоит в том, чтобы очищать ввод перед его использованием.
          • File Inclusion. В этой атаке пользователь может "случайно" указать файл для отображения или выполнения в данных, передаваемых на сервер. После загрузки этот файл может выполняться на веб-сервере или на стороне клиента (что приводит к XSS-атаке). Решение состоит в том, чтобы дезинфицировать ввод перед его использованием.
          • Внедрение команд. Атаки с внедрением команд позволяют злоумышленнику выполнять произвольные системные команды в операционной системе хоста. Решение состоит в том, чтобы дезинфицировать вводимые пользователем данные до того, как их можно будет использовать в системных вызовах.
          • @@ -143,20 +143,20 @@ original_slug: Learn/Server-side/First_steps/Веб_Безопасность

            Вы можете предпринять ряд других конкретных шагов:

              -
            • Используйте более эффективное управление паролями. Поощряйте регулярную смену надежных паролей. Рассмотрите возможность двухфакторной аутентификации для вашего сайта, чтобы в дополнение к паролю пользователь должен был ввести другой код аутентификации (обычно тот, который доставляется через какое-то физическое оборудование, которое будет иметь только пользователь, например, код в SMS, отправленном на его телефон).
            • -
            • Настройте свой веб-сервер для использования HTTPS и HTTP Strict Transport Security (HSTS). HTTPS шифрует данные, передаваемые между вашим клиентом и сервером. Это гарантирует, что учетные данные для входа, файлы cookie, данные запросов POST и информация заголовка не будут легко доступны для злоумышленников.
            • -
            • Следите за наиболее популярными угрозами (текущий список OWASP находится здесь) и в первую очередь устраняйте наиболее распространенные уязвимости.
            • +
            • Используйте более эффективное управление паролями. Поощряйте регулярную смену надёжных паролей. Рассмотрите возможность двухфакторной аутентификации для вашего сайта, чтобы в дополнение к паролю пользователь должен был ввести другой код аутентификации (обычно тот, который доставляется через какое-то физическое оборудование, которое будет иметь только пользователь, например, код в SMS, отправленном на его телефон).
            • +
            • Настройте свой веб-сервер для использования HTTPS и HTTP Strict Transport Security (HSTS). HTTPS шифрует данные, передаваемые между вашим клиентом и сервером. Это гарантирует, что учётные данные для входа, файлы cookie, данные запросов POST и информация заголовка не будут легко доступны для злоумышленников.
            • +
            • Следите за наиболее популярными угрозами (текущий список OWASP находится здесь) и в первую очередь устраняйте наиболее распространённые уязвимости.
            • Используйте инструменты сканирования уязвимостей, чтобы выполнить автоматическое тестирование безопасности на вашем сайте. Позже ваш очень успешный веб-сайт может также обнаруживать ошибки, предлагая вознаграждение за обнаружение ошибок, как это делает здесь Mozilla.
            • -
            • Храните и отображайте только те данные, которые вам нужны. Например, если ваши пользователи должны хранить конфиденциальную информацию, такую как данные кредитной карты, отображайте часть номера карты только для того, чтобы он мог быть идентифицирован пользователем, и недостаточно, чтобы его мог скопировать злоумышленник и использовать на другом сайте. Самый распространенный шаблон в настоящее время - отображение только последних 4 цифр номера кредитной карты.
            • +
            • Храните и отображайте только те данные, которые вам нужны. Например, если ваши пользователи должны хранить конфиденциальную информацию, такую как данные кредитной карты, отображайте часть номера карты только для того, чтобы он мог быть идентифицирован пользователем, и недостаточно, чтобы его мог скопировать злоумышленник и использовать на другом сайте. Самый распространённый шаблон в настоящее время - отображение только последних 4 цифр номера кредитной карты.
            -

            Веб-фреймворки могут помочь смягчить многие из наиболее распространенных уязвимостей.

            +

            Веб-фреймворки могут помочь смягчить многие из наиболее распространённых уязвимостей.

            Резюме

            -

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

            +

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

            -

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

            +

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

            {{PreviousMenu("Learn/Server-side/First_steps/Web_frameworks", "Learn/Server-side/First_steps")}}

            diff --git a/files/ru/learn/server-side/index.html b/files/ru/learn/server-side/index.html index 66645f65dd..ee1cb35976 100644 --- a/files/ru/learn/server-side/index.html +++ b/files/ru/learn/server-side/index.html @@ -26,7 +26,7 @@ translation_of: Learn/Server-side

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

            -

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

            +

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

            Вам потребуется понимать "как работает веб". Мы рекомендуем вам сначала ознакомиться с темами:

            @@ -44,11 +44,11 @@ translation_of: Learn/Server-side
            Первые шаги в программировании веб-сайтов на стороне сервера
            -
            Этот модуль посвящен информации о технологиях программирования веб-сайтов на стороне сервера, попутно отвечая и на фундаментальные вопросы о серверном программировании — "что это такое", "чем оно отличается от программирования на стороне клиента", и "почему оно так востребовано" — и обозревая некоторые из наиболее популярных серверных веб-фреймворков, а также объясняя как выбрать подходящий для вашего сайта. Напоследок мы организуем вводный раздел о безопасности веб-сервера.
            +
            Этот модуль посвящён информации о технологиях программирования веб-сайтов на стороне сервера, попутно отвечая и на фундаментальные вопросы о серверном программировании — "что это такое", "чем оно отличается от программирования на стороне клиента", и "почему оно так востребовано" — и обозревая некоторые из наиболее популярных серверных веб-фреймворков, а также объясняя как выбрать подходящий для вашего сайта. Напоследок мы организуем вводный раздел о безопасности веб-сервера.
            Веб-фреймворк Django (Python)
            Django является чрезвычайно популярным и полнофункциональным серверным веб-фреймворком, написанным на Python. Этот модуль объяснит почему Django настолько хороший серверный веб-фреймворк, как установить среду разработки и как с его помощью можно выполнять привычные задачи.
            Веб-фреймворк Express (Node.js/JavaScript)
            -
            Express - популярный веб-фреймворк, написанный на JavaScript и размещенный в среде окружения node.js. Модуль объясняет некоторые из ключевых преимуществ этой структуры, как настроить среду разработки и как выполнять общие задачи для веб-разработки и развертывания.
            +
            Express - популярный веб-фреймворк, написанный на JavaScript и размещённый в среде окружения node.js. Модуль объясняет некоторые из ключевых преимуществ этой структуры, как настроить среду разработки и как выполнять общие задачи для веб-разработки и развертывания.
            Сервер на Node без фреймворков
            В этой статье представлен простой статический файловый сервер, построенный с использованием чистого Node.js, для тех из вас, кто не хочет использовать фреймворк.
            diff --git a/files/ru/learn/server-side/node_server_without_framework/index.html b/files/ru/learn/server-side/node_server_without_framework/index.html index 087627c20a..0a1a548668 100644 --- a/files/ru/learn/server-side/node_server_without_framework/index.html +++ b/files/ru/learn/server-side/node_server_without_framework/index.html @@ -5,7 +5,7 @@ translation_of: Learn/Server-side/Node_server_without_framework ---
            {{LearnSidebar}}
            -

            Здесь вы найдете описание простого статического сервера, который построен сугубо на Node.js без использования какого-либо фреймворка .

            +

            Здесь вы найдёте описание простого статического сервера, который построен сугубо на Node.js без использования какого-либо фреймворка .

            Node.js может использовать множество фреймворков, которые могут помочь создать сервер

            @@ -81,4 +81,4 @@ console.log('Server running at http://127.0.0.1:8125/');

    Задание

    -

    Попробуйте добавить в этот код описание как работает этот код. Как вариант еще можно добавить функционал динамических запросов.

    +

    Попробуйте добавить в этот код описание как работает этот код. Как вариант ещё можно добавить функционал динамических запросов.

    -- cgit v1.2.3-54-g00ecf