Цель лекции: Создать модель данных приглашения и реализовать ее; создание страницы отправки приглашения; ознакомиться с системой интернационализации; научиться работать с системой кэширования.
Ключевые термины: интернационализация, проект, электронная почта, кэширование, память, файл, Django, модель, класс, язык, перевод, строка, тестирование, получатель, отправитель
В этой лекции, мы подготовим наше приложение для развертывания в рабочей фазе, используя различные функции фреймворка Django. Мы добавим поддержку нескольких языков, повысим производительность за счет кэширования и автоматизированного тестирования и настроим проект для рабочего окружения. В этой главе есть много интересной и полезной информации, поэтому убедитесь, что вы прошли через нее перед интернет-публикацией приложения!
Разрешение нашим пользователям приглашать своих друзей несет в себе множество преимуществ. Люди будут более склонны присоединиться к нашему сайту, если их друзья уже присоединились. После того, как они присоединяться, они также пригласят своих друзей и так далее, что означает намного больше пользователей для нашего приложения. Таким образом, это хорошая идея -включить функцию "пригласить друга" в нашем приложении.
Для построения функции требуются следующие компоненты:
В этом разделе мы осуществим каждый из этих компонентов. Но, поскольку этот раздел включает в себя отправку сообщений электронной почты, нам сначала нужно настроить Django для отправки электронной почты, добавив некоторые параметры в файл settings.py.Таким образом, откройте settings.py и добавьте следующие строки:
SITE_HOST="127.0.0.1:8000" DEFAULT_FROM_EMAIL='MyTwitter<noreply@mytwitter.com>' </noreply@mytwitter.com> EMAIL_HOST = "mail.yourisp.com" EMAIL_PORT = '' EMAIL_HOST_USER = ' usemame+mail.yourisp.com' EMAIL_HOST_PASSWORD = ''
Давайте посмотрим, что делает каждая переменная в предыдущем коде:
Если на вашей машине разработки работает почтовый сервер, скорее всего, это так, то вам нужно ввести исходящий почтовый сервер вашего провайдера. Для получения дополнительной информации обратитесь к своему провайдеру.
Чтобы проверить правильность настройки, запустите интерактивную оболочку и введите следующее:
>>> from django.core.mail import EmailMessage
>>>email=EmailMessage('Hello','World',to=['your_email@example.com'])
>>> email.send()
Замените параметр your_email@example.com вашим адресом электронной почты. Если предшествующий вызов для отправки почты не вызывает исключение и вы получите сообщение электронной почты, то все устанавливается в противном случае, вам необходимо проверить настройки с вашим провайдером и повторить попытку.
Но, что делать, если вы не получите какую-либо информацию от провайдера? Мы можем попробовать пойти альтернативным путем: использовать Gmail для отправки почты (конечно, не от noreply@mytweet.example.com, но от реальной электронной почты ).Давайте посмотрим на изменения, которые вам придется сделать в файле settings.py проекта MyTweeets для этого.
Удалите предыдущие записи файла settings.py целиком и добавьте следующее:
EMAIL_USE_TLS = True EMAIL_HOST = ‘smtp.gmail.com' EMAIL_HOST_USER = ' ID вашей электронной почты gmail’ EMAIL_HOST_PASSWORD = "gmail пароль" EMAIL_PORT = 587 SITE_HOST = "127.0.0.1:8000"
Если вы получаете ошибку, такую как:
(534,'5.7.9 Application-specific password required. Learn more at\ n5.7.9 http://support.google.com/accounts/bin/answer.py?answer=185833 zr2sm8629305pbb.83 - gsmtp')
Это означает, что параметр email_host_password требует пароль авторизации приложения, это не ваш пароль электронной почты. Прочледуйте по ссылке, упомянутой в разделе, чтобы получить более подробную информацию о том, как создать его.
После создания, попробуйте отправить почту снова из командной строки, используя следующие команды:
>>> from django.core.mail import EmailMessage >>>email=EmailMessage(1Hello1,'World', to=[1your_email@example.com']) >>> email.send()
Здесь параметр your_email@example.com является любым адресом электронной почты, на который вы хотите отправить почту. Адрес электронной почты будет адресом электронной почты Gmail, который мы указали после переменной:
EMAIL_HOST_USER = ' ID вашей электронной почты gmail’
Теперь, после того как параметры заданы правильно, отправка электронной почты в Django лишь кусок пирога! Мы будем использовать функцию EmailMessage чтобы отправить приглашение, но сперва, давайте создадим модель данных для сохранения приглашения.
Приглашение состоит из следующих данных:
Нам также необходимо хранить код активации для приглашения. Этот код будет отправлен с приглашением по электронной почте. Код будет выполнять две цели:
Имея в виду предыдущую информацию, давайте создадим модель данных приглашения. Откройте файл user_profile/models.py и добавьте следующий код:
class Invitation(models.Model):
email = models.EmailField(unique=True)
code = models.CharField(max_length=100)
sender = models.ForeignKey(User)
def __unicode__(self):
return '%s, %s' % (self.sender.username, self.email)
Здесь не должно быть ничего нового или трудного для понимания этой модели. Просто мы определили поля для имени получателя, адреса электронной почты получателя, кода активации иотправителя приглашения. Мы также создали метод __unicode__ для отладки и разрешили модель в интерфейсе администрирования.Не забудьте выполнить команду python manage.py syncdb для создания новой модели таблицы в базе данных.
Мы также создадим форму приглашения для этого. Создайте файл с именем forms.py в каталоге user_profile и обновите его следующим кодом:
from django import forms
class InvitationForm(forms.Form):
email = forms.CharField(widget=forms.TextInput(attrs={'size': 32, 'placeholder': 'Email Address of Friend to invite.', 'class':'form-control'}))
Создание страницы просмотра откуда будут направляться приглашения аналогично созданию других страниц, которые мы создали для поиска и формs твита, которую мы сделаем, создав новый файл под названием template/invite. html:
{% extends "base.html" %}
{% load staticfiles %}
{% block content %}
<div class="row clearfix">
<div class="col-md-6 col-md-offset-3 column">
{% if success == "1" %}
<div class="alert alert-success" role="alert">Invitation Email was successfully sent to {{ email }}</div>
{% endif %}
{% if success == "0" %}
<div class="alert alert-danger" role="alert">Failed to send Invitation Email to {{ email }}</div>
{% endif %}
<form id="search-form" action="" method="post">{% csrf_token %}
<div class="input-group input-group-sm">
{{ invite.email.errors }}
{{ invite.email }}
<span class="input-group-btn">
<button class="btn btn-search" type="submit">Invite</button>
</span>
</div>
</form>
</div>
</div>
{% endblock %}
URL-запись для этого будет следующей :
url(r'^invite/$', Invite.as_view()),
Теперь нам нужно создать методы get() и post(), чтобы отправить приглашение с помощью этой формы.
Так как отправка электронной почты более характерна для пользователя, чем твиты, мы создадим этот метод в user_profile, в противовес представлению tweets, которjt мы использовали ранее.
Обновите файл user_profile/views.py следующим кодом:
from django.views.generic import View
from django.conf import settings
from django.shortcuts import render
from django.template import Context
from django.template.loader import render_to_string
from user_profile.forms import InvitationForm, RegisterForm
from django.core.mail import EmailMultiAlternatives
from user_profile.models import Invitation, User
from django.http import HttpResponseRedirect
import hashlib
class Invite(View):
def get(self, request):
params = dict()
success = request.GET.get('success')
email = request.GET.get('email')
invite = InvitationForm()
params["invite"] = invite
params["success"] = success
params["email"] = email
return render(request, 'invite.html', params)
def post(self, request):
global invitation
form = InvitationForm(self.request.POST)
if form.is_valid():
email = form.cleaned_data['email']
subject = 'Invitation to join MyTweet App'
sender_name = request.user.username
sender_email = request.user.email
invite_code = Invite.generate_invite_code(email)
link = 'http://%s/invite/accept/%s/' % (settings.SITE_HOST, invite_code)
context = Context({"sender_name": sender_name, "sender_email": sender_email, "email": email, "link": link})
invite_email_template = render_to_string('partials/_invite_email_template.html', context)
msg = EmailMultiAlternatives(subject, invite_email_template, settings.EMAIL_HOST_USER, [email], cc=[settings.EMAIL_HOST_USER])
user = User.objects.get(username=request.user.username)
invitation = Invitation()
invitation.email = email
invitation.code = invite_code
invitation.sender = user
invitation.save()
success = msg.send()
return HttpResponseRedirect('/invite?success='+str(success)+'email='+email)
@staticmethod
def generate_invite_code(email):
secret = settings.SECRET_KEY
if isinstance(email, unicode):
email = email.encode('utf-8')
activation_key = hashlib.sha1(secret+email).hexdigest()
return activation_key
Здесь метод get () так же прост, как и отображениефайла invite.html с формой приглашения в качестве параметра, флагом success и переменной email первоначально не заданной.
Метод post() обычная форма проверки и концепция извлечения переменной; код, который вы увидите в первый раз выглядит следующим образом:
invite_code = Invite.generate_invite_code(email)
Это на самом деле вызов статической функции, создающий токен активации с уникальным ключом для каждого приглашенного пользователя. Метод render_to_string работает , когда вы загружаете шаблон под названием _invite_email_template.html и ему нужно передать следующие переменные:
Шаблон будет потом использоваться для отображения тела приглашения по электронной почте. После этого мы используем метод EmailMultiAlternatives для отправки письма, как мы делали во время интерактивного сеанса в предыдущем разделе.
Есть несколько замечаний, которые нужно здесь сделать:
render_to_string() и render() для построения тела сообщения в отличие от обычных вызовов render_to_response.Если вы помните, это ранее в этой книге это использовалось для отображения шаблонов.Мы делаем это здесь, потому что мы не отображаем веб-страницы.Поскольку метод send() загружает шаблон под названием _invite_email_template.html, создайте файл с этим именем в каталоге templates и вставьте следующее содержимое:
Привет
{{sender_name}} ({{sender_email}}) приглашает вас присоединиться к Mytweet.
Присоединитtcm, пожалуйста, нажав по ссылке{{link}}.
Это письмо было отправлено на {{email}}. Если вы считаете, оно послано ошибочно, пожалуйста, проигнорируйте.
Мы на полпути к имплементации функцию "пригласить друга". На данный момент, нажатие на ссылку выдает ошибку 404 "страница не найдена", таким образом, далее, мы напишем представление для его обработки.
Мы добились хорошего прогресса; Пользователи теперь имеют возможность отправлять приглашения своим друзьям по электронной почте. Следующий шаг заключается в создании механизма, который обрабатывает ссылку активации в приглашениях. Вот краткое изложение того, что мы собираемся делать.
Мы построим представление, которое обрабатывает ссылку активации.Это представление проверяет, что код приглашения действительно существует в базе данных, и что пользователь, который зарегистрировался, автоматически подписывается на пользователя, который отправил ссылку и он перенаправляется на страницу регистрации.
Давайте начнем с записи URL для представления. Откройте файл urls.py и добавьте выделенную строку к нему:
url(r'^invite/accept/(\w+)/$', InviteAccept.as_view()),
Создайте класс с именем InviteAccept() в файле user_profile/views.py.Создайте класс с именем InviteAccept() в файле user_profile/views.py.
Логически, InviteAccept будет работать когда пользователям будет предложено зарегистрироваться для приложения, и если они уже зарегистрированы, их попросят подписаться на пользователя который пригласил их.
Ради простоты мы перенаправим пользователя к странице регистрации с помощью кода активации, так, что когда он зарегистрируется, он автоматически становятся подписчиком.
Рассмотрим следующий код:
class InviteAccept(View):
def get(self, request, code):
return HttpResponseRedirect('/register?code='+code)
Затем мы напишем страницу регистрации с помощью следующего кода:
class Register(View):
def get(self, request):
params = dict()
registration_form = RegisterForm()
code = request.GET.get('code')
params['code'] = code
params['register'] = registration_form
return render(request, 'registration/register.html', params)
pass
def post(self, request):
form = RegisterForm(request.POST)
if form.is_valid():
print("HI")
username = form.cleaned_data['username']
email = form.cleaned_data['email']
password = form.cleaned_data['password']
try:
print("Already registered")
except:
user = User()
user.username = username
user.email = email
commit = True
user = super(user, self).save(commit=False)
user.set_password(password)
if commit:
user.save()
Как вы можете видеть, представление соответствует формату URL-адреса, послал по электронной почте приглашение. Код активации захватывается из URL-адреса, используя регулярное выражение и затем, передается в виде параметра.
Это заняло немного времени, но мы смогли найти хорошее применение нашим знаниям Django ддя имплементации этого.Вы можете теперь нажать на ссылку приглашения, что вы получили по электронной почте, чтобы увидеть, что происходит. Вы будете перенаправлены на страницу регистрации; можно создать новый аккаунт там, войти и обратите внимание, как новая учетная запись и ваша исходная запись, стал подписчиками отправителя.
Люди не будут использовать наше приложение, если они не могут читать его страницы. Пока мы занимались только с англоговорящими пользователями. Однако есть люди во всем мире, которые не знают английского языка или предпочитают использовать затем родной язык. Чтобы привлечь этих людей, было бы неплохо предложить интерфейс нашего приложения на нескольких языках. Это позволит преодолеть языковой барьер и открыть новые горизонты для нашего приложения, особенно в регионах, где английский язык не является распространенным
Как вы уже догадались, Django предоставляет все компоненты, необходимые для перевода проекта на несколько языков .Система, которая отвечает за предоставление этой возможности называется функцией интернационализации (il8n). Процесс перевода проекта Django довольно прост.
Вы выполните следующие три действия:
Мы рассмотрим каждый шаг подробно в следующих подразделах. В конце раздела этой главы наше приложение будет поддерживать несколько языков, и вы сможете перевести любой другой проект Django с легкостью.
Первый шаг в переводе приложения - указать Django, какие строки должны быть переведены. Вообще говоря строки, которые являются частью представления и шаблона должны быть переведены, в то время как строки, которые вводятся пользователем не требуется переводить.Маркировка строк как переводимых делается с помощью вызова функции. От имени функции и от того, как она называется, зависит, где находится строка: в представлении, шаблоне, модели или форме.
Этот шаг гораздо проще, , чем первоначально выглядит. Давайте узнаем об этом на примере .Мы переведем функциональную возможность"приглашение подписчика" ф в нашем приложении. Процесс перевода остальной части приложения будет точно таким же. Откройте файл user_profile/view.py и сделать подсвеченные изменения в представление:
from django.utils.translation import ugettext as __
from django.views.generic import View
from django.conf import settings
from django.shortcuts import render
from django.template import Context
from django.template.loader import render_to_string
from user_profile.forms import InvitationForm, RegisterForm
from django.core.mail import EmailMultiAlternatives
from user_profile.models import Invitation, User
from django.http import HttpResponseRedirect
import hashlib
class Invite(View):
def get(self, request):
params = dict()
success = request.GET.get('success')
email = request.GET.get('email')
invite = InvitationForm()
params["invite"] = invite
params["success"] = success
params["email"] = email
return render(request, 'invite.html', params)
def post(self, request):
global invitation
form = InvitationForm(self.request.POST)
if form.is_valid():
email = form.cleaned_data['email']
subject = 'Invitation to join MyTweet App'
sender_name = request.user.username
sender_email = request.user.email
invite_code = Invite.generate_invite_code(email)
link = 'http://%s/invite/accept/%s/' % (settings.SITE_HOST, invite_code)
context = Context({"sender_name": sender_name, "sender_email": sender_email, "email": email, "link": link})
invite_email_template = render_to_string('partials/_invite_email_template.html', context)
msg = EmailMultiAlternatives(subject, invite_email_template, settings.EMAIL_HOST_USER, [email], cc=[settings.EMAIL_HOST_USER])
user = User.objects.get(username=request.user.username)
invitation = Invitation()
invitation.email = email
invitation.code = invite_code
invitation.sender = user
invitation.save()
success = msg.send()
return HttpResponseRedirect('/invite?success='+str(success)+'email='+email)
@staticmethod
def generate_invite_code(email):
secret = settings.SECRET_KEY
if isinstance(email, unicode):
email = email.encode('utf-8')
activation_key = hashlib.sha1(secret+email).hexdigest()
return activation_key
Заметьте, что строка субъекта начинается с символа "_"; альтернативно, вы могли написать так:
from django.utils.translation import ugettext subject = ugettext'Invitation to join MyTweet App'
В любом случае, это отлично работает.
Как вы можете видеть, изменения минимальны:
Это было довольно просто, не так ли? Однако, давайте немного посмотрим, что нам нужно сделать здесь. Первое сообщение использует строку форматирования, и мы применяем оператор % после вызова функции _ (). Это необходимо, чтобы избежать перевода адреса электронной почты. Также предпочтительнее использовать именованные форматы, которые дают вам больший контроль, пока вы оставляете фактический перевод на потом. Таким образом вы можете определить следующий код:
message= \
_('An invitation was sent to %(email)s.') % {
'email': invitation.email}
Теперь, когда мы знаем, как пометить строки как переводимые в представлениях, давайте перейдем к шаблонам. Откройте файл invite.html в каталоге templates и измените его следующим образом:
{% extends "base.html" %}
{% load staticfiles %}
{% load i18n %}
{% block content %}
<div class="row clearfix">
<div class="col-md-6 col-md-offset-3 column">
{% if success == "1" %}
<div class="alert alert-success" role="alert">
{ % trans Invitation Email was successfully sent to %} {{ email }}
</div>
{% endif %}
{% if success == "0" %}
<div class="alert alert-danger" role="alert">Failed to send Invitation Email to {{ email }}</div>
{% endif %}
<form id="search-form" action="" method="post">{% csrf_token %}
<div class="input-group input-group-sm">
{{ invite.email.errors }}
{{ invite.email }}
<span class="input-group-btn">
<button class="btn btn-search" type="submit">Invite</button>
</span>
</div>
</form>
</div>
</div>
{% endblock %}
Здесь, мы разместили параметр{% load i18n %} в начале шаблона, чтобы дать ему доступ к тегам перевода. Тег <load> обычно используется для включения дополнительных тегов шаблона, которые не доступны по умолчанию.Вам нужно поместить его в верхней части каждого шаблона, который использует теги перевода .i18n это сокращение для интернационализации, который является именем фреймворка Django, предоставляющим функции перевода.
Далее мы использовали тег шаблона trans для обозначения строки как переводимой. Этот тег шаблона работает точно так же, как функция gettext в представлениях. Стоит отметить, что тег trans не работает, если строка содержит переменную шаблона.
В этом случае вам будет нужно использовать тег blocktrans:
{% blocktrans %}
Можно передать переменную блока, такую как {{variable}} также внутри блока {% endblocktrans %}, чтобы сделать его более значимым для читателя.
Теперь вы знаете, как бороться с переводимыми строки и в шаблонах. Итак давайте перейдем к формам и моделям. Маркировка строки как переводимой в форме или модели немного отличается от представления. Чтобы узнать, как это делается, откройте файл user_profile/models.py и измените форму приглашения следующим образом:
django.utils.translation gettext_lazy as _
class InvitationForm(forms.Form):
email = forms.CharField(widget=forms.TextInput(attrs={'size': 32, 'placeholder': _('Email Address of Friend to invite.'), 'class':'form-control'}))
Единственная разница состоит в том, что мы импортировали функцию gettext_lazy вместо gettext. gettext_lazy создает задержку перевода строки, пока возращаемый результат не будет доступен.Здесь это необходимо потому, что атрибуты формы создаются только один раз: когда приложение запущено. Если мы используем функцию gettext, переведенные надписи будут храниться в форме атрибутов, используя язык по умолчанию (обычно английский) и никогда не будут переводиться снова. Однако если мы используем функцию gettext_lazy, функция будет возвращать специальный объект, который будет переводить строку каждый раз, когда осуществляется доступ к нему, и, следовательно, перевод будет сделан правильно. Эта особенность делает функцию gettext_lazy идеально подходящей для атрибутов формы и модели.
На этом мы закончим, маркировку строки вида "пригласить друга" для перевода.
Чтобы помочь вам вспомнить, что охватил этот подраздел ,вот краткий обзор методов, используемых для обозначения переводимых строк:
Конечно,существуют особые случаи, которые могут быть обработаны отдельно. Например вы можете перевести значения параметров по умолчанию в представлениях, используя функцию gettext_lazy вместо gettext. До тех пор, как вы понимаете разницу между этими двумя функциями, вы в состоянии решить, когда вам нужно это осуществлять.
Теперь, когда мы закончили, маркировку строк для перевода, следующим шагом является создание файла перевода для каждого языка, поддержку которого мы хотим обеспечить. Этот файл содержит все переводимые строки вместе с их переводами и создается с помощью утилиты, предоставляемой Django.
Создадим файл перевода. Во-первых вам нужно найти файл с именем make-messages py в каталоге bin внутри каталога установки Django. Самый простой способ найти его — с помощью функции поиска вашей операционной системы. После того как вы найдете его, скопируйте его в ваш системный путь (/usr/bin/ в Linux и Mac OS X и C:\windows\ в Windows ).
Кроме того убедитесь, что это исполняемый файл, выполнив следующую команду в Linux и Mac OS X (этот шаг не требуется для пользователей Windows):
sudo chmod + x /usr/bin/make-messages.py
Утилита make-messages py использует пакет программного обеспечения под названием GNU gettext для извлечения переводимых строк из исходного кода.Т аким образом вам нужно установить этот пакет.
Для Linux найдите пакет в ваш менеджере пакетов и установите его. Пользователи Windows могут найти установщик пакета на http: //gnuwin32.sourcef orge.NET/packages/gettext.htm.
Наконец, пользователи Mac OS X могут найти версию пакета для их операционной системы, а также инструкции по установке на http://gettext.DarwinPorts.com.
Как только у вас установлен пакет GNU gettext, откройте терминал, перейдите в папку проекта, создайте там каталог locale , а затем запустите следующую команду:
make-messages.py -1 de
Эта команда создаст файл перевода для немецкого языка. Переменная de -это языковой код для немецкого языка. Если вы хотите перевести еще на один язык, поставьте его языковыой код вместо de и продолжайте делать это остальной части главы .В дополнение к этому,если вы хотите поддержать больше чем один язык, запустите предыдущую команду для каждого языка и примените инструкции оставшейся части раздела всех языков.
После выполнения предыдущей команды, она создаст файл с названием django.po в locale/de/LC_MESSAGES /. Это файл перевода для немецкого языка. Откройте его в текстовом редакторе, чтобы увидеть, как он выглядит. Файл начинается с некоторых метаданных, таких как дата создания и набор символов. После этого вы найдете запись для каждой переводимой строки. Каждая запись состоит из имени файла, номера строки, самой строки и пустой строки под ней, где должен быть перевод.Вот пример записи из файла:
#: user_profile/forms.py msgid "Friend's Name" msgstr ""
Чтобы перевести строку, просто используйте свой текстовый редактор, чтобы набрать перевод в пустой строке в третьей строке. Можно также использовать редактор специализированного перевода, например Poedit (доступен для всех основных операционных систем на http //www.poedit.net/), но для нашего простого файла, должно быть достаточно обычного редактора текста.Убедитесь, что вы установили допустимый символ в разделе метаданных файла.Я рекомендую вам использовать UTF-8:
"Content-Type: text/plain; charset=UTF-8\n"
Вы можете отметить, что перевод файла содержит несколько строк интерфейса администрирования. Это потому, что шаблон администратора admin/base_site.html использует тег шаблона trans для обозначения строки как переводимой. Эти строки не нужно переводить; Django уже поставляется с переводом файлов для них.
Как только вы закончите перевод, вам необходимо скомпилировать файл перевода в формате, который можно использовать с Django. Этоо можно сделать с помощью другой утилиты, предоставляемой Django, командой compile-messages.py. Найдите и поместите этот файл в ваш системный путь и убедитесь, что это исполняемый файл, следуя той же процедуре, какой мы следовали с командой make-messages.py.
Далее, выполните следующую команду в каталоге вашего проекта:
compile-messages.py
Если утилита жалуется на ошибку в файле (например, отсутствует знак кавычек), исправьте ошибку и попробуйте еще раз. После того, как все завершилось успешно, утилита создаст скомпилированный перевод в файле django.mo в том же каталоге и все будет установлено для следующего шага в данном разделе.
Django поставляется с системой il8n, она по умолчанию включена. Это можно проверить путем поиска строки в файле settings.py:
USE_I18N = True
Существует два способа настройки системы il8n.Можно установить язык глобально для всех пользователей или позволить пользователям указывать предпочитаемые ими языки индивидуально.
Мы увидим, как сделать оба этих варианта в этом подразделе.
Чтобы задать активный язык глобально, найдите в файле settings.py переменную LANGUAGE_CODE и назначьте предпочитаемый вами язык кода к нему. Например если вы хотите задать немецкий язык языком по умолчанию для нашего проекта, измените код языка следующим:
LANGUAGE_CODE = "de"
Теперь запустите сервер разработки, если он еще не запущен и перейдите к странице "пригласить друга". Там, вы обнаружите, что строки были изменены согласно тому, что вы ввели в немецком переводе файла. Теперь измените значение переменной LANGUAGE_CODE на "en" и обратите внимание, как страница возвращается обратно на английский.
Второй способ настройки заключается в том, чтобы позволить пользователям выбирать язык. Чтобы сделать это, мы должны разрешить класс под названием LocaleMiddleware. Проще говоря, middleware — это класс, который обрабатывает объект запроса или ответа. Многие компоненты Django созданы для использования классов middleware для имплементации функций. Чтобы увидеть это, откройте файл settings.py и найдите переменную MIDDLEWARE_CLASSES. Вы найдете там список строк, и одна из них будет django.contrib.sessions.middleware.SessionMiddleware, которая прикрепляет данные сессии к объекту запроса. Нам не нужно знать, как имплементированы классы middleware перед их использованием. Для включения LocaleMiddleware, просто добавьте путь его класса в список MIDDLEWARE_CLASSES. Следует убедиться, что вы поместили LocaleMiddleware после SessionMiddleware потому что язык middleware использует API сессии, как мы увидим далее. Откройте файл settings.py и измените файл, как это подчеркивается в следующем фрагменте кода:
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
Язык middleware определяет активный язык для пользователя, для этого выполняетследующие действия:
Проделав все описанные выше шаги, Django ищет код языка, который соответствует одному из доступных файлов перевода. Чтобы эффективно использовать язык middleware, нам нужно представление, которое позволяет пользователю выбрать язык и соответствующим образом обновляет данные сеcсии. К счастью,Django уже поставляется с таким представлением для нашего использования. Представление называется setlanguage, и он ожидает, что код языка содержится в GET переменной с именем языка. Он обновляет данные сессии с помощью этой переменной и перенаправляет пользователя на исходную страницу.Чтобы включить это представление, отредактируйте файл urls.py и добавьте следующие выделенные строки:
urlpattems = patterns # il8n (r'Ail8n/', include(1django.conf.urls.il8n1)), )
Добавление предыдущих строк похоже на то, как мы добавили записи для интерфейса администратора. Если вы помните из предыдущей главы, функция include() может использоваться для включения URL-записей из другого приложения под определенным путем. Теперь, мы можем позволить пользователю изменить язык на немецкий, предоставив ссылку, например, /i18n/setlang/language=de. Мы изменим базовый шаблон для добавления таких ссылок на все страницы. Откройте файл base.html и добавьте следующие выделенные строки к нему:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtmll/DTD/xhtmll-transitional.dtd" > <html></html> <head></head> [...] </head> <body></body> [...1 <div id="footer"></div> Django Mytweets<br> Languages <a href="/il8n/setlang/?language=en">EN</a> <a href="/il8n/setlang/?language=de">DE</a> </body> </html>
Кроме того мы стилизуем новый подвал, добавив следующий CSS код для стиля
site_media/style.css:
#footer { margin-top: 2em; text-align: center;
}
Теперь функциональность i18n нашего приложения готова. Укажите вашему браузеру на страницу "пригласить друга" и попробуйте ссылки на новые языки в нижней части страницы. Язык должен изменится, согласно той ссылке, по которой вы перешли.
Прежде чем мы завершим этот раздел, нужно сделать несколько замечаний:
Этот разделе было немного длинным, но вы узнали из него об очень важных функциях. Предлагая приложения на нескольких языках, мы сделаем его доступным для более широкой аудитории, что дает ему больший потенциал для привлечения все большего числа пользователей. Это на самом деле относится к любому веб-приложению, и теперь, мы сможем перевести любого проект Django на несколько языков с легкостью.
В следующем разделе, мы перейдем к другой теме. Когда база пользователей вашего приложения вырастет, это увеличит нагрузку на ваш сервер, и вы начнете искать пути для улучшения производительности вашего приложения. Здесь на помощь приходит кэширование
Так что пожалуйста, прочитайте дальше, чтобы узнать об очень важной технике!
Страницы веб-приложений создаются динамически. Для обработки ввода пользователя и создания вывода каждый раз, когда страница запрашивается выполняется код. Есть много накладных расходов, участвующих в создании динамических страниц, особенно по сравнению с обслуживанием статических html файлов. Код может подключиться к базе данных, выполнять дорогие вычисления, обрабатывать файлы и так далее. В то же время, если сайт может генерировать страницы с кодом- это именно то, что делает веб-сайт динамичным и интерактивным.
Но было бы замечательно, если бы мы могли получить лучшее из обоих миров? Это именно то, что делает кэширование, и это фунция, которая имплементирована на большинстве сайтов со средним или большим трафиком. Когда страница запрашивается, кэширование сохраняет созданный HTML-код страницы и использует его позже, когда же страница запрашивается снова. Это убирает много накладных расходов, избегая генерирования одной и той же страницы снова и снова. Конечно, кэшированные страницы не сохраняются навсегда. Когда страница кэшируется, устанавливается срок действия для кэша. По истечении срока действия кэшированная страница удаляется и создается страница и снова кэшируется. Срок обычно составляет от нескольких секунд до нескольких минут, в зависимости от загруженности сайта. Срок гарантирует, что кэш обновляется периодически и что пользователи получают обновления содержимого, и в то же время, это снижает издержки генерации страниц.
Хотя кэширование особенно полезно для сайтов со средним и большим трафиком, сайты с низким трафиком могут также им воспользоваться. Если на сайте внезапно случится всплеск большого трафика, возможно потому, что он был показан на сайте основных новостей, можно включить кэширование, чтобы уменьшить нагрузку на сервер и помочь вашему сайту пережить всплеск большого трафика. Позже, когда трафик пойдет на спад, вы можете отключить кэширование. Таким образом кэширование также полезно для небольших сайтов. Вы никогда не знаете, когда это вам может понадобиться, так что лучше запастись информацией заранее.
Мы начнем этот раздел в включения системы кэширования. Чтобы использовать кэширование, необходимо сначала выбрать кэширование внутреннего интерфейса и задавать свой выбор в переменной с именем CACHE_BACKEND в файле settings.py.Содержимое этой переменной зависит от кэширования внутреннего интерфейса, который вы выбрали. Некоторыми из доступных вариантов являются:
CACHE_BACKEND = ' simple’:///'
python manage.py createcachetable cache_table
Затем добавьте следующую строку к файлу settings.py:
CACHE_BACKEND = ' db://cache_table'
Здесь в таблица кэша была названа cache_table. Вы можете назвать ее, как вы хотите, до тех пор, пока название не конфликтует с существующей таблицей.
CACHE_BACKEND = "file:///tmp/django_cache"
Здесь переменная /tmp/django_cache используется для хранения файлов кэша. Вы можете задавать другой путь, если вам так нравится.
CACHE_BACKEND = 'memcached://ip:port/'
Если вы не уверены, какой сделать выбор в этом разделе, возьмите простое кэширование, если же вы в процессе работы столкнетесь сбольшим трафиком и захотите улучшить производительность сервера, выберите кэширование в базу данных или память, в зависимости от того, что доступно на вшем сервере. С другой стороны, если у вас сайт со средним или большим трафиком, я рекомедую вам использовать кэширование в память, так как это действительно самое быстрое решение, доступное для Django. Информация, приведенная в этом разделе, приводится безотносительно к вашему выбору.
Таким образом, примите решение о кэшировании и вставьте соответствующую переменную CACHE_BACKEND в файл settings.py. Далее, вы должны задать продолжительность срока действия кэшированных страниц в секундах. Добавьте следующую строку в файл settings.py для кэширования страниц в течении пяти минут:
CACHE_MIDDLEWARE_SECONDS = 60 5
Теперь мы включили систему кэширования. Продолжайте читать, чтобы узнать о том, как использовать кэширование для повышения производительности вашего приложения:
Можно настроить Django, чтобы кэшировать весь сайт или конкретные представления. Мы изучим, как это делать в этом подразделе.
Чтобы кэшировать весь сайт, добавьте класс CacheMiddleware к классу MIDDLEWARE_ CLASSES в файле settings.py:
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.middleware.Cache.CacheMiddleware',
'django.middleware.doc.XViewMiddleware',
'django.middleware.locale.LocaleMiddleware',
)
Здесь мы определили такой порядок, какой он был, когда мы добавили язык middleware. Класс CacheMiddleware следует добавить после сессии и аутентификации промежуточного классы и перед LocaleMiddleware.
Вот и все, что вам нужно для кэширования вашего сайта на Django. Теперь всякий раз, когда страница запрашивается, Django будет сохранять созданный HTML-код и использовать его позже. Важно понимать, что система кэширования только кэширует страницы, которые не имеют переменных GET и POST.Таким образом, наши пользователи по-прежнему будет возможность отправлять твиты и подписываться на друзей, потому что представления этих страниц ожидают переменных GET или POST. С другой стороны, страницы, таких как списки твитов и хэштегов также будут кэшироваться.
Иногда, вам хочется кэшировать только отдельные страницы вашего веб-сайта — возможно сайт с высоким трафиком связан с этой вашей страницей, так что большая часть трафика будет направляться на определенную страницу. В этом случае, следует кэшировать только эту страницу. Еще один хороший кандидат для кэширования — страница, которую дорого создавать., даже если бы она будет создана один раз каждые пять минут или около того. Страница с облаком тегов в нашем приложении вписывается в последний случай. Каждый раз, когда страница запрашивается, Django перебирает все теги в базе данных, и считает количество твитов для каждого тега. Это является ресурсоемкой операцией, потому что она требует большое количество запросов к базе данных. Таким образом кэширование этого представления является хорошей идеей.
Чтобы кэшировать представления, основанные на классе HashTag, вы просто применяете метод, называемый cache_page и параметр кэширования вместе с ним. Попробуйте это, изменив файл mytweets /urls.py как указано в следующем коде:
from django.views.decorators.cache import cache_page url(r'^search/hashTag$', cache_page(60 * 15)(SearchHashTag.as_view())),
На этой информации мы и закончим этот раздел. Кэширование будет необходимо, когда вы впервые выпустите свой публичный веб-сайт Однако когда ваш сайт вырастет, или если вы вдруг получите всплеск большого трафика, система кэширования, безусловно, станет удобной. Таким образом, помните об этом, когда отслеживаете производительность вашего приложения.
Далее мы собираемся узнать об инструментах тестирования Django. Тестирование может быть утомительной задачей. Было бы здорово, если вы могли бы запустить одну команду и она позаботилась о тестировании вашего сайта? Django позволяет вам сделать это, и мы узнаем об этом в следующем разделе.
Фрагменты шаблона могут быть кэшированы в следующей манере::
% load cache %}
{% cache 500 sidebar %}
.. sidebar ..
{% endcache %}
На протяжении этой книги мы иногда изменяли представления, которые мы писали ранее. На самом деле это происходит довольно часто при разработке программного обеспечения. Вы можете изменить или даже переписать функцию для изменения деталей имплементации, поскольку изменились требования, или просто для того, чтобы рефакторить код и сделать его более читабельным.
Когда вы изменяете функцию, вы должны проверить ее еще раз, чтобы убедиться, что ваши изменения не приводят к ошибке. Однако тестирование станет скучной задачей, если вам нужно повторять те же тесты снова и снова, каждый раз, когда вы изменяете функцию. Вы также можете забыть проверить все аспекты функционирования, если они хорошо не задокументированы. Очевидно это не идеальная ситуация; нам определенно нужно создать более совершенный механизм для обработки тестирования.
К счастью, для этого уже существует решение. Это называется юнит-тестированием. Идея состоит в том, что вы пишете код для тестирования кода. Тестирование кода вызывает ваши функции и проверяет, что они ведут себя как, ожидалось и выводит на печать отчет с результатами. Вы только должны написать код тестирования один раз. Далее, всякий раз, когда вы хотите организовать проверку, можно просто запустить код тестирования и изучить отчет с результатом.
Python поставляется с инструментами для юнит-тестирования. Он расположен в модуле юнит-тестирования. Django расширяет эти инструменты, добавляя поддержку тестирования представлений. Мы узнаем, как использовать юнит-тестирование Django в этом разделе.
В порядке взаимодействия с представлениями, Django предоставляет класс, который эмулирует функциональность браузера. Можно использовать его для того, чтобы посылать запросы вашему приложению и получать ответы. Давайте узнаем об этом с помощью интерактивной консоли. Запустите консоль с помощью этой команды:
python manage.py shell
Импортируйте класс Client (), создайте объект Client и получите домашнюю страницу приложения, используя запрос GET:
>>>from django.test.client import Client client = Client()
>>> response = client.get("/")
>>> print response
X-Frame-Options: SAMEORIGIN Content-Type: text/html; charset=utf-8
<html>
<head>
<link href = "/static/css/bootstrap.min. css"
rel="stylesheet" media="screen">
</head>
<body>
cnav class="navbar navbar-default" role="navigation">
<a class="navbar-brand" href="#">MyTweets</a>
</nav> cdiv class="container">
</div>
<nav class="navbar navbar-default navbar-fixed-bottom" role="navigation">
<p class="navbar-text navbar-right">Footer</p>
</nav>
<script src="/static/js/jquery-2.1.1.min.js"></script>
<script src="/static/js/bootstrap.min.js"></script>
<script src="/static/js/base.js"></script> </body> </html>
>>>
Попробуйте отправить запрос POST к представлению login. Выходные данные будут меняться в зависимости от того, предоставили ли вы правильные учетные данные или нет:
>>> print client.post('/login/',{' username': 'ваше имя',
'password': 'ваш пароль'})
Наконец если существует представление, которое разрешено только вошедшим в систему пользователям,вы можете отправить такой запрос для него:
>>> print client.login('/friend/invite/', 'yourusername',
'yourpassword')
Как вы можете видеть из интерактивного сеанса, класс Client ()предоставляет три метода:
Класс Client () способен отслеживать состояние, что означает, что он сохраняет свое состояние между запросами. После того как вы вошли в систему, далее запросы будут обрабатываться при входе в систему. Объект ответа возвращается методами класса Client (), содержащими следующие атрибуты:
Эти поля являются полезными для проверки, был ли успешен тест или нет, как мы увидим дальше. Не стесняйтесь экспериментировать больше с классом Client (). Важно понять, как это работает, прежде чем вы перейдете к следующему подразделу, где мы создадим первый юнит-тест.
Тестирование регистрации представления
Теперь, когда вы знакомы с классом Client (), напишем ваш первый тест. Юнит-тесты должны находиться в модуле с именем tests.py внутри каталога приложения. Каждый тест должен быть методом в классе, производном от модуля django.test.TestCase. Имя метода должно начинаться со слова test. Имея это в виду мы напишем метод теста, который пытается зарегистрировать новую учетную запись пользователя. Таким образом создайте файл с именем tests.py внутри каталога bookmarks и напечатайте в него следующее содержимое:
from django.test import TestCase
from django.test.client import Client
class ViewTest(TestCase) :
def setUp (self):
self.client = Client()
def testregisterpage(self):
data = {
'username': 'testuser',
'email': 'test_user@example.com',
'passwordl': 'passl23',
'password2‘: 'passl23'
}
response = self.client.post('/register/', data) self.assertEqual(response.status_code, 302) }
Давайте пройдемся по коду построчно:
Как вы помните из предыдущей главы, представление регистрации перенаправляет пользователя, если запрос завершается успешно.
Мы проверили объект ответа с помощью метода assertEqual().Этот метод наследуется от класса TestCase. Это вызывает исключение, если два переданных аргументов не равны. Если возникает исключение, окружение тестирования узнает,тест не был пройден; в противном случае, если исключение не появляется, предполагается, что тест успешно пройден.
Класс TestCase предоставляет набор методов для использования в тестировании. Вот список важных методов:
Теперь, когда вы понимаете тестовый класс, давайте запустим реальный тест, выполнив команду:
python manage.py test Результат будет примерно следующим: Creating test database... Creating table authmessage Creating table authgroup Creating table authuser Creating table authpermission [. ..] Loading 1initialdata' fixtures... No fixtures found. Ran 1 test in 0.170s OK Destroying test database...
Так что же здесь произошло? Окружение тестирования начинается с создания тестовой базы данных с таблицами аналогичными тем, которые существуют в реальной базе данных. Далее выполняются тесты, найденные в тестирующем модуле. И в завершении будет напечатан отчет о результатах и произойдет уничтожение тестовой базы данных.
Наш тест прошел успешно. Чтобы увидеть, какой будет вывод, если тест окажется не пройденным , измените представление test_register_page в файле tests.py путем удаления необходимой формы поля:
def test_register_page(self): data = {
'username1: 'test_user',
'email': 1test_user@example.com1,
'passwordl': '1',
# 'password2': 11'
}
response = self.client.post('/register/', data) self.assertEqual(response.status_code, 302)
Теперь выполните команду python manage.py test снова, чтобы увидеть результаты:
FAIL: testregisterpage (mytweets.userprofile.tests.ViewTest) ------------------------------------------------------------ Traceback (most recent call last): File "mytweets/userprofile/tests.py", line 19, in test_ register_page self.assertEqual(response.status_code, 302) AssertionError: 200 1= 302 ------------------------------------------------------------- Ran 1 test in 0.170s FAILED (failures=l)
Наш тест работает! Django обнаружил ошибку и дал нам точные подробности того, что произошло. Не забудьте вернуть тест к своей первоначальной форме, как только вы закончите. А сейчас давайте напишем еще один тест, чуть более сложный, чтобы понять лучше инструменты тестирования.
Существует множество других сценариев, для которых можно написать юнит-тесты:
Выше перечислены только примеры. Написание юнит- тестов для охвата как можно больших вариантов использования имеет важное значение для поддержания здоровых приложения и сведения к минимуму ошибкок и регрессий. Чем больше юнит-тестов вы пишете, тем более вы можете быть уверены, что приложение проходит все тесты. Django делает чрезвычайно простым юнит- тестирование приложения, поэтому используйте этот факт.
Контрольные вопросы
Упражнения
Упражнение 1.
Закончить перевод проекта
Упражнение 2.
Упражнение 2.
Упражнение 3.
Реализовать одну из систем кэширования для проекта
Упражнение 4.
Создать файл перевода проекта
Список тем, эссе
Краткие итоги
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.