************************* Setting Up Frontend Login ************************* "Django comes with a user authentication system. It handles user accounts, groups, permissions and cookie-based user sessions." -- :djangodocs:`User authentication in Django | Django documentation ` So far you can only create and edit bookmarks with the admin site. The next steps will show you how to set up a login form in the frontend. .. index:: Authentication, Login Django comes with an app named ``django.contrib.auth`` which includes everything necessary to authenticate a user. The core element is the model ``User`` that you :ref:`already used ` to store the owner in the ``Bookmark`` model. It contains fields to store username, password and email. You can find a full list of its fields in the :djangodocs:`documentation `. .. _login-process: The authentication works this way: If a user logs in, a cookie with a unique session id is set. The browser will send this cookie with every request. With the session id the according user is mapped to the request and you can access the ``User`` object with ``request.user`` like :ref:`already done ` in the ``bookmark_user`` view. We'll create two views to allow users to login without using the admin site. URLconf ======= First, you have to add the import of the ``reverse_lazy()`` function at the top and two additional URLs to the end of URLconf :file:`mysite/urls.py`. .. literalinclude:: ../src/mysite/mysite/urls.py :linenos: :emphasize-lines: 18,23-26 The function ``reverse_lazy()`` is similar to the ``url`` template tag you have used in the :ref:`previous chapter `. It returns a link to the URL passed to it as the first argument, but can even be executed before your project’s URLConf is loaded. The URLs ``/login/`` and ``/logout/`` are linked here with the corresponding views. These views are included in Django and don't have to be created. You just have to configure the template for the login view and the redirect of the logout view. .. _login-url-settings: Configuration ============= Next, you create three new constants at the end of file :file:`settings.py`: .. literalinclude:: ../src/mysite/mysite/settings.py :lines: 110-112 :lineno-start: 110 .. doctest:: :hide: >>> settings.LOGIN_URL == 'mysite_login' True >>> settings.LOGOUT_URL == 'mysite_logout' True >>> settings.LOGIN_REDIRECT_URL == 'marcador_bookmark_list' True These constants configure the automatic redirect after the login and the logout. For example if a user who is not authenticated wants to access a protected page, she'll be automatically redirected to ``/login/`` where she can log in because this is the URL where ``mysite_login`` refers to. The constants should either be simple strings which match a named URL pattern from the URLconf or URLs relative to the current domain. Since this template uses some functionality provided by ``crispy_forms`` we will add it to ``INSTALLED_APPS`` in the settings file: .. literalinclude:: ../src/mysite/mysite/settings.py :lines: 31-42 :emphasize-lines: 11 :lineno-start: 31 ``crispy_forms`` comes with a template pack for :ref:`Bootstrap 3 `. As this is not the default template pack we have to configure ``crispy_forms`` to use it by adding the following line to the end of the file :file:`settings.py`: .. literalinclude:: ../src/mysite/mysite/settings.py :lines: 114 :lineno-start: 114 .. index:: Forms inside a template Templates ========= The main login template ----------------------- Now you can create the template for the login form :file:`mysite/templates/login.html`. .. literalinclude:: ../src/mysite/templates/login.html :language: html+django :linenos: First we create a form in the block ``content``. The ``
`` tag gets attributes to make it send a POST request to the login view. The template gets a variable ``form`` from the login view which contains the login form. With ``{{ form|crispy }}`` Django creates all necessary input fields. Of course you can also render all fields separately. How to do that is described in the :djangodocs:`documentation `. The next row contains the template tag ``{% csrf_token %}``. It is used to activate Django's :djangodocs:`protection against manipulated form requests ` (Cross Site Request Forgery). After that comes a hidden input field which gets the value from the variable ``next``. ``next`` contains the path to which the user should be redirected after a successful login. Usually this is the value of the constant ``LOGIN_REDIRECT_URL`` which you :ref:`defined ` in :file:`settings.py`. The default value is replaced if you request the page with an additional query parameter. For example ``/login/?next=/user/bob/`` will redirect the user to the page with Bob's bookmarks after the login. Finally we create a button to submit the form. The login template for the navigation ------------------------------------- Now comes the template for login through the navigation bar :file:`mysite/templates/toggle_login.html`: The goal of this template is to show different content in the navigation bar, depending on the users login state. If the user is logged in, she should see a link to the page with her bookmarks and a button to log out. If she is not logged in, there should be input fields for username and password as well as a login button. .. literalinclude:: ../src/mysite/templates/toggle_login.html :language: html+django :lines: 1-2, 4-26 :linenos: The difference between these two states is done with help of the ``if`` tag and the condition ``user.is_authenticated``. The variable ``user`` refers to the :ref:`already mentioned ` user object which is available in all templates. The method ``is_authenticated`` returns ``True`` if the user is authenticated or ``False`` if not. Because this template gets included in :file:`base.html` to display it on every page, the form can't be rendered automatically like in the last template. This is because only the login view provides the variable ``form``. Instead we set the input fields manually. Please note that the attribute ``name`` has to be equal to the field name in the ``User`` model. The template :file:`mysite/templates/base.html` originally contains the following login form: .. literalinclude:: ../src/mysite/templates/base.orig.html :language: html+django :lines: 43-51 :dedent: 10 This gets replaced with a block in which you use the ``include`` tag to embed the template :file:`mysite/templates/toggle_login.html`. .. literalinclude:: ../src/mysite/templates/base.html :language: html+django :lines: 43-45 :dedent: 10 .. raw:: latex \newpage Test the frontend login ======================= Now users can log in and out in the frontend using the form and the dropdown menu at the top, which are rendered using the :file:`mysite/templates/toggle_login.html` template: .. image:: /images/marcador-latest-bookmarks.* :alt: Frontend Bookmark List View :align: center .. raw:: latex \newpage Call http://127.0.0.1:8000/user/admin/ to see the login form which you build at first in :file:`mysite/templates/login.html` (replace ``admin`` with the name of the user you created when executing :ref:`createsuperuser `): .. image:: /images/marcador-login.* :alt: Frontend Login Form :align: center The main login form is also used if the authentication via the form at the top fails.