diff --git a/files/ru/learn/server-side/django/admin_site/index.md b/files/ru/learn/server-side/django/admin_site/index.md index ae29d70a82ac11..2d37ae45f1a020 100644 --- a/files/ru/learn/server-side/django/admin_site/index.md +++ b/files/ru/learn/server-side/django/admin_site/index.md @@ -40,7 +40,8 @@ admin.site.register(Genre) admin.site.register(BookInstance) ``` -> **Примечание:** Если вы приняли участие в создании модели для представления естественного языка книги ([см. обучающую статью о моделях](/ru/docs/Learn/Server-side/Django/Models)), импортируйте и зарегистрируйте её тоже! +> [!NOTE] +> В строках выше предполагается, что вы приняли вызов создать модель, отражающую естественный язык книги ([см. обучающую статью о моделях](/ru/docs/Learn/Server-side/Django/Models))! Это самый простой способ регистрации модели или моделей. Админ-панель имеет множество настроек. Мы рассмотрим другие способы регистрации ваших моделей ниже. @@ -74,7 +75,8 @@ python3 manage.py runserver ![Admin Site - Book Add](admin_book_add.png) -> **Примечание:** А сейчас, хотелось бы, чтобы вы добавили несколько книг, авторов и жанров (например, Фэнтези) в ваше приложение. Удостоверьтесь, что каждый автор и жанр включает пару различных книг (позже, когда мы реализуем представления "list" и "detail", это сделает их более интересными). +> [!NOTE] +> А сейчас, хотелось бы, чтобы вы добавили несколько книг, авторов и жанров (например, Фэнтези) в ваше приложение. Удостоверьтесь, что каждый автор и жанр включает пару различных книг (позже, когда мы реализуем представления "list" и "detail", это сделает их более интересными). После того, когда книги добавлены, для перехода на главную страницу админ-панели кликните на ссылке **Home** в верхней части страницы. Потом кликните на ссылке **Books** для отображения текущего списка книг (или на одной из других ссылок, чтобы увидеть список соответствующей модели). После добавления нескольких книг список может выглядеть наподобие скриншота ниже. Отображается название каждой из книг. Его возвращает метод `__str__()` в модели Book, созданной в предыдущей статье. @@ -190,7 +192,8 @@ class BookAdmin(admin.ModelAdmin): К сожалению, мы не можем напрямую поместить поле genre в `list_display`, так как оно является `ManyToManyField` (Django не позволяет это из-за большой "стоимости" доступа к базе данных). Вместо этого мы определим функцию `display_genre` для получения строкового представления информации (вызов этой функции есть в `list_display`, её определение см. ниже). -> **Примечание:** Получение здесь значения поля `genre` возможно не самая хорошая идея вследствие "стоимости" операции базы данных. Мы показываем это, потому что вызов функций в ваших моделях может быть очень полезен по другим причинам, например, для добавления ссылки _Delete_ рядом с каждым пунктом списка. +> [!NOTE] +> Получение здесь значения поля `genre` возможно не самая хорошая идея вследствие "стоимости" операции базы данных. Мы показываем это, потому что вызов функций в ваших моделях может быть очень полезен по другим причинам, например, для добавления ссылки _Delete_ рядом с каждым пунктом списка. Добавьте следующий код в вашу модель `Book` (**models.py**). В нем создаётся строка из первых трёх значений поля `genre` (если они существуют) и `short_description`, которое может быть использовано в админ-панели. @@ -209,7 +212,8 @@ class BookAdmin(admin.ModelAdmin): Модель `Genre` (и модель `Language`, если вы её определили) имеет единственное поле. Поэтому нет необходимости создания для них дополнительных моделей с целью отображения дополнительных полей. -> **Примечание:** целесообразно, чтобы в списке модели `BookInstance` отображались хотя бы статус и ожидаемая дата возврата. Мы добавили это в качестве "испытания" в конце этой статьи! +> [!NOTE] +> Целесообразно, чтобы в списке модели `BookInstance` отображались хотя бы статус и ожидаемая дата возврата. Мы добавили это в качестве "испытания" в конце этой статьи! ### Добавление фильтров списка @@ -228,7 +232,8 @@ class BookInstanceAdmin(admin.ModelAdmin): По умолчанию в представлениях деталей отображаются все поля по вертикали в порядке их объявления в модели. Вы можете изменить порядок декларации, какие поля отображаются (или исключены), используются ли разделы для организации информации, отображаются ли поля горизонтально или вертикально, и даже какие виджеты редактирования используются в админ-формах. -> **Примечание:** Модели LocalLibrary относительно просты, поэтому нам не нужно менять макет, но мы всё равно внесём некоторые изменения, просто чтобы показать вам, как это сделать. +> [!NOTE] +> Модели LocalLibrary относительно просты, поэтому нам не нужно менять макет, но мы всё равно внесём некоторые изменения, просто чтобы показать вам, как это сделать. #### Управление отображаемыми и вложенными полями @@ -246,7 +251,8 @@ class AuthorAdmin(admin.ModelAdmin): ![Admin Site - Improved Author Detail](admin_improved_author_detail.png) -> **Примечание:** Так же, вы можете использовать `exclude` атрибут для объявления списка атрибутов, которые будут исключены из формы (все остальные атрибуты в модели, будут отображаться). +> [!NOTE] +> Так же, вы можете использовать `exclude` атрибут для объявления списка атрибутов, которые будут исключены из формы (все остальные атрибуты в модели, будут отображаться). #### Разделение на секции/Выделение подробного представления @@ -297,7 +303,8 @@ class BookAdmin(admin.ModelAdmin): В этом случае, всё, что мы сделали - объявили наш встроенный класс tablular, который просто добавляет все поля из _встроенной_ модели. Вы можете указать все виды дополнительной информации для макета, включая отображаемые поля, их порядок, независимо от того, являются ли они только для чтения или нет, и т. д. (См. [TabularInline](https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.TabularInline) для получения дополнительной информации). -> **Примечание:** В этой функции есть некоторые неприятные ограничения! На скриншоте выше у нас есть три существующих экземпляра книги, за которыми следуют три поля для новых экземпляров книги (которые очень похожи!). Было бы лучше НЕ иметь лишних экземпляров книг по умолчанию и просто добавить их с помощью ссылки **Add another Book instance** или иметь возможность просто перечислять `BookInstance`s как нечитаемые здесь ссылки. Первый вариант можно сделать, установив `extra` атрибут в 0 в модели `BookInstanceInline`, попробуйте сами. +> [!NOTE] +> В этой функции есть некоторые неприятные ограничения! На скриншоте выше у нас есть три существующих экземпляра книги, за которыми следуют три поля для новых экземпляров книги (которые очень похожи!). Было бы лучше НЕ иметь лишних экземпляров книг по умолчанию и просто добавить их с помощью ссылки **Add another Book instance** или иметь возможность просто перечислять `BookInstance`s как нечитаемые здесь ссылки. Первый вариант можно сделать, установив `extra` атрибут в 0 в модели `BookInstanceInline`, попробуйте сами. ## Проверьте себя diff --git a/files/ru/learn/server-side/django/authentication/index.md b/files/ru/learn/server-side/django/authentication/index.md index fe99e24b015b37..accccd5bbd624d 100644 --- a/files/ru/learn/server-side/django/authentication/index.md +++ b/files/ru/learn/server-side/django/authentication/index.md @@ -15,7 +15,8 @@ slug: Learn/Server-side/Django/Authentication Django предоставляет систему аутентификации и авторизации ("permission") пользователя, реализованную на основе фреймворка работы с сессиями, который мы рассматривали в [предыдущей части](/ru/docs/Learn/Server-side/Django/Sessions). Система аутентификации и авторизации позволяет вам проверять учётные данные пользователей и определять какие действия какой пользователь может выполнять. Данный фреймворк включает в себя встроенные модели для `Пользователей` и `Групп` (основной способ применения прав доступа для более чем одного пользователя), непосредственно саму систему прав доступа (permissions)/флаги, которые определяют может ли пользователь выполнить задачу, с какой формой и отображением для авторизованных пользователей, а так же получить доступ к контенту с ограниченным доступом. -> **Примечание:** В соответствии с идеологией Django система аутентификации является очень общей и, таким образом, не предоставляет некоторые возможности, которые присутствуют в других системах веб-аутентификации. Решениями некоторых общих задач занимаются пакеты сторонних разработчиков, например, защита от подбора пароля (через стороннюю библиотеку OAuth). +> [!NOTE] +> В соответствии с идеологией Django система аутентификации является очень общей и, таким образом, не предоставляет некоторые возможности, которые присутствуют в других системах веб-аутентификации. Решениями некоторых общих задач занимаются пакеты сторонних разработчиков, например, защита от подбора пароля (через стороннюю библиотеку OAuth). В данном разделе руководства мы покажем вам реализацию аутентификации пользователя на сайте [LocalLibrary](/ru/docs/Learn/Server-side/Django/Tutorial_local_library_website), создание страниц входа/выхода, добавления разграничения доступа (permissions) к вашим моделям, а также продемонстрируем контроль за доступом к некоторым страницам. Мы будем использовать аутентификацию/авторизацию для показа пользователям и сотрудникам библиотеки, списков книг, которые были взяты на прокат. @@ -27,7 +28,8 @@ Django предоставляет систему аутентификации и Аутентификация была подключена автоматически когда мы создали [скелет сайта](/ru/docs/Learn/Server-side/Django/skeleton_website) (в части 2), таким образом на данный момент вам ничего не надо делать. -> **Примечание:** Необходимые настройки были выполнены для нас, когда мы создали приложение при помощи команды `django-admin startproject`. Таблицы базы данных для пользователей и модели авторизации были созданы, когда в первый раз выполнили команду `python manage.py migrate`. +> [!NOTE] +> Необходимые настройки были выполнены для нас, когда мы создали приложение при помощи команды `django-admin startproject`. Таблицы базы данных для пользователей и модели авторизации были созданы, когда в первый раз выполнили команду `python manage.py migrate`. Соответствующие настройки сделаны в параметрах `INSTALLED_APPS` и `MIDDLEWARE` файла проекта (**locallibrary/locallibrary/settings.py**), как показано ниже: @@ -50,7 +52,8 @@ MIDDLEWARE = [ Вы уже создали своего первого пользователя когда мы рассматривали [Административная панель сайта Django](/ru/docs/Learn/Server-side/Django/Admin_site) в части 4 (это был суперпользователь, созданный при помощи команды `python manage.py createsuperuser`). Наш суперпользователь уже авторизован и имеет все необходимые уровни доступа к данным и функциям, таким образом нам необходимо создать тестового пользователя для отработки соответствующей работы сайта. В качестве наиболее быстрого способа, мы будем использовать административную панель сайта для создания соответствующих групп и аккаунтов _locallibrary_. -> **Примечание:** вы можете создавать пользователей программно, как показано ниже. Например, вам мог бы подойти данный способ в том случае, если вы разрабатываете интерфейс, который позволяет пользователям создавать их собственные аккаунты (вы не должны предоставлять доступ пользователям к административной панели вашего сайта). +> [!NOTE] +> Вы можете создавать пользователей программно, как показано ниже. Например, вам мог бы подойти данный способ в том случае, если вы разрабатываете интерфейс, который позволяет пользователям создавать их собственные аккаунты (вы не должны предоставлять доступ пользователям к административной панели вашего сайта). > > ```python > from django.contrib.auth.models import User @@ -89,7 +92,8 @@ MIDDLEWARE = [ Вот и все! Теперь у вас есть учётная запись «обычного члена библиотеки», которую вы сможете использовать для тестирования (как только добавим страницы, чтобы пользователи могли войти в систему). -> **Примечание:** Попробуйте создать другого пользователя, например "Библиотекаря". Так же создайте группу "Библиотекарей" и добавьте туда своего только что созданного библиотекаря +> [!NOTE] +> Попробуйте создать другого пользователя, например "Библиотекаря". Так же создайте группу "Библиотекарей" и добавьте туда своего только что созданного библиотекаря ## Настройка представлений проверки @@ -97,7 +101,8 @@ Django предоставляет почти все, что нужно для с В этом разделе мы покажем, как интегрировать систему по умолчанию в Сайт LocalLibrary и создать шаблоны. Мы поместим их в основные URL проекта. -> **Примечание:** вы не должны использовать этот код, но вполне вероятно, что вы хотите, потому что это делает вещи намного проще. Вам почти наверняка потребуется изменить код обработки формы, если вы измените свою модель пользователя (сложная тема!) но даже в этом случае вы всё равно сможете использовать функции просмотра запасов. +> [!NOTE] +> Вы не должны использовать этот код, но вполне вероятно, что вы хотите, потому что это делает вещи намного проще. Вам почти наверняка потребуется изменить код обработки формы, если вы измените свою модель пользователя (сложная тема!) но даже в этом случае вы всё равно сможете использовать функции просмотра запасов. > **Примечание:**В этом случае мы могли бы разумно поместить страницы аутентификации, включая URL-адреса и шаблоны, в наше приложение каталога. Однако, если бы у нас было несколько приложений, было бы лучше отделить это общее поведение входа в систему и иметь его доступным на всем сайте, так что это то, что мы показали здесь! @@ -114,9 +119,8 @@ urlpatterns += [ Перейдите по `http://127.0.0.1:8000/accounts/` URL (обратите внимание на косую черту!), Django покажет ошибку, что он не смог найти этот URL, и перечислить все URL, которые он пытался открыть. Из этого вы можете увидеть URL-адреса, которые будут работать, например: -> **Примечание:** Примечание. Использование вышеуказанного метода добавляет следующие URL-адреса с именами в квадратных скобках, которые могут использоваться для изменения сопоставлений URL-адресов. Вам не нужно реализовывать что-либо ещё - приведённое выше сопоставление URL-адресов автоматически отображает указанные ниже URL-адреса. - -> **Примечание:** +> [!NOTE] +> Использование вышеуказанного метода добавляет следующие URL-адреса с именами в квадратных скобках, которые могут использоваться для изменения сопоставлений URL-адресов. Вам не нужно реализовывать что-либо ещё - приведённое выше сопоставление URL-адресов автоматически отображает указанные ниже URL-адреса. > > ```python > accounts/ login/ [name='login'] @@ -144,7 +148,8 @@ URL-адреса (и неявные представления), которые Для этого сайта мы разместим наши HTML-страницы в каталоге **templates / registration /**. Этот каталог должен находиться в корневом каталоге проекта, то есть в том же каталоге, что и в каталоге и папках **locallibrary**). Создайте эти папки сейчас. -> **Примечание:** ваша структура папок теперь должна выглядеть как показано внизу: +> [!NOTE] +> Ваша структура папок теперь должна выглядеть так: > locallibrary (django project folder) > |\_catalog > |\_locallibrary @@ -357,7 +362,8 @@ Someone asked for password reset for email \{{ email }}. Follow the link below: Вы сможете проверить функцию сброса пароля по ссылке на странице входа. **Имейте в виду, что Django отправляет только сбросные электронные письма на адреса (пользователи), которые уже хранятся в его базе данных!** -> **Примечание:** Система сброса пароля требует, чтобы ваш сайт поддерживал электронную почту, что выходит за рамки этой статьи, поэтому эта часть **ещё не будет работать.** Чтобы разрешить тестирование, поместите следующую строку в конец файла settings.py. Это регистрирует любые письма, отправленные на консоль (чтобы вы могли скопировать ссылку на сброс пароля с консоли). +> [!NOTE] +> Система сброса пароля требует, чтобы ваш сайт поддерживал электронную почту, что выходит за рамки этой статьи, поэтому эта часть **ещё не будет работать.** Чтобы разрешить тестирование, поместите следующую строку в конец файла settings.py. Это регистрирует любые письма, отправленные на консоль (чтобы вы могли скопировать ссылку на сброс пароля с консоли). > > ```python > EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' @@ -395,7 +401,8 @@ Someone asked for password reset for email \{{ email }}. Follow the link below: Мы создаём URL-адрес для входа и выхода из системы, используя тег шаблона URL-адреса и имена соответствующих конфигураций URLs. Также обратите внимание на то, как мы добавили `?next=\{{request.path}}` в конец URLs. Это означает, что следующий URL-адрес содержит адрес (URL) текущей страницы, в конце связанного URL-адреса. После того, как пользователь успешно выполнил вход в систему, представления будут использовать значение "`next`" чтобы перенаправить пользователя обратно на страницу, где они сначала нажали ссылку входа / выхода из системы. -> **Примечание:** Попробуйте! Если вы находитесь на главной странице и вы нажимаете «Вход / Выход» на боковой панели, то после завершения операции вы должны вернуться на ту же страницу. +> [!NOTE] +> Попробуйте! Если вы находитесь на главной странице и вы нажимаете «Вход / Выход» на боковой панели, то после завершения операции вы должны вернуться на ту же страницу. ### Тестирование в представлениях @@ -409,7 +416,8 @@ def my_view(request): ... ``` -> **Примечание:** Вы можете сделать то же самое вручную, путём тестирования `request.user.is_authenticated`, но декоратор намного удобнее! +> [!NOTE] +> Вы можете сделать то же самое вручную, путём тестирования `request.user.is_authenticated`, но декоратор намного удобнее! Аналогичным образом, самый простой способ ограничить доступ к зарегистрированным пользователям в ваших представлениях на основе классов - это производные от `LoginRequiredMixin`. Вы должны объявить этот mixin сначала в списке суперкласса, перед классом основного представления. @@ -468,7 +476,8 @@ def is_overdue(self): return False ``` -> **Примечание:** Сначала мы проверим, является ли `due_back` пустым, прежде чем проводить сравнение. Пустое поле `due_back` заставило Django выкидывать ошибку, а не показывать страницу: пустые значения не сопоставимы. Это не то, что мы хотели бы, чтобы наши пользователи испытывали! +> [!NOTE] +> Сначала мы проверим, является ли `due_back` пустым, прежде чем проводить сравнение. Пустое поле `due_back` заставило Django выкидывать ошибку, а не показывать страницу: пустые значения не сопоставимы. Это не то, что мы хотели бы, чтобы наши пользователи испытывали! Теперь, когда мы обновили наши модели, нам нужно будет внести новые изменения в проект, а затем применить эти миграции: @@ -501,7 +510,8 @@ class BookInstanceAdmin(admin.ModelAdmin): Теперь, когда возможно кредитовать книги конкретному пользователю, зайдите и заработайте на нескольких записей в `BookInstance`. Установите `borrowed` поле вашему тестовому пользователю, сделайте `status` «В займе» и установите сроки оплаты как в будущем, так и в прошлом. -> **Примечание:** Мы не будем описывать процесс, так как вы уже знаете, как использовать Admin сайт! +> [!NOTE] +> Мы не будем описывать процесс, так как вы уже знаете, как использовать Admin сайт! ### Займ в представлении diff --git a/files/ru/learn/server-side/django/deployment/index.md b/files/ru/learn/server-side/django/deployment/index.md index b4231b9222eafb..4db9ae5a1afc90 100644 --- a/files/ru/learn/server-side/django/deployment/index.md +++ b/files/ru/learn/server-side/django/deployment/index.md @@ -35,19 +35,22 @@ slug: Learn/Server-side/Django/Deployment - Сервер приложений, который передаёт "динамические" запросы между сайтом Django и веб-сервером. - Базу данных, от которой зависит ваш сайт. -> **Примечание:** У вас может быть потребность в обратном прокси, балансировщике загрузки и так далее. +> [!NOTE] +> У вас может быть потребность в обратном прокси, балансировщике загрузки и так далее. Сервер может быть вашим собственным с подключением к интернету по скоростному каналу, но более общим подходом является применение "облачных решений". Что действительно имеет значение, так это то, что ваш код запускается на некотором удалённом компьютере (возможно и "виртуальном"), в хостинговом дата-центре. Удалённый сервер обычно предоставляет определённый доступ к компьютерным ресурсам (процессору, оперативной памяти, памяти на жёстких носителях и так далее) и соединение с интернетом за некоторую цену. Такой тип удалённого доступа к вычислительному/сетевому железу называется _Инфраструктура как Сервис (Infrastructure as a Service - IaaS)_. Множество IaaS поставщиков предлагают услуги по предустановке какой-либо операционной системы, на которую вы можете установить необходимые для вашего рабочего окружения компоненты. Другие поставщики предлагают вам выбрать уже готовые полноценные рабочие окружения, возможно, включающие в себя Django и настроенный веб-сервер. -> **Примечание:** Готовые окружения могут сделать настройку вашего веб-сайта очень простой задачей, поскольку они имеют минимальную конфигурацию, однако, либо количество доступных опций может быть недостаточным, или они будут соответствовать устаревшей операционной системе. Часто, более предпочтительно установить необходимые компоненты самостоятельно, таким образом вы получите то, что вам необходимо, а в последующем, при обновлении системы, уже будете знать что нужно делать! +> [!NOTE] +> Готовые окружения могут сделать настройку вашего веб-сайта очень простой задачей, поскольку они имеют минимальную конфигурацию, однако, либо количество доступных опций может быть недостаточным, или они будут соответствовать устаревшей операционной системе. Часто, более предпочтительно установить необходимые компоненты самостоятельно, таким образом вы получите то, что вам необходимо, а в последующем, при обновлении системы, уже будете знать что нужно делать! Некоторые провайдеры поддерживают Django как часть своего предложения _Платформа как Сервис (Platform as a Service_ - PaaS). При данном виде хостинга вам не нужно беспокоиться о большей части окружения (веб-сервере, сервере приложений, балансировщике загрузки), так как сама платформа берёт это на себя (включая все моменты, касающиеся роста и развития вашего приложения). В данном случае развёртывание приложения является достаточно простой задачей, - вам нужно сконцентрироваться только на вашем приложении, а не на инфраструктуре. Некоторые разработчики выбирают более гибкое решение, предоставляемое IaaS, в то время как другие предпочитают иметь наименьшие накладные расходы и простое масштабирование, предоставляемое PaaS. Когда вы только начинаете, то система типа PaaS является предпочтительной и это именно то, что мы будем использовать в данном руководстве. -> **Примечание:** Если вы выбираете хостинг с поддержкой Python/Django, то он должен иметь инструкцию по установке веб-сайта Django, учитывающую различные конфигурации веб-сервера, сервера приложений, обратного прокси и так далее (это не имеет значение, если вы выбрали PaaS). Например, существует множество инструкций "шаг-за-шагом" для различный конфигураций в [Документации DigitalOcean по Django](https://www.digitalocean.com/community/tutorials?q=django). +> [!NOTE] +> Если вы выбираете хостинг с поддержкой Python/Django, то он должен иметь инструкцию по установке веб-сайта Django, учитывающую различные конфигурации веб-сервера, сервера приложений, обратного прокси и так далее (это не имеет значение, если вы выбрали PaaS). Например, существует множество инструкций "шаг-за-шагом" для различный конфигураций в [Документации DigitalOcean по Django](https://www.digitalocean.com/community/tutorials?q=django). ## Выбор хостинг провайдера @@ -69,13 +72,15 @@ slug: Learn/Server-side/Django/Deployment Многие провайдеры имеют "basic" (базовый) тариф, предоставляющий достаточный уровень вычислительной мощности с небольшим количеством ограничений. [Digital Ocean](https://www.digitalocean.com/) и [Python Anywhere](https://www.pythonanywhere.com/) являются примерами провайдеров, которые предлагают относительно недорогой базовый тариф (от $5 до $10USD в месяц). -> **Примечание:** Необходимо помнить, что цена не является единственным критерием выбора. Если ваш сайт успешен, то может так случиться, что масштабирование станет самым важным элементом вашего внимания при выборе услуг хостинга. +> [!NOTE] +> Необходимо помнить, что цена не является единственным критерием выбора. Если ваш сайт успешен, то может так случиться, что масштабирование станет самым важным элементом вашего внимания при выборе услуг хостинга. ## Подготовка веб-сайта к публикации [Скелет сайта](/ru/docs/Learn/Server-side/Django/skeleton_website) был создан при помощи инструментов _django-admin_ и _manage.py_, которые настроены таким образом, чтобы сделать разработку проще. Многие настройки файла проекта (определённых в **settings.py**) должны быть изменены перед публикацией сайта, либо из-за вопросов безопасности, либо производительности. -> **Примечание:** Общепринятым решением является иметь отдельный файл **settings.py** для публикации, который импортирует важные настройки из внешних файлов, или из переменных окружения. Доступ к данному файлу должен быть ограничен, даже если остальная часть исходного кода доступна в публичном репозитории. +> [!NOTE] +> Общепринятым решением является иметь отдельный файл **settings.py** для публикации, который импортирует важные настройки из внешних файлов, или из переменных окружения. Доступ к данному файлу должен быть ограничен, даже если остальная часть исходного кода доступна в публичном репозитории. Критически важные настройки файла **settings.py**: @@ -115,7 +120,8 @@ DEBUG = bool( os.environ.get('DJANGO_DEBUG', True) ) Значение `DEBUG` будет `True` по умолчанию и станет `False`, в том случае, если переменная окружения `DJANGO_DEBUG` будет проинициализирована пустой строкой, то есть, `DJANGO_DEBUG=''`. -> **Примечание:** Было бы более понятным, если бы мы могли просто установить и снять с `DJANGO_DEBUG` непосредственно на `True` и `False` , напрямую, а не использовать «любую строку» или «пустую строку» (соответственно). К сожалению, значения переменных среды хранятся как строки Python и единственная строка, которая оценивается как `False` является пустой строкой (например, `bool('')==False`). +> [!NOTE] +> Было бы более понятным, если бы мы могли просто установить и снять с `DJANGO_DEBUG` непосредственно на `True` и `False` , напрямую, а не использовать «любую строку» или «пустую строку» (соответственно). К сожалению, значения переменных среды хранятся как строки Python и единственная строка, которая оценивается как `False` является пустой строкой (например, `bool('')==False`). Весь перечень настроек для разворачивания вашего сайта находится по ссылке [Deployment checklist](https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/) (Django docs). Кроме того, вы можете получить список настроек, выполнив в терминале команду: @@ -165,7 +171,8 @@ Heroku запускает сайты Django внутри одного, или б Когда мы выполним все, что необходимо для нашего сайта мы можем создать аккаунт Heroku, получить доступ к клиенту Heroku и использовать его, для установки нашего веб-сайта. -> **Примечание:** Инструкции, перечисленные ниже, соответствуют процессу работы с Heroku во время написания данной статьи (английской версии - прим. перев.). Если Heroku значительно изменит этот процесс, вы можете воспользоваться соответствующим описанием: [Heroku начало работы с Django](https://devcenter.heroku.com/articles/getting-started-with-python#introduction). +> [!NOTE] +> Инструкции, перечисленные ниже, соответствуют процессу работы с Heroku во время написания данной статьи (английской версии - прим. перев.). Если Heroku значительно изменит этот процесс, вы можете воспользоваться соответствующим описанием: [Heroku начало работы с Django](https://devcenter.heroku.com/articles/getting-started-with-python#introduction). На этом завершается краткий обзор начала работы с Heroku (более подробное руководство [Как работает Heroku](https://devcenter.heroku.com/articles/how-heroku-works)). @@ -173,7 +180,8 @@ Heroku запускает сайты Django внутри одного, или б Heroku тесно интегрирована с системой управления версиями исходного кода **git**, используя её для загрузки / синхронизации любых изменений, которые вы вносите в живую систему. Он делает это, добавляя новый «удалённый» репозиторий heroku с именем heroku, указывающий на репозиторий для вашего источника в облаке Heroku. Во время разработки вы используете **git** для хранения изменений в вашем «master» репозитории. Когда вы хотите развернуть свой сайт, вы синхронизируете свои изменения в репозитории Heroku. -> **Примечание:** Если вы привыкли следовать хорошей практике разработки программного обеспечения, вы, вероятно, уже используете git или какую-либо другую систему SCM. Если у вас уже есть git-репозиторий, вы можете пропустить этот шаг. +> [!NOTE] +> Если вы привыкли следовать хорошей практике разработки программного обеспечения, вы, вероятно, уже используете git или какую-либо другую систему SCM. Если у вас уже есть git-репозиторий, вы можете пропустить этот шаг. Существует множество способов работы с git, но одним из самых простых является создание учётной записи в [Github](https://github.com/), создание репозитория там, а затем синхронизация с ним локально: @@ -256,7 +264,8 @@ Heroku тесно интегрирована с системой управле Когда эти операции завершатся, вернитесь на страницу Github где вы создали свой репозиторий, обновите страницу, и убедитесь, что ваше приложение полностью загружено. При надобности обновить файлы на репозитории - повторите цикл ввода команд add/commit/push. -> **Примечание:** Это хороший момент для создания резервной копии вашего «ванильного» проекта — в то время как некоторые изменения, которые мы собираемся сделать в следующих разделах, могут быть полезны для развёртывания на любой платформе (или разработке), которые другие могут не использовать. +> [!NOTE] +> Это хороший момент для создания резервной копии вашего «ванильного» проекта — в то время как некоторые изменения, которые мы собираемся сделать в следующих разделах, могут быть полезны для развёртывания на любой платформе (или разработке), которые другие могут не использовать. > > _Лучший способ_ сделать это - использовать _git_ для управления вашими изменениями. С _git_ вы можете не только вернуться к определённой старой версии, но и сохранить её в отдельной «ветке» ваших производственных изменений, and cherry-pick - выбрать любые изменения для перемещения между ветвями производства и развития. [Изучение Git](https://help.github.com/articles/good-resources-for-learning-git-and-github/) будет стоить усилий, но это выходит за рамки данной темы. Самый простой способ сделать это - просто скопировать файлы в другое место. Используйте тот подход, который наилучшим образом соответствует вашим знаниям git! @@ -313,7 +322,7 @@ db_from_env = dj_database_url.config(conn_max_age=500) DATABASES['default'].update(db_from_env) ``` -> **Примечание:** +> [!NOTE] > > - Мы все ещё будем использовать SQLite во время разработки, поскольку `DATABASE_URL` переменная среды не будет установлена на нашем компьютере разработки. > - Значение `conn_max_age=500` делает соединение постоянным, что намного эффективнее, чем воссоздавать соединение в каждом цикле запросов. Однако это необязательно и при необходимости можно удалить. @@ -337,7 +346,8 @@ pip3 install psycopg2 Во время разработки мы использовали Django и веб-сервер разработки Django для обслуживания наших статических файлов (CSS, JavaScript и т. Д.). В производственной среде вместо этого мы обычно обслуживаем статические файлы из сети доставки контента (CDN) или веб-сервера. -> **Примечание:** Обслуживание статических файлов через Django / веб-приложение неэффективно, потому что запросы должны проходить через ненужный дополнительный код (Django), а не обрабатываться непосредственно веб-сервером или полностью отдельным CDN. Хотя это не имеет значения для местного использования во время разработки, это будет иметь значительное влияние на производительность, если мы будем использовать тот же подход в производстве. +> [!NOTE] +> Обслуживание статических файлов через Django / веб-приложение неэффективно, потому что запросы должны проходить через ненужный дополнительный код (Django), а не обрабатываться непосредственно веб-сервером или полностью отдельным CDN. Хотя это не имеет значения для местного использования во время разработки, это будет иметь значительное влияние на производительность, если мы будем использовать тот же подход в производстве. Чтобы упростить размещение статических файлов отдельно от веб-приложения Django, Django предоставляет средство сбора данных для сбора этих файлов для развёртывания (имеется переменная параметров, определяющая, где файлы должны собираться при запуске collectstatic). Шаблоны Django относятся к месту размещения статических файлов относительно переменной параметров (STATIC_URL), так что это можно изменить, если статические файлы перемещаются на другой хост / сервер. @@ -370,7 +380,8 @@ STATIC_URL = '/static/' Существует множество способов обслуживания статических файлов на производстве (мы видели соответствующие настройки Django в предыдущих разделах). Heroku рекомендует использовать проект WhiteNoise для обслуживания статических активов непосредственно из Gunicorn в производстве. -> **Примечание:** Heroku автоматически вызывает collectstatic и готовит ваши статические файлы для использования WhiteNoise после того, как он загрузит ваше приложение. Посмотрите [WhiteNoise](https://warehouse.python.org/project/whitenoise/) документацию для объяснения того, как она работает, и почему реализация является относительно эффективным методом для обслуживания этих файлов. +> [!NOTE] +> Heroku автоматически вызывает collectstatic и готовит ваши статические файлы для использования WhiteNoise после того, как он загрузит ваше приложение. Посмотрите [WhiteNoise](https://warehouse.python.org/project/whitenoise/) документацию для объяснения того, как она работает, и почему реализация является относительно эффективным методом для обслуживания этих файлов. Шаги по настройке _WhiteNoise_ для использования в проекте: @@ -425,7 +436,8 @@ psycopg2==2.6.2 whitenoise==3.2.2 ``` -> **Примечание:** Убедитесь, что строка **psycopg2**, подобная приведённой выше, присутствует! Даже если вы не установили это локально, вы должны добавить это в **requirements.txt**. +> [!NOTE] +> Убедитесь, что строка **psycopg2**, подобная приведённой выше, присутствует! Даже если вы не установили это локально, вы должны добавить это в **requirements.txt**. #### Среда выполнения @@ -435,7 +447,8 @@ whitenoise==3.2.2 python-3.5.2 ``` -> **Примечание:** Heroku поддерживает только небольшое количество [Python runtimes](https://devcenter.heroku.com/articles/python-support#supported-python-runtimes). (на момент написания статьи, в том числе и выше). Heroku будет использовать поддерживаемую среду выполнения независимо от значения, указанного в этом файле. +> [!NOTE] +> Heroku поддерживает только небольшое количество [Python runtimes](https://devcenter.heroku.com/articles/python-support#supported-python-runtimes). (на момент написания статьи, в том числе и выше). Heroku будет использовать поддерживаемую среду выполнения независимо от значения, указанного в этом файле. #### Сохраните изменения в Github и перепроверьте @@ -483,7 +496,8 @@ heroku help heroku create ``` -> **Примечание:** вы можете назвать удалённый, если хотите, указав значение после «create». Если вы этого не сделаете, вы получите случайное имя. Имя используется в URL-адресе по умолчанию. +> [!NOTE] +> Вы можете назвать удалённый, если хотите, указав значение после «create». Если вы этого не сделаете, вы получите случайное имя. Имя используется в URL-адресе по умолчанию. Затем мы можем подтолкнуть наше приложение в репозиторий heroku как показано ниже. Это позволит загрузить приложение, упаковать его в dyno, запустить collectstatic, и запустить сам сайт. @@ -545,7 +559,8 @@ DATABASE_URL: postgres://uzfnbcyxidzgrl:j2jkUFDF6OGGqxkgg7Hk3ilbZI@ec2-54-243-20 Если вы вспомните из раздела, посвящённого [getting the website ready to publish](#Getting_your_website_ready_to_publish), мы должны установить переменные среды для `DJANGO_SECRET_KEY` и `DJANGO_DEBUG`. Давайте сделаем это сейчас. -> **Примечание:** Секретный ключ должен быть действительно секретным! Один из способов генерации нового ключа - создать новый проект Django (`django-admin startproject someprojectname`) а затем получить ключ, который генерируется для вас в его **settings.py**. +> [!NOTE] +> Секретный ключ должен быть действительно секретным! Один из способов генерации нового ключа - создать новый проект Django (`django-admin startproject someprojectname`) а затем получить ключ, который генерируется для вас в его **settings.py**. Мы устанавливаем `DJANGO_SECRET_KEY` используя команду `config:set` (как показано ниже). Не забудьте использовать свой секретный ключ! @@ -581,7 +596,8 @@ git push origin master git push heroku master ``` -> **Примечание:** После завершения обновления сайта на Heroku введите URL-адрес, который не существует (например, **/catalog/doesnotexist/**). Раньше это отображало бы подробную страницу отладки, но теперь вы должны просто увидеть простую страницу «Не найдено». +> [!NOTE] +> После завершения обновления сайта на Heroku введите URL-адрес, который не существует (например, **/catalog/doesnotexist/**). Раньше это отображало бы подробную страницу отладки, но теперь вы должны просто увидеть простую страницу «Не найдено». ### Отладка diff --git a/files/ru/learn/server-side/django/development_environment/index.md b/files/ru/learn/server-side/django/development_environment/index.md index 37cb03519fc72f..15a5b906538a20 100644 --- a/files/ru/learn/server-side/django/development_environment/index.md +++ b/files/ru/learn/server-side/django/development_environment/index.md @@ -36,7 +36,8 @@ Django очень гибок с точки зрения способа и мес Каждый из этих вариантов требует немного разной настройки и установки. Следующие подразделы объяснят некоторые аспекты вашего выбора. Далее мы покажем вам, как установить Django на некоторые операционные системы, и эта установка будет предполагаться на всём протяжении данного модуля. -> **Примечание:** Другие возможные способы установки можно найти в официальной документации Django. Мы ссылаемся на [соответствующие документы](#furtherreading). +> [!NOTE] +> Другие возможные способы установки можно найти в официальной документации Django. Мы ссылаемся на [соответствующие документы](#furtherreading). #### Какие операционные системы поддерживаются? @@ -48,7 +49,8 @@ Django очень гибок с точки зрения способа и мес Мы рекомендуем использовать самую последнюю доступную версию - на момент написания статьи это Python 3.6. -> **Примечание:** Python 2.7 не может быть использован вместе с Django 2.0 (последние поддерживаемые серии для Python 2.7 - Django 1.11.x). +> [!NOTE] +> Python 2.7 не может быть использован вместе с Django 2.0 (последние поддерживаемые серии для Python 2.7 - Django 1.11.x). #### Откуда можно скачать Django? @@ -66,13 +68,15 @@ Django поддерживает 4 основных базы данных (Postgr Для данной статьи (и большей части модуля) мы будем использовать базу данных _SQLite_, которая сохраняет свои данные в файл. SQLite предназначен для использования в качестве облегчённой базы данных и не может поддерживать высокий уровень параллелизма. Это, однако, отличный выбор для приложений, которые в основном предназначены только для чтения. -> **Примечание:** Django сконфигурирован для использования SQLite по умолчанию, при создании вашего проекта с использованием стандартных инструментов (django-admin). Это отличный выбор для начала работы, потому что он не требует дополнительной настройки. +> [!NOTE] +> Django сконфигурирован для использования SQLite по умолчанию, при создании вашего проекта с использованием стандартных инструментов (django-admin). Это отличный выбор для начала работы, потому что он не требует дополнительной настройки. #### Глобальная установка или установка в виртуальную среду Python? Когда вы устанавливаете Python 3 на свой компьютер, вы получаете единую глобальную среду (набор установленных пакетов) для вашего кода Python, которая доступна любому коду на компьютере. Вы можете установить любые пакеты Python, необходимые вам в этой среде, но только одну конкретную версию конкретного пакета. -> **Примечание:** Установленные в глобальную среду приложения Python потенциально могут конфликтовать друг с другом (т.е. если они зависят от разных версий одного и того же пакета). +> [!NOTE] +> Установленные в глобальную среду приложения Python потенциально могут конфликтовать друг с другом (т.е. если они зависят от разных версий одного и того же пакета). Если вы устанавливаете Django в среду по умолчанию (глобальную), то будете способны сфокусироваться на одной версии Django на вашем компьютере. Это может быть проблемой в случае, если вы захотите создать новые веб-сайты (при помощи новой версии Django) во время поддержки веб-сайтов со старой версией. @@ -86,7 +90,8 @@ Django поддерживает 4 основных базы данных (Postgr Этот раздел коротко описывает то, как вы можете проверить имеющиеся версии и при необходимости установить новые для Ubuntu Linux 16.04, Mac OS X, and Windows 10. -> **Примечание:** В зависимости от платформы, вы можете иметь возможность установки Python/pip из собственного менеджера пакетов операционной системы или при помощи других инструментов. Для большинства платформ вы можете скачать необходимые установочные файлы из и установить их при помощи соответствующего специфичного для платформы метода. +> [!NOTE] +> В зависимости от платформы, вы можете иметь возможность установки Python/pip из собственного менеджера пакетов операционной системы или при помощи других инструментов. Для большинства платформ вы можете скачать необходимые установочные файлы из и установить их при помощи соответствующего специфичного для платформы метода. ### Ubuntu 16.04 @@ -158,7 +163,8 @@ py -3 -V pip list ``` -> **Примечание:** Установщик должен сделать все, что необходимо для корректной работы указанной команды. Однако, если вы видите сообщение о том, что Python не может быть найден, вам может потребоваться добавить его в системный путь. +> [!NOTE] +> Установщик должен сделать все, что необходимо для корректной работы указанной команды. Однако, если вы видите сообщение о том, что Python не может быть найден, вам может потребоваться добавить его в системный путь. ## Использование Django внутри виртуальной среды Python @@ -224,11 +230,13 @@ export PROJECT_HOME=$HOME/Devel source /usr/local/bin/virtualenvwrapper.sh ``` -> **Примечание:** Переменная `VIRTUALENVWRAPPER_PYTHON` указывает на обычное расположение Python3. Если virtualenv не работает во время тестирования, то вам следует проверить, находится ли интерпретатор Python в нужном расположении (и затем поменять его соответствующим образом в значении переменной). +> [!NOTE] +> Переменная `VIRTUALENVWRAPPER_PYTHON` указывает на обычное расположение Python3. Если virtualenv не работает во время тестирования, то вам следует проверить, находится ли интерпретатор Python в нужном расположении (и затем поменять его соответствующим образом в значении переменной). Эти строки такие же, как в случае с Ubuntu, но файл загрузки в вашей домашней директории назван иначе - **.bash_profile**. -> **Примечание:** Если вы не можете найти и изменить **.bash_profile** при помощи Finder, то можно также открыть его при помощи редактора терминала _nano_. +> [!NOTE] +> Если вы не можете найти и изменить **.bash_profile** при помощи Finder, то можно также открыть его при помощи редактора терминала _nano_. > > Команды в этом случае выглядят примерно так: > @@ -275,7 +283,8 @@ virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/t_env7/bin/get Теперь вы находитесь внутри виртуальной области и можете установить Django и начать разработку. -> **Примечание:** С этого момента в этой статье (и всем модуле) пожалуйста учитывайте, что любые команды запускаются в виртуальной среде Python, как та, что мы показали выше. +> [!NOTE] +> С этого момента в этой статье (и всем модуле) пожалуйста учитывайте, что любые команды запускаются в виртуальной среде Python, как та, что мы показали выше. ### Использование виртуальной среды @@ -306,7 +315,8 @@ py -3 -m django --version 1.10.10 ``` -> **Примечание:** Для Windows вы запускаете скрипты _Python 3_ с префиксом команды `py -3`, в то время как для Linux/Mac OSX префикс - `python3`. +> [!NOTE] +> Для Windows вы запускаете скрипты _Python 3_ с префиксом команды `py -3`, в то время как для Linux/Mac OSX префикс - `python3`. > **Предупреждение:** **Важно**: В оставшейся части материала используется вариант команды _Linux_ для вызова Python 3 (`python3`) . Если вы работаете в _Windows,_ то просто замените этот префикс на: `py -3` @@ -343,7 +353,8 @@ Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C. ``` -> **Примечание:** Указанная команда демонстрирует выполнение для Linux/Mac OS X. В настоящий момент вы можете проигнорировать предупреждения о "13 непримененных миграциях"! +> [!NOTE] +> Указанная команда демонстрирует выполнение для Linux/Mac OS X. В настоящий момент вы можете проигнорировать предупреждения о "13 непримененных миграциях"! Как только сервер запущен, вы можете посмотреть сайт, перейдя по следующему адресу в вашем браузере: `http://127.0.0.1:8000/`. Вы должны увидеть, что сайт выглядит следующим образом: diff --git a/files/ru/learn/server-side/django/django_assessment_blog/index.md b/files/ru/learn/server-side/django/django_assessment_blog/index.md index dd09ad837d4ef6..292104f916e064 100644 --- a/files/ru/learn/server-side/django/django_assessment_blog/index.md +++ b/files/ru/learn/server-side/django/django_assessment_blog/index.md @@ -207,7 +207,8 @@ slug: Learn/Server-side/Django/django_assessment_blog - Страница BlogListView (страница на всех блогах) использует ожидаемый шаблон (например, по умолчанию) - BlogListView разбивает записи на 5 (по крайней мере, на первой странице) -> **Примечание:** Конечно, есть много других тестов, которые вы можете запустить. Используйте на своё усмотрение, но мы ожидаем, что вы сделаете хотя бы тесты выше. +> [!NOTE] +> Конечно, есть много других тестов, которые вы можете запустить. Используйте на своё усмотрение, но мы ожидаем, что вы сделаете хотя бы тесты выше. В следующем разделе показаны [скриншоты](#Screenshots) сайта, который выполняет перечисленные выше требования. diff --git a/files/ru/learn/server-side/django/forms/index.md b/files/ru/learn/server-side/django/forms/index.md index 6497b8f713f805..4eefa67b8eaba4 100644 --- a/files/ru/learn/server-side/django/forms/index.md +++ b/files/ru/learn/server-side/django/forms/index.md @@ -87,7 +87,8 @@ slug: Learn/Server-side/Django/Forms Django предоставляет несколько инструментов и приёмов, которые помогают вам во время выполнения задач, описанных выше. Наиболее фундаментальным из них является класс `Form`, который упрощает генерацию HTML-формы и очистку/валидацию её данных. В следующем разделе мы опишем процесс работы с формами при помощи практического примера по созданию страницы, которая позволит библиотекарям обновлять информацию о книгах. -> **Примечание:** Понимание того, как используется класс `Form` поможет вам когда мы будем рассматривать классы фреймворка Django, для работы с формами более "высокого уровня". +> [!NOTE] +> Понимание того, как используется класс `Form` поможет вам когда мы будем рассматривать классы фреймворка Django, для работы с формами более "высокого уровня". ## HTML-форма обновления книги. Класс Form и функция отображения @@ -164,7 +165,8 @@ class RenewBookForm(forms.Form): Второй момент касается того случая, когда наше значение "выпадает за рамки" и мы "выкидываем" исключение `ValidationError`, в котором указываем текст, который мы хотим показать на форме, для случая когда были введены неправильные данные. Пример, показанный выше, оборачивает данный текст при помощи [функции перевода Django](https://docs.djangoproject.com/en/1.10/topics/i18n/translation/) `ugettext_lazy()` (импортируемую через `_()`), которая может вам пригодиться, если вы планируете перевести ваш сайт в будущем. -> **Примечание:** Существует множество других методов и примеров валидации различных форм, которые можно найти в [Формы и валидация поля](https://docs.djangoproject.com/en/1.10/ref/forms/validation/) (Django docs). Например, в случае, если у вас имеется много полей, которые зависят один от другого, вы можете переопределить функцию [Form.clean()](https://docs.djangoproject.com/en/1.10/ref/forms/api/#django.forms.Form.clean) и, при необходимости, "выкинуть" `ValidationError`. +> [!NOTE] +> Существует множество других методов и примеров валидации различных форм, которые можно найти в [Формы и валидация поля](https://docs.djangoproject.com/en/1.10/ref/forms/validation/) (Django docs). Например, в случае, если у вас имеется много полей, которые зависят один от другого, вы можете переопределить функцию [Form.clean()](https://docs.djangoproject.com/en/1.10/ref/forms/api/#django.forms.Form.clean) и, при необходимости, "выкинуть" `ValidationError`. В целом, это все, что нам понадобится для создания формы в данном примере! @@ -184,7 +186,8 @@ urlpatterns += [ Данная конфигурация перенаправит запросы с адресов формата **/catalog/book/_\_/renew/** в функции с именем `renew_book_librarian()` в **views.py**, туда же передаст идентификатор id записи `BookInstance` в качестве параметра с именем `pk`. Шаблон соответствует только если **pk** это правильно отформатированный **uiid.** -> **Примечание:** Вместо имени "pk" мы можем использовать любое другое, по нашему желанию, потому что мы имеем полный контроль над функцией отображения (которого у нас нет в случае использования встроенного обобщённого класса отображения, который ожидает параметр с определённым именем). Тем не менее имя `pk` является понятным сокращением от "primary key", поэтому мы его тут и используем! +> [!NOTE] +> Вместо имени "pk" мы можем использовать любое другое, по нашему желанию, потому что мы имеем полный контроль над функцией отображения (которого у нас нет в случае использования встроенного обобщённого класса отображения, который ожидает параметр с определённым именем). Тем не менее имя `pk` является понятным сокращением от "primary key", поэтому мы его тут и используем! ### Отображение @@ -353,7 +356,8 @@ def renew_book_librarian(request, pk): Код формы относительно прост. В первую очередь мы объявляем тэг `form`, затем определяем куда будут отправлены данные (`action`) и каким способом (`method`, в данном случае "HTTP POST") — если обратитесь к обзору раздела [Формы HTML](#HTML_forms) в верхней части данной страницы, то найдёте там замещение, что пустое значение атрибута `action`, означает, что данные из формы будут переданы обратно по текущему URL-адресу данной страницы (чего мы и хотим!). Внутри тэга формы мы объявляем кнопку `submit` при помощи которой мы можем отправить наши данные. Блок `{% csrf_token %}`, добавленный первой строкой внутри блока формы, является частью фреймворка Django и служит для борьбы с CSRF. -> **Примечание:** Добавляйте `{% csrf_token %}` в каждый шаблон Django, в котором вы создаёте форму для отправки данных методом `POST`. Это поможет уменьшить вероятность взлома вашего сайта злоумышленниками. +> [!NOTE] +> Добавляйте `{% csrf_token %}` в каждый шаблон Django, в котором вы создаёте форму для отправки данных методом `POST`. Это поможет уменьшить вероятность взлома вашего сайта злоумышленниками. Все что осталось, это указать переменную `\{{form}}`, которую мы передали в шаблон в словаре контекста. Возможно это вас не удивит, но таким образом мы предоставим возможность форме отрендерить свои поля с их метками, виджетами и дополнительными текстами, и в результате мы получим следующее: @@ -375,7 +379,8 @@ def renew_book_librarian(request, pk): ``` -> **Примечание:** Возможно это не очевидно, поскольку наша форма содержит только одно поле, но по умолчанию каждое поле формы помещается в её собственную строку таблицы (поэтому переменная `\{{form}}` находится внутри тэга `table`. Тот же результат можно получить, если воспользоваться следующим вызовом `\{{ form.as_table }}`. +> [!NOTE] +> Возможно это не очевидно, поскольку наша форма содержит только одно поле, но по умолчанию каждое поле формы помещается в её собственную строку таблицы (поэтому переменная `\{{form}}` находится внутри тэга `table`. Тот же результат можно получить, если воспользоваться следующим вызовом `\{{ form.as_table }}`. Если вы ввели неправильную дату, то на странице вы должны получить список сообщений об ошибках (показано жирным ниже). @@ -424,7 +429,8 @@ def renew_book_librarian(request, pk): {% endif %} ``` -> **Примечание:** Помните что, для того чтобы перейти на страницу обновления книги, ваш тестовый логин должен иметь разрешение доступа типа "`catalog.can_mark_returned`"(возможно надо воспользоваться вашим аккаунтом для суперпользователя). +> [!NOTE] +> Помните что, для того чтобы перейти на страницу обновления книги, ваш тестовый логин должен иметь разрешение доступа типа "`catalog.can_mark_returned`"(возможно надо воспользоваться вашим аккаунтом для суперпользователя). Вы можете попробовать вручную создать URL-адрес для тестирования, например — `http://127.0.0.1:8000/catalog/book//renew/` (правильный идентификатор записи id для bookinstance можно получить, если перейти на страницу детальной информации книги и скопировать поле `id`). @@ -460,7 +466,8 @@ class RenewBookModelForm(ModelForm): fields = ['due_back',] ``` -> **Примечание:** Это не выглядит сильно проще, чем просто использовать класс `Form` (и это действительно так, поскольку мы используем только одно поле). Тем не менее, если вы хотите иметь много полей, то такой способ построения формы может значительно уменьшить количество кода и ускорить разработку! +> [!NOTE] +> Это не выглядит сильно проще, чем просто использовать класс `Form` (и это действительно так, поскольку мы используем только одно поле). Тем не менее, если вы хотите иметь много полей, то такой способ построения формы может значительно уменьшить количество кода и ускорить разработку! Оставшаяся часть информации касается объявления полей модели (то есть, текстовых меток, виджетов, текстов, сообщений об ошибках). Если они недостаточно "правильные", то тогда мы можем переопределить их в нашем классе `Meta` при помощи словаря, содержащего поле, которое надо изменить и его новое значение. Например, в нашей форме мы могли бы поменять текст метки для поля "_Renewal date_" (вместо того, чтобы оставить текст по умолчанию: _Due date_), а кроме того мы хотим написать другой вспомогательный текст. Класс `Meta`, представленный ниже, показывает вам, как переопределить данные поля. Кроме того, при необходимости, вы можете установить значения для виджетов `widgets` и сообщений об ошибках `error_messages`. @@ -594,7 +601,8 @@ urlpatterns += [ Страницы создания, обновления и удаления автора теперь готовы к тестированию (мы не будем создавать на них ссылки в отдельном меню, но вы, если хотите, можете их сделать). -> **Примечание:** Наблюдательные пользователи могли заметить, что мы ничего не делаем, чтобы предотвратить несанкционированный доступ к страницам! Мы оставили это в качестве упражнения для вас (подсказка: вы можете использовать `PermissionRequiredMixin` и, либо создать новое разрешение, или воспользоваться нашим прежним `can_mark_returned`). +> [!NOTE] +> Наблюдательные пользователи могли заметить, что мы ничего не делаем, чтобы предотвратить несанкционированный доступ к страницам! Мы оставили это в качестве упражнения для вас (подсказка: вы можете использовать `PermissionRequiredMixin` и, либо создать новое разрешение, или воспользоваться нашим прежним `can_mark_returned`). ### Тестирование страницы diff --git a/files/ru/learn/server-side/django/generic_views/index.md b/files/ru/learn/server-side/django/generic_views/index.md index 0199bcc8d82a04..0908b30ec9315c 100644 --- a/files/ru/learn/server-side/django/generic_views/index.md +++ b/files/ru/learn/server-side/django/generic_views/index.md @@ -56,7 +56,8 @@ class BookListView(generic.ListView): Это всё! Обобщённое отображение выполнит запрос к базе данных, получит все записи заданной модели (`Book`), затем отрендерит (отрисует) соответствующий шаблон, расположенный в **/locallibrary/catalog/templates/catalog/book_list.html** (который мы создадим позже). Внутри данного шаблона вы можете получить доступ к списку книг при помощи переменной шаблона `object_list` ИЛИ `book_list` (если обобщить, то "`the_model_name_list`"). -> **Примечание:** Этот, выглядящий странно, путь к файлу шаблона не является опечаткой — обобщённое отображение ищет файл шаблона `/application_name/the_model_name_list.html` (`catalog/book_list.html`, в данном случае) внутри директории приложения `/application_name/templates/` (у нас - `/catalog/templates/)`. +> [!NOTE] +> Этот, выглядящий странно, путь к файлу шаблона не является опечаткой — обобщённое отображение ищет файл шаблона `/application_name/the_model_name_list.html` (`catalog/book_list.html`, в данном случае) внутри директории приложения `/application_name/templates/` (у нас - `/catalog/templates/)`. Вы можете использовать атрибуты для того, чтобы изменить поведение по умолчанию. Например, вы могли бы указать другой файл шаблона, например, если в вашем распоряжении имеется несколько отображений, которые используют одну и ту же модель, или вам позарез захотелось бы использовать другое имя переменной шаблона, если `book_list` не является интуитивно понятным. Возможно, наиболее полезным вариантом является изменение/отфильтрованные результата запроса к базе данных — таким образом, вместо перечисления всех книг вы могли бы показывать 5 наиболее популярных. @@ -102,7 +103,8 @@ class BookListView(generic.ListView): - Затем добавить в контекст новую информацию. - Затем вернуть новый (обновлённый) контекст. -> **Примечание:** Посмотрите [Встроенные обобщённые классы отображения](https://docs.djangoproject.com/en/1.10/topics/class-based-views/generic-display/) (Django docs) для ознакомления с большим количеством примеров того, что вы могли бы сделать. +> [!NOTE] +> Посмотрите [Встроенные обобщённые классы отображения](https://docs.djangoproject.com/en/1.10/topics/class-based-views/generic-display/) (Django docs) для ознакомления с большим количеством примеров того, что вы могли бы сделать. ### Создание шаблона Отображения Списка @@ -172,7 +174,8 @@ class BookListView(generic.ListView): Кроме того, внутри нашего шаблона, мы можем вызывать _функции_ модели — в данном случае, мы вызываем `Book.get_absolute_url()` для получения URL-адреса, который мы используем для показа детальной информации о книге. Данный вызов работает только для функции у которой нет аргументов (в шаблоне не существует возможности передать аргументы в функцию!) -> **Примечание:** Мы должны быть достаточно осмотрительными для того, чтобы избегать "сторонних эффектов" когда мы вызываем функции из шаблона. В данном случае мы просто получаем URL-адрес, но функции могут делать всё что угодно — мы не хотели бы "убить" наша базу данных (например) просто отрендеривая наш шаблон! +> [!NOTE] +> Мы должны быть достаточно осмотрительными для того, чтобы избегать "сторонних эффектов" когда мы вызываем функции из шаблона. В данном случае мы просто получаем URL-адрес, но функции могут делать всё что угодно — мы не хотели бы "убить" наша базу данных (например) просто отрендеривая наш шаблон! #### Обновление базового шаблона @@ -210,7 +213,8 @@ urlpatterns = [ В отличие от предыдущих преобразований, в данном случае мы применяем наше регулярное выражение (РВ) для сопоставления "настоящего паттерна", а не просто строки. Данное РВ сопоставляет любой URL-адрес, который начинается с `book/`, за которым до конца строки (до маркера конца строки - $) следуют одна, или более _цифр_. В процессе выполнения данного преобразования, оно "захватывает" цифры и передаёт их в функцию отображения как параметр с именем `pk`. -> **Примечание:** как было отмечено ранее, наш преобразуемый URL-адрес в реальности выглядит вот так `catalog/book/` (потому что мы находимся в приложении **catalog**, то подразумевается каталог `/catalog/`). +> [!NOTE] +> Как было отмечено ранее, наш преобразуемый URL-адрес в реальности выглядит вот так `catalog/book/` (потому что мы находимся в приложении **catalog**, то подразумевается каталог `/catalog/`). > **Предупреждение:** **Важно**: Обобщённый класс отображения подробной информации ожидает получить параметр с именем pk. Если вы пишете свою собственную функцию отображения, то тогда вы можете использовать параметр с любым именем, который пожелаете, или вообще передавать информацию в безымянном аргументе. @@ -218,7 +222,8 @@ urlpatterns = [ Паттерны [регулярного выражения](https://docs.python.org/3/library/re.html) является невероятно мощным инструментом преобразования. Пока что, мы не очень много говорили о них, поскольку мы сопоставляли URL-адреса с простыми строками (а не паттернами), и потому что они не интуитивны и пугающий для начинающих. -> **Примечание:** Без паники! Мы будем рассматривать и использовать достаточно простые паттерны и при этом хорошо задокументированные! +> [!NOTE] +> Без паники! Мы будем рассматривать и использовать достаточно простые паттерны и при этом хорошо задокументированные! В первую очередь вы должны знать что обычно регулярные выражения объявляются при помощи строкового литерала (то есть, они заключены в кавычки: **r'<ваше регулярное выражение>'**). @@ -248,7 +253,8 @@ urlpatterns = [ Вы можете захватить (указать) несколько паттернов в одном преобразовании и, тем самым, закодировать много различной информации в URL-адресе. -> **Примечание:** В качестве дополнительного задания, рассмотрите возможность того, как вы могли бы закодировать url на список всех книг, вышедших в определённый год, месяц, день и какое РВ (паттерн) должно соответствовать этому. +> [!NOTE] +> В качестве дополнительного задания, рассмотрите возможность того, как вы могли бы закодировать url на список всех книг, вышедших в определённый год, месяц, день и какое РВ (паттерн) должно соответствовать этому. #### Передача дополнительных настроек в ваши преобразования URL-адресов @@ -259,7 +265,8 @@ url(r'^/url/$', views.my_reused_view, {'my_template_name': 'some_path'}, name='a url(r'^/anotherurl/$', views.my_reused_view, {'my_template_name': 'another_path'}, name='anotherurl'), ``` -> **Примечание:** И дополнительные настройки, и именованные захваченные паттерны передаются в отображение как именованные параметры. Если вы используете одинаковое имя и для захваченного паттерна и для дополнительной настройки, то последняя будет отброшена, а в отображение будет передано значение захваченного паттерна. +> [!NOTE] +> И дополнительные настройки, и именованные захваченные паттерны передаются в отображение как именованные параметры. Если вы используете одинаковое имя и для захваченного паттерна и для дополнительной настройки, то последняя будет отброшена, а в отображение будет передано значение захваченного паттерна. ### Отображение (на основе класса) @@ -298,7 +305,8 @@ def book_detail_view(request,pk): В первую очередь отображение пытается получить определённую запись о книге из модели. Если ей это не удаётся, то "выбрасывается" исключение `Http404`, которое сигнализирует, что данная книга не найдена "not found". Последним шагом является, как обычно, вызов функции `render()` с именем соответствующего шаблона и данных о книге, передаваемых в параметре с именем `context` (в виде словаря). -> **Примечание:** Функция `get_object_or_404()` (показана закомментированной) является удобным "ярлыком" для генерации исключения `Http404` если запись не найдена. +> [!NOTE] +> Функция `get_object_or_404()` (показана закомментированной) является удобным "ярлыком" для генерации исключения `Http404` если запись не найдена. ### Создание шаблона детальной информации @@ -330,7 +338,8 @@ def book_detail_view(request,pk): {% endblock %} ``` -> **Примечание:** Ссылка на автора в шаблоне содержит пустой URL-адрес, потому что мы ещё не создали страницу детальной информации об авторе. Когда это произойдёт, вы должны будете обновить данный URL-адрес как указано ниже: +> [!NOTE] +> Ссылка на автора в шаблоне содержит пустой URL-адрес, потому что мы ещё не создали страницу детальной информации об авторе. Когда это произойдёт, вы должны будете обновить данный URL-адрес как указано ниже: > > ```django > \{{ book.author }} @@ -353,7 +362,8 @@ def book_detail_view(request,pk): Этот метод создан, потому что вы, на стороне "многим" данной связи, объявили поле `ForeignKey` (один-ко многим). Поскольку вы ничего не объявили на другой стороне ("один") данной модели (то есть, модель `Book` "ничего не знает" про модель `BookInstance`), то она не имеет никакой возможности (по умолчанию) для получения множества соответствующих записей. Для того, чтобы обойти эту проблему, Django конструирует соответствующую функцию "обратного просмотра" ("reverse lookup"), которой вы можете воспользоваться. Имя данной функции создаётся в нижнем регистре и состоит из имени модели, в которой был объявлен `ForeignKey` (то есть, `bookinstance`), за которым следует `_set` (то есть функция, созданная для `Book` будет иметь вид `bookinstance_set()`). -> **Примечание:** Здесь мы используем `all()` для получения всех записей (по умолчанию). Вы, наверное, могли бы использовать метод `filter()` для получения подмножества записей в коде, но, к сожалению, вы НЕ можете применить данный вызов в шаблоне, потому что вы не можете передать в нем (в шаблоне) аргументы в функцию. +> [!NOTE] +> Здесь мы используем `all()` для получения всех записей (по умолчанию). Вы, наверное, могли бы использовать метод `filter()` для получения подмножества записей в коде, но, к сожалению, вы НЕ можете применить данный вызов в шаблоне, потому что вы не можете передать в нем (в шаблоне) аргументы в функцию. > > Обратите внимание, что если вы не определяете порядок выдачи данных (в вашем отображении, или в модели), то сервер разработки "выкинет" сообщения об ошибках, похожие на следующие: > @@ -398,7 +408,8 @@ def book_detail_view(request,pk): На данный момент мы должны были создать все необходимое для показа страниц со списком книг и детальной информацией. Запустите сервер (`python3 manage.py runserver`) и откройте ваш браузер `http://127.0.0.1:8000/`. -> **Предупреждение:** Не кликайте на каком-либо авторе, - ссылки пока не заданы — это будет вашим дополнительным заданием! +> [!WARNING] +> Не кликайте на каком-либо авторе, - ссылки пока не заданы — это будет вашим дополнительным заданием! Кликните ссылку **All books** для перехода на страницу со списком книг. @@ -477,7 +488,7 @@ class BookListView(generic.ListView): Соответствующий код для URL-преобразований и отображений должен быть идентичным коду для списка книг и детальной информации о книге `Book`, который мы создали ранее. Шаблоны будут отличаться, но будут иметь похожее поведение. -> **Примечание:** : +> [!NOTE] > > - Когда вы создадите URL-преобразование для страницы списка авторов вам понадобится обновить ссылку **All authors** в базовом шаблоне. Следуйте [тем же путём](#Update_the_base_template), который мы проделали когда обновляли ссылку **All books**. > - Когда вы создадите URL-преобразование для страницы с детальной информацией об авторе, вы должны будете обновить [шаблон детальной информации о книге](#Creating_the_Detail_View_template) (**/locallibrary/catalog/templates/catalog/book_detail.html**), таким образом, чтобы ссылка автора указывала на страницу с детальной информации о нем (а не быть пустой). Данная ссылка будет иметь вид как указано жирным во фрагменте ниже. diff --git a/files/ru/learn/server-side/django/home_page/index.md b/files/ru/learn/server-side/django/home_page/index.md index e2143335ce826e..98a77ad41dfbb2 100644 --- a/files/ru/learn/server-side/django/home_page/index.md +++ b/files/ru/learn/server-side/django/home_page/index.md @@ -41,7 +41,8 @@ slug: Learn/Server-side/Django/Home_page Последние два URL-адреса применяются для показа детальной информации об определённой книге, или авторе — в себе они содержат соответствующее значение идентификатора (показан как ``, выше). URL-преобразование получает данную информацию и передаёт её в отображение, которое применяет её для запроса к базе данных. Для кодирования и применения данной информации в вашем URL-адресе нам понадобится только одно url-преобразование, соответствующее отображение и шаблон страницы для показа любой книги (или автора). -> **Примечание:** Django позволяет вам конструировать ваши URL-адреса любым, удобным для вас, способом — вы можете закодировать информацию в теле URL-адреса, как показано выше, или использовать URL-адрес типа `GET` (например, `/book/?id=6`). Независимо от ваших предпочтений, URL-адреса должны быть понятными, логичными и читабельными ([посмотрите совет W3C здесь](https://www.w3.org/Provider/Style/URI)). +> [!NOTE] +> Django позволяет вам конструировать ваши URL-адреса любым, удобным для вас, способом — вы можете закодировать информацию в теле URL-адреса, как показано выше, или использовать URL-адрес типа `GET` (например, `/book/?id=6`). Независимо от ваших предпочтений, URL-адреса должны быть понятными, логичными и читабельными ([посмотрите совет W3C здесь](https://www.w3.org/Provider/Style/URI)). > > Документация Django рекомендует кодировать информацию в теле URL-адреса, на практике это приводит к лучшей структуре сайта. @@ -51,7 +52,8 @@ slug: Learn/Server-side/Django/Home_page Первой страницей, которую мы создадим, будет главная страница сайта (`catalog/`). Она будет небольшой статической HTML-страницей, которая будет показывать вычисленные "количества" различных записей из базы данных. Для того, чтобы проделать данную работу мы вначале создадим URL-преобразование, затем отображение и шаблон. -> **Примечание:** Лучше уделить больше внимания на данный раздел, поскольку информация, представленная здесь, применяется для создания всех страниц сайта. +> [!NOTE] +> Лучше уделить больше внимания на данный раздел, поскольку информация, представленная здесь, применяется для создания всех страниц сайта. ### URL-преобразование @@ -81,7 +83,8 @@ urlpatterns = [ Home. ``` -> **Примечание:** Мы могли бы, конечно, жёстко указать прямую ссылку (то есть, `Home`), но тогда, если мы изменим адрес нашей домашней страницы (например на `/catalog/index`), то данные ссылки перестанут корректно работать. Применение "обратного" url-преобразования более гибкий и эффективный подход! +> [!NOTE] +> Мы могли бы, конечно, жёстко указать прямую ссылку (то есть, `Home`), но тогда, если мы изменим адрес нашей домашней страницы (например на `/catalog/index`), то данные ссылки перестанут корректно работать. Применение "обратного" url-преобразования более гибкий и эффективный подход! ### Отображения (на основе функций) @@ -130,7 +133,8 @@ def index(request): Шаблон это текстовый файл, который определяет структуру и расположение данных в файле, кроме того, в нем размещают специальные метки (placeholders), которые используются для показа реального содержимого, то есть данных. По умолчанию Django ищет файлы шаблонов в директории с именем '**templates**' внутри вашего приложения. Например, внутри индексной функции отображения, которую мы только что создали, вызов `render()` будет пытаться найти файл **/locallibrary/catalog/templates/_index.html_** и в случае неудачи сгенерирует ошибку о том, что файл не найден. Вы можете увидеть данную ошибку, если вы сохраните предыдущие изменения, затем перейдёте в браузер и наберёте в адресной строке `127.0.0.1:8000`. В результате, в окно браузера будет выведено сообщение об ошибке "TemplateDoesNotExist at /catalog/" и некоторая другая информация. -> **Примечание:** На самом деле, в зависимости от настроек проекта, Django просматривает несколько мест в поисках шаблона (поиск в директории приложения осуществляется по умолчанию!). Вы можете найти больше информации о шаблонах и форматах, которые они поддерживают, перейдя по ссылке [Шаблоны](https://docs.djangoproject.com/en/1.10/topics/templates/) (Django docs). +> [!NOTE] +> На самом деле, в зависимости от настроек проекта, Django просматривает несколько мест в поисках шаблона (поиск в директории приложения осуществляется по умолчанию!). Вы можете найти больше информации о шаблонах и форматах, которые они поддерживают, перейдя по ссылке [Шаблоны](https://docs.djangoproject.com/en/1.10/topics/templates/) (Django docs). #### Расширение шаблонов @@ -174,7 +178,8 @@ def index(request): Базовый шаблон, который мы планируем использовать для сайта _LocalLibrary_, представлен ниже. Как вы видите, данный фрагмент содержит HTML код и объявляет следующие блоки `title`, `sidebar` и `content`. Мы добавили заголовок по умолчанию (который, возможно, мы захотим изменить), а также боковую панель навигации, содержащей ссылки на списки всех книг и авторов (панель навигации, мы, вероятно, не будем менять/замещать, но, тем не менее, добавив этот блок, мы оставим для себя такую возможность). -> **Примечание:** Во фрагменте мы используем два дополнительных шаблонных тега: `url` и `load static`. Они будут описаны в следующих разделах. +> [!NOTE] +> Во фрагменте мы используем два дополнительных шаблонных тега: `url` и `load static`. Они будут описаны в следующих разделах. Создайте новый файл — **/locallibrary/catalog/templates/_base_generic.html_** — и добавьте в него следующее содержимое: @@ -254,7 +259,8 @@ def index(request): В данном фрагменте, в разделе _Динамическое содержимое,_ мы объявили метки (_шаблонные переменные_) для информации, которую мы получаем из соответствующего отображения. Данные переменные объявляются при помощи "двойных фигурных скобок" (в предыдущем фрагменте выделено жирным). -> **Примечание:** Переменные шаблона заключаются в двойные фигурные скобки (`\{{ num_books }}`) , а тэги шаблона (функции шаблона), помещаются в одинарные фигурные скобки со знаками процента (`{% extends "base_generic.html" %}`). +> [!NOTE] +> Переменные шаблона заключаются в двойные фигурные скобки (`\{{ num_books }}`) , а тэги шаблона (функции шаблона), помещаются в одинарные фигурные скобки со знаками процента (`{% extends "base_generic.html" %}`). Важно отметить, что данные переменные имеют имена, соответствующие именам передаваемых _ключей_ из словаря переменной `context`, которая, в свою очередь, передаётся из отображения, во время вызова функции `render()` (смотри ниже). При отрисовке шаблона, вместо этих ключей будут подставлены, соответствующие им, _значения_. @@ -288,7 +294,8 @@ return render( style="width:555px;height:540px;" /> ``` -> **Примечание:** Фрагменты выше указывают пути расположения файлов, но Django не использует их по умолчанию. В процессе разработки сервер использует значения, указанные в глобальном файле URL-преобразований (**/locallibrary/locallibrary/urls.py**), который мы создали в части [создание скелета сайта](/ru/docs/Learn/Server-side/Django/skeleton_website). В дальнейшем, в продакшене, вам нужно будет уточнить параметры расположения статических файлов. Мы вернёмся к этому позже. +> [!NOTE] +> Фрагменты выше указывают пути расположения файлов, но Django не использует их по умолчанию. В процессе разработки сервер использует значения, указанные в глобальном файле URL-преобразований (**/locallibrary/locallibrary/urls.py**), который мы создали в части [создание скелета сайта](/ru/docs/Learn/Server-side/Django/skeleton_website). В дальнейшем, в продакшене, вам нужно будет уточнить параметры расположения статических файлов. Мы вернёмся к этому позже. Для получения более подробной информации о работе со статическими файлами обратитесь к документации по ссылке [Управление статическими файлами](https://docs.djangoproject.com/en/1.10/howto/static-files/) (Django docs). @@ -308,7 +315,8 @@ return render( ![Index page for LocalLibrary website](index_page_ok.png) -> **Примечание:** На данном этапе вы не сможете воспользоваться ссылками на страницы **All books** и **All authors**, потому что url-адреса, отображения и шаблоны для данных страниц не созданы (мы просто объявили метки для соответствующих ссылок в базовом шаблоне `base_generic.html`). +> [!NOTE] +> На данном этапе вы не сможете воспользоваться ссылками на страницы **All books** и **All authors**, потому что url-адреса, отображения и шаблоны для данных страниц не созданы (мы просто объявили метки для соответствующих ссылок в базовом шаблоне `base_generic.html`). ## Проверьте себя diff --git a/files/ru/learn/server-side/django/index.md b/files/ru/learn/server-side/django/index.md index 5f672566af42c8..ae0b2f968c9beb 100644 --- a/files/ru/learn/server-side/django/index.md +++ b/files/ru/learn/server-side/django/index.md @@ -13,7 +13,8 @@ Django является чрезвычайно популярным и полн Рекомендуется базовое понимание концепций программирования и языка Python, но это не обязательно для освоения основных понятий. -> **Примечание:** Python является одним из самых доступных в чтении и понимании для новичков языком программирования. Тем не менее, если вы захотите глубже понять этот модуль, в Интернете сейчас доступны многочисленные бесплатные книги и учебные пособия (новички в программирование возможно захотят посетить [Python for Non Programmers](https://wiki.python.org/moin/BeginnersGuide/NonProgrammers) на вики-страницах python.org). +> [!NOTE] +> Python является одним из самых доступных в чтении и понимании для новичков языком программирования. Тем не менее, если вы захотите глубже понять этот модуль, в Интернете сейчас доступны многочисленные бесплатные книги и учебные пособия (новички в программирование возможно захотят посетить [Python for Non Programmers](https://wiki.python.org/moin/BeginnersGuide/NonProgrammers) на вики-страницах python.org). ## Руководство diff --git a/files/ru/learn/server-side/django/introduction/index.md b/files/ru/learn/server-side/django/introduction/index.md index 36e1c724320e0e..f18e6a6dbb62e0 100644 --- a/files/ru/learn/server-side/django/introduction/index.md +++ b/files/ru/learn/server-side/django/introduction/index.md @@ -46,7 +46,8 @@ Django был разработан в период с 2003 по 2005 год ко Django продолжает расти и улучшаться с момента его первого релиза (1.0) в сентябре 2008 года до недавно выпущенной версии 3.1 (2020). В каждой версии добавлены новые функциональные возможности и исправлены ошибки, начиная от поддержки новых типов баз данных, шаблонизаторов и кеширования, до добавления «общих» функций просмотра и классов (уменьшающих объём кода, который разработчики должны писать для ряда программных задач). -> **Примечание:** Ознакомьтесь с [примечаниями к версии](https://docs.djangoproject.com/en/3.1/releases/) на сайте Django, чтобы увидеть что изменилось в последних версиях и как много работы было проделано, чтобы улучшить Django. +> [!NOTE] +> Ознакомьтесь с [примечаниями к версии](https://docs.djangoproject.com/en/3.1/releases/) на сайте Django, чтобы увидеть что изменилось в последних версиях и как много работы было проделано, чтобы улучшить Django. Django — это процветающий совместный проект с открытым исходным кодом, в котором заняты многие тысячи пользователей и участников. Несмотря на то, что у него всё ещё есть некоторые особенности, которые отражают его происхождение, Django превратился в универсальный фреймворк, способный разрабатывать веб-сайты любого типа. @@ -81,7 +82,8 @@ Django «умеренно гибкий» и, следовательно, обе - **Models:** Модели представляют собой объекты Python, которые определяют структуру данных приложения и предоставляют механизмы для управления (добавления, изменения, удаления) и выполнения запросов в базу данных. - **Templates:** Template (англ. «шаблон») — это текстовый файл, определяющий структуру или разметку страницы (например HTML-страницы), с полями для подстановки, которые используются для вывода актуального содержимого. _View_ может динамически создавать HTML-страницы, используя HTML-шаблоны и заполняя их данными из модели (_model)._ Шаблон может быть использован для определения структуры файлов любых типов, не обязательно HTML. -> **Примечание:** Django реализует уровневую архитектуру "Model View Template (MVT)". Она имеет много общего с более известной архитектурой [Model View Controller](/ru/docs/Web/Apps/Fundamentals/Modern_web_app_architecture/MVC_architecture). +> [!NOTE] +> Django реализует уровневую архитектуру "Model View Template (MVT)". Она имеет много общего с более известной архитектурой [Model View Controller](/ru/docs/Web/Apps/Fundamentals/Modern_web_app_architecture/MVC_architecture). Следующие разделы дадут вам понимание того, как выглядят основные части Django (мы их изучим более детально чуть позже на курсе, когда будет настраивать окружение разработчика). @@ -122,7 +124,8 @@ def index(request): return HttpResponse('Hello from Django!') ``` -> **Примечание:** Немного Python: +> [!NOTE] +> Немного о Python: > > - [Модули Python](https://docs.python.org/3/tutorial/modules.html) это библиотеки функций, сохранённые в различных файлах, которые мы можем использовать в нашем коде. Здесь мы импортируем только объект `HttpResponse` из модуля `django.http` чтобы использовать его в нашем отображении (view): `from django.http import HttpResponse` . Также есть другие способы импортирования некоторых или всех объектов модуля. > - Функции объявляются с помощью ключевого слова `def`, как показано выше, с именованными параметрами, перечисленными в скобках после имени функции; строка завершается двоеточием. Заметьте, что следующие строки содержат отступы. Отступы важны, так как они определяют, какие строки кода находятся внутри конкретного блока (обязательные отступы — это ключевая особенность Python и одна из причин, почему код на Python так легко читать). @@ -152,7 +155,8 @@ class Team(models.Model): team_level = models.CharField(max_length=3,choices=TEAM_LEVELS,default='U11') ``` -> **Примечание:** Немного Python: +> [!NOTE] +> Немного о Python: > > - Python поддерживает «объектно-ориентированное программирование», то есть стиль программирования, в котором мы организуем наш код в объекты, которые включают связанные данные и функции для работы с этими данными. Объекты также могут наследовать / расширять / выводить из других объектов, позволяя использовать одинаковое поведение между связанными объектами. В Python мы используем ключевое слово `class`, чтобы определить «скелет» для объекта. Мы можем создать несколько конкретных _экземпляров_ типа объекта на основе модели в классе. > diff --git a/files/ru/learn/server-side/django/models/index.md b/files/ru/learn/server-side/django/models/index.md index 276a6a708a1ef7..324f4b782d194a 100644 --- a/files/ru/learn/server-side/django/models/index.md +++ b/files/ru/learn/server-side/django/models/index.md @@ -35,7 +35,8 @@ slug: Learn/Server-side/Django/Models ![LocalLibrary Model UML - v3](local_library_model_uml.png) -> **Примечание:** Примечание. В следующем разделе приведён базовый пример, поясняющий, как модели определяются и используются. Когда вы его прочитаете, подумайте, как мы построим каждую из моделей на диаграмме выше. +> [!NOTE] +> В следующем разделе приведён базовый пример, поясняющий, как модели определяются и используются. Когда вы его прочитаете, подумайте, как мы построим каждую из моделей на диаграмме выше. ## Модель для начинающих @@ -166,7 +167,8 @@ def get_absolute_url(self): return reverse('model-detail-view', args=[str(self.id)]) ``` -> **Примечание:** Примечание. Предполагается, что вы будете использовать URL-адреса, например / myapplication / mymodelname / 2, для отображения отдельных записей для вашей модели (где «2» - это идентификатор для определённой записи), вам нужно будет создать URL-карту, чтобы передать ответ и идентификатор «Образцовое представление модели» (которое будет выполнять работу, необходимую для отображения записи). Вышеуказанная функция reverse () может «перевернуть» ваш URL-адрес (в приведённом выше примере с именем «model-detail-view»), чтобы создать URL-адрес правильного формата. +> [!NOTE] +> Предполагается, что вы будете использовать URL-адреса, например / myapplication / mymodelname / 2, для отображения отдельных записей для вашей модели (где «2» - это идентификатор для определённой записи), вам нужно будет создать URL-карту, чтобы передать ответ и идентификатор «Образцовое представление модели» (которое будет выполнять работу, необходимую для отображения записи). Вышеуказанная функция reverse () может «перевернуть» ваш URL-адрес (в приведённом выше примере с именем «model-detail-view»), чтобы создать URL-адрес правильного формата. > > Конечно, для выполнения этой работы вам всё равно придётся писать сопоставление URL-адрес, просмотр и шаблон! @@ -188,7 +190,8 @@ a_record = MyModelName(my_field_name="Instance #1") a_record.save() ``` -> **Примечание:** Примечание. Если вы не указали какое-либо поле в качестве primary_key, новая запись будет выдаваться автоматически, с идентификатором имени поля. Вы можете запросить это поле после сохранения указанной выше записи, и оно будет иметь значение 1. +> [!NOTE] +> Если вы не указали какое-либо поле в качестве primary_key, новая запись будет выдаваться автоматически, с идентификатором имени поля. Вы можете запросить это поле после сохранения указанной выше записи, и оно будет иметь значение 1. Вы можете получить доступ к полям в этой новой записи с использованием синтаксиса точек и изменить значения. Вы должны вызвать save (), чтобы сохранить изменённые значения в базе данных. @@ -206,7 +209,8 @@ a_record.save() Вы можете искать записи, соответствующие определённым критериям, используя атрибут объектов модели (предоставляемый базовым классом). -> **Примечание:** Примечание. Объяснение того, как искать записи, используя «абстрактную» модель и имена полей, может быть немного запутанным. В приведённом ниже обсуждении мы будем ссылаться на модель книги с полями названия и жанра, где жанр также является моделью с единственным именем в поле. +> [!NOTE] +> Объяснение того, как искать записи, используя «абстрактную» модель и имена полей, может быть немного запутанным. В приведённом ниже обсуждении мы будем ссылаться на модель книги с полями названия и жанра, где жанр также является моделью с единственным именем в поле. Мы можем получить все записи для модели как объект QuerySet, используя `objects.all()`. QuerySet - это итерируемый объект, означающий, что он содержит несколько объектов, которые мы можем перебирать / прокручивать. @@ -229,7 +233,8 @@ number_wild_books = Book.objects.filter(title__contains='wild').count() 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'. +> [!NOTE] +> Вы можете использовать символы подчёркивания (\_\_) для навигации по многим уровням отношений (ForeignKey / ManyToManyField) по своему усмотрению. Например, книга, имеющая разные типы, определяемая с использованием дополнительной связи «обложка», может иметь имя параметра: type\_\_cover\_\_name\_\_exact = 'hard'. Существует гораздо больше возможностей для запросов, включая обратные поиски от связанных моделей, цепочки фильтров, возврат меньшего набора значений и т. д. Для получения дополнительной информации см. [Making queries](https://docs.djangoproject.com/en/2.2/topics/db/queries/) (Django Docs, \[EN]). @@ -351,7 +356,8 @@ class BookInstance(models.Model): Модель \_\_str \_\_ () представляет объект BookInstance, используя комбинацию его уникального идентификатора и связанного с ним заголовка книги. -> **Примечание:** Примечание. Немного Python: +> [!NOTE] +> Немного о Python: > > - Значение, возвращаемое \_\_str \_\_ (), является форматированной строкой. В строке мы используем % S для объявления 'placeholders'. После строки укажем %, а затем кортеж, содержащий значения, которые будут вставлены в заполнители. Если у вас просто один заполнитель, вы можете опустить кортеж - например, 'Моё значение:% S' % переменная. > diff --git a/files/ru/learn/server-side/django/sessions/index.md b/files/ru/learn/server-side/django/sessions/index.md index 78fd82d03a3d26..9ec5bf41fe51df 100644 --- a/files/ru/learn/server-side/django/sessions/index.md +++ b/files/ru/learn/server-side/django/sessions/index.md @@ -53,7 +53,8 @@ MIDDLEWARE = [ Ниже представлены фрагменты кода, которые показывают вам как получать, задавать и удалять некоторые данные при помощи ключа "`my_car`", связанного с текущей сессией (браузером). -> **Примечание:** Одной из самых грандиозных вещей в Django является то, что вам не надо думать о механизме, который связывает сессию с текущим запросом в отображении. Во фрагменте ниже, всё что вам надо знать, это то, что `my_car` связана с тем браузером, который отправил текущий запрос. +> [!NOTE] +> Одной из самых грандиозных вещей в Django является то, что вам не надо думать о механизме, который связывает сессию с текущим запросом в отображении. Во фрагменте ниже, всё что вам надо знать, это то, что `my_car` связана с тем браузером, который отправил текущий запрос. ```python # Получение значения сессии при помощи ключа(то есть, 'my_car'). @@ -95,7 +96,8 @@ request.session['my_car']['wheels'] = 'alloy' request.session.modified = True ``` -> **Примечание:** вы можете изменить поведение сессий таким образом, чтобы они записывали любое своё изменение в базу данных и отправляли куки, при каждом запросе, путём установки `SESSION_SAVE_EVERY_REQUEST = True`, в файле настроек проекта (**locallibrary/locallibrary/settings.py**). +> [!NOTE] +> Вы можете изменить поведение сессий таким образом, чтобы они записывали любое своё изменение в базу данных и отправляли куки, при каждом запросе, путём установки `SESSION_SAVE_EVERY_REQUEST = True`, в файле настроек проекта (**locallibrary/locallibrary/settings.py**). ## Простой пример — получение числа визитов @@ -124,7 +126,8 @@ def index(request): В первую очередь мы получаем значение `'num_visits'` из сессии, возвращая 0, если оно не было установлено ранее. Каждый раз при получении запроса, мы увеличиваем данное значение на единицу и сохраняем его обратно в сессии (до следующего посещения данной страницы пользователем). Затем переменная `num_visits` передаётся в шаблон через переменную контекста `context`. -> **Примечание:** Можно проверить наличие поддержки куки в браузере (для примера, смотрите [Как использовать сессии](https://docs.djangoproject.com/en/1.10/topics/http/sessions/)), или разработать наш UI таким образом, чтобы это не имело значения. +> [!NOTE] +> Можно проверить наличие поддержки куки в браузере (для примера, смотрите [Как использовать сессии](https://docs.djangoproject.com/en/1.10/topics/http/sessions/)), или разработать наш UI таким образом, чтобы это не имело значения. Для показа значения переменной, из следующего фрагмента добавьте нижнюю строчку кода в ваш шаблон главной страницы сайта (**/locallibrary/catalog/templates/index.html**), в его нижний раздел "Dynamic content": diff --git a/files/ru/learn/server-side/django/skeleton_website/index.md b/files/ru/learn/server-side/django/skeleton_website/index.md index 5389d82f2efa17..d1fa77bcd50fbf 100644 --- a/files/ru/learn/server-side/django/skeleton_website/index.md +++ b/files/ru/learn/server-side/django/skeleton_website/index.md @@ -20,7 +20,8 @@ slug: Learn/Server-side/Django/skeleton_website 1. Использовать `django-admin` для создания папки проекта, шаблонов остальных файлов, и скрипта для управления проектом (**manage.py**). 2. Использовать **manage.py** _для создания одного или нескольких_ приложений. - > **Примечание:** Сайт может состоять из одной или нескольких различных частей, например: основная часть, блог, вики, раздел загрузок, и так далее. Философия Django подталкивает разработчиков создавать эти части, как разные **приложения**, которые, если понадобится, могут быть использованы повторно в других проектах. + > [!NOTE] + > Сайт может состоять из одной или нескольких различных частей, например: основная часть, блог, вики, раздел загрузок, и так далее. Философия Django подталкивает разработчиков создавать эти части, как разные **приложения**, которые, если понадобится, могут быть использованы повторно в других проектах. 3. Зарегистрировать в настройках эти приложения, чтобы использовать их в проекте. 4. Настроить маршруты url адресов для каждого из приложений. @@ -79,7 +80,8 @@ locallibrary/ python3 manage.py startapp catalog ``` -> **Примечание:** приведённая выше команда справедлива для GNU Linux/Mac OS. На Windows команда должна иметь вид: `py -3 manage.py startapp catalog` +> [!NOTE] +> Приведённая выше команда справедлива для GNU Linux/Mac OS. На Windows команда должна иметь вид: `py -3 manage.py startapp catalog` > > Если вы работаете под Windows, заменяйте команду `python3` на `py -3` в этой и следующих статьях. @@ -106,7 +108,8 @@ locallibrary/ - Папка _migrations_ используется, чтобы хранить"миграции" — файлы, которые позволяют вам автоматически обновлять базу данных по мере изменения моделей. - **\_\_init\_\_.py** — пустой файл для того, чтобы Django и Python распознавали папку как [Python модуль](https://docs.python.org/3/tutorial/modules.html#packages) и позволяет нам использовать его объекты внутри других частей проекта. -> **Примечание:** Заметили, что некоторых файлов не хватает? В то время, как там нашли себе место файлы для контроллеров(views) и моделей(models), файлов для настройки url соотносителя, шаблонов, и статичных файлов создано не было. Далее мы покажем, как их создать (они не обязательны для каждого сайта, но нужны в данном примере). +> [!NOTE] +> Заметили, что некоторых файлов не хватает? В то время, как там нашли себе место файлы для контроллеров(views) и моделей(models), файлов для настройки url соотносителя, шаблонов, и статичных файлов создано не было. Далее мы покажем, как их создать (они не обязательны для каждого сайта, но нужны в данном примере). ## Регистрация папки с приложением @@ -128,7 +131,8 @@ INSTALLED_APPS = [ Новая строка указывает на файл конфигурации приложения (`CatalogConfig`), который был создан в **/locallibrary/catalog/apps.py** , когда вы создали приложение. -> **Примечание:** Легко заметить, что в `INSTALLED_APPS` уже подключено большое количество приложений (и объектов `MIDDLEWARE`, ниже в файле конфигурации). Они добавляют поддержку [админ-панели Django](/ru/docs/Learn/Server-side/Django/Admin_site) и, как следствие, огромное количество функциональности (включая сессии, аутентификацию и прочее). +> [!NOTE] +> Легко заметить, что в `INSTALLED_APPS` уже подключено большое количество приложений (и объектов `MIDDLEWARE`, ниже в файле конфигурации). Они добавляют поддержку [админ-панели Django](/ru/docs/Learn/Server-side/Django/Admin_site) и, как следствие, огромное количество функциональности (включая сессии, аутентификацию и прочее). ## Настройка базы данных @@ -232,7 +236,8 @@ from django.conf.urls.static import static urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) ``` -> **Примечание:** Существуют различные способы дополнения списка `urlpatterns` (в примере мы просто добавляли объект, используя оператор `+=` чтобы чётко разделить изначальный и дописанный код). Вместо этого, мы могли бы добавить соотношения внутрь определения переменной: +> [!NOTE] +> Существуют различные способы дополнения списка `urlpatterns` (в примере мы просто добавляли объект, используя оператор `+=` чтобы чётко разделить изначальный и дописанный код). Вместо этого, мы могли бы добавить соотношения внутрь определения переменной: > > ``` > urlpatterns = [ path('admin/', admin.site.urls), @@ -272,19 +277,22 @@ python3 manage.py makemigrations python3 manage.py migrate ``` -> **Предупреждение:** Необходимо выполнять команды выше каждый раз, когда вы меняете модели таким образом, что структура таблицы изменится(включая добавления и удаления как отдельных полей, так и целых моделей). +> [!WARNING] +> Необходимо выполнять команды выше каждый раз, когда вы меняете модели таким образом, что структура таблицы изменится(включая добавления и удаления как отдельных полей, так и целых моделей). `Команда makemigrations` _создаёт_ (но не применяет) миграции для всех приложений, которые установлены в ваш проект (вы так же можете указать в конце имя конкретного приложения, чтобы создать миграции только для него). Это даёт вам возможность проверить код перед тем, как их применить — когда вы станете хорошо разбираться в Django, то сможете даже менять их! Команда `migrate` применяет созданные миграции к базе (Django отслеживает, какие миграции были созданы для данной базы). -> **Примечание:** Посмотрите раздел [Миграции](https://docs.djangoproject.com/en/2.2/topics/migrations/) в документации Django чтобы получить информацию о менее распространённых командах для управления миграциями. +> [!NOTE] +> Посмотрите раздел [Миграции](https://docs.djangoproject.com/en/2.2/topics/migrations/) в документации Django чтобы получить информацию о менее распространённых командах для управления миграциями. ### Запуск сайта Во время разработки, вы можете проверить свой сайт, разместив его на _встроенном отладочном сервере_, и просмотрев его в своём браузере. -> **Примечание:** Отладочный веб-сервер не настолько функционален и производителен, для постоянного размещения , но это самый простой способ запустить свой сайт на Django и проверить его на наличие ошибок. По умолчанию, он разместит сайт на вашем компьютере (`http://127.0.0.1:8000/)`, но вы так же можете указать различные компьютеры в вашей сети для этой цели. Для получения большего количества информации загляните в раздел [django-admin и manage.py: отладочный сервер](https://docs.djangoproject.com/en/2.2/ref/django-admin/) документации Django. +> [!NOTE] +> Отладочный веб-сервер не настолько функционален и производителен, для постоянного размещения , но это самый простой способ запустить свой сайт на Django и проверить его на наличие ошибок. По умолчанию, он разместит сайт на вашем компьютере (`http://127.0.0.1:8000/)`, но вы так же можете указать различные компьютеры в вашей сети для этой цели. Для получения большего количества информации загляните в раздел [django-admin и manage.py: отладочный сервер](https://docs.djangoproject.com/en/2.2/ref/django-admin/) документации Django. Запустите веб-сервер, используя команду _runserver_ (в той же папке, что и **manage.py**): @@ -306,11 +314,13 @@ python3 manage.py runserver Не волнуйтесь! Эта страница должна появиться и сообщить нам, что мы ещё не настроили ни одной страницы в модуле `catalogs.urls` (на который мы были перенаправлены запросили корневой URL сайта). -> **Примечание:** Показанная выше страница открывает нам одно из замечательных свойств Django — автоматические отчёты об ошибках. На экране с ошибкой отображается множество полезной информации, когда страница не найдена, или ошибка была вызвана кодом. В данном случае, мы видим, что запрошенный URL не соответствует ни одному шаблону (из указанных). Подобные отчёты будут выключены при DEBUG=False (когда мы разместим приложение в Сеть), в этом случае будет показана менее информативная, но более дружелюбная к пользователю страница(которую вам надо будет создать - прим. переводчика). +> [!NOTE] +> Показанная выше страница открывает нам одно из замечательных свойств Django — автоматические отчёты об ошибках. На экране с ошибкой отображается множество полезной информации, когда страница не найдена, или ошибка была вызвана кодом. В данном случае, мы видим, что запрошенный URL не соответствует ни одному шаблону (из указанных). Подобные отчёты будут выключены при DEBUG=False (когда мы разместим приложение в Сеть), в этом случае будет показана менее информативная, но более дружелюбная к пользователю страница(которую вам надо будет создать - прим. переводчика). На данном этапе, мы поняли, что Django работает должным образом! -> **Примечание:** вам следует перезапускать миграцию и заново тестировать сайт, после того как вы делаете важные изменения. Поверьте, это не займёт много времени! +> [!NOTE] +> Вам следует перезапускать миграцию и заново тестировать сайт, после того как вы делаете важные изменения. Поверьте, это не займёт много времени! ## Домашнее задание diff --git a/files/ru/learn/server-side/django/testing/index.md b/files/ru/learn/server-side/django/testing/index.md index fcfe9e80255ebd..f5a7256f98caad 100644 --- a/files/ru/learn/server-side/django/testing/index.md +++ b/files/ru/learn/server-side/django/testing/index.md @@ -62,7 +62,8 @@ class YourTestClass(TestCase): Самый подходящий базовый класс для большинства тестов это [django.test.TestCase](https://docs.djangoproject.com/en/1.10/topics/testing/tools/#testcase). Этот класс создаёт чистую базу данных перед запуском своих методов, а также запускает каждую функцию тестирования в его собственной транзакции. У данного класса также имеется тестовый [Клиент](https://docs.djangoproject.com/en/1.10/topics/testing/tools/#django.test.Client), который вы можете использовать для имитации взаимодействия пользователя с кодом на уровне отображения. В следующих разделах мы сконцентрируемся на юнит-тестах, которые будут созданы на основе класса [TestCase](https://docs.djangoproject.com/en/1.10/topics/testing/tools/#testcase). -> **Примечание:** Класс [django.test.TestCase](https://docs.djangoproject.com/en/1.10/topics/testing/tools/#testcase) очень удобен, но он может приводить к замедленной работе в некоторых случаях (не для каждого теста необходимо настраивать базу данных, или имитировать взаимодействие с отображением). Когда вы познакомитесь с работой данного класса, то сможете заменить некоторые из ваших тестов на более простые классы тестирования. +> [!NOTE] +> Класс [django.test.TestCase](https://docs.djangoproject.com/en/1.10/topics/testing/tools/#testcase) очень удобен, но он может приводить к замедленной работе в некоторых случаях (не для каждого теста необходимо настраивать базу данных, или имитировать взаимодействие с отображением). Когда вы познакомитесь с работой данного класса, то сможете заменить некоторые из ваших тестов на более простые классы тестирования. ### Что вы должны тестировать? @@ -88,7 +89,8 @@ class Author(models.Model): Подобным же образом вы должны убедиться, что методы `get_absolute_url()` и `__str__()` ведут себя как требуется, потому что они являются частью вашей бизнес логики. В случае функции `get_absolute_url()` вы можете быть уверены, что функция из Django `reverse()` была реализована правильно и, следовательно, вы тестируете только то, чтобы соответствующий вызов в отображении был правильно определён. -> **Примечание:** Проницательные читатели могут заметить, что мы можем некоторым образом ограничить дату рождения и смерти какими-то граничными значениями и выполнять проверку, чтобы дата смерти шла после рождения. В Django данное ограничение может быть добавлено к вашим классам форм (хотя вы и можете определить валидаторы для этих полей, они будут проявлять себя только на уровне форм, а не уровне модели). +> [!NOTE] +> Проницательные читатели могут заметить, что мы можем некоторым образом ограничить дату рождения и смерти какими-то граничными значениями и выполнять проверку, чтобы дата смерти шла после рождения. В Django данное ограничение может быть добавлено к вашим классам форм (хотя вы и можете определить валидаторы для этих полей, они будут проявлять себя только на уровне форм, а не уровне модели). Ну что же, усвоив данную информацию, давайте перейдём к процессу определения и запуска тестов. @@ -109,7 +111,8 @@ catalog/ В проекте _LocalLibrary_ создайте файловую структуру, указанную выше. Файл **\_\_init\_\_.py** должен быть пустым (так мы говорим Питону, что данная директория является пакетом). Вы можете создать три тестовых файла при помощи копирования и переименования файла-образца **/catalog/tests.py**. -> **Примечание:** Скелет тестового файла **/catalog/tests.py** был создан автоматически когда мы выполняли [построение скелета сайта Django](/ru/docs/Learn/Server-side/Django/skeleton_website). Является абсолютно "легальным" действием - поместить все ваши тесты в данный файл, тем не менее, если вы проводите тесты "правильно", то вы очень быстро придёте к очень большому и неуправляемому файлу тестирования. +> [!NOTE] +> Скелет тестового файла **/catalog/tests.py** был создан автоматически когда мы выполняли [построение скелета сайта Django](/ru/docs/Learn/Server-side/Django/skeleton_website). Является абсолютно "легальным" действием - поместить все ваши тесты в данный файл, тем не менее, если вы проводите тесты "правильно", то вы очень быстро придёте к очень большому и неуправляемому файлу тестирования. > > Можете удалить данный файл, поскольку больше он нам не понадобится. @@ -155,13 +158,15 @@ class YourTestClass(TestCase): - `setUpTestData()` вызывается каждый раз перед запуском теста на уровне настройки всего класса. Вы должны использовать данный метод для создания объектов, которые не будут модифицироваться/изменяться в каком-либо из тестовых методов. - `setUp()` вызывается перед каждой тестовой функцией для настройки объектов, которые могут изменяться во время тестов (каждая функция тестирования будет получать "свежую" версию данных объектов). -> **Примечание:** . Классы тестирования также содержат метод `tearDown()`, который мы пока не используем. Этот метод не особенно полезен для тестирования баз данных, поскольку базовый класс `TestCase` автоматически разрывает соединения с ними. +> [!NOTE] +> Классы тестирования также содержат метод `tearDown()`, который мы пока не используем. Этот метод не особенно полезен для тестирования баз данных, поскольку базовый класс `TestCase` автоматически разрывает соединения с ними. Далее идут несколько методов, которые используют функции `Assert`, проверяющие условия "истинно" (true), "ложно" (false) или равенство (`AssertTrue`, `AssertFalse`, `AssertEqual`). Если условия не выполняются как ожидалось, то это приводит к провалу теста и выводу соответствующего сообщения об ошибке на консоль. Функции проверки утверждений `AssertTrue`, `AssertFalse`, `AssertEqual` реализованы в **unittest**. В данном фреймворке существуют и другие подобные функции, а кроме того, [специфические для Django функции](https://docs.djangoproject.com/en/1.10/topics/testing/tools/#assertions) проверки, например, перехода из/к отображению (`assertRedirects`), проверки использования какого-то конкретного шаблона (`assertTemplateUsed`) и так далее. -> **Примечание:** В обычной ситуации у вас нет необходимости вызывать функции **print()** из методов теста, как во фрагменте выше. Мы поступили так только для того, чтобы вы в консоле увидели порядок вызова тестовых функций класса. +> [!NOTE] +> В обычной ситуации у вас нет необходимости вызывать функции **print()** из методов теста, как во фрагменте выше. Мы поступили так только для того, чтобы вы в консоле увидели порядок вызова тестовых функций класса. ## Как запускать тесты @@ -204,7 +209,8 @@ Destroying test database for alias 'default'... Как видите, один тест провалился и мы можем точно увидеть в какой именно функции это произошло и почему (так и было задумано, поскольку `False` не равен `True`!). -> **Примечание:** Самая важная вещь, которую нужно извлечь из тестового выхода выше, заключается в том, что это гораздо более ценно, если вы используете описательные/информативные имена для ваших объектов и методов. +> [!NOTE] +> Самая важная вещь, которую нужно извлечь из тестового выхода выше, заключается в том, что это гораздо более ценно, если вы используете описательные/информативные имена для ваших объектов и методов. Текст выделенный жирным, обычно не должен появляться в тестовом выводе (это результат работы функций `print()` в наших тестах). Он показывает, что вызов метода `setUpTestData()` происходит один раз для всего класса в целом, а вызовы`setUp()` осуществляются перед каждым методом. @@ -319,7 +325,8 @@ self.assertEquals(field_label,'first name') - Мы не можем получить поле `verbose_name` напрямую через `author.first_name.verbose_name`, потому что `author.first_name` является _строкой_. Вместо этого, нам надо использовать атрибут `_meta` объекта автора для получения того экземпляра поля, который будет использоваться для получения дополнительной информации. - Мы выбрали метод `assertEquals(field_label,'first name')` вместо `assertTrue(field_label == 'first name')`, потому что, в случае провала теста, в выводе будет указано какое именно значение содержит метка и это немного облегчит нам задачу по отладке кода. -> **Примечание:** Тесты для текстовых меток `last_name` и `date_of_birth`, а также тест длины поля `last_name` были опущены. Добавьте свою версию этих тестов, соблюдая соглашение об именовании и следуя структуре логики, представленной выше. +> [!NOTE] +> Тесты для текстовых меток `last_name` и `date_of_birth`, а также тест длины поля `last_name` были опущены. Добавьте свою версию этих тестов, соблюдая соглашение об именовании и следуя структуре логики, представленной выше. Кроме того, нам надо провести тесты наших собственных методов. Они просто проверяют, что имена объектов имеют следующие значения "Last Name, First Name" и что URL-адрес, по которому мы получаем экземпляр `Author`, такой как ожидается. @@ -436,7 +443,8 @@ class RenewBookFormTest(TestCase): Оставшиеся функции проверяют валидность дат, то есть их нахождение внутри определённого интервала, а также невалидность для значений, которые находятся вне заданного интервала. Для получения исходного значения мы использовали функцию получения текущей даты (`datetime.date.today()`), а также функцию `datetime.timedelta()` (которая принимает определённое число дней, или недель). Затем мы просто создали форму, передавая ей наши данные и проверяя её на валидность. -> **Примечание:** В данном примере мы не использовали ни базу данных, ни тестовый клиент. Рассмотрите модификацию этих тестов при помощи класса [SimpleTestCase](https://docs.djangoproject.com/en/1.10/topics/testing/tools/#django.test.SimpleTestCase). +> [!NOTE] +> В данном примере мы не использовали ни базу данных, ни тестовый клиент. Рассмотрите модификацию этих тестов при помощи класса [SimpleTestCase](https://docs.djangoproject.com/en/1.10/topics/testing/tools/#django.test.SimpleTestCase). > > Нам также надо бы проверять возникновение ошибок, которые появляются если форма не валидна. Но, обычно, это относится к процессу вывода информации, таким образом, мы позаботимся об этом в следующем разделе. @@ -537,7 +545,8 @@ class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView): Добавьте тестовый код следующего фрагмента в **/catalog/tests/test_views.py**. В нем, для создания нескольких аккаунтов и объектов `BookInstance` которые будут использоваться в дальнейших тестах, мы используем метод `SetUp()` (вместе с соответствующими книгами и другими записями). Половина книг бронируется тестовыми пользователями, но в начале для них всех мы устанавливаем статус "доступно". Использование метода `SetUp()` предпочтительнее чем `setUpTestData()`, поскольку в дальнейшем мы будем модифицировать некоторые объекты. -> **Примечание:** Метод `setUp()` создаёт книгу с заданным языком `Language`, но _ваш_ код может не включать в себя модель `Language`, поскольку это было _домашним заданием_. В таком случае просто закомментируйте соответствующие строки. Поступите также и в следующем разделе, посвящённом `RenewBookInstancesViewTest.` +> [!NOTE] +> Метод `setUp()` создаёт книгу с заданным языком `Language`, но _ваш_ код может не включать в себя модель `Language`, поскольку это было _домашним заданием_. В таком случае просто закомментируйте соответствующие строки. Поступите также и в следующем разделе, посвящённом `RenewBookInstancesViewTest.` ```python import datetime @@ -807,7 +816,8 @@ class RenewBookInstancesViewTest(TestCase): self.assertRedirects(resp, reverse('all-borrowed') ) ``` -> **Предупреждение:** Вместо перехода к отображению _all-borrowed_, добавленного в качестве _домашнего задания_, вы можете перенаправить пользователя на домашнюю страницу '/'. В таком случае, исправьте две последние строки тестового кода на код, показанный ниже. Присваивание `follow=True`, в запросе, гарантирует что запрос вернёт окончательный URL-адрес пункта назначения (следовательно проверяется `/catalog/`, а не `/`). +> [!WARNING] +> Вместо перехода к отображению _all-borrowed_, добавленного в качестве _домашнего задания_, вы можете перенаправить пользователя на домашнюю страницу '/'. В таком случае, исправьте две последние строки тестового кода на код, показанный ниже. Присваивание `follow=True`, в запросе, гарантирует что запрос вернёт окончательный URL-адрес пункта назначения (следовательно проверяется `/catalog/`, а не `/`). > > ```python > resp = self.client.post(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}), {'renewal_date':valid_date_in_future},follow=True ) diff --git a/files/ru/learn/server-side/django/web_application_security/index.md b/files/ru/learn/server-side/django/web_application_security/index.md index 82fe2f409a6cec..56d6ebbd5a3e5e 100644 --- a/files/ru/learn/server-side/django/web_application_security/index.md +++ b/files/ru/learn/server-side/django/web_application_security/index.md @@ -36,7 +36,8 @@ XSS это термин, применяющийся для описания кл ``. ![Author Form XSS test](author_create_form_alert_xss.png) - > **Примечание:** Это безобидный скрипт, который, если будет выполнен, отобразит окно с сообщением "Test alert" в вашем браузере. Если данное окно отображается при открытии страницы с созданной подобным образом записью - значит сайт уязвим перед атаками XSS. + > [!NOTE] + > Это безобидный скрипт, который, если будет выполнен, отобразит окно с сообщением "Test alert" в вашем браузере. Если данное окно отображается при открытии страницы с созданной подобным образом записью - значит сайт уязвим перед атаками XSS. 5. Нажмите **Submit** для сохранения записи. 6. После сохранения автора - он должен быть отображён, как показано ниже. Так как сработала защита от XSS - команда `alert()` не будет запущена. Вместо этого скрипт будет отображаться как обычный текст.![Author detail view XSS test](author_detail_alert_xss.png) @@ -58,7 +59,8 @@ XSS это термин, применяющийся для описания кл CSRF атаки позволяют атакующему выполнять действия от имени другого пользователя без его согласия. Например, предположим что есть хакер, который хочет добавить авторов в наше приложение LocalLibrary. -> **Примечание:** Очевидно, что наш хакер делает это не ради денег! Более амбициозные хакеры могут использовать описываемый подход для выполнения более опасных задач (например, переводы денег пользователей на их личные счета и т.д). +> [!NOTE] +> Очевидно, что наш хакер делает это не ради денег! Более амбициозные хакеры могут использовать описываемый подход для выполнения более опасных задач (например, переводы денег пользователей на их личные счета и т.д). Для того, чтобы сделать это, хакер может создать HTML файл, подобный продемонстрированному ниже, который будет содержать форму создания автора (похожую на ту, что мы разрабатывали в предыдущих частях руководства), которая будет отправлена как только данный файл будет загружен в браузер. Хакер отправит данный файл всем Библиотекарям и будет ждать пока кто-либо из них откроет файл (он содержит только безобидную информацию, честно!). Если файл будет открыт любым залогиненным пользователем, с правами Библиотекаря - тогда форма будет отправлена от его имени и создаст нового пользователя. diff --git a/files/ru/learn/server-side/express_nodejs/development_environment/index.md b/files/ru/learn/server-side/express_nodejs/development_environment/index.md index e644834be8c0c7..d2aceb253ab3ce 100644 --- a/files/ru/learn/server-side/express_nodejs/development_environment/index.md +++ b/files/ru/learn/server-side/express_nodejs/development_environment/index.md @@ -23,7 +23,8 @@ _Node_ и _Express_ упрощают настройку вашего компь NPM также можно использовать для (глобальной) установки Express Application Generator, удобного инструмента для создания каркасных веб-приложений Express, которые следуют шаблону MVC. Генератор приложений является необязательным, поскольку вам не нужно использовать этот инструмент для создания приложений, использующих Express, или для приложений для создан Express, имеющих одинаковую архитектурную разметку или зависимости. Мы будем использовать его, потому что это значительно облегчает начало работы и продвигает модульную структуру приложения. -> **Примечание:** Примечание: в отличие от некоторых других веб-сред, среда разработки не включает отдельный веб-сервер разработки. В Node / Express веб-приложение создаёт и запускает собственный веб-сервер! +> [!NOTE] +> В отличие от некоторых других веб-сред, среда разработки не включает отдельный веб-сервер разработки. В _Node_/_Express_ веб-приложение создаёт и запускает собственный веб-сервер! Существуют и другие периферийные инструменты, которые являются частью типичной среды разработки, в том числе текстовые редакторы или IDE для редактирования кода и инструменты управления исходным кодом, такие как Git, для безопасного управления различными версиями вашего кода. Мы предполагаем, что вы уже установили подобные инструменты (в частности, текстовый редактор). @@ -49,7 +50,8 @@ NPM также можно использовать для (глобальной) Чтобы использовать Express, сначала необходимо установить Nodejs и Node Package Manager (NPM) в вашей операционной системе. В следующих разделах описывается самый простой способ установки версии Nodejs с долгосрочной поддержкой (LTS) в Ubuntu Linux 16.04, macOS и Windows 10. -> **Примечание:** Совет: В следующих разделах показан самый простой способ установки Node и NPM на наши целевые платформы ОС. Если вы используете другую ОС или просто хотите увидеть некоторые другие подходы для текущих платформ, см. Установка Node.js через менеджер пакетов (nodejs.org). +> [!NOTE] +> Совет: В следующих разделах показан самый простой способ установки Node и NPM на наши целевые платформы ОС. Если вы используете другую ОС или просто хотите увидеть некоторые другие подходы для текущих платформ, см. Установка Node.js через менеджер пакетов (nodejs.org). ### Windows и macOS @@ -115,7 +117,8 @@ v8.11.3 Код импортирует модуль «http» и использует его для создания сервера (createServer ()), который обрабатывает HTTP-запросы на порту 3000. Затем сценарий выводит на консоль сообщение о том, какой URL-адрес браузера можно использовать для тестирования сервера. Функция createServer () принимает в качестве аргумента колбэк-функцию, которая будет вызываться при получении HTTP-запроса - она просто возвращает ответ с кодом состояния HTTP 200 («ОК») и простым текстом «Hello World». - > **Примечание:** Замечание: не беспокойтесь, если вы ещё не совсем понимаете, что делает этот код! Мы объясним наш код более подробно, как только мы начнём использовать Express! + > [!NOTE] + > Не беспокойтесь, если вы ещё не совсем понимаете, что делает этот код! Мы объясним наш код более подробно, как только мы начнём использовать Express! 2. Запустите сервер, перейдя в тот же каталог, что и ваш файл hellonode.js в командной строке, и вызвав узел вместе с именем скрипта, например так: @@ -130,7 +133,8 @@ v8.11.3 Помимо самого Node, NPM является наиболее важным инструментом для работы с приложениями Node. NPM используется для получения любых пакетов (библиотек JavaScript), которые необходимы приложению для разработки, тестирования и / или производства, а также может использоваться для запуска тестов и инструментов, используемых в процессе разработки. -> **Примечание:** С точки зрения Node, Express - это просто ещё один пакет, который вам нужно установить с помощью NPM, а затем установить его в своём собственном коде. +> [!NOTE] +> С точки зрения Node, Express - это просто ещё один пакет, который вам нужно установить с помощью NPM, а затем установить его в своём собственном коде. Вы можете вручную использовать NPM для получения каждого необходимого пакета отдельно. Обычно мы вместо этого управляем зависимостями, используя простой текстовый файл с именем package.json. В этом файле перечислены все зависимости для конкретного «пакета» JavaScript, включая имя пакета, версию, описание, исходный файл для выполнения, производственные зависимости, зависимости разработки, версии Node, с которыми он может работать, и т. Д. Файл package.json должен содержать все, что нужно NPM для загрузки и запуска вашего приложения (если вы пишете библиотеку многократного использования, вы можете использовать это определение для загрузки пакета в репозиторий npm и сделать его доступным для других пользователей). @@ -138,7 +142,8 @@ v8.11.3 Следующие шаги показывают, как вы можете использовать NPM для загрузки пакета, сохранить его в зависимостях проекта, а затем потребовать его в приложении Node. -> **Примечание:** Здесь мы показываем инструкции для получения и установки пакета Express. Позже мы покажем, как этот пакет и другие уже указаны для нас с помощью Express Application Generator. Этот раздел предоставлен, потому что полезно понять, как работает NPM и что создаётся генератором приложений. +> [!NOTE] +> Здесь мы показываем инструкции для получения и установки пакета Express. Позже мы покажем, как этот пакет и другие уже указаны для нас с помощью Express Application Generator. Этот раздел предоставлен, потому что полезно понять, как работает NPM и что создаётся генератором приложений. 1. Сначала создайте каталог для вашего нового приложения и перейдите в него: @@ -238,13 +243,15 @@ npm install eslint --save-dev } ``` -> **Примечание:** Примечание: «Линтеры» - это инструменты, которые выполняют статический анализ программного обеспечения, чтобы распознавать и сообщать о приверженности / несоблюдении некоторого набора лучших практик кодирования. +> [!NOTE] +> «Линтеры» - это инструменты, которые выполняют статический анализ программного обеспечения, чтобы распознавать и сообщать о приверженности / несоблюдении некоторого набора лучших практик кодирования. ### Запуск задач В дополнение к определению и извлечению зависимостей вы также можете определить именованные скрипты в ваших файлах package.json и вызвать NPM, чтобы выполнить их с помощью команды run-script. Этот подход обычно используется для автоматизации выполнения тестов и частей набора инструментов разработки или сборки (например, запуска инструментов для минимизации JavaScript, сжатия изображений, LINT / анализа вашего кода и т. Д.). -> **Примечание:** Для запуска тестов и других внешних инструментов могут также использоваться такие исполнители, как Gulp и Grunt. +> [!NOTE] +> Для запуска тестов и других внешних инструментов могут также использоваться такие исполнители, как Gulp и Grunt. Например, чтобы определить скрипт для запуска зависимости разработки eslint, которую мы указали в предыдущем разделе, мы могли бы добавить следующий блок скрипта в наш файл package.json (при условии, что наш источник приложения находится в папке / src / js): @@ -282,7 +289,8 @@ npm install express-generator -g express helloworld ``` -> **Примечание:** Вы также можете указать библиотеку шаблонов для использования и ряд других настроек. Используйте команду help, чтобы увидеть все параметры: +> [!NOTE] +> Вы также можете указать библиотеку шаблонов для использования и ряд других настроек. Используйте команду help, чтобы увидеть все параметры: > > ```bash > express --help @@ -290,7 +298,8 @@ express helloworld NPM создаст новое приложение Express в подпапке вашего текущего местоположения, отображая процесс сборки на консоли. По завершении инструмент отобразит команды, которые необходимо ввести, чтобы установить зависимости Node и запустить приложение. -> **Примечание:** Новое приложение будет иметь файл package.json в своём корневом каталоге. Вы можете открыть это, чтобы увидеть, какие зависимости установлены, включая Express и библиотеку шаблонов Jade: +> [!NOTE] +> Новое приложение будет иметь файл package.json в своём корневом каталоге. Вы можете открыть это, чтобы увидеть, какие зависимости установлены, включая Express и библиотеку шаблонов Jade: > > ```js > { diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/author_list_page/index.md b/files/ru/learn/server-side/express_nodejs/displaying_data/author_list_page/index.md index 65935c06233c4b..e20a9e0d6323e5 100644 --- a/files/ru/learn/server-side/express_nodejs/displaying_data/author_list_page/index.md +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/author_list_page/index.md @@ -59,7 +59,8 @@ block content ![Author List Page - Express Local Library site](locallibary_express_author_list.png) -> **Примечание:** Представление дат продолжительности жизни автора выглядит безобразно! Это можно исправить, если использовать [тот же подход](/ru/docs/Learn/Server-side/Express_Nodejs/Displaying_data#date_formatting) , который применялся для списка `BookInstance` (добавить в модель `Author` виртуальное свойство продолжительности жизни). Но в этот раз, однако, некоторые даты могут отсутствовать, и ссылки на несуществующие свойства игнорируются, если не задан строгий режим. Метод `moment()` возвращает текущее время, и нежелательно, чтобы отсутствующие даты форматировались как "сегодня". Один из способов состоит в том, чтобы форматирующая функция возвращала пустую строку, если дата не существует. Например: +> [!NOTE] +> Представление дат продолжительности жизни автора выглядит безобразно! Это можно исправить, если использовать [тот же подход](/ru/docs/Learn/Server-side/Express_Nodejs/Displaying_data#date_formatting) , который применялся для списка `BookInstance` (добавить в модель `Author` виртуальное свойство продолжительности жизни). Но в этот раз, однако, некоторые даты могут отсутствовать, и ссылки на несуществующие свойства игнорируются, если не задан строгий режим. Метод `moment()` возвращает текущее время, и нежелательно, чтобы отсутствующие даты форматировались как "сегодня". Один из способов состоит в том, чтобы форматирующая функция возвращала пустую строку, если дата не существует. Например: > > `return this.date_of_birth ? moment(this.date_of_birth).format('YYYY-MM-DD') : '';` diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/date_formatting_using_moment/index.md b/files/ru/learn/server-side/express_nodejs/displaying_data/date_formatting_using_moment/index.md index d403cc20f1bf4f..4d04e278742101 100644 --- a/files/ru/learn/server-side/express_nodejs/displaying_data/date_formatting_using_moment/index.md +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/date_formatting_using_moment/index.md @@ -7,7 +7,8 @@ slug: Learn/Server-side/Express_Nodejs/Displaying_data/Date_formatting_using_mom Подход, который будет использован, состоит в создании виртуального свойства в модели `BookInstance`, которое будет возвращать отформатированную дату. Форматирование будет производиться с использованием [moment](https://www.npmjs.com/package/moment), легковесной библиотеки JavaScript для разбора, проверки, изменения и форматирования дат. -> **Примечание:** Можно применять _moment_ для форматирования непосредственно в шаблонах Pug, а можно отформатировать строку в других местах. Использование виртуального свойства позволяет получить дату, отформатированную точно так же, как при помощи `due_date`. +> [!NOTE] +> Можно применять _moment_ для форматирования непосредственно в шаблонах Pug, а можно отформатировать строку в других местах. Использование виртуального свойства позволяет получить дату, отформатированную точно так же, как при помощи `due_date`. ## Установка moment @@ -34,7 +35,8 @@ BookInstanceSchema.virtual("due_back_formatted").get(function () { }); ``` -> **Примечание:** Метод format method может вывести дату почти по любому образцу. Синтаксис для представления различных составляющих даты можно найти в документации ( [moment documentation](http://momentjs.com/docs/#/displaying/)). +> [!NOTE] +> Метод `format` может вывести дату почти в любом формате. Синтаксис для представления различных составляющих даты можно найти в [документации](http://momentjs.com/docs/#/displaying/). ## Обновляем представление diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/genre_detail_page/index.md b/files/ru/learn/server-side/express_nodejs/displaying_data/genre_detail_page/index.md index f079159c2d0e27..da1249dd0d08d3 100644 --- a/files/ru/learn/server-side/express_nodejs/displaying_data/genre_detail_page/index.md +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/genre_detail_page/index.md @@ -54,7 +54,8 @@ exports.genre_detail = function (req, res, next) { 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 })`. -> **Примечание:** If the genre does not exist in the database (i.e. it may have been deleted) then `findById()` will return successfully with no results. In this case we want to display a "not found" page, so we create an `Error` object and pass it to the `next` middleware function in the chain. +> [!NOTE] +> If the genre does not exist in the database (i.e. it may have been deleted) then `findById()` will return successfully with no results. In this case we want to display a "not found" page, so we create an `Error` object and pass it to the `next` middleware function in the chain. > > ```js > if (results.genre == null) { @@ -102,7 +103,8 @@ Run the application and open your browser to . Select th ![Genre Detail Page - Express Local Library site](locallibary_express_genre_detail.png) -> **Примечание:** You might get an error similar to this: +> [!NOTE] +> You might get an error similar to this: > > ```bash > Cast to ObjectId failed for value " 59347139895ea23f9430ecbb" at path "_id" for model "Genre" diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/home_page/index.md b/files/ru/learn/server-side/express_nodejs/displaying_data/home_page/index.md index 891cc6082325c2..9973389cc2a8c7 100644 --- a/files/ru/learn/server-side/express_nodejs/displaying_data/home_page/index.md +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/home_page/index.md @@ -9,7 +9,8 @@ l10n: Мы уже создали маршрут для главной страницы. теперь необходимо обновить функции контроллера, чтобы он получал количество записей из базы данных и создавал представление (шаблон), который можно использовать для отображения страницы. -> **Примечание:** Мы будем использовать Mongoose для получения информации из базы данных. +> [!NOTE] +> Мы будем использовать Mongoose для получения информации из базы данных. > Поэтому перед продолжением чтения может быть полезным ознакомится с [Учебником по Mongoose](/ru/docs/Learn/Server-side/Express_Nodejs/mongoose#учебник_по_mongoose). ## Маршрут @@ -125,7 +126,8 @@ block content Под заголовком _Dynamic content_ мы выводим данные о количестве записей в каждой модели. Обратите внимание, что значения в шаблоне — это ключи из объекта, который мы передали в функцию `render()`. -> **Примечание:** Мы не экранируем значения счётчиков (то есть мы используем синтаксис `!{}`) потому что эти значения рассчитываются системой. Если же информация поступает от пользователей, то мы должны экранировать переменные. +> [!NOTE] +> Мы не экранируем значения счётчиков (то есть мы используем синтаксис `!{}`) потому что эти значения рассчитываются системой. Если же информация поступает от пользователей, то мы должны экранировать переменные. ## Как это будет выглядеть? @@ -133,7 +135,8 @@ block content ![Главная страница - Сайт LocalLibrary](locallibary_express_home.png) -> **Примечание:** Вы пока не сможете использовать ссылки в боковой панели, потому что это ещё не реализовано. Если вы попробуете, то получите ошибки вида «NOT IMPLEMENTED: Book list». +> [!NOTE] +> Вы пока не сможете использовать ссылки в боковой панели, потому что это ещё не реализовано. Если вы попробуете, то получите ошибки вида «NOT IMPLEMENTED: Book list». ## Следующие шаги diff --git a/files/ru/learn/server-side/express_nodejs/displaying_data/template_primer/index.md b/files/ru/learn/server-side/express_nodejs/displaying_data/template_primer/index.md index fb9e99e617e8bd..751b9050489f11 100644 --- a/files/ru/learn/server-side/express_nodejs/displaying_data/template_primer/index.md +++ b/files/ru/learn/server-side/express_nodejs/displaying_data/template_primer/index.md @@ -11,7 +11,8 @@ slug: Learn/Server-side/Express_Nodejs/Displaying_data/Template_primer Разные языки шаблонов используют различные подходы для определения внешнего вида и разметки позиций для данных—некоторые используют HTML для определения внешнего вида, тогда как другие применяют различные форматы разметки, которые затем должны компилироваться в HTML. Pug - второго типа; он использует _представление_ (_representation)_ HTML, в котором первое слово в каждой строке обычно представляет элемент HTML, а отступы в следующих строках применяются, чтобы представить вложенные элементы. Результатом является определение страницы, которое транслируется непосредственно в HTML, и которое, вероятно, более краткое и легче читается. -> **Примечание:** недостаток применения _Pug_ - это чувствительность к отступам и пробелам (если добавить лишний пробел в "плохом" месте, можно получить невразумительный код ошибки). Однако, если ваши шаблоны уже действуют, их очень легко читать и поддерживать. +> [!NOTE] +> Недостаток применения _Pug_ - это чувствительность к отступам и пробелам (если добавить лишний пробел в "плохом" месте, можно получить невразумительный код ошибки). Однако, если ваши шаблоны уже действуют, их очень легко читать и поддерживать. ## Конфигурация шаблона @@ -98,7 +99,8 @@ p This is a line with #[em some emphasis] and #[strong strong text] markup. p This line has an un-escaped string: !{' is emphasised'}, an escaped string: #{' is not emphasised'}, and escaped variables: #{title}. ``` -> **Примечание:** Почти всегда желательно экранировать данные, полученные от пользователей (при помощи синтаксиса **`#{}`** ). Данные, которым можно верить (т.е. подсчитанное количество записей, могут быть выведены без экранирования значений. +> [!NOTE] +> Почти всегда желательно экранировать данные, полученные от пользователей (при помощи синтаксиса **`#{}`** ). Данные, которым можно верить (т.е. подсчитанное количество записей, могут быть выведены без экранирования значений. Можно использовать символ конвейера ('**|**') в начале строки, чтобы отметить простой текст ("[plain text](https://pugjs.org/language/plain-text.html)"). Например, дополнительный текст, приведённый ниже, будет показан в той же строке, что и предыдущий, но не будет относиться к ссылке. diff --git a/files/ru/learn/server-side/express_nodejs/forms/create_bookinstance_form/index.md b/files/ru/learn/server-side/express_nodejs/forms/create_bookinstance_form/index.md index 659a08d6fdf12e..7ba748ea66e8a6 100644 --- a/files/ru/learn/server-side/express_nodejs/forms/create_bookinstance_form/index.md +++ b/files/ru/learn/server-side/express_nodejs/forms/create_bookinstance_form/index.md @@ -151,7 +151,8 @@ block content The view structure and behaviour is almost the same as for the **book_form.pug** template, so we won't go over it again. -> **Примечание:** The above template hard-codes the _Status_ values (Maintenance, Available, etc.) and does not "remember" the user's entered values. Should you so wish, consider reimplementing the list, passing in option data from the controller and setting the selected value when the form is re-displayed. +> [!NOTE] +> The above template hard-codes the _Status_ values (Maintenance, Available, etc.) and does not "remember" the user's entered values. Should you so wish, consider reimplementing the list, passing in option data from the controller and setting the selected value when the form is re-displayed. ## Как это выглядит? diff --git a/files/ru/learn/server-side/express_nodejs/forms/delete_author_form/index.md b/files/ru/learn/server-side/express_nodejs/forms/delete_author_form/index.md index a8e0549a030085..9fad844fbd40da 100644 --- a/files/ru/learn/server-side/express_nodejs/forms/delete_author_form/index.md +++ b/files/ru/learn/server-side/express_nodejs/forms/delete_author_form/index.md @@ -44,7 +44,8 @@ exports.author_delete_get = function (req, res, next) { Контроллер получает id экземпляра `Author` для удаления из параметра URL (`req.params.id`). Он использует метод `async.parallel()` , чтобы получить запись автора и параллельно вс связанные книги. Когда оба параметра авершины, он рендерит страницу **`author_delete`**.pug, передаёт значения для `title`, `author`, и `author_books`. -> **Примечание:** Если `findById()` не возвращает результатов, то автор отсутствует в базе данных. В этом случае удалять нечего, поэтому сразу выводим список всех авторов. +> [!NOTE] +> Если `findById()` не возвращает результатов, то автор отсутствует в базе данных. В этом случае удалять нечего, поэтому сразу выводим список всех авторов. > > ```js > }, function(err, results) { @@ -100,7 +101,8 @@ exports.author_delete_post = function (req, res, next) { Сначала мы проверяем, что был предоставлен id (он отправляется через параметры тела формы, а не через версию в URL). Затем мы получаем автора и связанные с ним книги так же, как и для маршрута `GET`. Если книг нет, то удаляем объект автора и перенаправляем в список всех авторов. Если есть ещё книги, то мы просто перерисовываем форму, передавая автора и список книг, которые нужно удалить. -> **Примечание:** Мы можем проверить, возвращает ли вызов `findbyid ()` какой-либо результат, и если нет, немедленно отобразить список всех авторов.Для краткости мы оставили код как есть выше (он всё равно вернёт список авторов, если id не будет найден, но это произойдёт после `findByIdAndRemove()`). +> [!NOTE] +> Мы можем проверить, возвращает ли вызов `findbyid ()` какой-либо результат, и если нет, немедленно отобразить список всех авторов.Для краткости мы оставили код как есть выше (он всё равно вернёт список авторов, если id не будет найден, но это произойдёт после `findByIdAndRemove()`). ## View @@ -146,7 +148,8 @@ block content Затем мы добавим элемент управления `Delete` в представление сведений об авторе (страница сведений-хорошее место для удаления записи). -> **Примечание:** В полном объёме контроль будет доступен только авторизованным пользователям. Однако на данный момент у нас нет системы авторизации! +> [!NOTE] +> В полном объёме контроль будет доступен только авторизованным пользователям. Однако на данный момент у нас нет системы авторизации! Откройте **author_detail.pug** и добавьте следующие строки внизу. @@ -172,7 +175,8 @@ p ![](locallibary_express_author_delete_withbooks.png) -> **Примечание:** Другие страницы для удаления объектов могут быть реализованы примерно таким же образом. Мы оставили это как задачи. +> [!NOTE] +> Другие страницы для удаления объектов могут быть реализованы примерно таким же образом. Мы оставили это как задачи. ## Next steps diff --git a/files/ru/learn/server-side/express_nodejs/forms/index.md b/files/ru/learn/server-side/express_nodejs/forms/index.md index 318c4fa9a6a1e9..48441456bb6aed 100644 --- a/files/ru/learn/server-side/express_nodejs/forms/index.md +++ b/files/ru/learn/server-side/express_nodejs/forms/index.md @@ -19,7 +19,8 @@ slug: Learn/Server-side/Express_Nodejs/forms В этом уроке мы покажем вам, как вышеуказанные операции могут быть выполнены в _Express_. По пути мы расширим веб-сайт _LocalLibrary_, чтобы пользователи могли создавать, редактировать и удалять элементы из библиотеки. -> **Примечание:** Мы не рассматривали, как ограничить определённые маршруты аутентифицированными или авторизованными пользователями, поэтому на данный момент любой пользователь сможет вносить изменения в базу данных. +> [!NOTE] +> Мы не рассматривали, как ограничить определённые маршруты аутентифицированными или авторизованными пользователями, поэтому на данный момент любой пользователь сможет вносить изменения в базу данных. ### HTML Forms @@ -121,7 +122,8 @@ const { sanitizeBody } = require("express-validator/filter"); .isAlpha().withMessage('Name must be alphabet letters.'), ``` - > **Примечание:** Вы также можете добавить встроенные средства очистки, такие как `trim()`, как показано выше. Однако средства очистки, применяемые здесь, применяются только к шагу проверки. Если требуется очистить конечный результат, необходимо использовать отдельный метод очистки, как показано ниже. + > [!NOTE] + > Вы также можете добавить встроенные средства очистки, такие как `trim()`, как показано выше. Однако средства очистки, применяемые здесь, применяются только к шагу проверки. Если требуется очистить конечный результат, необходимо использовать отдельный метод очистки, как показано ниже. - [`sanitizeBody(fields)`](https://github.com/ctavan/express-validator#sanitizebodyfields): Задаёт поле тела для очистки. затем операции очистки последовательно соединяются с этим методом. Например, операция очистки `escape()`, описанная ниже, удаляет символы HTML из переменной name, которые могут использоваться в атаках сценариев между сайтами JavaScript. @@ -164,7 +166,8 @@ const { sanitizeBody } = require("express-validator/filter"); - Создайте объект, используя объекты, которые уже существуют (таким образом, пользователи должны будут создать все необходимые экземпляры автора и жанра, прежде чем пытаться создать любые объекты книги). - Удалите объект, если на него не ссылаются другие объекты (например, вы не сможете удалить книгу, пока не будут удалены все связанные объекты BookInstance). -> **Примечание:** Более" надёжная " реализация может позволить создавать зависимые объекты при создании нового объекта и удалять любой объект в любое время (например, путём удаления зависимых объектов или путём удаления ссылок на удалённый объект из базы данных). +> [!NOTE] +> Более надёжная реализация может позволить создавать зависимые объекты при создании нового объекта и удалять любой объект в любое время (например, путём удаления зависимых объектов или путём удаления ссылок на удалённый объект из базы данных). ### Маршруты diff --git a/files/ru/learn/server-side/express_nodejs/forms/update_book_form/index.md b/files/ru/learn/server-side/express_nodejs/forms/update_book_form/index.md index d8ba676a8fa34d..a1375e049dd553 100644 --- a/files/ru/learn/server-side/express_nodejs/forms/update_book_form/index.md +++ b/files/ru/learn/server-side/express_nodejs/forms/update_book_form/index.md @@ -187,7 +187,8 @@ exports.book_update_post = [ option(value=author._id) #{author.name} ``` -> **Примечание:** Это изменение кода необходимо для того, чтобы форму book_form можно было использовать как для создания, так и для обновления объектов book (без этого при создании формы на маршруте `GET` возникает ошибка). +> [!NOTE] +> Это изменение кода необходимо для того, чтобы форму book_form можно было использовать как для создания, так и для обновления объектов book (без этого при создании формы на маршруте `GET` возникает ошибка). ## Добавить кнопку обновления @@ -211,7 +212,8 @@ exports.book_update_post = [ ![](locallibary_express_book_update_noerrors.png) -> **Примечание:** Другие страницы для обновления объектов могут быть реализованы примерно таким же образом. Мы оставили это как задание. +> [!NOTE] +> Другие страницы для обновления объектов могут быть реализованы примерно таким же образом. Мы оставили это как задание. ## Next steps diff --git a/files/ru/learn/server-side/express_nodejs/index.md b/files/ru/learn/server-side/express_nodejs/index.md index 5f2b0fd11fa3e0..77bd8d6d1d03ad 100644 --- a/files/ru/learn/server-side/express_nodejs/index.md +++ b/files/ru/learn/server-side/express_nodejs/index.md @@ -11,7 +11,8 @@ Express представляет собой популярный веб-фрей Перед началом этого модуля вам необходимо представлять, что из себя представляет серверное программирование и веб-фреймворки, желательно из прочтения статей другого модуля [Server-side website programming first steps](/ru/docs/Learn/Server-side/First_steps). Знакомство с основными концепциями программирования и языком программирования [JavaScript](/ru/docs/Web/JavaScript) будет очень полезным, но оно не является обязательным для понимания базовых понятий этого модуля. -> **Примечание:** Этот веб-сайт содержит множество источников для изучения JavaScript _в контексте разработки на стороне клиента_: [JavaScript](/ru/docs/Web/JavaScript), [JavaScript Guide](/ru/docs/Web/JavaScript/Guide), [JavaScript Basics](/ru/docs/Learn/Getting_started_with_the_web/JavaScript_basics), [JavaScript](/ru/docs/Learn/JavaScript) (изучение). Ключевые особенности и концепции языка JavaScript остаются сходными и для серверной разработки на Node.js и используемый материал достаточно релевантен. Node.js предоставляет [additional APIs](https://nodejs.org/dist/latest-v6.x/docs/api/) для обеспечения функциональности, которая полезна для "безбраузерной" разработки, т.е. для создания HTTP-сервера и доступа к файловой системе, но не поддерживает JavaScript APIs для работы с браузером и DOM. +> [!NOTE] +> Этот веб-сайт содержит множество источников для изучения JavaScript _в контексте разработки на стороне клиента_: [JavaScript](/ru/docs/Web/JavaScript), [JavaScript Guide](/ru/docs/Web/JavaScript/Guide), [JavaScript Basics](/ru/docs/Learn/Getting_started_with_the_web/JavaScript_basics), [JavaScript](/ru/docs/Learn/JavaScript) (изучение). Ключевые особенности и концепции языка JavaScript остаются сходными и для серверной разработки на Node.js и используемый материал достаточно релевантен. Node.js предоставляет [additional APIs](https://nodejs.org/dist/latest-v6.x/docs/api/) для обеспечения функциональности, которая полезна для "безбраузерной" разработки, т.е. для создания HTTP-сервера и доступа к файловой системе, но не поддерживает JavaScript APIs для работы с браузером и DOM. > > Это руководство обеспечит вас некоторой информацией о работе с Node.js и Express, но также существуют и другие многочисленные отличные ресурсы в Интернете и книгах — некоторые из них доступны из тем [How do I get started with Node.js](http://stackoverflow.com/a/5511507/894359) (StackOverflow) и [What are the best resources for learning Node.js?](https://www.quora.com/What-are-the-best-resources-for-learning-Node-js?) (Quora). diff --git a/files/ru/learn/server-side/express_nodejs/introduction/index.md b/files/ru/learn/server-side/express_nodejs/introduction/index.md index 44925c6a53007e..f00b5dd13b1a32 100644 --- a/files/ru/learn/server-side/express_nodejs/introduction/index.md +++ b/files/ru/learn/server-side/express_nodejs/introduction/index.md @@ -85,7 +85,8 @@ node hello.js В то время как сам express довольно минималистичный, разработчики создали совместимые пакеты промежуточного программного обеспечения для решения практически любой проблемы с веб-разработкой. Существуют библиотеки для работы с куки-файлами, сеансами, входами пользователей, параметрами URL, данными POST, заголовками безопасности и многими другими. Вы можете найти список пакетов промежуточного программного обеспечения, поддерживаемых командой Express в [Express Middleware](http://expressjs.com/en/resources/middleware.html) (наряду со списком некоторых популярных пакетов сторонних производителей) . -> **Примечание:** Гибкость это палка о двух концах. Существуют пакеты промежуточного программного обеспечения (middleware) для решения практически любых проблем или для удовлетворения любых ваших требований, но правильный выбор подходящих пакетов иногда может быть проблемой. Также нет «правильного пути» для структурирования приложения, и многие примеры, которые вы можете найти в Интернете, не являются оптимальными или лишь показывают небольшую часть того, что вам нужно сделать для разработки веб-приложения. +> [!NOTE] +> Гибкость это палка о двух концах. Существуют пакеты промежуточного программного обеспечения (middleware) для решения практически любых проблем или для удовлетворения любых ваших требований, но правильный выбор подходящих пакетов иногда может быть проблемой. Также нет «правильного пути» для структурирования приложения, и многие примеры, которые вы можете найти в Интернете, не являются оптимальными или лишь показывают небольшую часть того, что вам нужно сделать для разработки веб-приложения. ## Откуда это все взялось? @@ -123,7 +124,8 @@ Express предоставляет методы позволяющие указ Сначала давайте рассмотрим стандартный пример Express Hello World (мы обсудим каждую часть этого ниже и в следующих разделах). -> **Примечание:** Совет: Если у вас уже установлены Node и Express (или если вы устанавливаете их, как показано в следующей статье), вы можете сохранить этот код в файле с именем app.js и запустить его в командной строке, вызвав узел app.js. отражения). +> [!NOTE] +> Совет: Если у вас уже установлены Node и Express (или если вы устанавливаете их, как показано в следующей статье), вы можете сохранить этот код в файле с именем app.js и запустить его в командной строке, вызвав узел app.js. отражения). ```js var express = require("express"); @@ -157,7 +159,8 @@ var app = express(); Вы также можете создавать свои собственные модули, которые можно импортировать таким же образом. -> **Примечание:** Совет: вы захотите создать свои собственные модули, потому что это позволяет вам организовать ваш код в управляемые части - монолитное однофайловое приложение трудно понять и поддерживать. Использование модулей также помогает вам управлять пространством имён, поскольку при использовании модуля импортируются только те переменные, которые вы явно экспортировали. +> [!NOTE] +> Совет: вы захотите создать свои собственные модули, потому что это позволяет вам организовать ваш код в управляемые части - монолитное однофайловое приложение трудно понять и поддерживать. Использование модулей также помогает вам управлять пространством имён, поскольку при использовании модуля импортируются только те переменные, которые вы явно экспортировали. Чтобы сделать объекты доступными вне модуля, вам просто нужно назначить их объекту экспорта. Например, модуль square.js ниже представляет собой файл, который экспортирует методы area () и perimeter (): @@ -177,7 +180,8 @@ var square = require("./square"); // Here we require() the name of the file with console.log("The area of a square with a width of 4 is " + square.area(4)); ``` -> **Примечание:** Примечание. Вы также можете указать абсолютный путь к модулю (или имя, как мы делали изначально). +> [!NOTE] +> Вы также можете указать абсолютный путь к модулю (или имя, как мы делали изначально). Если вы хотите экспортировать полный объект в одном назначении, а не создавать его по одному свойству за раз, назначьте его для module.exports, как показано ниже (вы также можете сделать это, чтобы сделать корень объекта экспорта конструктором или другой функцией) : @@ -217,9 +221,11 @@ console.log("Second"); Есть несколько способов, которыми асинхронный API уведомляет ваше приложение о том, что оно завершено. Наиболее распространённый способ - зарегистрировать колбэк-функцию при вызове асинхронного API, который будет вызываться после завершения операции. Это подход, использованный выше. -> **Примечание:** Совет: Использование колбэков может быть довольно «грязным», если у вас есть последовательность зависимых асинхронных операций, которые должны выполняться по порядку, потому что это приводит к нескольким уровням вложенных колбэков. Эта проблема широко известна как «ад колбэков». Эту проблему можно решить с помощью хороших методов кодирования (см. ), использования такого модуля, как async, или даже перехода к функциям ES6, таким как Promises. +> [!NOTE] +> Совет: Использование колбэков может быть довольно «грязным», если у вас есть последовательность зависимых асинхронных операций, которые должны выполняться по порядку, потому что это приводит к нескольким уровням вложенных колбэков. Эта проблема широко известна как «ад колбэков». Эту проблему можно решить с помощью хороших методов кодирования (см. ), использования такого модуля, как async, или даже перехода к функциям ES6, таким как Promises. -> **Примечание:** Примечание. Общим соглашением для Node и Express является использование колбэков с ошибками. В этом соглашении первое значение в ваших колбэк-функциях является значением ошибки, в то время как последующие аргументы содержат данные об успехе. В этом блоге есть хорошее объяснение того, почему этот подход полезен: путь Node.js - понимание колбэков с ошибками (fredkschott.com). +> [!NOTE] +> Общим соглашением для Node и Express является использование колбэков с ошибками. В этом соглашении первое значение в ваших колбэк-функциях является значением ошибки, в то время как последующие аргументы содержат данные об успехе. В этом блоге есть хорошее объяснение того, почему этот подход полезен: путь Node.js - понимание колбэков с ошибками (fredkschott.com). ### Создание обработчиков маршрута @@ -233,7 +239,8 @@ app.get("/", function (req, res) { Колбэк-функция принимает запрос и объект ответа в качестве аргументов. В этом случае метод просто вызывает send () в ответе, чтобы вернуть строку «Hello World!» Существует ряд других методов ответа для завершения цикла запрос / ответ, например, вы можете вызвать res.json () для отправки ответа JSON или res.sendFile () для отправки файла. -> **Примечание:** Совет по JavaScript: вы можете использовать любые имена аргументов, которые вам нравятся, в колбэк-функциях; при вызове колбэка первый аргумент всегда будет запросом, а второй всегда будет ответом. Имеет смысл назвать их так, чтобы вы могли идентифицировать объект, с которым работаете, в теле колбэка. +> [!NOTE] +> Совет по JavaScript: вы можете использовать любые имена аргументов, которые вам нравятся, в колбэк-функциях; при вызове колбэка первый аргумент всегда будет запросом, а второй всегда будет ответом. Имеет смысл назвать их так, чтобы вы могли идентифицировать объект, с которым работаете, в теле колбэка. Объект приложения 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 (). @@ -269,7 +276,8 @@ router.get("/about", function (req, res) { module.exports = router; ``` -> **Примечание:** Примечание. Добавление маршрутов к объекту Router аналогично добавлению маршрутов к объекту приложения (как показано ранее). +> [!NOTE] +> Добавление маршрутов к объекту Router аналогично добавлению маршрутов к объекту приложения (как показано ранее). Чтобы использовать маршрутизатор в нашем главном файле приложения, нам потребуется () модуль route (wiki.js), а затем вызовите use () в приложении Express, чтобы добавить маршрутизатор в путь обработки промежуточного программного обеспечения. Эти два маршрута будут доступны из / wiki / и / wiki / about /. @@ -285,7 +293,8 @@ app.use("/wiki", wiki); Промежуточное программное обеспечение широко используется в приложениях Express для задач от обслуживания статических файлов до обработки ошибок и сжатия HTTP-ответов. Принимая во внимание, что функции маршрута заканчивают цикл запроса-ответа HTTP, возвращая некоторый ответ клиенту HTTP, функции промежуточного программного обеспечения обычно выполняют некоторую операцию над запросом или ответом и затем вызывают следующую функцию в «стеке», которая может быть большим количеством промежуточного программного обеспечения или маршрута обработчик. Порядок вызова промежуточного программного обеспечения зависит от разработчика приложения. -> **Примечание:** Примечание. Промежуточное программное обеспечение может выполнять любую операцию, выполнять любой код, вносить изменения в объект запроса и ответа, а также может завершать цикл запрос-ответ. Если он не завершает цикл, он должен вызвать next (), чтобы передать управление следующей функции промежуточного программного обеспечения (или запрос останется зависшим). +> [!NOTE] +> Промежуточное программное обеспечение может выполнять любую операцию, выполнять любой код, вносить изменения в объект запроса и ответа, а также может завершать цикл запрос-ответ. Если он не завершает цикл, он должен вызвать next (), чтобы передать управление следующей функции промежуточного программного обеспечения (или запрос останется зависшим). Большинство приложений используют стороннее промежуточное программное обеспечение для упрощения общих задач веб-разработки, таких как работа с файлами cookie, сессиями, аутентификацией пользователя, доступом к данным запросов POST и JSON, ведение журнала и т. д. Список пакетов промежуточного программного обеспечения, поддерживаемых командой Express, можно найти. (который также включает в себя другие популярные сторонние пакеты). Другие экспресс-пакеты доступны в диспетчере пакетов NPM. @@ -305,7 +314,8 @@ app.use(logger('dev')); ... ``` -> **Примечание:** Примечание. Промежуточное программное обеспечение и функции маршрутизации вызываются в том порядке, в котором они были объявлены. Для некоторого промежуточного программного обеспечения важен порядок (например, если промежуточное программное обеспечение сеанса зависит от промежуточного программного обеспечения cookie, то сначала должен быть добавлен обработчик cookie). Почти всегда случается так, что промежуточное ПО вызывается перед настройкой маршрутов, иначе ваши обработчики маршрутов не будут иметь доступа к функциям, добавленным вашим промежуточным ПО. +> [!NOTE] +> Промежуточное программное обеспечение и функции маршрутизации вызываются в том порядке, в котором они были объявлены. Для некоторого промежуточного программного обеспечения важен порядок (например, если промежуточное программное обеспечение сеанса зависит от промежуточного программного обеспечения cookie, то сначала должен быть добавлен обработчик cookie). Почти всегда случается так, что промежуточное ПО вызывается перед настройкой маршрутов, иначе ваши обработчики маршрутов не будут иметь доступа к функциям, добавленным вашим промежуточным ПО. Вы можете написать свои собственные функции промежуточного программного обеспечения, и вам, вероятно, придётся это сделать (хотя бы для создания кода обработки ошибок). Единственное различие между функцией промежуточного программного обеспечения и обратным вызовом обработчика маршрута состоит в том, что функции промежуточного программного обеспечения имеют третий аргумент, следующий: какие функции промежуточного программного обеспечения должны вызываться, если они не завершают цикл запроса (когда вызывается функция промежуточного программного обеспечения, она содержит следующую функцию). это надо называть). @@ -335,7 +345,8 @@ app.get("/", a_middleware_function); app.listen(3000); ``` -> **Примечание:** Совет по JavaScript: выше мы объявляем функцию промежуточного программного обеспечения отдельно, а затем устанавливаем её в качестве колбэка. В нашей предыдущей функции обработчика маршрута мы объявили колбэк-функцию, когда она использовалась. В JavaScript любой подход является допустимым. +> [!NOTE] +> Совет по JavaScript: выше мы объявляем функцию промежуточного программного обеспечения отдельно, а затем устанавливаем её в качестве колбэка. В нашей предыдущей функции обработчика маршрута мы объявили колбэк-функцию, когда она использовалась. В JavaScript любой подход является допустимым. Документация по Express содержит намного больше отличной информации по использованию и написанию промежуточного программного обеспечения Express. @@ -394,9 +405,11 @@ app.use(function (err, req, res, next) { Express поставляется со встроенным обработчиком ошибок, который заботится обо всех оставшихся ошибках, которые могут возникнуть в приложении. Эта промежуточная функция обработки ошибок по умолчанию добавляется в конец стека функций промежуточного программного обеспечения. Если вы передаёте ошибку в next () и не обрабатываете её в обработчике ошибок, она будет обработана встроенным обработчиком ошибок; ошибка будет записана клиенту с трассировкой стека. -> **Примечание:** Примечание. Трассировка стека не включена в производственную среду. Чтобы запустить его в производственном режиме, необходимо установить переменную среды NODE_ENV в «производство». +> [!NOTE] +> Трассировка стека не включена в производственную среду. Чтобы запустить его в производственном режиме, необходимо установить переменную среды NODE_ENV в «производство». -> **Примечание:** Примечание. HTTP404 и другие коды состояния «ошибка» не считаются ошибками. Если вы хотите справиться с этим, вы можете добавить функцию промежуточного программного обеспечения для этого. Для получения дополнительной информации см. FAQ. +> [!NOTE] +> HTTP404 и другие коды состояния «ошибка» не считаются ошибками. Если вы хотите справиться с этим, вы можете добавить функцию промежуточного программного обеспечения для этого. Для получения дополнительной информации см. FAQ. Для получения дополнительной информации см. [Error handling](http://expressjs.com/en/guide/error-handling.html) (Express docs). diff --git a/files/ru/learn/server-side/express_nodejs/mongoose/index.md b/files/ru/learn/server-side/express_nodejs/mongoose/index.md index e95abd08380ada..72325acd9c1073 100644 --- a/files/ru/learn/server-side/express_nodejs/mongoose/index.md +++ b/files/ru/learn/server-side/express_nodejs/mongoose/index.md @@ -36,7 +36,8 @@ Express-приложения могут использовать различн Преимущество применения ORM состоит в том, что программисты могут сосредоточиться на объектах JavaScript, а не на семантике базы данных — особенно, если требуется работать с разными базами данных (на одном или разных веб-сайтах). Они также дают очевидное место для валидации и проверки данных. -> **Примечание:** Совет: Применение ODM / ORMs часто приводит к снижению затрат на разработку и обслуживание! Если вы не очень хорошо знакомы с языком запросов базы данных или если производительность не имеет первостепенного значения, следует серьёзно рассмотреть возможность применения ODM. +> [!NOTE] +> Совет: Применение ODM / ORMs часто приводит к снижению затрат на разработку и обслуживание! Если вы не очень хорошо знакомы с языком запросов базы данных или если производительность не имеет первостепенного значения, следует серьёзно рассмотреть возможность применения ODM. ### Какую модель ORM/ODM следует использовать? @@ -60,7 +61,8 @@ Express-приложения могут использовать различн Это сочетание ODM и БД весьма популярно в сообществе Node, частично потому, что система хранения документов и запросов очень похожа на JSON и поэтому знакома разработчикам JavaScript. -> **Примечание:** Не обязательно знать MongoDB, чтобы использовать Mongoose, хотя [документацию Mongoose](http://mongoosejs.com/docs/guide.html) легче использовать и понимать, если вы уже знакомы с MongoDB. +> [!NOTE] +> Не обязательно знать MongoDB, чтобы использовать Mongoose, хотя [документацию Mongoose](http://mongoosejs.com/docs/guide.html) легче использовать и понимать, если вы уже знакомы с MongoDB. Далее показано, как определить и получить доступ к схеме и моделям Mongoose для примера веб-сайта LocalLibrary. @@ -80,17 +82,20 @@ Express-приложения могут использовать различн Также показаны отношения между моделями, включая множественные отношения. Числа на линиях связи показывают максимум и минимум моделей, участвующих отношении. Например, линия между `Book` и `Genre` показывает, что `Book` и `Genre` связаны. Числа на этой линии рядом с моделью `Book` показывают, что жанр может быть связан с любым количеством книг, а числа на другом конце линии рядом с `Genre` отмечают, что книга может быть связана с любым количеством жанров. -> **Примечание:** Как показано в [Учебнике по Mongoose](#Mongoose_Справочник) ниже, часто лучше иметь поле, определяющее отношение между документами (моделями), только в одной модели (обратное отношение можно найти по присвоенному идентификатору `_id` в другой модели). Ниже мы предпочли задать отношения между Book/Genre и между Book/Author в схеме Book, а отношение между Book/BookInstance — в схеме BookInstance. Этот выбор в некотором смысле был произвольным — таким же хорошим мог бы быть выбор другого поля в другой схеме. +> [!NOTE] +> Как показано в [Учебнике по Mongoose](#Mongoose_Справочник) ниже, часто лучше иметь поле, определяющее отношение между документами (моделями), только в одной модели (обратное отношение можно найти по присвоенному идентификатору `_id` в другой модели). Ниже мы предпочли задать отношения между Book/Genre и между Book/Author в схеме Book, а отношение между Book/BookInstance — в схеме BookInstance. Этот выбор в некотором смысле был произвольным — таким же хорошим мог бы быть выбор другого поля в другой схеме. ![Mongoose Library Model with correct cardinality](library_website_-_mongoose_express.png) -> **Примечание:** В следующем разделе дан базовый учебник, в котором объясняется, как задавать и как использовать модели. При чтении обратите внимание, как будут создаваться модели, приведённые на диаграмме. +> [!NOTE] +> В следующем разделе дан базовый учебник, в котором объясняется, как задавать и как использовать модели. При чтении обратите внимание, как будут создаваться модели, приведённые на диаграмме. ## Учебник по Mongoose В этом разделе кратко описано как подключиться к базе MongoDB с помощью Mongoose, как определить схемы и модели, как сформировать основные запросы. -> **Примечание:** На этот учебник значительно повлияло руководство [Mongoose quick start](https://www.npmjs.com/package/mongoose) на _npm_ и [официальная документация](http://mongoosejs.com/docs/guide.html). +> [!NOTE] +> На этот учебник значительно повлияло руководство [Mongoose quick start](https://www.npmjs.com/package/mongoose) на _npm_ и [официальная документация](http://mongoosejs.com/docs/guide.html). ### Установка Mongoose и MongoDB @@ -102,7 +107,8 @@ npm install mongoose Установка _Mongoose_ добавит все зависимости, включая драйвер MongoDB, но не установит саму базу данных. При желании установить сервер MongoDB локально, можно [скачать установочный файл здесь](https://www.mongodb.com/download-center) для своей операционной системы и установить его. Также можно использовать облако MongoDB. -> **Примечание:** В примере для хранения базы данных мы используем облачный сервис [sandbox tier](https://mlab.com/plans/pricing/) ("песочницу"). Это удобно для разработки и имеет смысл для руководства, потому что такой подход делает "установку" базы данных независимой от операционной системы (база данных как веб-сервис — это также подход, который вы можете использовать для своей базы данных, находящейся в реальной эксплуатации). +> [!NOTE] +> В примере для хранения базы данных мы используем облачный сервис [sandbox tier](https://mlab.com/plans/pricing/) ("песочницу"). Это удобно для разработки и имеет смысл для руководства, потому что такой подход делает "установку" базы данных независимой от операционной системы (база данных как веб-сервис — это также подход, который вы можете использовать для своей базы данных, находящейся в реальной эксплуатации). ### Подключение к MongoDB @@ -126,7 +132,8 @@ db.on("error", console.error.bind(console, "MongoDB connection error:")); При помощи `mongoose.connection` можно получить стандартный объект `Connection`. После подключения в экземпляре `Connection` возникает событие open (открыт). -> **Примечание:** Если необходимо создать дополнительные подключения, можно использовать `mongoose.createConnection()`. При этом будут применены те же БД URI (хост, БД, порт, опции и т.д.), что и в `connect()` и будет возвращён объект `Connection`. +> [!NOTE] +> Если необходимо создать дополнительные подключения, можно использовать `mongoose.createConnection()`. При этом будут применены те же БД URI (хост, БД, порт, опции и т.д.), что и в `connect()` и будет возвращён объект `Connection`. ### Определение и создание моделей @@ -134,7 +141,8 @@ db.on("error", console.error.bind(console, "MongoDB connection error:")); Схемы "компилируются " в окончательную модель методом `mongoose.model()`. После создания модели её можно использовать для поиска, создания, обновления и удаления объектов данного типа. -> **Примечание:** Каждой модели соответствует _коллекция_ _документов_ в ДБ MongoDB. Документы будут содержать поля тех типов, которые заданы в модели `Schema`. +> [!NOTE] +> Каждой модели соответствует _коллекция_ _документов_ в ДБ MongoDB. Документы будут содержать поля тех типов, которые заданы в модели `Schema`. #### Определение схем данных @@ -174,7 +182,8 @@ var SomeModel = mongoose.model("SomeModel", SomeModelSchema); Первый аргумент - уникальное имя создаваемой для модели коллекции(Mongoose создаст коллекцию для модели _SomeModel_), второй аргумент - схема, которая используется для создания модели. -> **Примечание:** После создания классов модели они могут применяться для создания, обновления или удаления записей в базе, для выполнения запросов по всем записям или по их подмножествам. Как это делать, будет показано в разделе [Использование моделей](#Using_models), и когда будут создаваться представления. +> [!NOTE] +> После создания классов модели они могут применяться для создания, обновления или удаления записей в базе, для выполнения запросов по всем записям или по их подмножествам. Как это делать, будет показано в разделе [Использование моделей](#Using_models), и когда будут создаваться представления. #### Типы схемы (поля) @@ -251,7 +260,8 @@ Mongoose предусматривает встроенные валидатор Виртуальные свойства - это свойства документа, которые можно читать (get) и задавать (set), но которые не хранятся в MongoDB. Методы "геттеры" полезны для форматирования и соединения полей, а "сеттеры" применяют для декомпозиции отдельных значений на несколько частей перед сохранением в БД. Пример из документации собирает (и разбирает) виртуальное свойство "полное имя" из полей "имя" и "фамилия", что удобнее, чем конструировать полное имя каждый раз, когда оно используется в шаблоне. -> **Примечание:** В библиотеке виртуальное свойство будет применено для определения уникального URL каждой записи в модели по пути и по значению `_id` записи. +> [!NOTE] +> В библиотеке виртуальное свойство будет применено для определения уникального URL каждой записи в модели по пути и по значению `_id` записи. Подробная информация - в разделе [Virtuals](http://mongoosejs.com/docs/guide.html#virtuals) (документация Mongoose). @@ -322,7 +332,8 @@ Athlete.find({ sport: "Tennis" }, "name age", function (err, athletes) { Если задать колбэк-функцию так, как показано выше, запрос будет выполнен немедленно. Однако колбэк-функция будет вызвана только после завершения поиска. -> **Примечание:** Все колбэк-функции в Mongoose используют образец `callback(error, result)`. Если при выполнении запроса возникает ошибка, параметр `error` будет содержать объект error, а `result` будет null. При успешном запросе параметр `error` будет null, а `result` будет содержать результат запроса. +> [!NOTE] +> Все колбэк-функции в Mongoose используют образец `callback(error, result)`. Если при выполнении запроса возникает ошибка, параметр `error` будет содержать объект error, а `result` будет null. При успешном запросе параметр `error` будет null, а `result` будет содержать результат запроса. Если не задать колбэк-функцию, API вернёт переменную типа [Query](http://mongoosejs.com/docs/api.html#query-js). Можно использовать объект запроса, чтобы создать и выполнить свой запрос (с колбэк-функцией) позже, при помощи метода `exec()`. @@ -365,7 +376,8 @@ Athlete. - [`findOne()`](http://mongoosejs.com/docs/api.html#query_Query-findOne): Находит один документ, удовлетворяющий заданному критерию. - [`findByIdAndRemove()`](http://mongoosejs.com/docs/api.html#model_Model.findByIdAndRemove), [`findByIdAndUpdate()`](http://mongoosejs.com/docs/api.html#model_Model.findByIdAndUpdate), [`findOneAndRemove()`](http://mongoosejs.com/docs/api.html#query_Query-findOneAndRemove), [`findOneAndUpdate()`](http://mongoosejs.com/docs/api.html#query_Query-findOneAndUpdate): Находит один документ по `id` или по критерию, а затем или обновляет, или удаляет его. Эти методы весьма полезны для обновления или удаления записей. -> **Примечание:** Есть также метод [`count()`](http://mongoosejs.com/docs/api.html#model_Model.count), который определяет количество записей, соответствующих условию. Он полезен при выполнении подсчётов без фактического извлечения записей. +> [!NOTE] +> Есть также метод [`count()`](http://mongoosejs.com/docs/api.html#model_Model.count), который определяет количество записей, соответствующих условию. Он полезен при выполнении подсчётов без фактического извлечения записей. Запросы полезны и во многих других случаях. Дополнительная информация - в [Queries](http://mongoosejs.com/docs/queries.html) (документация Mongoose). @@ -426,7 +438,8 @@ Story.findOne({ title: "Bob goes sledding" }) }); ``` -> **Примечание:** Внимательные читатели заметили, что автор добавлен к рассказу, но ничего не сделано, чтобы добавить рассказ к массиву рассказов `stories` автора. Как же тогда получить список всех рассказов конкретного автора? Один из возможных вариантов - добавить автора в массив рассказов, но при этом пришлось бы хранить данные об авторах и рассказах в двух местах и поддерживать их актуальность. +> [!NOTE] +> Внимательные читатели заметили, что автор добавлен к рассказу, но ничего не сделано, чтобы добавить рассказ к массиву рассказов `stories` автора. Как же тогда получить список всех рассказов конкретного автора? Один из возможных вариантов - добавить автора в массив рассказов, но при этом пришлось бы хранить данные об авторах и рассказах в двух местах и поддерживать их актуальность. > > Лучше получить `_id` нашего автора _author_, и применить `find()` для поиска этого идентификатора в поле "author" всех рассказов. > @@ -477,7 +490,8 @@ SomeModel.find(callback_function); В этом руководстве мы будем использовать базу данных в "песочнице" ("[sandbox](https://mlab.com/plans/pricing/)") - бесплатный облачный сервис, предоставляемый [mLab](https://mlab.com/welcome/). Такая база не очень подходит для промышленных веб-сайтов, поскольку не имеет избыточности, но она очень удобна для разработки и прототипирования. Мы используем её, так как она бесплатна, её легко установить, и потому что mLab - популярный поставщик _базы данных как сервиса,_ и это может быть разумным выбором для промышленной базы данных (на данный момент другие известные возможности включают [Compose](https://www.compose.com/), [ScaleGrid](https://scalegrid.io/pricing.html) и [MongoDB Atlas](https://www.mongodb.com/cloud/atlas)). -> **Примечание:** При желании можно установить БД MongoDb локально, загрузив и установив [подходящие для вашей системы двоичные файлы](https://www.mongodb.com/download-center). В этом случае приводимые ниже инструкции не изменятся, за исключением URL базы данных, который нужно будет задать для установки соединения. +> [!NOTE] +> При желании можно установить БД MongoDb локально, загрузив и установив [подходящие для вашей системы двоичные файлы](https://www.mongodb.com/download-center). В этом случае приводимые ниже инструкции не изменятся, за исключением URL базы данных, который нужно будет задать для установки соединения. Первым делом надо [создать аккаунт](https://mlab.com/signup/) на mLab (это бесплатно, требует только основных контактных данных и ознакомления с условиями обслуживания). @@ -586,7 +600,8 @@ module.exports = mongoose.model("Author", AuthorSchema); Мы объявим также в схеме AuthorSchema [виртуальное](#Virtual_properties) свойство "url" , которое позволит получить абсолютный URL конкретного экземпляра модели — используем это свойство в шаблонах, если потребуется получить связь с конкретным автором. -> **Примечание:** Объявить в схеме URL как виртуальные свойства - хорошая идея, т.к. URL отдельного элемента при необходимости изменения требует коррекции только в одном месте. +> [!NOTE] +> Объявить в схеме URL как виртуальные свойства - хорошая идея, т.к. URL отдельного элемента при необходимости изменения требует коррекции только в одном месте. > Сейчас связь при помощи этого URL ещё не работает, так как у нас ещё нет кода, поддерживающего маршруты для экземпляров модели. Мы построим его в следующей статье! В конце модуля экспортируется модель. @@ -678,7 +693,8 @@ module.exports = mongoose.model("BookInstance", BookInstanceSchema); 1. Загрузите (или создайте) файл [populatedb.js](https://raw.githubusercontent.com/hamishwillee/express-locallibrary-tutorial/master/populatedb.js) в каталоге _express-locallibrary-tutorial_ (на том же уровне, что и `package.json`). - > **Примечание:** Не обязательно понимать, как работает [populatedb.js](https://raw.githubusercontent.com/hamishwillee/express-locallibrary-tutorial/master/populatedb.js); он просто помещает некоторые данные в базу данных. + > [!NOTE] + > Не обязательно понимать, как работает [populatedb.js](https://raw.githubusercontent.com/hamishwillee/express-locallibrary-tutorial/master/populatedb.js); он просто помещает некоторые данные в базу данных. 2. Введите в корне проекта команду для установки модуля _async,_ который потребуется скрипту populatedb.js (роль async обсудим в следующих руководствах) @@ -694,7 +710,8 @@ module.exports = mongoose.model("BookInstance", BookInstanceSchema); 4. Скрипт должен выполниться до конца, выводя в терминал создаваемые элементы. -> **Примечание:** Откройте свою базу на [Lab](https://mlab.com/home). Вы сможете увидеть коллекции Book, Author, Genre, BookInstance (книги, авторы, жанры, экземпляры книг) и просмотреть содержащиеся в них документы. +> [!NOTE] +> Откройте свою базу на [Lab](https://mlab.com/home). Вы сможете увидеть коллекции Book, Author, Genre, BookInstance (книги, авторы, жанры, экземпляры книг) и просмотреть содержащиеся в них документы. ## Итог diff --git a/files/ru/learn/server-side/express_nodejs/routes/index.md b/files/ru/learn/server-side/express_nodejs/routes/index.md index d4f9554eed46d0..226a074f304416 100644 --- a/files/ru/learn/server-side/express_nodejs/routes/index.md +++ b/files/ru/learn/server-side/express_nodejs/routes/index.md @@ -35,7 +35,8 @@ slug: Learn/Server-side/Express_Nodejs/routes Есть несколько способов создания маршрутов. В этом уроке мы используем промежуточные запросы `express.Router,` так как они позволяют группировать обработчики маршрутов для определённой части сайта и получать к ним доступ через общий префикс маршрута. Все маршруты, связанные с библиотекой, будут сохранены в модуле "catalog", и если мы добавим маршруты для обработки учётных записей пользователей или других функций, мы сможем сгруппировать их отдельно. -> **Примечание:** Маршруты приложения Express уже кратко рассматривались в [Express Introduction > Creating route handlers](/ru/docs/Learn/Server-side/Express_Nodejs/Introduction#Creating_route_handlers) (Введение -> Создание обработчиков маршрутов). Применение _Router_ обеспечивает лучшую поддержку модульности (как обсуждается в первой подсекции ниже), а в остальном очень похоже на определение маршрутов непосредственно в объекте приложения _Express_. +> [!NOTE] +> Маршруты приложения Express уже кратко рассматривались в [Express Introduction > Creating route handlers](/ru/docs/Learn/Server-side/Express_Nodejs/Introduction#Creating_route_handlers) (Введение -> Создание обработчиков маршрутов). Применение _Router_ обеспечивает лучшую поддержку модульности (как обсуждается в первой подсекции ниже), а в остальном очень похоже на определение маршрутов непосредственно в объекте приложения _Express_. В оставшейся части этого раздела представлен обзор того, как Router может быть использован для определения маршрутов. @@ -64,7 +65,8 @@ router.get("/about", function (req, res) { module.exports = router; ``` -> **Примечание:** В примере колбэк-функции обработчиков маршрутов определены непосредственно в функциях роутеров. А в LocalLibrary мы определим эти колбэк-функции в отдельном модуле контроллера. +> [!NOTE] +> В примере колбэк-функции обработчиков маршрутов определены непосредственно в функциях роутеров. А в LocalLibrary мы определим эти колбэк-функции в отдельном модуле контроллера. Чтобы использовать модуль роутера в главном приложении, прежде всего следует выполнить `require()` модуля маршрута (**wiki.js**). Потом вызовем `use()` для приложения Express с аргументом, в котором указан URL-путь 'wiki', что добавит Router к пути обработки промежуточного слоя. @@ -89,7 +91,8 @@ router.get("/about", function (req, res) { Эта колбэк-функция имеет три аргумента takes three arguments (обычно именуемых как указано: `req`, `res`, `next`), которые соответствуют объекту HTTP запроса, ответу HTTP, и _следующей_ функции в цепочке промежуточных элементов. -> **Примечание:** Функции в Router - это промежуточный слой ([middleware](/ru/docs/Learn/Server-side/Express_Nodejs/Introduction#Using_middleware)) are [Express](/ru/docs/Learn/Server-side/Express_Nodejs/Introduction#Using_middleware), что означает, что они должны или завершить (ответить на) запрос reqили вызвать следующую (`next)` функцию в цепочке. В нашем случае запрос завершается вызовом `send()`, поэтому аргумент `next` не нужен (и поэтому не указан). +> [!NOTE] +> Функции в Router - это промежуточный слой ([middleware](/ru/docs/Learn/Server-side/Express_Nodejs/Introduction#Using_middleware)) are [Express](/ru/docs/Learn/Server-side/Express_Nodejs/Introduction#Using_middleware), что означает, что они должны или завершить (ответить на) запрос reqили вызвать следующую (`next)` функцию в цепочке. В нашем случае запрос завершается вызовом `send()`, поэтому аргумент `next` не нужен (и поэтому не указан). > > Выше у функции роутера только один колбэк-аргумент, но можно указать столько таких аргументов, сколько хотите, или указать массив колбэк-функций. каждая из функций - это элемент в цепочке промежуточного слоя, и они будут вызываться в порядке их добавления в цепочку (если предыдущая функция не завершит запрос). @@ -128,7 +131,8 @@ app.get(/.*fish$/, function (req, res) { }) ``` -> **Примечание:** Большинство наших маршрутов для библиотеки будут просто строками, а не образцами строк или регулярными выражениями. Кроме того, будут использоваться параметры маршрутов, что обсуждается в следующем разделе. +> [!NOTE] +> Большинство наших маршрутов для библиотеки будут просто строками, а не образцами строк или регулярными выражениями. Кроме того, будут использоваться параметры маршрутов, что обсуждается в следующем разделе. ### Параметры маршрутов @@ -146,7 +150,8 @@ app.get('/users/:userId/books/:bookId', function (req, res) { Имена параметров пути должны состоять из "символов слова" (A-Z, a-z, 0-9, и \_). -> **Примечание:** URL _/book/create_ будет соответствовать маршрутам вида `/book/:bookId` (и '`create`' станет значением "bookId"). Будет использован первый маршрут, соответствующий введённому URL, поэтому, если необходимо обрабатывать URL вида `/book/create` отдельно, обработчик этого маршрута должен быть расположен до маршрута `/book/:bookId` . +> [!NOTE] +> URL _/book/create_ будет соответствовать маршрутам вида `/book/:bookId` (и '`create`' станет значением "bookId"). Будет использован первый маршрут, соответствующий введённому URL, поэтому, если необходимо обрабатывать URL вида `/book/create` отдельно, обработчик этого маршрута должен быть расположен до маршрута `/book/:bookId` . Для начала этих сведений достаточно - если потребуется, можно найти дополнительную информацию в документации Express: [Basic routing](http://expressjs.com/en/starter/basic-routing.html) (основы маршрутизации) и [Routing guide](http://expressjs.com/en/guide/routing.html) (руководство по маршрутизации). В следующем разделе показано, как задать маршруты и контроллеры для нашей библиотеки LocalLibrary. @@ -165,7 +170,8 @@ app.get('/users/:userId/books/:bookId', function (req, res) { В противоположность этому, другие URL используются для работы с определёнными экземплярами документов и моделей — индивидуальность элементов кодируется в URL (как `` выше). Параметры путей используются для извлечения информации и передачи её в обработчик пути (в следующей статье мы применим этот приём для того, чтобы динамически определять, какую информацию следует получить из БД). Кодирование информации в URL-адресе позволяет обойтись одним маршрутом для каждого ресурса определенного типа (например, можно обойтись одним маршрутом для обработки отображения любой отдельной записи о книге). -> **Примечание:** Express позволяет строить URL любым способом, который вам нравится — можно кодировать информацию в теле URL как показано выше или использовать URL `GET` -запрос с параметрами (например, `/book/?id=6`). Какой бы подход вы не применяли, URL должны быть ясными, логичными и читаемыми (ознакомьтесь с советами [W3C](https://www.w3.org/Provider/Style/URI)). +> [!NOTE] +> Express позволяет строить URL любым способом, который вам нравится — можно кодировать информацию в теле URL как показано выше или использовать URL `GET` -запрос с параметрами (например, `/book/?id=6`). Какой бы подход вы не применяли, URL должны быть ясными, логичными и читаемыми (ознакомьтесь с советами [W3C](https://www.w3.org/Provider/Style/URI)). Далее мы создадим колбэк-функции обработчиков маршрутов и код маршрутов для всех указанных выше URL. @@ -561,7 +567,8 @@ router.get("/", function (req, res) { }); ``` -> **Примечание:** Это первое использование метода ответа [redirect()](https://expressjs.com/en/4x/api.html#res.redirect) . Он делает перенаправление на указанную страницу, и по умолчанию устанавливает код возврата HTTP в "302 Found" (найдено). Если требуется, можно изменить код возврата. Путь можно задавать как абсолютный или как относительный. +> [!NOTE] +> Это первое использование метода ответа [redirect()](https://expressjs.com/en/4x/api.html#res.redirect) . Он делает перенаправление на указанную страницу, и по умолчанию устанавливает код возврата HTTP в "302 Found" (найдено). Если требуется, можно изменить код возврата. Путь можно задавать как абсолютный или как относительный. ### Обновление app.js @@ -583,7 +590,8 @@ app.use("/users", usersRouter); app.use("/catalog", catalogRouter); // Add catalog routes to middleware chain. ``` -> **Примечание:** Мы добавили модуль каталога в путь`'/catalog'`. Этот путь будет предшествовать всем путям, определённым в модуле каталога. Например, для доступа к списку книг URL будет таким: `/catalog/books/`. +> [!NOTE] +> Мы добавили модуль каталога в путь`'/catalog'`. Этот путь будет предшествовать всем путям, определённым в модуле каталога. Например, для доступа к списку книг URL будет таким: `/catalog/books/`. Вот так. Теперь у нас есть пути и фиктивные функции, подготовленные для всех URL, которые мы собираемся поддерживать на веб-сайте LocalLibrary. diff --git a/files/ru/learn/server-side/express_nodejs/skeleton_website/index.md b/files/ru/learn/server-side/express_nodejs/skeleton_website/index.md index ff537a0ecd3e7a..0742a6c984f3c8 100644 --- a/files/ru/learn/server-side/express_nodejs/skeleton_website/index.md +++ b/files/ru/learn/server-side/express_nodejs/skeleton_website/index.md @@ -60,13 +60,15 @@ express Можно выбрать движок представления (шаблон), используя `--view` параметр `--css` позволяет выбрать движок для создания CSS. -> **Примечание:** Другие опции (`--hogan`, `--ejs`, `--hbs` и пр.) для выбора шаблонизатора устарели. Используйте `--view` (или `-v`)! +> [!NOTE] +> Другие опции (`--hogan`, `--ejs`, `--hbs` и пр.) для выбора шаблонизатора устарели. Используйте `--view` (или `-v`)! ### Какой движок представлений следует использовать? `Express-generator` даёт возможность сконфигурировать несколько популярных движков, включая [EJS](https://www.npmjs.com/package/ejs), [Hbs](http://github.com/donpark/hbs), [Pug](https://pugjs.org/api/getting-started.html) (Jade), [Twig](https://www.npmjs.com/package/twig), и [Vash](https://www.npmjs.com/package/vash), но по умолчанию выбран Jade. Экспресс сразу после установки может поддерживать большое количество и других шаблонизаторов. -> **Примечание:** При желании использовать шаблонизатор, который не поддерживается генератором, просмотрите документацию [Using template engines with Express](https://expressjs.com/en/guide/using-template-engines.html) и документацию для нужного шаблонизатора. +> [!NOTE] +> При желании использовать шаблонизатор, который не поддерживается генератором, просмотрите документацию [Using template engines with Express](https://expressjs.com/en/guide/using-template-engines.html) и документацию для нужного шаблонизатора. Как правило, следует выбрать шаблонизатор, который имеет всю необходимую вам функциональность и обеспечивает вам высокую производительность - так же, как вы выбираете любой другой компонент! Некоторые критерии для сравнения шаблонизаторов: @@ -84,7 +86,8 @@ express - Поддержка асинхронных операций и потоковой передачи. - Возможность использования как на клиенте, так и на сервере. Возможность применения движка шаблона на клиенте позволяет обслуживать данные и выполнять все действия или их большую часть на стороне клиента. -> **Примечание:** В интернете множество ресурсов, которые помогут сравнить различные варианты! +> [!NOTE] +> В интернете множество ресурсов, которые помогут сравнить различные варианты! Для этого проекта мы используем шаблонизатор [Pug](https://pugjs.org/api/getting-started.html) (в прошлом назывался Jade) — один из популярнейших Express/JavaScript шаблонизаторов, который поддерживается в Express-generator "из коробки". @@ -92,7 +95,8 @@ express _Express Application Generator_ позволяет создавать проекты, настроенные для применения шаблонизаторов CSS: [LESS](http://lesscss.org/), [SASS](http://sass-lang.com/), [Compass](http://compass-style.org/), [Stylus](http://stylus-lang.com/). -> **Примечание:** простой CSS имеет некоторые ограничения, затрудняющие выполнение задач. Шаблонизаторы CSS позволяют использовать более эффективный подход для создании таблиц стилей CSS, но требуют компиляции файлов таблиц стилей в стандартный CSS для применения в браузере. +> [!NOTE] +> Простой CSS имеет некоторые ограничения, затрудняющие выполнение задач. Шаблонизаторы CSS позволяют использовать более эффективный подход для создании таблиц стилей CSS, но требуют компиляции файлов таблиц стилей в стандартный CSS для применения в браузере. Как и в случае с шаблонизаторами сайта, следует применять шаблонизатор, обеспечивающий высокую производительность работы. В этом проекте мы используем обычный CSS (по умолчанию), поскольку простота наших требований к CSS не оправдает применение чего-то более сложного. @@ -173,7 +177,8 @@ express express-locallibrary-tutorial --view=pug У нас получилось веб-приложение на базе Express, работающее по адресу _localhost:3000_. -> **Примечание:** Можно также запустить приложение командой `npm start`. Переменная DEBUG, указанная в примере, включает логирование в консоль для дальнейшей отладки. Так, при посещении страницы веб-приложения, вы увидите похожий вывод в консоль: +> [!NOTE] +> Можно также запустить приложение командой `npm start`. Переменная DEBUG, указанная в примере, включает логирование в консоль для дальнейшей отладки. Так, при посещении страницы веб-приложения, вы увидите похожий вывод в консоль: > > ```bash > >SET DEBUG=express-locallibrary-tutorial:* & npm start @@ -235,7 +240,8 @@ SET DEBUG=express-locallibrary-tutorial:* & npm run devstart DEBUG=express-locallibrary-tutorial:* npm run devstart ``` -> **Примечание:** Сейчас после изменения любого файла проекта сервер будет перезапускаться (или можно самостоятельно перезапустить его, введя `rs` в командной строке). Вам всё равно придётся обновить страницу в браузере . +> [!NOTE] +> Сейчас после изменения любого файла проекта сервер будет перезапускаться (или можно самостоятельно перезапустить его, введя `rs` в командной строке). Вам всё равно придётся обновить страницу в браузере . > > Теперь мы должны выполнять команду "`npm run` _\_" а не просто `npm start`, поскольку "start", это, по сути, команда NPM, сопоставленная сценарию в файле package.json. Можно заменить команду в сценарии "start", но, так как мы хотим использовать nodemon только во время разработки, разумно создать новую команду сценария. @@ -365,7 +371,8 @@ var index = require("./routes/index"); var users = require("./routes/users"); ``` -> **Примечание:** Здесь мы только импортируем модули. В действительности эти пути ещё не используются — это произойдёт в файле несколько позже. +> [!NOTE] +> Здесь мы только импортируем модули. В действительности эти пути ещё не используются — это произойдёт в файле несколько позже. Далее, импортированные модули express применяются для создания объекта app, который потом устанавливает движки-шаблоны представления. Установка движков состоит их двух частей. В первой мы задаём значение 'view', указывая папку, в которой будут размещаться шаблоны (у нас это /views). Во второй мы задаём значение движка 'view engine', указывая на библиотеку шаблона (у нас — "pug"). @@ -396,7 +403,8 @@ app.use("/", index); app.use("/users", users); ``` -> **Примечание:** . пути, указанные выше ('/' и '`/users'`) рассматриваются как префиксы путей, определённых в импортированных файлах. Так, например, если импортированный модуль users определяет путь для /profile, для доступа следует указать /users/profile. Мы поговорим подробнее о путях в последующей статье. +> [!NOTE] +> Пути, указанные выше ('/' и '`/users'`) рассматриваются как префиксы путей, определённых в импортированных файлах. Так, например, если импортированный модуль users определяет путь для /profile, для доступа следует указать /users/profile. Мы поговорим подробнее о путях в последующей статье. Последняя в файле промежуточная библиотека добавляет методы обработки ошибок и ответов 404 от HTTP. @@ -444,7 +452,8 @@ module.exports = router; Путь определяет колбэк-функцию, которая будет вызвана, когда обнаружится HTTP GET-запрос корректного вида. Образец для сопоставления пути задаётся при импорте модуля — ('`/users`') плюс что-то, определяемое в этом файле ('`/`'). Иными словами, этот путь будет использован, когда получен URL-запрос `/users/`. -> **Примечание:** запустите сервер и задайте в браузере URL `http://localhost:3000/users/`. Вы должны увидеть сообщение: 'respond with a resource'. +> [!NOTE] +> Запустите сервер и задайте в браузере URL `http://localhost:3000/users/`. Вы должны увидеть сообщение: 'respond with a resource'. Стоит отметить, что колбэк-функция имеет третий аргумент - '`next`', т. е. является не простой колбэк-функцией, а колбэк-функцией промежуточного модуля. Пока третий аргумент не используется, но будет полезен в дальнейшем, если мы захотим создать несколько обработчиков пути `'/'`. diff --git a/files/ru/learn/server-side/first_steps/client-server_overview/index.md b/files/ru/learn/server-side/first_steps/client-server_overview/index.md index f023de2d4e0380..5f2cccda4a091d 100644 --- a/files/ru/learn/server-side/first_steps/client-server_overview/index.md +++ b/files/ru/learn/server-side/first_steps/client-server_overview/index.md @@ -45,7 +45,8 @@ slug: Learn/Server-side/First_steps/Client-Server_overview Вы можете сформировать простой `GET` запрос кликнув по ссылке или через поиск по сайту (такой как страница поисковой системы). Например, HTTP-запрос, отправленный во время выполнения запроса "client server overview" на сайте MDN, будет во многом похож на текст ниже (он не будет идентичным, потому что части сообщения зависят от вашего браузера/настроек). -> **Примечание:** Формат HTTP сообщения определён в «веб-стандарте» ([RFC7230](http://www.rfc-editor.org/rfc/rfc7230.txt)). Вам не нужно знать этот уровень детализации, но, по крайней мере, теперь вы знаете, откуда это появилось! +> [!NOTE] +> Формат HTTP сообщения определён в «веб-стандарте» ([RFC7230](http://www.rfc-editor.org/rfc/rfc7230.txt)). Вам не нужно знать этот уровень детализации, но, по крайней мере, теперь вы знаете, откуда это появилось! #### Запрос @@ -171,13 +172,15 @@ X-Cache-Info: not cacheable; request wasn't a GET or HEAD Content-Length: 0 ``` -> **Примечание:** HTTP-ответы и запросы, показанные в этих примерах, были захвачены с помощью приложения [Fiddler](https://www.telerik.com/download/fiddler), но вы можете получить аналогичную информацию с помощью веб-снифферов (например, ) или с помощью расширений браузера, таких как HttpFox. Вы можете попробовать это сами. Воспользуйтесь любым из предложенных инструментов, а затем перейдите по сайту и отредактируйте информацию профиля, чтобы увидеть различные запросы и ответы. В большинстве современных браузеров также есть инструменты, которые отслеживают сетевые запросы (например, инструмент [Network Monitor](/ru/docs/Tools/Network_Monitor) в Firefox). +> [!NOTE] +> HTTP-ответы и запросы, показанные в этих примерах, были захвачены с помощью приложения [Fiddler](https://www.telerik.com/download/fiddler), но вы можете получить аналогичную информацию с помощью веб-снифферов (например, ) или с помощью расширений браузера, таких как HttpFox. Вы можете попробовать это сами. Воспользуйтесь любым из предложенных инструментов, а затем перейдите по сайту и отредактируйте информацию профиля, чтобы увидеть различные запросы и ответы. В большинстве современных браузеров также есть инструменты, которые отслеживают сетевые запросы (например, инструмент [Network Monitor](/ru/docs/Tools/Network_Monitor) в Firefox). ## Статические сайты _Статический сайт_ — это тот, который возвращает тот же жёсткий кодированный контент с сервера всякий раз, когда запрашивается конкретный ресурс. Например, если у вас есть страница о товаре в `/static/myproduct1.html`, эта же страница будет возвращена каждому пользователю. Если вы добавите ещё один подобный товар на свой сайт, вам нужно будет добавить ещё одну страницу (например, `myproduct2.html`) и так далее. Это может стать действительно неэффективным — что происходит, когда вы попадаете на тысячи страниц товаров? Вы повторяли бы много кода на каждой странице (основной шаблон страницы, структуру и т. д.), И если бы вы захотели изменить что-либо в структуре страницы — например, добавить новый раздел «связанные товары» — тогда вам придётся менять каждую страницу отдельно. -> **Примечание:** Статические сайты превосходны, когда у вас небольшое количество страниц и вы хотите отправить один и тот же контент каждому пользователю. Однако их обслуживание может потребовать значительных затрат по мере увеличения количества страниц. +> [!NOTE] +> Статические сайты превосходны, когда у вас небольшое количество страниц и вы хотите отправить один и тот же контент каждому пользователю. Однако их обслуживание может потребовать значительных затрат по мере увеличения количества страниц. Давайте вспомним, как это работает, снова взглянув на диаграмму архитектуры статического сайта, на которую мы смотрели в последней статье. @@ -253,7 +256,8 @@ urlpatterns = [ ] ``` -> **Примечание:** Первые параметры в функциях `url()` могут выглядеть немного необычно (например, `r'^junior/$'`, потому что они используют метод сопоставления шаблонов под названием «регулярные выражения» (RegEx или RE). Вам не нужно знать, как работают регулярные выражения на этом этапе, кроме того, что они позволяют нам сопоставлять шаблоны в URL-адресе (а не жёстко закодированные значения выше) и использовать их в качестве параметров в наших функциях просмотра. В качестве примера, действительно простой RegEx может говорить «соответствовать одной заглавной букве, за которой следуют от 4 до 7 строчных букв». +> [!NOTE] +> Первые параметры в функциях `url()` могут выглядеть немного необычно (например, `r'^junior/$'`, потому что они используют метод сопоставления шаблонов под названием «регулярные выражения» (RegEx или RE). Вам не нужно знать, как работают регулярные выражения на этом этапе, кроме того, что они позволяют нам сопоставлять шаблоны в URL-адресе (а не жёстко закодированные значения выше) и использовать их в качестве параметров в наших функциях просмотра. В качестве примера, действительно простой RegEx может говорить «соответствовать одной заглавной букве, за которой следуют от 4 до 7 строчных букв». Веб-фреймворк также упрощает функцию просмотра для получения информации из базы данных. Структура наших данных определяется в моделях, которые являются классами Python, которые определяют поля, которые должны храниться в основной базе данных. Если у нас есть модель с именем _Team_ с полем «_team_type_», мы можем использовать простой синтаксис запроса, чтобы получить все команды, имеющие определённый тип. diff --git a/files/ru/learn/server-side/first_steps/introduction/index.md b/files/ru/learn/server-side/first_steps/introduction/index.md index 20c5e188b9101f..f1847f80af7f86 100644 --- a/files/ru/learn/server-side/first_steps/introduction/index.md +++ b/files/ru/learn/server-side/first_steps/introduction/index.md @@ -73,7 +73,8 @@ slug: Learn/Server-side/First_steps/Introduction И снова, поскольку и клиентская и серверная части используют фреймворки, области очень разные и, следовательно, фреймворки тоже разные. Фреймворки клиентской части упрощают вёрстку и представление данных, тогда как фреймворки серверной части обеспечивают много «обычной» функциональности веб-сервера, которую вы, возможно, в противном случае, должны были осуществлять самостоятельно (например, поддержка сессий, поддержка пользователей и аутентификация, простой доступ к базе данных, шаблонам библиотек и т. д.). -> **Примечание:** Фреймворки клиентской части часто используются для ускорения написания кода клиентской части, но вы также можете решить писать весь код руками; на самом деле, написание кода руками может быть более быстрым и эффективным, если вам нужен небольшой простой веб-сайт UI. +> [!NOTE] +> Фреймворки клиентской части часто используются для ускорения написания кода клиентской части, но вы также можете решить писать весь код руками; на самом деле, написание кода руками может быть более быстрым и эффективным, если вам нужен небольшой простой веб-сайт UI. > > И, наоборот, вы практически никогда не посмотрите в сторону написания кода серверной части веб-приложения без фреймворка: осуществление жизненно важной функции, такой как HTTP сервер действительно сложно сделать с нуля, скажем, на Python, но веб-фреймворки для Python, такие как Django, обеспечивают это из коробки наряду с другими полезными инструментами. @@ -95,7 +96,8 @@ slug: Learn/Server-side/First_steps/Introduction Из-за того, что информация находится в базе данных, её также можно легко передать и обновить через другие бизнес системы (например, отслеживание). -> **Примечание:** вам не нужно сильно напрягать своё воображение, чтобы увидеть достоинства кода серверной части для эффективного хранения и передачи информации: +> [!NOTE] +> Вам не нужно сильно напрягать своё воображение, чтобы увидеть достоинства кода серверной части для эффективного хранения и передачи информации: > > 1. Зайдите на [Amazon](https://www.amazon.com/) или в другой интернет-магазин. > 2. Введите в поиск несколько ключевых слов и заметьте, как структура страницы не изменилась, тогда как результаты изменились. @@ -128,7 +130,8 @@ slug: Learn/Server-side/First_steps/Introduction - Социальные сети, такие как Facebook, позволяют пользователям полностью контролировать свои данные, но только своим друзьям разрешать просматривать или комментировать их. Пользователь определяет, кто может просматривать его данные и, более того, чьи данные появляются на его стене. Авторизация — центральная часть опыта взаимодействия. - Сайт, на котором вы находитесь прямо сейчас, контролирует доступ к контенту: статьи видны всем, но только авторизованные пользователи могут редактировать контент. Чтобы проверить это, нажмите на кнопку «Редактировать» в верхней части страницы, и, если вы авторизованы, вы увидите редакторский интерфейс, а если нет — вас перенаправит на страницу авторизации. -> **Примечание:** Рассмотрим другие реальные примеры, где доступ к контенту контролируется. Например, что вы можете увидеть, если зайдёте на сайт вашего банка? Авторизуйтесь через вашу учётную запись, и какую дополнительную информацию вы можете просматривать и редактировать? Что за информацию вы можете увидеть, которую может редактировать только банк? +> [!NOTE] +> Рассмотрим другие реальные примеры, где доступ к контенту контролируется. Например, что вы можете увидеть, если зайдёте на сайт вашего банка? Авторизуйтесь через вашу учётную запись, и какую дополнительную информацию вы можете просматривать и редактировать? Что за информацию вы можете увидеть, которую может редактировать только банк? ### Хранение информации о сессии/состоянии @@ -136,7 +139,8 @@ slug: Learn/Server-side/First_steps/Introduction Это позволяет, например, сайту знать, что пользователь был предварительно авторизован и выводить ссылки на его адрес электронной почты или историю заказов или, возможно, сохранить прогресс простой игры, так чтобы пользователь мог вернуться на сайт продолжить с того места, где он закончил. -> **Примечание:** Посетите новостной сайт, у которого есть подписка и откройте ветку тегов (например, [The Age](http://www.theage.com.au/)). Продолжайте посещать сайт в течение нескольких часов/дней. В итоге вас начнёт перенаправлять на страницы, объясняющие, как оформить платную подписку, а сами статьи станут вам недоступны. Эта информация является примером сессии, сохранённой в куки-файлах. +> [!NOTE] +> Посетите новостной сайт, у которого есть подписка и откройте ветку тегов (например, [The Age](http://www.theage.com.au/)). Продолжайте посещать сайт в течение нескольких часов/дней. В итоге вас начнёт перенаправлять на страницы, объясняющие, как оформить платную подписку, а сами статьи станут вам недоступны. Эта информация является примером сессии, сохранённой в куки-файлах. ### Уведомления и средства связи @@ -148,7 +152,8 @@ slug: Learn/Server-side/First_steps/Introduction - Amazon регулярно отправляет письма на электронную почту, предлагающие товары, похожие на те, которые уже были куплены или просматривались вами, которые могут вас заинтересовать. - Веб-сервер может посылать сообщения администратору сайта, предупреждая его о том, что на сервере заканчивается память или о подозрительной активности пользователя. -> **Примечание:** Самый распространённый вид уведомлений – это «подтверждение регистрации». Возьмите почти любой интересующий вас крупный сайт (Google, Amazon, Instagram и т. п.) и создайте новую учётную запись, используя ваш адрес электронной почты. Вскоре вы получите письмо, подтверждающее факт вашей регистрации или содержащее информацию о необходимости активировать вашу учётную запись. +> [!NOTE] +> Самый распространённый вид уведомлений – это «подтверждение регистрации». Возьмите почти любой интересующий вас крупный сайт (Google, Amazon, Instagram и т. п.) и создайте новую учётную запись, используя ваш адрес электронной почты. Вскоре вы получите письмо, подтверждающее факт вашей регистрации или содержащее информацию о необходимости активировать вашу учётную запись. ### Анализ данных @@ -156,7 +161,8 @@ slug: Learn/Server-side/First_steps/Introduction Например, и Amazon, и Google рекламируют товары на основании предыдущих поисков (и покупок). -> **Примечание:** Если вы пользуетесь Facebook, зайдите на вашу стену и посмотрите на ряд постов. Заметьте, что некоторые посты не идут по порядку: в частности, посты с большим количеством «лайков» часто находятся выше по списку, чем остальные. Также взгляните на рекламу, которую вам показывают, вы вероятно увидите рекламу товаров, которые искали на других сайтах. Алгоритм Facebook для выделения контента и рекламы может казаться мистикой, но очевидно, что он зависит от ваших лайков и запросов поиска! +> [!NOTE] +> Если вы пользуетесь Facebook, зайдите на вашу стену и посмотрите на ряд постов. Заметьте, что некоторые посты не идут по порядку: в частности, посты с большим количеством «лайков» часто находятся выше по списку, чем остальные. Также взгляните на рекламу, которую вам показывают, вы вероятно увидите рекламу товаров, которые искали на других сайтах. Алгоритм Facebook для выделения контента и рекламы может казаться мистикой, но очевидно, что он зависит от ваших лайков и запросов поиска! ## Подведение итогов diff --git a/files/ru/learn/server-side/first_steps/web_frameworks/index.md b/files/ru/learn/server-side/first_steps/web_frameworks/index.md index 828bfbd84e4c0b..1b42d3795143c5 100644 --- a/files/ru/learn/server-side/first_steps/web_frameworks/index.md +++ b/files/ru/learn/server-side/first_steps/web_frameworks/index.md @@ -124,7 +124,8 @@ def youngest(request): Например, система шаблонов Django позволяет вам задавать переменные с использованием синтаксиса «двойных велосипедных рулей» (например, `\{{ имя_переменной }}`), которые будут заменены значениями, передаваемыми из функции «view» при отрисовке страницы. Система шаблонов также обеспечивает поддержку выражений (с синтаксисом: `{% выражение %}`), которые позволяют шаблонам выполнять простые операции, такие как повторение значений списка, передаваемых в шаблон. -> **Примечание:** Многие другие системы шаблонов используют аналогичный синтаксис, например: Jinja2 (Python), handlebars (JavaScript), moustache (JavaScript) и т. п. +> [!NOTE] +> Многие другие системы шаблонов используют аналогичный синтаксис, например: Jinja2 (Python), handlebars (JavaScript), moustache (JavaScript) и т. п. Фрагмент кода ниже показывает, как это работает. Продолжая пример «самой молодой команды» из предыдущего раздела, HTML-шаблон передаёт представлению переменную списка `youngest_teams`. Внутри скелета HTML у нас есть выражение, которое сначала проверяет, существует ли переменная `youngest_teams`, а затем повторяет её в цикле `for`. На каждой итерации шаблон отображает значение `team_name` команды в элементе списка. @@ -170,7 +171,8 @@ def youngest(request): Если вы абсолютный новичок в программировании, вы, вероятно, выберете свою среду на основе «простоты обучения». В дополнение к «простоте использования» самого языка, ваши самые ценные ресурсы — это высококачественная документация / учебные пособия и активное сообщество, помогающее новым пользователям. Мы выбрали [Django](https://www.djangoproject.com/) (Python) и [Express](http://expressjs.com/) (Node/JavaScript) для написания наших примеров далее в курсе, главным образом потому, что они просты в освоении и имеют хорошую поддержку. -> **Примечание:** Давайте перейдём к основным веб-сайтам для [Django](https://www.djangoproject.com/) (Python) и [Express](http://expressjs.com/) (Node/JavaScript) и ознакомимся с их документацией и сообществом. +> [!NOTE] +> Давайте перейдём к основным веб-сайтам для [Django](https://www.djangoproject.com/) (Python) и [Express](http://expressjs.com/) (Node/JavaScript) и ознакомимся с их документацией и сообществом. > > 1. Перейдите к основным сайтам (ссылки выше) > @@ -190,7 +192,8 @@ def youngest(request): Фреймворки на стороне сервера, представленные ниже, представляют собой несколько самых популярных из доступных на момент написания. Все они имеют всё, что вам нужно для продуктивной работы — они с открытым исходным кодом, находятся в процессе активной разработки, имеют полные энтузиазма сообщества, создающие документацию и помогающие пользователям на форумах, и используются на большом количестве выдающихся веб-сайтов. Существует также много других замечательных серверных фреймворков, которые вы можете найти с помощью обычного поиска в Интернете. -> **Примечание:** Описания взяты (частично) с веб-сайтов фреймворка! +> [!NOTE] +> Описания взяты (частично) с веб-сайтов фреймворка! ### Django (Python) diff --git a/files/ru/learn/server-side/first_steps/website_security/index.md b/files/ru/learn/server-side/first_steps/website_security/index.md index 20c47c97f20a8e..79b20e3b320181 100644 --- a/files/ru/learn/server-side/first_steps/website_security/index.md +++ b/files/ru/learn/server-side/first_steps/website_security/index.md @@ -31,7 +31,8 @@ slug: Learn/Server-side/First_steps/Website_security XSS (_Cross-Site Scripting_ - Межсайтовый скриптинг) это термин, используемый для описания типа атак, которые позволяют злоумышленнику внедрять вредоносный код _через_ веб-сайт в браузеры других пользователей. Поскольку внедрённый код поступает в браузер с сайта, он является _доверенным_ и может выполнять такие действия, как отправка авторизационного файла *cookie*пользователя злоумышленнику. Когда у злоумышленника есть файл _cookie_, он может войти на сайт, как если бы он был пользователем, и сделать все, что может пользователь, например, получить доступ к данным кредитной карты, просмотреть контактные данные или изменить пароли. -> **Примечание:** Уязвимости XSS исторически встречались чаще, чем любые другие виды угроз безопасности. +> [!NOTE] +> Уязвимости XSS исторически встречались чаще, чем любые другие виды угроз безопасности. Уязвимости XSS делятся на _отражённые_ и _хранимые_, в зависимости от того, как сайт возвращает внедрённый код в браузер. @@ -68,7 +69,8 @@ SELECT * FROM users WHERE name = 'a';DROP TABLE users; SELECT * FROM userinfo WH Чтобы избежать такого рода атак, вы должны убедиться, что любые пользовательские данные, которые передаются в запрос SQL, не могут изменить природу запроса. Один из способов сделать это - экранировать все символы пользовательского ввода, которые имеют особое значение в SQL. -> **Примечание:** Примечание. Инструкция SQL обрабатывает символ ' как начало и конец строкового литерала. Поместив обратную косую черту перед этим символом (\ '), мы экранируем символ и говорим SQL вместо этого трактовать его как символ (только часть строки). +> [!NOTE] +> Инструкция SQL обрабатывает символ ' как начало и конец строкового литерала. Поместив обратную косую черту перед этим символом (\ '), мы экранируем символ и говорим SQL вместо этого трактовать его как символ (только часть строки). В следующей инструкции мы экранируем символ '. Теперь SQL будет интерпретировать имя как всю строку, выделенную жирным шрифтом (это действительно очень странное имя, но безопасное). @@ -112,7 +114,8 @@ CSRF-атаки позволяют злоумышленнику выполнят Почти все эксплойты безопасности, описанные в предыдущих разделах, успешны, когда веб-приложение доверяет данным из браузера. Что бы вы ни делали для повышения безопасности своего веб-сайта, вы должны дезинфицировать все данные, исходящие от пользователей, прежде чем они будут отображаться в браузере, использоваться в запросах SQL или передаваться в вызов операционной системы или файловой системы. -> **Предупреждение:** Внимание! Самый важный урок, который вы можете извлечь о безопасности веб-сайтов: **никогда не доверяйте данным из браузера**. Это включает, помимо прочего, данные в параметрах URL-адресов запросов `GET`, запросов `POST`, заголовков HTTP и файлов cookie, а также файлов, загруженных пользователем. Всегда проверяйте и дезинфицируйте все входящие данные. Всегда предполагайте худшее! +> [!WARNING] +> Внимание! Самый важный урок, который вы можете извлечь о безопасности веб-сайтов: **никогда не доверяйте данным из браузера**. Это включает, помимо прочего, данные в параметрах URL-адресов запросов `GET`, запросов `POST`, заголовков HTTP и файлов cookie, а также файлов, загруженных пользователем. Всегда проверяйте и дезинфицируйте все входящие данные. Всегда предполагайте худшее! Вы можете предпринять ряд других конкретных шагов: