Введение в Django

Расширение и развертывание

Показывать лекцию целиком

Цель лекции: Создать модель данных приглашения и реализовать ее; создание страницы отправки приглашения; ознакомиться с системой интернационализации; научиться работать с системой кэширования.

Ключевые термины: интернационализация, проект, электронная почта, кэширование, память, файл, 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 = ''
    

    Давайте посмотрим, что делает каждая переменная в предыдущем коде:

  • SITE_HOST: Это имя вашего сервера. Оставьте его пока как 127.0.0.l: 8000.Когда мы развернем наш сервер в следующей главе, мы изменим его.
  • DEFAULT_FROM_EMAIL: Это адрес электронной почты, который появляется в поле From для исходящего почтового сервера. Для пользователя хоста введите свое имя плюс ваш почтовый сервер, как показано в предыдущем образце кода. Оставьте это поле пустым, если ваш провайдер не требует этого.
  • DEFAULT_FROM_EMAIL: Это адрес электронной почты, который появляется в поле From для исходящего почтового сервера. Для пользователя хоста введите свое имя плюс ваш почтовый сервер, как показано в предыдущем образце кода. Оставьте это поле пустым, если ваш провайдер не требует этого.
  • EMAIL_PORT: Это номер порта сервера электронной почты.Если вы оставите его пустым, будет использоваться значение по умолчанию (25).Вам также нужно получить его от вашего провайдера.
  • EMAIL_HOST_USER И EMAIL_HOST_PASSWORD: Это имя пользователя и пароль, для электронной почты,отправленной Django.
  • Если на вашей машине разработки работает почтовый сервер, скорее всего, это так, то вам нужно ввести исходящий почтовый сервер вашего провайдера. Для получения дополнительной информации обратитесь к своему провайдеру.

    Чтобы проверить правильность настройки, запустите интерактивную оболочку и введите следующее:

    >>> 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 и ему нужно передать следующие переменные:

  • sender_name: это имя лица, который пригласил вас или отправителя электронной почты
  • sender_email: это адрес электронной почты отправителя
  • email: это адрес электронной почты человека, который был приглашен
  • link: это ссылка принятия приглашения
  • Шаблон будет потом использоваться для отображения тела приглашения по электронной почте. После этого мы используем метод EmailMultiAlternatives для отправки письма, как мы делали во время интерактивного сеанса в предыдущем разделе.

    Есть несколько замечаний, которые нужно здесь сделать:

  • Форматом ссылки активации является http: //SlTE_HOST/invite/accept/ code /.Мы мы напишем представление, чтобы обрабатывать такие URL-адреса в этом разделе.
  • В первый раз мы используем шаблон для отображения чего-то, отличного от веб-страницы.Как вы можете видеть, система шаблонов является достаточно гибкой и позволяет нам строить письма, а также веб-страницу или любой другой текст по этому вопросу.
  • Мы использовали методы 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 ддя имплементации этого.Вы можете теперь нажать на ссылку приглашения, что вы получили по электронной почте, чтобы увидеть, что происходит. Вы будете перенаправлены на страницу регистрации; можно создать новый аккаунт там, войти и обратите внимание, как новая учетная запись и ваша исходная запись, стал подписчиками отправителя.

    Интернационализация (i18n) - предложение сайта на нескольких языках

    Люди не будут использовать наше приложение, если они не могут читать его страницы. Пока мы занимались только с англоговорящими пользователями. Однако есть люди во всем мире, которые не знают английского языка или предпочитают использовать затем родной язык. Чтобы привлечь этих людей, было бы неплохо предложить интерфейс нашего приложения на нескольких языках. Это позволит преодолеть языковой барьер и открыть новые горизонты для нашего приложения, особенно в регионах, где английский язык не является распространенным

    Как вы уже догадались, Django предоставляет все компоненты, необходимые для перевода проекта на несколько языков .Система, которая отвечает за предоставление этой возможности называется функцией интернационализации (il8n). Процесс перевода проекта Django довольно прост.

    Вы выполните следующие три действия:

  • Задать, какие строки должны быть переведены в приложении — например, состояние и сообщения об ошибках могут быть переведены, тогда как имена не требуют перевода.
  • Создайте файл перевода для каждого языка, который вы хотите поддерживать.
  • Включить и настроить систему ilSn
  • Мы рассмотрим каждый шаг подробно в следующих подразделах. В конце раздела этой главы наше приложение будет поддерживать несколько языков, и вы сможете перевести любой другой проект 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'
    

    В любом случае, это отлично работает.

    Как вы можете видеть, изменения минимальны:

  • Мы импортировали функцию под названием ugettext из django.utils.translation.
  • Мы использовали ключевое слово as, чтобы назначить более короткое имя функции (символ подчеркивания). Мы сделали это, потому что эта функция будет использоваться для обозначения строки как переводимой в представлениях, и так как это является весьма распространенной задачей, дать функции более короткое имя – хорошая идея.
  • Мы пометили строку как переводимую просто передав ее функции __.
  • Это было довольно просто, не так ли? Однако, давайте немного посмотрим, что нам нужно сделать здесь. Первое сообщение использует строку форматирования, и мы применяем оператор % после вызова функции _ (). Это необходимо, чтобы избежать перевода адреса электронной почты. Также предпочтительнее использовать именованные форматы, которые дают вам больший контроль, пока вы оставляете фактический перевод на потом. Таким образом вы можете определить следующий код:

    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 (как правило, импортируется как _)
  • В шаблонах, пометка переводимых строк осуществляется с помощью тега шаблона trans для строк, которые не содержат переменных и тега blocktrans для строк, которые их содержат
  • Для форм и моделей, пометка переводимых строк осуществляется с помощью функции 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 в том же каталоге и все будет установлено для следующего шага в данном разделе.

    Включение и настройка системы i18n

    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_language в данных сессии.
  • Если ключ не существует, он ищет файл cookie по имени django_language.
  • Если cookie-файл не существует, он ищет код языка в заголовке Accept-Language HTTP. Он отправляется браузером на веб-сервер, указывая на каких языках вы предпочитаете получать содержимое.
  • Если все это не получилось, используется переменная LANGUAGE_CODE language_code в файле settings.py.
  • Проделав все описанные выше шаги, 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 нашего приложения готова. Укажите вашему браузеру на страницу "пригласить друга" и попробуйте ссылки на новые языки в нижней части страницы. Язык должен изменится, согласно той ссылке, по которой вы перешли.

    Прежде чем мы завершим этот раздел, нужно сделать несколько замечаний:

  • Вы можете получить доступ к языку, активному в данное время активный язык в представлениях, с помощью атрибута language_code запроса.
  • Django, сам переведен на ряд языков.Вы видите это, вызывая формы ошибки во время выбора языка, когда активен язык, отличный от английского. Сообщения об ошибках будут отображаться на выбранном языке даже несмотря на то, что вы не переводите их самостоятельно.
  • В шаблонах,когда используется переменная RequestContext, текущий активный языкдоступен с помощью переменной шаблона LANGUAGE_CODE.
  • Этот разделе было немного длинным, но вы узнали из него об очень важных функциях. Предлагая приложения на нескольких языках, мы сделаем его доступным для более широкой аудитории, что дает ему больший потенциал для привлечения все большего числа пользователей. Это на самом деле относится к любому веб-приложению, и теперь, мы сможем перевести любого проект Django на несколько языков с легкостью.

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

    Так что пожалуйста, прочитайте дальше, чтобы узнать об очень важной технике!

    Кэширование - улучшение производительности вашего сайта во время большого трафика

    Страницы веб-приложений создаются динамически. Для обработки ввода пользователя и создания вывода каждый раз, когда страница запрашивается выполняется код. Есть много накладных расходов, участвующих в создании динамических страниц, особенно по сравнению с обслуживанием статических html файлов. Код может подключиться к базе данных, выполнять дорогие вычисления, обрабатывать файлы и так далее. В то же время, если сайт может генерировать страницы с кодом- это именно то, что делает веб-сайт динамичным и интерактивным.

    Но было бы замечательно, если бы мы могли получить лучшее из обоих миров? Это именно то, что делает кэширование, и это фунция, которая имплементирована на большинстве сайтов со средним или большим трафиком. Когда страница запрашивается, кэширование сохраняет созданный HTML-код страницы и использует его позже, когда же страница запрашивается снова. Это убирает много накладных расходов, избегая генерирования одной и той же страницы снова и снова. Конечно, кэшированные страницы не сохраняются навсегда. Когда страница кэшируется, устанавливается срок действия для кэша. По истечении срока действия кэшированная страница удаляется и создается страница и снова кэшируется. Срок обычно составляет от нескольких секунд до нескольких минут, в зависимости от загруженности сайта. Срок гарантирует, что кэш обновляется периодически и что пользователи получают обновления содержимого, и в то же время, это снижает издержки генерации страниц.

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

    Включение кэширования

    Мы начнем этот раздел в включения системы кэширования. Чтобы использовать кэширование, необходимо сначала выбрать кэширование внутреннего интерфейса и задавать свой выбор в переменной с именем CACHE_BACKEND в файле settings.py.Содержимое этой переменной зависит от кэширования внутреннего интерфейса, который вы выбрали. Некоторыми из доступных вариантов являются:

  • Простое кэширование: Для этого кэша данные хранятся в памяти процесса. Это полезно только для тестирования, система кэширования во время разработки и не должна использоваться в рабочей фазе. Чтобы включить ее, добавьте следующую строку в файл settings.py:
    CACHE_BACKEND = ' simple’:///' 
  • Кэширование базы данных: В этом случае, данные кэша хранятся в таблице базы данных. Чтобы создать таблицу кэша, выполните команду:
    python manage.py createcachetable cache_table

    Затем добавьте следующую строку к файлу settings.py:

    CACHE_BACKEND = ' db://cache_table'

    Здесь в таблица кэша была названа cache_table. Вы можете назвать ее, как вы хотите, до тех пор, пока название не конфликтует с существующей таблицей.

  • Файловая система кэширования: Здесь, данные кэша хранятся в локальной файловой системе. Чтобы использовать ее, добавьте добавьте следующую строку к файлу settings.py:
    CACHE_BACKEND = "file:///tmp/django_cache" 

    Здесь переменная /tmp/django_cache используется для хранения файлов кэша. Вы можете задавать другой путь, если вам так нравится.

  • Кэширование в память: Кэширование в память является продвинутым, высокоэффективным и обеспечивающим быстрое кэширование средством. Установка и настройка этого способа выходит за рамки этой книги, но если у вас есть сервер, использующий такое кэширование, вы определить его IP и порт в файле settings.py, как показано:
    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 ()предоставляет три метода:

  • get: Этот метод отправляет GET запрос к представлению. В качестве параметра принимает URL-адрес представления. Вы можете передать этому методу дополнительный словарь GET переменных.
  • post: Этот метод отправляет отправляет запрос POST в представление.Он принимает URL-адрес представления и словарь POST переменных в качестве параметров.
  • login: Этот метод отправляет GET запрос к представлению, которое доступно только для вошедших в систему пользователей .В качестве параметров она принимает URL представления, имя пользователя и пароль.
  • Класс Client () способен отслеживать состояние, что означает, что он сохраняет свое состояние между запросами. После того как вы вошли в систему, далее запросы будут обрабатываться при входе в систему. Объект ответа возвращается методами класса Client (), содержащими следующие атрибуты:

  • status_code: это HTTP статус ответа
  • content: это тело ответа страницы
  • template: это экземпляр шаблона, используемый для отображения страницы; Если были использованы несколько шаблонов, этот атрибут будет содержать список шаблонов объектов
  • context: это объект контекста, используемый для отображения шаблона.
  • Эти поля являются полезными для проверки, был ли успешен тест или нет, как мы увидим дальше. Не стесняйтесь экспериментировать больше с классом 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) }
    

    Давайте пройдемся по коду построчно:

  • Во-первых, мы импортировали классы TestCase и Client.
  • Далее мы определили класс под названием ViewTest(), который является производным от класса TestCase. Как я уже говорил ранее, все тестовые классы должен быть производными от этого базового класса.
  • После этого, мы определили метод setUp(). Этот метод вызывается, когда начинается процесс тестирования. Здесь мы создали объект клиента.
  • Наконец мы определили метод под названием test_register_page. Имя метода начинается со слова тест, указывающее, что это метод теста. Этот метод отправляет запрос POST в представление регистрации и проверяет код статуса на равенство с числом 302. Это число является HTTP статусом для перенаправления.
  • Как вы помните из предыдущей главы, представление регистрации перенаправляет пользователя, если запрос завершается успешно.

    Мы проверили объект ответа с помощью метода assertEqual().Этот метод наследуется от класса TestCase. Это вызывает исключение, если два переданных аргументов не равны. Если возникает исключение, окружение тестирования узнает,тест не был пройден; в противном случае, если исключение не появляется, предполагается, что тест успешно пройден.

    Класс TestCase предоставляет набор методов для использования в тестировании. Вот список важных методов:

  • assertEqual: Он ожидает, что два значения равны
  • assertNotEquals: Он ожидает , что два значения, будут неравны
  • assertTrue: Ожидается значение True
  • assertFalse: Ожидается значение False
  • Теперь, когда вы понимаете тестовый класс, давайте запустим реальный тест, выполнив команду:

    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.

    Создать файл перевода проекта

    Список тем, эссе

  • Разработка юнит-тестов для прототипа системы модерации твитов
  • Разработка юнит-тестов для прототипа системы регистрации пользователей
  • Разработка юнит-тестов для продвинутой системы комментирования
  • Разработка юнит-тестов для прототипа системы ведения пользовательских блогов
  • Разработка юнит-тестов для прототипа системы ведения пользовательских блогов
  • Разработка юнит-тестов для прототипа веб-сервиса для хранения изображений
  • Разработка юнит-тестов для прототипа веб-сервиса электронной почты
  • Разработка юнит-тестов для прототипа сервиса для ведения списка ежедневных дел
  • Разработка юнит-тестов для прототипа сервиса для учета рабочего времени
  • Разработка юнит-тестов для приложения для твитов
  • Краткие итоги

  • Ознакомились с системой интернационализации
  • Научились помечать строки как переводимые
  • Научились создавать файл перевода
  • Создали модель приглашения
  • Создали страницу приглашения
  • Изучили систему кэширования
  • Настроили систему кэширования для нашего проекта
  • Рассмотрели основы юнит-тестирования
  • Реализовали простейший юнит-тест для нашего проекта
  • Выполнили настройки для отправки приглашений
  • Вернуться к учебному плану