Контакты

Обыкновенный logout html view. Представления log in и log out. Создадаем главную страницу

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

Вы можеть быть даже слышали о шаблонах проектирования и даже листали эти прекрасные книги:

  • Э. Гамма, Р. Хелм, Р. Джонсон, Дж. Влиссидесс «Приемы объектно ориентированного проектирования. Паттерны проектирования»;
  • М. Фаулер «Архитектура корпоративных программных приложений».
А многие, не испугавшись огромных руководств и документаций, пытались изучить какой-либо из современных фреймворков и столкнувшись со сложностью понимания (в силу наличия множества архитектруных концепций хитро увязанных между собой) отложили изучение и применение современных интсрументов в «долгий ящик».

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

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

1. Теория

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

Рассмотрим концептуальную схему шаблона MVC (на мой взгляд — это наиболее удачная схема из тех, что я видел):

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

Типичную последовательность работы MVC-приложения можно описать следующим образом:

  1. При заходе пользователя на веб-ресурс, скрипт инициализации создает экземпляр приложения и запускает его на выполнение.
    При этом отображается вид, скажем главной страницы сайта.
  2. Приложение получает запрос от пользователя и определяет запрошенные контроллер и действие. В случае главной страницы, выполняется действие по умолчанию (index ).
  3. Приложение создает экземпляр контроллера и запускает метод действия,
    в котором, к примеру, содержаться вызовы модели, считывающие информацию из базы данных.
  4. После этого, действие формирует представление с данными, полученными из модели и выводит результат пользователю.
Модель — содержит бизнес-логику приложения и включает методы выборки (это могут быть методы ORM), обработки (например, правила валидации) и предоставления конкретных данных, что зачастую делает ее очень толстой, что вполне нормально.
Модель не должна напрямую взаимодействовать с пользователем. Все переменные, относящиеся к запросу пользователя должны обрабатываться в контроллере.
Модель не должна генерировать HTML или другой код отображения, который может изменяться в зависимости от нужд пользователя. Такой код должен обрабатываться в видах.
Одна и та же модель, например: модель аутентификации пользователей может использоваться как в пользовательской, так и в административной части приложения. В таком случае можно вынести общий код в отдельный класс и наследоваться от него, определяя в наследниках специфичные для подприложений методы.

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

Контроллер — связующее звено, соединяющее модели, виды и другие компоненты в рабочее приложение. Контроллер отвечает за обработку запросов пользователя. Контроллер не должен содержать SQL-запросов. Их лучше держать в моделях. Контроллер не должен содержать HTML и другой разметки. Её стоит выносить в виды.
В хорошо спроектированном MVC-приложении контроллеры обычно очень тонкие и содержат только несколько десятков строк кода. Чего, не скажешь о Stupid Fat Controllers (SFC) в CMS Joomla. Логика контроллера довольно типична и большая ее часть выносится в базовые классы.
Модели, наоборот, очень толстые и содержат большую часть кода, связанную с обработкой данных, т.к. структура данных и бизнес-логика, содержащаяся в них, обычно довольно специфична для конкретного приложения.

1.1. Front Controller и Page Controller

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

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

Рассмотрим два варианта адресной строки, по которым показывается какой-то текст и профиль пользователя.

Первый вариант:

  1. www.example.com/article.php?id=3
  2. www.example.com/user.php?id=4
Здесь каждый сценарий отвечает за выполнение определённой команды.

Второй вариант:

  1. www.example.com/index.php?article=3
  2. www.example.com/index.php?user=4
А здесь все обращения происходят в одном сценарии index.php .

Подход с множеством точек взаимодействия вы можете наблюдать на форумах с движком phpBB. Просмотр форума происходит через сценарий viewforum.php , просмотр топика через viewtopic.php и т.д. Второй подход, с доступом через один физический файл сценария, можно наблюдать в моей любимой CMS MODX, где все обращения проходят черезindex.php .

Эти два подхода совершенно различны. Первый — характерен для шаблона контроллер страниц (Page Controller), а второй подход реализуется паттерном контроллер запросов (Front Controller). Контроллер страниц хорошо применять для сайтов с достаточно простой логикой. В свою очередь, контроллер запросов объединяет все действия по обработке запросов в одном месте, что даёт ему дополнительные возможности, благодаря которым можно реализовать более трудные задачи, чем обычно решаются контроллером страниц. Я не буду вдаваться в подробности реализации контроллера страниц, а скажу лишь, что в практической части будет разработан именно контроллер запросов (некоторое подобие).

1.2. Маршрутизация URL

Маршрутизация URL позволяет настроить приложение на прием запросов с URL, которые не соответствуют реальным файлам приложения, а также использовать ЧПУ , которые семантически значимы для пользователей и предпочтительны для поисковой оптимизации.

К примеру, для обычной страницы, отображающей форму обратной связи, URL мог бы выглядеть так:
http://www.example.com/contacts.php?action=feedback

Приблизительный код обработки в таком случае:
switch ($_GET ["action" ]) { case "about" : require_once ("about.php" ); // страница "О Нас" break ; case "contacts" : require_once ("contacts.php" ); // страница "Контакты" break ; case "feedback" : require_once ("feedback.php" ); // страница "Обратная связь" break ; default : require_once ("page404.php" ); // страница "404" break ; }
Думаю, почти все так раньше делали.

С использованием движка маршрутизации URL вы сможете для отображения той же информации настроить приложение на прием таких запросов:
http://www.example.com/contacts/feedback

Здесь contacts представляет собой контроллер, а feedback — это метод контроллера contacts, отображающий форму обратной связи и т.д. Мы еще вернемся к этому вопросу в практической части.

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

2. Практика

Для начала создадим следующую структуру файлов и папок:

Забегая вперед, скажу, что в папке core будут храниться базовые классы Model, View и Controller.
Их потомки будут храниться в директориях controllers, models и views. Файл index.php это точка в хода в приложение. Файлbootstrap.php инициирует загрузку приложения, подключая все необходимые модули и пр.

Будем идти последовательно; откроем файл index.php и наполним его следующим кодом:
ini_set("display_errors" , 1 ); require_once "application/bootstrap.php" ;
Тут вопросов возникнуть не должно.

Следом, сразу же перейдем к фалу bootstrap.php :
require_once "core/model.php" ; require_once "core/view.php" ; require_once "core/controller.php" ; require_once "core/route.php" ; Route::start(); // запускаем маршрутизатор
Первые три строки будут подключать пока что несуществующие файлы ядра. Последние строки подключают файл с классом маршрутизатора и запускают его на выполнение вызовом статического метода start.

2.1. Реализация маршрутизатора URL

Пока что отклонимся от реализации паттерна MVC и займемся мрашрутизацией. Первый шаг, который нам нужно сделать, записать следующий код в .htaccess :
RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule .* index.php [L]
Этот код перенаправит обработку всех страниц на index.php , что нам и нужно. Помните в первой части мы говорили о Front Controller?!

Маршрутизацию мы поместим в отдельный файл route.php в директорию core. В этом файле опишем класс Route, который будет запускать методы контроллеров, которые в свою очередь будут генерировать вид страниц.

Содержимое файла route.php

class Route { static function start () { // контроллер и действие по умолчанию $controller_name = "Main" ; $action_name = "index" ; $routes = explode("/" , $_SERVER ["REQUEST_URI" ]); // получаем имя контроллера if (!empty ($routes )) { $controller_name = $routes ; } // получаем имя экшена if (!empty ($routes )) { $action_name = $routes ; } // добавляем префиксы $model_name = "Model_" .$controller_name ; $controller_name = "Controller_" .$controller_name ; $action_name = "action_" .$action_name ; // подцепляем файл с классом модели (файла модели может и не быть) $model_file = strtolower($model_name ).".php" ; $model_path = "application/models/" .$model_file ; if (file_exists($model_path )) { include "application/models/" .$model_file ; } // подцепляем файл с классом контроллера $controller_file = strtolower($controller_name ).".php" ; $controller_path = "application/controllers/" .$controller_file ; if (file_exists($controller_path )) { include "application/controllers/" .$controller_file ; } else { /* правильно было бы кинуть здесь исключение, но для упрощения сразу сделаем редирект на страницу 404 */ Route::ErrorPage404(); } // создаем контроллер $controller = new $controller_name ; $action = $action_name ; if (method_exists($controller , $action )) { // вызываем действие контроллера $controller ->$action (); } else { // здесь также разумнее было бы кинуть исключение Route::ErrorPage404(); } } function ErrorPage404 () { $host = "http://" .$_SERVER ["HTTP_HOST" ]."/" ; header("HTTP/1.1 404 Not Found" ); header("Status: 404 Not Found" ); header("Location:" .$host ."404" ); } }


Замечу, что в классе реализована очень упрощенная логика (несмотря на объемный код) и возможно даже имеет проблемы безопасности. Это было сделано намерено, т.к. написание полноценного класса маршрутизации заслуживает как минимум отдельной статьи. Рассмотрим основные моменты…

В элементе глобального массива $_SERVER["REQUEST_URI"] содержится полный адрес по которому обратился пользователь.
Например: example.ru/contacts/feedback

С помощью функции explode производится разделение адреса на составлющие. В результате мы получаем имя контроллера, для приведенного примера, это контроллер contacts и имя действия, в нашем случае — feedback .

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

Таким образом, при переходе, к примеру, по адресу:
example.com/portfolio
или
example.com/portfolio/index
роутер выполнит следующие действия:

  1. подключит файл model_portfolio.php из папки models, содержащий класс Model_Portfolio;
  2. подключит файл controller_portfolio.php из папки controllers, содержащий класс Controller_Portfolio;
  3. создаст экземпляр класса Controller_Portfolio и вызовет действие по умолчанию — action_index, описанное в нем.
Если пользователь попытается обратиться по адресу несуществующего контроллера, к примеру:
example.com/ufo
то его перебросит на страницу «404»:
example.com/404
То же самое произойдет если пользователь обратится к действию, которое не описано в контроллере.

2.2. Возвращаемся к реализации MVC

Перейдем в папку core и добавим к файлу route.php еще три файла: model.php, view.php и controller.php

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

Содержимое файла model.php
class Model { public function get_data () { } }
Класс модели содержит единственный пустой метод выборки данных, который будет перекрываться в классах потомках. Когда мы будем создавать классы потомки все станет понятней.

Содержимое файла view.php
class View { //public $template_view; // здесь можно указать общий вид по умолчанию. function generate ($content_view , $template_view , $data = null) { /* if(is_array($data)) { // преобразуем элементы массива в переменные extract($data); } */ include "application/views/" .$template_view ; } }
Не трудно догадаться, что метод generate предназначен для формирования вида. В него передаются следующие параметры:

  1. $content_file — виды отображающие контент страниц;
  2. $template_file — общий для всех страниц шаблон;
  3. $data — массив, содержащий элементы контента страницы. Обычно заполняется в модели.
Функцией include динамически подключается общий шаблон (вид), внутри которого будет встраиваться вид
для отображения контента конкретной страницы.

В нашем случае общий шаблон будет содержать header, menu, sidebar и footer, а контент страниц будет содержаться в отдельном виде. Опять же это сделано для упрощения.

Содержимое файла controller.php
class Controller { public $model ; public $view ; function __construct () { $this ->view = new View(); } } }
Метод action_index — это действие, вызываемое по умолчанию, его мы перекроем при реализации классов потомков.

2.3. Реализация классов потомков Model и Controller, создание View"s

Теперь начинается самое интересное! Наш сайт-визитка будет состоять из следущих страниц:
  1. Главная
  2. Услуги
  3. Портфолио
  4. Контакты
  5. А также — страница «404»
Для каждой из страниц имеется свой контроллер из папки controllers и вид из папки views. Некоторые страницы могут использовать модель или модели из папки models.

На предыдущем рисунке отдельно выделен файл template_view.php — это шаблон, содержащий общую для всех страниц разметку. В простейшем случае он мог бы выглядеть так:
<html lang ="ru" > <head > <meta charset ="utf- 8 "> <title > Главнаяtitle > head > <body > $content_view ; ?> body > html >
Для придания сайту презентабельного вида сверстаем CSS шаблон и интегририруем его в наш сайт путем изменения структуры HTML-разметки и подключения CSS и JavaScript файлов:
<link rel ="stylesheet" type ="text/css" href ="/css/style.css" /> <script src ="/js/jquery-1.6.2.js" type ="text/javascript" > script >

В конце статьи, в разделе «Результат», приводится ссылка на GitHub-репозиторий с проектом, в котором проделаны действия по интеграции простенького шаблона.

2.3.1. Создадаем главную страницу

Начнем с контроллера controller_main.php , вот его код:
class Controller_Main extends Controller { function action_index () { $this ->view->generate("main_view.php" , "template_view.php" ); } }
В метод generate экземпляра класса View передаются имена файлов общего шаблона и вида c контентом страницы.
Помимо индексного действия в контроллере конечно же могут содержаться и другие действия.

Файл с общим видом мы рассмотрели ранее. Рассмотрим файл контента main_view.php :
<h1 > Добро пожаловать!h1 > <p > <img src ="/images/office-small.jpg" align ="left" > <a href ="/" > ОЛОЛОША TEAMa > - команда первоклассных специалистов в области разработки веб-сайтов с многолетним опытом коллекционирования мексиканских масок, бронзовых и каменных статуй из Индии и Цейлона, барельефов и изваяний, созданных мастерами Экваториальной Африки пять-шесть веков назад... p >
Здесь содержиться простая разметка без каких либо PHP-вызовов.
Для отображения главной странички можно воспользоваться одним из следующих адресов:

  • методы библиотек, реализующих абстракицю данных. Например, методы библиотеки PEAR MDB2;
  • методы ORM;
  • методы для работы с NoSQL;
  • и др.
  • Для простоты, здесь мы не будем использовать SQL-запросы или ORM-операторы. Вместо этого мы сэмулируем реальные данные и сразу возвратим массив результатов.
    Файл модели model_portfolio.php поместим в папку models. Вот его содержимое:
    class Model_Portfolio extends Model { public function get_data () { return array (array ("Year" => "2012" , "Site" => "http://DunkelBeer.ru" , "Description" => "Промо-сайт темного пива Dunkel от немецкого производителя Löwenbraü выпускаемого в России пивоваренной компанией "CАН ИнБев"." ), array ("Year" => "2012" , "Site" => "http://ZopoMobile.ru" , "Description" => "Русскоязычный каталог китайских телефонов компании Zopo на базе Android OS и аксессуаров к ним." ), // todo ); } }

    Класс контроллера модели содержится в файле controller_portfolio.php , вот его код:
    class Controller_Portfolio extends Controller { function __construct () { $this ->model = new Model_Portfolio(); $this ->view = new View(); } function action_index () { $data = $this ->model->get_data(); $this ->view->generate("portfolio_view.php" , "template_view.php" , $data ); } }
    В переменную data записывается массив, возвращаемый методом get_data , который мы рассматривали ранее.
    Далее эта переменная передается в качестве параметра метода generate , в который также передаются: имя файла с общим шаблон и имя файла, содержащего вид c контентом страницы.

    Вид содержащий контент страницы находится в файле portfolio_view.php .

    Портфолио

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


    Ссылка на GitHub: https://github.com/vitalyswipe/tinymvc/zipball/v0.1

    А вот в этой версии я набросал следующие классы (и соответствующие им виды):

    • Controller_Login в котором генерируется вид с формой для ввода логина и пароля, после заполнения которой производится процедура аутентификации и в случае успеха пользователь перенаправляется в админку.
    • Contorller_Admin с индексным действием, в котором проверяется был ли пользователь ранее авторизован на сайте как администратор (если был, то отображается вид админки) и действием logout для разлогинивания.
    Аутентификация и авторизация — это другая тема, поэтому здесь она не рассматривается, а лишь приводится ссылка указанная выше, чтобы было от чего оттолкнуться.

    4. Заключение

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

    Но, использование веб-фреймворков, типа Yii или Kohana, состоящих из нескольких сотен файлов, при разработке простых веб-приложений (например, сайтов-визиткок) не всегда целесообразно. Теперь мы умеем создавать красивую MVC модель, чтобы не перемешивать Php, Html, CSS и JavaScript код в одном файле.

    Данная статья является скорее отправной точкой для изучения CMF, чем примером чего-то истинно правильного, что можно взять за основу своего веб-приложения. Возможно она даже вдохновила Вас и вы уже подумываете написать свой микрофреймворк или CMS, основанные на MVC. Но, прежде чем изобретать очередной велосипед с «блекджеком и шлюхами», еще раз подумайте, может ваши усилия разумнее направить на развитие и в помощь сообществу уже существующего проекта?!

    P.S.: Статья была переписана с учетом некоторых замечаний, оставленных в комментариях. Критика оказалась очень полезной. Судя по отклику: комментариям, обращениям в личку и количеству юзеров добавивших пост в избранное затея написать этот пост оказалось не такой уж плохой. К сожалению, не возможно учесть все пожелания и написать больше и подробнее по причине нехватки времени… но возможно это сделают те таинственные личности, кто минусовал первоначальный вариант. Удачи в проектах!

    5. Подборка полезных ссылок по сабжу

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

    This example demonstrates how to automatically logout with default Spring security configuration.

    To logout, we just need to access URL "/logout" with POST request.

    In the POST /logout form, we also need to include the CSRF token, which is a protection against CSRF attack .

    Let"s see the example how to do that.

    Java Config class

    @Configuration @EnableWebSecurity @EnableWebMvc @ComponentScan public class AppConfig extends WebSecurityConfigurerAdapter { protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .anyRequest().authenticated() .and() .formLogin(); } @Override public void configure(AuthenticationManagerBuilder builder) throws Exception { builder.inMemoryAuthentication() .withUser("joe") .password("123") .roles("ADMIN"); } @Bean public ViewResolver viewResolver() { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setPrefix("/WEB-INF/views/"); viewResolver.setSuffix(".jsp"); return viewResolver; } }

    Note that, in above configuration, we are also overriding configure(HttpSecurity http) to omit the default Basic Authentication (see the original method in WebSecurityConfigurerAdapter source code) and use form based Authentication. We are doing so because browsers cache the Basic Authentication information aggressively (after the first successful login) and there is no way to logout the user in the current session. In most of the examples, we will not be using Basic Authentication mechanism.

    A controller

    @Controller public class ExampleController { @RequestMapping("/") public String handleRequest2(ModelMap map) { map.addAttribute("time", LocalDateTime.now().toString()); return "my-page"; } }

    The JSP page

    src/main/webapp/WEB-INF/views/my-page.jsp

    Spring Security Example

    Time: ${time}

    To try examples, run embedded tomcat (configured in pom.xml of example project below):

    Mvn tomcat7:run-war

    Output

    Initial access to URI "/" will redirect to "/login":

    After submitting user name and password as we setup in our AppConfig class:

    Clicking on "Logout" button:


    Example Project

    Dependencies and Technologies Used:

    • spring-security-web 4.2.3.RELEASE: spring-security-web.
    • spring-security-config 4.2.3.RELEASE: spring-security-config.
    • spring-webmvc 4.3.9.RELEASE: Spring Web MVC.
    • javax.servlet-api 3.1.0 Java Servlet API
    • JDK 1.8
    • Maven 3.3.9

    Отредактируйте файл urls.py приложения account :

    from django.conf.urls import url from . import views urlpatterns = [ # previous login view # url(r"^login/$", views.user_login, name="login"), # login / logout urls url(r"^login/$" , "django.contrib.auth.views.login" , name="login" ), url(r"^logout/$" , "django.contrib.auth.views.logout" , name="logout" ), url(r"^logout-then-login/$" , "django.contrib.auth.views.logout_then_login" , name="logout_then_login" ), ]

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

    Создайте новый каталог в каталоге шаблонов приложения account и назовите его registration. Создайте новый файл в новом каталоге, назовите его login.html

    {% extends "base.html" %} {% block title %}Log-in{% endblock %} {% block content %}

    Log-in

    {% if form.errors %}

    Your username and password didn"t match. Please try again.

    {% else %}

    Please, use the following form to log-in:

    {% endif %} {% endblock %}

    Этот шаблон для входа очень похож на созданный ранее. Джанго использует AuthenticationForm , расположенную в django.contrib.auth.forms . Эта форма пытается проверить подлинность пользователя и порождает ошибку проверки, если имя пользователя было не верно. В этом случае мы можем искать ошибки с помощью команды {% if form.errors %} . Обратите внимание, что мы добавили скрытый элемент для отправки значения переменной с именем next .

    Параметр next должен быть URL-адресом. Если этот параметр указан, то после входа пользователя в систему он перенаправляется на заданный URL-адрес.

    Теперь создайте шаблон logged_out.html внутри каталога шаблона registration и вставьте в него следующий код:

    {% extends "base.html" %} {% block title %}Logged out{% endblock %} {% block content %}

    Logged out

    You have been successfully logged out. You can log-in again.

    {% endblock %}

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

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

    Обратите внимание, что представление logout_then_login , включенное в наш urlconf , не нуждается в шаблоне, поскольку он выполняет перенаправление на log in view .

    Теперь создадим новый view для отображения панели мониторинга для пользователя, чтобы знать когда пользователь войдет в свою учетную запись. Откройте файл views.py приложения account и добавьте в него следующий код:

    from django.contrib.auth.decorators import login_required @login_required def dashboard (request) : return render(request, "account/dashboard.html" , {"section" : "dashboard" })

    Мы добавляем в наше представление декоратор login_required authentication framework. Декоратор login_required проверяет, прошел ли текущий пользователь аутентификацию. Если пользователь прошел аутентификацию, рпедставление выполнится; Если пользователь не прошел аутентификацию, он будет перенаправлян на страницу входа.

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

    Теперь необходимо создать шаблон для представления панели мониторинга. Создайте новый файл внутри шаблонов/учетной templates/account/ и назовите его dashboard.html :

    {% extends "base.html" %} {% block title %}Dashboard{% endblock %} {% block content %}

    Dashboard

    Welcome to your dashboard.

    {% endblock %}

    Затем добавьте следующий шаблон URL-адреса для этого измените файл urls.py приложения account :

    Urlpatterns = [ # ... url(r"^$" , views.dashboard, name="dashboard" ), ]

    Теперь отредактируйте файл settings.py :

    from django.core.urlresolvers import reverse_lazy LOGIN_REDIRECT_URL = reverse_lazy("dashboard" ) LOGIN_URL = reverse_lazy("login" ) LOGOUT_URL = reverse_lazy("logout" )
    • LOGIN_REDIRECT_URL : Сообщает о том, на какой URL-адрес перенаправлять пользователя после входа в систему.
    • LOGIN_URL : URL-адрес для перенаправления пользователя на вход (например, с помощью декоратора login_required )
    • LOGOUT_URL : URL-адрес для перенаправления пользователя на выход

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

    Для этого необходимо определить, вошел ли текущий пользователь в систему или нет, чтобы отобразить соответствующую текущему состоянию пользователя, ссылку. Текущий пользователь задается в HttpRequest объекте промежуточного класса authentication. Доступ к нему можно получить с помощью request.user . В запросе будет найден объект user, даже если user не прошел аутентификацию. Неаутентифицированный пользователь, задается в запросе в качестве экземпляра AnonymousUser . Наилучший способ проверки состояния аутентификаци текущего пользователя — вызов request.user.is_authenticated()

    Отредактируйте в шаблоне base.html

    с ID header:

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

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

    Откройте в браузере http://127.0.0.1:8000/account/login/ . Вы должны увидеть стриницу входа. Введите валидный логин и пароль. Вы увидите следующее:

    Можно увидеть, что раздел My dashboard выделен с помощью CSS, так как он имеет class selected . Поскольку пользователь прошел аутентификацию, имя пользователя отображается в правой части header-а. Щелкните ссылку Logout . Вы увидите следующую страницу:

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

    Если вы видите страницу log out из сайта администрирования Джанго, а не собственную страницу выхода из системы, проверьте настройки INSTALLED_APPS и убедитесь, что django.contrib.admin находится после account . Оба шаблона находятся в том же относительном пути, и загрузчик шаблона Джанго будет использовать первый найденный.

    Django comes with a lot of built-in resources for the most common use cases of a Web application. The registration app is a very good example and a good thing about it is that the features can be used out-of-the-box.

    With the Django registration app you can take advantages of the following features:

    • Login
    • Logout
    • Sign up
    • Password reset

    In this tutorial we will focus in the Login and Logout features. For sign up and password reset, check the tutorials below:

    Getting started

    Before we start, make sure you have django.contrib.auth in your INSTALLED_APPS and the authentication middleware properly configured in the MIDDLEWARE_CLASSES settings.

    Both come already configured when you start a new Django project using the command startproject . So if you did not remove the initial configurations you should be all set up.

    In case you are starting a new project just to follow this tutorial, create a user using the command line just so we can test the login and logout pages.

    $ python manage.py createsuperuser

    In the end of this article I will provide the source code of the example with the minimal configuration.

    Configure the URL routes

    First import the django.contrib.auth.views module and add a URL route for the login and logout views:

    from django.conf.urls import url from django.contrib import admin from django.contrib.auth import views as auth_views urlpatterns = [ url (r"^login/$" , auth_views . login , name = "login" ), url (r"^logout/$" , auth_views . logout , name = "logout" ), url (r"^admin/" , admin . site . urls ), ]

    Create a login template

    By default, the django.contrib.auth.views.login view will try to render the registration/login.html template. So the basic configuration would be creating a folder named registration and place a login.html template inside.

    Following a minimal login template:

    {% extends "base.html" %} {% block title %}Login{% endblock %} {% block content %}

    Login

    {% csrf_token %} {{ form.as_p }} {% endblock %}

    This simple example already validates username and password and authenticate correctly the user.

    Customizing the login view

    There are a few parameters you can pass to the login view to make it fit your project. For example, if you want to store your login template somewhere else than registration/login.html you can pass the template name as a parameter:

    url (r"^login/$" , auth_views . login , { "template_name" : "core/login.html" }, name = "login" ),

    You can also pass a custom authentication form using the parameter authentication_form , incase you have implemented a custom user model.

    Now, a very important configuration is done in the settings.py file, which is the URL Django will redirect the user after a successful authentication.

    Inside the settings.py file add:

    LOGIN_REDIRECT_URL = "home"

    The value can be a hardcoded URL or a URL name. The default value for LOGIN_REDIRECT_URL is /accounts/profile/ .

    It is also important to note that Django will try to redirect the user to the next GET param.

    Setting up logout view

    After acessing the django.contrib.auth.views.logout view, Django will render the registration/logged_out.html template. In a similar way as we did in the login view, you can pass a different template like so:

    url (r"^logout/$" , auth_views . logout , { "template_name" : "logged_out.html" }, name = "logout" ),

    Usually I prefer to use the next_page parameter and redirect either to the homepage of my project or to the login page when it makes sense.



  • Понравилась статья? Поделитесь ей
    ГодПроектОписание
    " .$row ["Year" ]."" .$row ["Site" ]."" .$row ["Description" ]."