В качестве хобби, я решил открыть для себя мир веб-разработки, попутно освещая свои успехи, а может и неудачи на пути к просветлению…

В настоящее время я публично описываю процесс создания веб-сайта с нуля на Django и Bootstrap, где задача разработать такие приложения как: аккаунты, вопросы, статьи и книги.

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

Создание веб-сайта с нуля на Django и Bootstrap. Аккаунты. Регистрация с подтверждением адреса электронной почты. Представления

Сергей Серов

Представления

В каталоге accounts открываем файл views.py и наполняем следующим:

from django.shortcuts import render, redirect
from django.contrib.auth import login
from django.conf import settings

from . import forms
from .utils import Vcode
from .decorators import anonymous_required


@anonymous_required
def join_view(request):
    form = forms.JoinForm(request.POST or None)
    if form.is_valid():
        form.save(request=request)
        return redirect('accounts:join_confirm')
    return render(request, 'accounts/join.html', {
        'form': form,
    })


@anonymous_required
def join_confirm_view(request, code):
    status = 'waiting'
    if code:
        vcode = Vcode(request)
        if vcode.is_valid(code, 'join'):
            status = 'success'
            user = vcode.get_inactive_user()
            # активируем и авторизуем пользователя
            user.is_active = True
            user.save()
            # привязываем вручную бэкенд авторизации для того чтоб не проводить доп. аутентификацию
            login(request, user, settings.ACCOUNTS_EMAILBACKEND)
        else:
            status = 'invalid'
    return render(request, 'accounts/join_confirm.html', {
        'status': status,
    })


@anonymous_required
def join_resend_view(request):
    form = forms.JoinResendForm(request.POST or None)
    if form.is_valid():
        form.send_vcode(request)
        return redirect('accounts:join_confirm')
    return render(request, 'accounts/join_resend.html', {
        'form': form,
    })

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

Если форма заполнена верно, переходим к сохранению и перенаправляем пользователя на страницу подтверждения.

Затем join_confirm_view берет на себе две задачи: сообщить пользователю о прохождении регистрации и просьбой потвердеть аккаунт перейдя по специально сгенерированной ссылке из письма и далее обработать ссылку сравнивая код и действия подтверждения.

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

Напоследок join_resend_view показывает форму для повторной отправки кода подтверждения и отправляет новое письмо если она корректно заполнена.

Декоратор

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

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

В директории accounts создаем файл decorators.py:

from django.shortcuts import render


def anonymous_required(view_func):
    def wrapped_view(request, *args, **kwargs):
        if request.user.is_anonymous:
            return view_func(request, *args, **kwargs)
        return render(request, 'accounts/anonymous_required.html')
    return wrapped_view

Шаблоны представлений и декоратора мы опишем в соответствующим разделе.

Маршруты

Для начала создаем маршруты внутри приложения. Переходим в accounts и создаем файл urls.py:

from django.conf.urls import url

from . import views

app_name = 'accounts'
urlpatterns = [
    url(r'^join/$', views.join_view, name='join'),
    url(r'^join/confirm/(?:(?P<code>\w+)/)?$', views.join_confirm_view, name='join_confirm'),
    url(r'^join/resend/$', views.join_resend_view, name='join_resend'),
]

Здесь мы просто подключаем ранее созданные представления к маршрутам давая им осмысленные имена. Данные сокращения удобно использовать внутри проекта, например, в шаблонах.

Теперь нам нужно подключить локальные маршруты приложения Аккаунты к глобальному файлу адресов проекта. В каталоге проекта переходим к директории zero и открываем urls.py и приводим к следующему виду:

from django.conf.urls import url, include
from django.contrib import admin
from django.conf.urls.static import static
from django.conf import settings

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^accounts/', include('accounts.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)


# Django Debug Toolbar

if settings.DEBUG:
    import debug_toolbar
    urlpatterns += [
        url(r'^__debug__/', include(debug_toolbar.urls)),
    ]