Шаблоны
В заключительной части мы создадим шаблоны для всех писем, утилит, декораторов и представлений.
Шаблоны писем
Переходим в каталог templates и создаем директорию accounts и в ней подкаталог vcode. Затем формируем файл subject.txt:
Ссылка для подтверждения операции
Далее в подкаталоге vcode cоздаем базовый файл для содержимого писем base.txt:
{% block action %}{% endblock %}
Для подтверждения операции просто откройте ссылку ниже или скопируйте и вставьте ее в Ваш бразуер.
{{ domain }}{% block link %}{% endblock %}
Создаем файл join.txt в подкаталоге vcode:
{% extends 'accounts/vcode/base.txt' %}
{% block action %}РЕГИСТРАЦИЯ{% endblock %}
{% block link %}{% url 'accounts:join_confirm' vcode %}{% endblock %}
Шаблон декоратора
В директории accounts создаем файл anonymous_required.html:
{% extends 'base.html' %}
{% load core_tags %}
{% block title %}Уведомление{% endblock %}
{% block main %}
<div class="accounts-anonymous-required">
<h1>Уведомление</h1>
{% alert_tag success %}
Вы уже вошли как <strong>{{ user.username }}</strong>. Возможно эта страница устарела или Вы на нее зашли по ошибке.
{% end_alert_tag %}
</div>
{% endblock %}
Здесь мы используем шаблонный тег alert_tag.
Шаблонные теги
В каталоге приложения core создаем директорию templatetags, название директории обязательно условие для поиска шаблонных тегов. Далее мы создаем пустой файл __init__.py и core_tags.py со следующим содержимым:
from django import template
from django.template.loader import render_to_string
register = template.Library()
@register.filter
def label_with_classes_filter(field, classes):
return field.label_tag(attrs={'class': classes})
@register.filter
def field_with_classes_filter(field, classes):
return field.as_widget(attrs={'class': classes})
def alert(status, body):
return render_to_string('core/alert.html', {
'status': status,
'body': body,
})
class AlertNode(template.Node):
def __init__(self, nodelist, status):
self.nodelist = nodelist
self.status = status
def render(self, context):
body = self.nodelist.render(context)
return alert(self.status, body)
@register.tag
def alert_tag(parser, token):
try:
tag_name, status = token.split_contents()
except ValueError:
raise template.TemplateSyntaxError('alert_tag принимает только один аргумент (статус уведомления)')
nodelist = parser.parse(['end_alert_tag'])
parser.delete_first_token()
return AlertNode(nodelist, status)
Первые два тега это хаки, которые добавляют классы, например, от фреймворка Bootstrap для правильного отображения полей формы.
Следующие объекты реализуют один шаблонный тег alert_tag. В основной функции мы передаем статус уведомления и само сообщение в шаблон. Статус влияет на цвет уведомления, например, класс success, Bootstrap отобразит зеленым цветом.
В директории templates создаем каталог core и шаблон с названием alert.html:
<div class="alert alert-{{ status }}" role="alert">
<i class="fa fa-exclamation-circle" aria-hidden="true"></i>
{{ body }}
</div>
Шаблон регистрации
В подкаталоге accounts создаем шаблон с названием join.html:
{% extends 'base.html' %}
{% block title %}Присоединиться{% endblock %}
{% block main %}
<div class="accounts-join">
<h1>Присоединиться</h1>
<form action="{% url 'accounts:join' %}" method="post">
{% csrf_token %}
{% include 'core/form_fields.html' %}
<button type="submit" class="btn btn-success">Присоединиться</button>
</form>
</div>
{% endblock %}
Для вывода непосредственно полей формы мы подключаем другой шаблон. Переходим в подкаталог core и создаем form_fields.html:
{% load core_tags %}
{% for error in form.non_field_errors %}
{% alert_tag danger %}
{{ error }}
{% end_alert_tag %}
{% endfor %}
{% for field in form %}
<div class="form-group{% if field.errors %} has-error{% endif %}">
{{ field|label_with_classes_filter:'control-label' }}
{{ field|field_with_classes_filter:'form-control' }}
{% if field.errors or field.help_text %}
<span class="help-block">{% if field.errors %}{{ field.errors }}{% else %}{{ field.help_text }}{% endif %}</span>
{% endif %}
</div>
{% endfor %}
Шаблон подтверждения
В подкаталоге accounts создаем файл join_confirm.html:
{% extends 'base.html' %}
{% load core_tags %}
{% block title %}Присоединиться (подтверждение){% endblock %}
{% block main %}
<div class="accounts-join-confirm">
<h1>Присоединиться (подтверждение)</h1>
{% if status == 'waiting' %}
{% alert_tag success %}
Мы выслали проверочный код на Ваш адрес электронной почты и с нетерпением ждем подтверждения.
{% end_alert_tag %}
<p>Если по каким-то причинам письмо не пришло Вы можете воспользоваться <a href="{% url 'accounts:join_resend' %}">формой повторной отправки кода</a>.</p>
<p>А если Вы видите это сообщение постоянно, то можете обратиться за помощью к администрации проекта.</p>
{% elif status == 'success' %}
{% alert_tag success %}
Поздравляем! Теперь Вы один из нас.
{% end_alert_tag %}
{% elif status == 'invalid' %}
{% alert_tag danger %}
Ваш код неверен или устарел, проверочные коды, как правило, не отличаются высокой продолжительностью жизни…
{% end_alert_tag %}
<p>Вы можете воспользоваться <a href="{% url 'accounts:join_resend' %}">формой повторной отправки кода</a>.</p>
{% endif %}
</div>
{% endblock %}
Шаблон повторной отправки кода
В подкаталоге accounts создаем шаблон join_resend.html:
{% extends 'base.html' %}
{% block title %}Реактивация{% endblock %}
{% block main %}
<div class="accounts-join-resend">
<h1>Реактивация</h1>
<form action="{% url 'accounts:join_resend' %}" method="post">
{% csrf_token %}
{% include 'core/form_fields.html' %}
<button type="submit" class="btn btn-success">Отправить</button>
</form>
</div>
{% endblock %}