Home > Django > Djangofantalega: Login e Logout

Djangofantalega: Login e Logout

14 Novembre 2016

3 – Djangofantalega: Login e Logout

Questa è la sequenza di come un utente debba gestire una squadra di
fantalega:

1 – Registrazione al sito da parte del nuovo User
2 – Spedizione link di conferma registrazione al nuovo User
3 – COnferma di registrazione
4 – Login/Logout

Siccome la fase di registrazione, come pure quella di Login, richiede
un form dove immettere i propri dati, quindi richiede urls dedicate,
quindi views e di conseguenza templates, per una questione di ordine
si tegono tutte queste cose separate dalla altre (app fantalega).
Per questo è bene creare una app dedicata di nome ‘log’:

python manage.py startapp log

controllare che nel file djangosite\settings.py sia presente ‘log’:

INSTALLED_APPS = [
    'fantalega.apps.FantalegaConfig',  # fantalega
    'log.apps.LogConfig',              # log
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'bootstrap3'  # aggiungere questa riga
]
...

Si userà Gmail per le mail quindi attenzione ai valori aggiunti alla
fine del file djangosite\settings.py.

...
# Gmail email settings
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_HOST_USER = '[email protected]'
EMAIL_HOST_PASSWORD = 'xxxxxxxx'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'

Aggiungere l’unico model UserProfile nel file log/models.py
Attenzione al percorso, si sta parlando della app ‘log’ e non ‘fantalega’!!

from django.db import models
from django.contrib.auth.models import User


# Create your models here.
class UserProfile(models.Model):
    user = models.OneToOneField(User)
    activation_key = models.CharField(max_length=40)
    key_expires = models.DateTimeField()

Semplicemente è stata creata una tabella con il field user che
altro non è che una relazione one-to-one con il modello User già fornito
da django, al quale si aggungono:
– activation_key, creata in fase di registrazione;
– key_expires tempo oltre il quale la chiave di attivazione non sarà più attiva.

L’unico form non presente e che verrà creato nel file log/forms.py è:

# noinspection PyUnresolvedReferences
from django import forms
# noinspection PyUnresolvedReferences
from django.utils.safestring import mark_safe
from django.contrib.auth.models import User


class RegistrationForm(forms.Form):
    username = forms.RegexField(
        regex=r'^\w+$',
        widget=forms.TextInput(attrs=dict(required=True, max_length=30)),
        label="Username",
        error_messages={'invalid': "This value must contain only letters,"
                                   " numbers and underscores."})
    email = forms.EmailField(
        widget=forms.TextInput(
            attrs=dict(required=True, max_length=30)), label="Email address")
    password1 = forms.CharField(
        widget=forms.PasswordInput(
            attrs=dict(required=True, max_length=30, render_value=False)),
        label="Password")
    password2 = forms.CharField(
        widget=forms.PasswordInput(
            attrs=dict(required=True, max_length=30, render_value=False)),
        label="Password (again)")

    def clean_username(self):
        try:
            user = User.objects.get(
                username__iexact=self.cleaned_data['username'])
        except User.DoesNotExist:
            return self.cleaned_data['username']
        raise forms.ValidationError(
            "The username already exists. Please try another one.")

    def clean(self):
        if 'password1' in self.cleaned_data and 'password2' \
                in self.cleaned_data:
            if self.cleaned_data['password1'] != self.cleaned_data['password2']:
                raise forms.ValidationError(
                    "The two password fields did not match.")
        return self.cleaned_data

Le urls che gestiscono tutte queste fasi, risiedono nel file log/urls.py

# noinspection PyUnresolvedReferences
from django.conf.urls import url
# noinspection PyUnresolvedReferences
from django.contrib import admin
from log import views as log_views
from django.contrib.auth import views as auth_views  # auth system


urlpatterns = [
    url(r'^login/$', auth_views.login,
        {'template_name': 'registration/login.html'},
        name='django.contrib.auth.views.login'),  # auth system
    url(r'^logout/$', auth_views.logout,
        {'template_name': 'registration/logged_out.html'},
        name='logout'),  # auth system
    url(r'^registration/$', log_views.register_user, name='registration'),
    url(r'^registration/success/$', log_views.register_success,
        name='reg_success'),
    url(r'^accounts/activate/(?P<activation_key>\w+)/$', log_views.activate,
        name='activate'),
    url(r'^expired/$', log_views.activation_link_expired, name='expired'),
    ]

queste ulrs vanno ovviamente incluse con include() nel file djangosite/urls.py

# noinspection PyUnresolvedReferences
from django.conf.urls import url, include
# noinspection PyUnresolvedReferences
from django.contrib import admin


urlpatterns = [
    url(r'^fantalega/', include('fantalega.urls')),
    url(r'^auth/', include('log.urls')),
    url(r'^admin/', admin.site.urls),
]

Le views che gestiscono il tutto sono:

from log.forms import RegistrationForm
from django.contrib.auth.models import User
import random
import hashlib
from django.utils import timezone
from django.template import Context
from django.template.loader import get_template
from django.core.mail import EmailMultiAlternatives
from django.urls import reverse
from django.shortcuts import render, redirect, get_object_or_404
from .models import UserProfile
from datetime import datetime
from django.contrib import messages


# Create your views here.
def register_user(request):
    if request.method == 'POST':
        form = RegistrationForm(request.POST)
        context = {'form': form}
        if form.is_valid():
            user = User.objects.create_user(
                username=form.cleaned_data['username'],
                password=form.cleaned_data['password1'],
                email=form.cleaned_data['email'])
            user.is_active = False
            user.save()
            salt = hashlib.sha1(str(random.random())).hexdigest()[:5]
            activation_key = hashlib.sha1(salt + user.username).hexdigest()
            now = datetime.today()
            key_expires = datetime(now.year, now.month, now.day + 2)
            profile = UserProfile(user=user, activation_key=activation_key,
                                  key_expires=key_expires)
            profile.save()
            email_subject = 'Your new <bancaldo> fantalega account confirmation'
            # go to https://www.google.com/settings/security/lesssecureapps
            # click on active
            location = reverse("activate", args=(activation_key,))
            activation_link = request.build_absolute_uri(location)
            template = get_template('registration/confirm_email.html')
            context = Context({'user': user.username,
                               'activation_link': activation_link})
            email_body = template.render(context)
            email = EmailMultiAlternatives(email_subject, email_body,
                                           '[email protected]>', [user.email])
            email.attach_alternative(email_body, 'text/html')
            print email_body  # debug: comment in production
            # email.send()  # decomment to send email
            messages.info(request,
                          "A confirmation mail has been sent to you.\n"
                          "You have 2 days before the link expires")
            return redirect('index')
    else:
        form = RegistrationForm()
        context = {'form': form}
    return render(request, 'registration/registration_form.html', context)


def activate(request, activation_key):
    user_profile = get_object_or_404(UserProfile, activation_key=activation_key)
    if user_profile.user.is_active:
        return render(request, 'registration/active.html',
                      {'user': request.user.username})
    if user_profile.key_expires < timezone.now():
        return render(request, 'registration/expired.html',
                      {'user': request.user.username})
    user_profile.user.is_active = True
    user_profile.user.save()
    messages.success(request, "You have confirmed with success!")
    return redirect('reg_success')


def register_success(request):
    return render(request, 'registration/success.html')


def activation_link_expired(request):
    return render(request, 'registration/expired.html')

Importantissimo!
perchè le mail funzionino con Gmail è necessario cliccare sul controllo
sicurezza di Gmail al link: https://www.google.com/settings/security/lesssecureapps

Infine, la pletora di templates che vanno posizionate in log/templates/registration
che sono:

log/templates/registration/active.html

{% extends "fantalega/base.html" %}
{% load bootstrap3 %}

{% block title %}Registration Successful{% endblock %}
{% block head %}
 already confirmed
{% endblock %}
{% block content %}
  <font color="green"><b>{{ user }}</b></font>, you have already confirmed!
  <br><br>
  <a href="{% url 'index' %}">Click here to login</a>
{% endblock %}

log/templates/registration/confirm_email.html

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
Dear {{ user }},<br>
Welcome to Bancaldo's Fantalega!<br>
To confirm your account please click on the following link:<br><br>
<a href="{{ activation_link }}">Click here to login</a>
<br><br>Sincerely,<br>
Bancaldo
<br><br>Note: replies to this email address are not monitored.
</body>
</html>

log/templates/registration/expired.html

{% extends "fantalega/base.html" %}
{% load bootstrap3 %}

{% block title %}activation key expired{% endblock %}

{% block content %}
  <br><br>
  <b>{{ user }}</b> <font color="red">Your activation key has expired</font>
  <br><br>
  <a href="{% url 'registration' %}">...try to register again</a>
{% endblock %}

log/templates/registration/logged_out.html

{% extends "fantalega/base.html" %}

{% block content %}
  you have been logged out!
  <br><br>
  <font color="green"><a href="{% url 'index' %}">Click here to login</a></font>

{% endblock %}

log/templates/registration/login.html

{% extends "fantalega/base.html" %}
{% load bootstrap3 %}

{% block content %}

{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}

{% if next %}
    {% if user.is_authenticated %}
    <p>Your account doesn't have access to this page. To proceed,
    please login with an account that has access.</p>
    {% else %}
    <p>Please login to see this page.</p>
    {% endif %}
{% endif %}

<form method="post" action="{% url 'django.contrib.auth.views.login' %}">
{% csrf_token %}
{% bootstrap_form form %}
  <input type="submit" class="btn" value="Login" name="login">
  <input type="hidden" name="next" value="{{ next }}" />
</form>
<br><br>
If you are not a registered user, please <a href="{% url 'registration' %}"> Sign up</a>

{% endblock %}

log/templates/registration/registration_form.html

{% extends "fantalega/base.html" %}
{% load bootstrap3 %}

{% block content %}

<form method="post" action="{% url 'registration' %}">
{% csrf_token %}
{% bootstrap_form form %}
 <input type="submit" class="btn" value="Register"
        name="get_registration">
</form>

{% endblock %}

log/templates/registration/success.html

{% extends "fantalega/base.html" %}
{% load bootstrap3 %}

{% block title %}Registration Successful{% endblock %}
{% block head %}
 Registration Completed Successfully
{% endblock %}
{% block content %}
    Thank you for registering.
  <br><br>
  <font color="green"><a href="{% url 'index' %}">Click here to login</a></font>
{% endblock %}

Prima di terminare è nessario aggiornare il database, visto che è stato
creato il model UserProfile:

python manage.py makemigrations log
python manage.py migrate

Aggiungere un link per il logout nella template fantalega/base.html

...
        <a class="navbar-brand" href="{% url 'seasons' %}">Seasons</a></div>
    {% endif %}

      <div class="navbar-collapse collapse">
        <ul class="nav navbar-nav navbar-right">
        {% if not user.is_anonymous %}
          <li><a class="navbar-brand"
             href="{% url 'logout' %}">
          <font color="orange">logout</font></a></li>
        {% endif %}
        </ul>
      </div>
    </div>
  </div>
{% endblock %}

Proteggere ora la view ‘seasons’ con il decoratore login_required

fantalega/views.py

# noinspection PyUnresolvedReferences
from django.shortcuts import render, redirect, get_object_or_404
from .models import Season
# noinspection PyUnresolvedReferences
from django.contrib import messages
from django.contrib.auth.decorators import login_required  # new import


@login_required  # new decorator
def index(request):
    return render(request, 'fantalega/index.html')


@login_required  # new decorator
def seasons(request):
    context = {'seasons': Season.objects.order_by('-name')}
    return render(request, 'fantalega/seasons.html', context)

e se non lo è già, riavviare il server recandosi all’indirizzo
http://127.0.0.1:8000/fantalega

Se lo User è rimasto connesso, a destra è possibile fare il logout.
Dopo di chè si viene reindirizzati alla pagina di logout dove è
presente un link alla pagina di login.

login

Se non si è registrati è possibile fare il signup.

registration

Terminata la registrazione di riceverà una mail con un link.
Cliccato il link si verrà attivati e sarà possibile effettuare il
login.

articoli precedenti
0 – indice
1 – Virtualenv e Git
2 – Models: Season

articoli successivi
4 – Models: League
5 – Models: Team
6 – Models: Match
7 – Models: Player
8 – Asta
9 – Models: Lineup
10 – Models: Trade
11 – Asta di riparazione
12 – Classifica

Categorie:Django Tag:
I commenti sono chiusi.