Djangofantalega: Login e Logout
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.
Se non si è registrati è possibile fare il signup.
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
Commenti recenti