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

Установка Django на Linux

Устанавливаем фреймворк Django на Linux-сервере (ОС Debian):

apt install python3-django

Пример на Django

Создание проекта Django

В текущем каталоге создаем каталог proj1 для нашего проекта:

django-admin startproject proj1
cd proj1/

Структура созданного каталога proj1 следующая:

Создали Django-проект для нашего примера веб-приложения

Запуск веб-сервера разработки

Запускаем веб-сервер разработки Django:

python3 manage.py runserver

По умолчанию веб-сервер разработки Django запускается на локальном IP адресе 127.0.0.1 и на порту 8000:

Запускаем веб-сервер разработки Django на IP 127.0.0.1 и порту 8000

Примечание: версии Django и Python у меня тут довольно древние, для реальной разработки на Django рекомендуется обновиться до последних версий.

Запуск веб-сервера разработки с заданными IP и портом

Поскольку мне нужен доступ к веб-серверу разработки Django с другого компьютера сети, то я перезапущу веб-сервер разработки Django на IP адресе 192.168.1.38 и на порту 8000:

python3 manage.py runserver 192.168.1.38:8000
Запускаем веб-сервер разработки Django на IP 192.168.1.38 и порту 8000

И пропишу в iptables разрешение на доступ по порту 8000:

iptables -A INPUT -p tcp -m tcp --dport 8000 -j ACCEPT
iptables-save > /etc/iptables.up.rules

Проверка соединения

Для проверки соединения с веб-сервером разработки открываем браузер и в адресной строке вводим:

http://192.168.1.38:8000/

Примечание: если веб-сервер разработки Django был запущен, как описано в разделе Запуск веб-сервера разработки, то IP адрес 192.168.1.38 следует заменить на 127.0.0.1, как в данном разделе статьи, так и во всех разделах ниже.

Если возникает ошибка DisallowedHost at / Invalid HTTP_HOST header. You may need to add to ALLOWED_HOSTS

Ошибка You may need to add to ALLOWED_HOSTS

то редактируем следующую строку в файле proj1/proj1/settings.py:

ALLOWED_HOSTS = ['192.168.1.38']

и перезапускаем веб-сервера разработки Django.

В случае успеха браузер отобразит сообщение It worked!

first Django-powered page

Ура! Мы готовы к разработке на фреймворке Django. Веб-сервер разработки Django не требует перезагрузки при внесении изменений в код существующих в проекте файлов Python. Но при добавлении новых файлов Python в проект, перезагрузка веб-сервера разработки все-таки понадобится.

Создание приложения

Создадим наше приложение опрос с голосованием app1 командой:

python3 manage.py startapp app1

Структура каталога proj1 стала следующей:

В Django проект proj1 добавили приложение app1

Проверяем работу представления

Представление — это то, как все будет отображаться. Настроим представление, а для этого добавим в файл proj1/app1/views.py следующие строки:

from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello, world!")

А теперь зададим URL, при вводе которого в адресной строке браузера будет отображаться наше представление «Hello, world!». Для этого файл proj1/proj1/urls.py приводим к виду:

from django.contrib import admin
from django.urls import path

from app1 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('app1/', views.index, name='index'),
]

Теперь, при вводе в адресной строке браузера:

http://192.168.1.38:8000/app1/

должно отобразиться наше представление «Hello, world!». Проверяем:

Проверяем работу отображения в веб-приложении

Настройка базы данных

По умолчанию в файле конфигурации proj1/proj1/settings.py настроено использование SQLite базы данных. SQLite база данных — это просто файл proj1/db.sqlite3. И этот файл создается автоматически.

Примечание: в реальных проектах на Django рекомендуется использовать более масштабируемую базу данных, например, PostgreSQL.

Для просмотра существующих таблиц в SQLite базе данных proj1/db.sqlite3 запускаем клиента командной строки SQLite базы данных:

sqlite3
Клиент командной строки SQLite базы данных

Подключаемся к нашей SQLite базе данных proj1/db.sqlite3, просматриваем список существующих таблиц и выходим из клиента командной строки базы данных:

.open db.sqlite3
.tables
.exit

В базе пока единственная таблица django_migrations.

По умолчанию в файле конфигурации proj1/proj1/settings.py подключено к нашему проекту некоторое количество базовых приложений, поставляемых с Django, таких, как аутентификация, сессии, сообщения и т.д. Создадим для этих приложений необходимые таблицы в базе данных:

python3 manage.py migrate

Если теперь просмотрим список существующих таблиц в базе данных proj1/db.sqlite3, то список уже будет состоять не из одной таблицы:

SQLite база данных для проекта Django

Примечание: список подключаемых к проекту базовых приложений настраивается в файле конфигурации proj1/proj1/settings.py в параметре INSTALLED_APPS.

Создание моделей

Для нашего приложения для голосования нам нужны следующие данные: текст вопроса (question_text), его дата публикации (pub_date), текст ответа (choice_text) и количество голосов (votes). Теперь отредактируем файл proj1/app1/models.py, чтобы он выглядел так:

from django.db import models

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
    def __str__(self):
        return self.question_text

class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)
    def __str__(self):
        return self.choice_text

Примечание: каждый ответ (Choice) связан с одним вопросом (Question). Это отношение один-к-одному. Такая связь данных определяется в Django с использованием ForeignKey.

В файле proj1/app1/models.py мы описали наши модели (Question и Choice) — по сути структуру нашей базы данных.

Подключим наше приложение app1 к проекту proj1. Для этого в файле конфигурации proj1/proj1/settings.py в параметре INSTALLED_APPS добавим строчку:

'app1.apps.App1Config',
Подключаем приложение к проекту Django

Проверяем, есть ли какие ошибки/проблемы в нашем проекте:

python3 manage.py check

Проблем нет? Запускаем автоматическое создание таблиц созданных моделей в базе данных:

python3 manage.py makemigrations app1
python3 manage.py migrate

Создание администратора

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

python3 manage.py createsuperuser
Создание администратора приложения Django

Администраторская часть приложения

Пример веб-приложения Django, который мы создаем, состоит из двух страниц: публичной с опросами и приватной (администраторской) для редактирования опросов. Django автоматически создает администраторскую часть приложения (сайта). Давайте взглянем на нее, находится она по адресу:

http://192.168.1.38:8000/admin/
Администраторская часть приложения Django

Примечание: для отображения на русском языке администраторской части приложения Django необходимо в файле конфигурации proj1/proj1/settings.py параметру LANGUAGE_CODE присвоить значение ‘ru-RU’.

Вводим имя администратора и его пароль (см. раздел Создание администратора) и увидим главную страницу администраторской части приложения:

Главная страница администратора Django

Пока в администраторской части есть возможность добавить/редактировать пользователей и групп пользователей. Данную функциональность предоставляет базовое приложение аутентификации Django (django.contrib.auth).

Чтобы появилась возможность добавления/редактирования опросов и ответов, отредактируем файл proj1/app1/admin.py:

from django.contrib import admin

from .models import Question, Choice

admin.site.register(Question)
admin.site.register(Choice)

Теперь администратор может добавлять, редактировать, удалять опросы (Questions) и ответы к ним (Choices):

Администратор может редактировать опросы и ответы к опросам

Вот так выглядит окно добавления опроса:

Добавление опроса

Окно редактирования/удаления опроса очень похоже не предыдущее:

Редактирование или удаление опроса

Окно добавления ответа к опросу:

Окно добавления ответа к опросу

А вот так выглядит окно со списком всех опросов:

Список всех опросов

Давайте немного настроим это окно (окно со списком всех опросов):

  1. добавим дату публикации опроса;
  2. добавим боковую панель «Фильтр» для фильтрации списка опросов по дате публикации;
  3. добавим поиск по тексту опроса.

Для этого отредактируем файл proj1/app1/admin.py. Удаляем строку:

admin.site.register(Question)

На ее место добавляем:

class QuestionAdmin(admin.ModelAdmin):
    list_display = ('question_text', 'pub_date')
    list_filter = ['pub_date']
    search_fields = ['question_text']

admin.site.register(Question, QuestionAdmin)
Настройка списка всех опросов

Фантастика! Django создал админку со всеми формами автоматически. Мы только прописали модели Question и Choice в файле proj1/app1/models.py, а Django знает, каким типам полей модели (CharField, DataTimeField) какие виджеты HTML соответствуют. А если внешний вид по умолчанию админки не устраивает, то его настройка занимает буквально несколько строк!

Публичная часть приложения

Переходим к разработке публичной части нашего примера веб-приложения на фреймворке Django. Нам понадобится четыре представления (см. пример простого представления в разделе Проверяем работу представления):

  1. главная страница со списком нескольких последних опросов (URL вида http://192.168.1.38:8000/app1/),
  2. страница опроса с формой для голосования (URL вида http://192.168.1.38:8000/app1/<question_id>/),
  3. страница опроса с результатом голосования (URL вида http://192.168.1.38:8000/app1/<question_id>/results/),
  4. страница опроса с обработкой голосования (URL вида http://192.168.1.38:8000/app1/<question_id>/vote/),

где <question_id> — это уникальный номер (идентификатор), присвоенный опросу при добавлении в базу данных.

Мы будем использовать систему шаблонов Django, чтобы отделить дизайн станицы от кода Python. Т.е. для каждого представления мы создадим свой HTML-шаблон, а представление будет использовать соответствующий шаблон.

Создаем каталог templates в каталоге proj1/app1/:

mkdir templates

По умолчанию Django ищет шаблоны в подкаталоге templates каталога приложения (app1).

Представление под номером 1

В каталоге templates создаем шаблон app1_index.html (для представления под номером 1) и добавляем в него следующий код:

{% if question_list %}
    <ul>
    {% for question in question_list %}
        <li><a href="/app1/{{ question.id }}/">{{ question.question_text }}</a></li>
    {% endfor %}
    </ul>
{% else %}
    <p>Опросов нет.</p>
{% endif %}

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

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

Чтобы проверить представление под номером 1, т.е. главную страницу со списком нескольких последних опросов, приведем файл proj1/app1/views.py к виду:

from django.views import generic

from .models import Choice, Question

class IndexView(generic.ListView):
    template_name = 'app1_index.html'
    def get_queryset(self):
        return Question.objects.order_by('-pub_date')[:3]

Здесь мы используем базовое представление Django ListView для отображения списка. С помощью атрибута template_name указываем базовому представлению, какой шаблон использовать. А для выборки нескольких последних опросов, мы делаем сортировку опросов по дате публикации и берем 3 самых последних.

Отредактируем файл proj1/proj1/urls.py. Удаляем старую строку:

path('app1/', views.index, name='index'),

Добавляем новую строку:

path('app1/', views.IndexView.as_view(), name='index'),

Проверяем работу главной страницы нашего примера приложения на Django:

Главная страница примера приложения на Django

Все отлично работает!

Представление под номером 2

Представление под номером 2 — это страница опроса с формой для голосования (URL вида http://192.168.1.38:8000/app1/<question_id>/).

В каталоге proj1/app1/templates/ создаем шаблон app1_detail.html и добавляем в шаблон код:

<form action="/app1/{{ question.id }}/vote/" method="post">
{% csrf_token %}
<fieldset>
    <legend><h1>{{ question.question_text }}</h1></legend>
    {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
    {% for choice in question.choice_set.all %}
        <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
        <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
    {% endfor %}
</fieldset>
<input type="submit" value="Голосовать">
</form>

Шаблон выводит текст опроса, варианты ответов и кнопку Голосовать. При нажатии на кнопку Голосовать форма form отправляет методом post данные choice=<идентификатор выбранного ответа>. Идентификатор ответа уникальный и присваивается ответу при добавлении его в базу данных. Тег шаблона {% csrf_token %} используется встроенной системой защиты Django против подделок межсайтовых запросов.

Чтобы проверить представление под номером 2, добавим в файл proj1/app1/views.py:

class DetailView(generic.DetailView):
    model = Question
    template_name = 'app1_detail.html'

Здесь мы использует базовое представление Django DetailView для отображения страницы подробностей. С помощью атрибута template_name указываем базовому представлению, какой шаблон использовать. С помощью атрибута model — какую модель использовать.

Базовое представление DetailView ожидает, что значение первичного ключа, получаемое из URL, будет называться pk. В соответствии с этой информацией добавим в файл proj1/proj1/urls.py следующий код:

path('app1/<int:pk>/', views.DetailView.as_view(), name='detail'),

Проверяем страницу опроса с формой для голосования:

Страница опроса с формой голосования

Пример представления Django работает отлично!

Представление под номером 3

Представление под номером 3 — это страница опроса с результатом голосования (URL вида http://192.168.1.38:8000/app1/<question_id>/results/).

В каталоге proj1/app1/templates создаем шаблон app1_results.html и добавляем в шаблон код:

<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>
<a href="{% url 'detail' question.id %}">Голосовать еще</a>

В файл представлений proj1/app1/views.py добавляем:

class ResultsView(generic.DetailView):
    model = Question
    template_name = 'app1_results.html'

Откроем файл proj1/proj1/urls.py и добавим строку:

 path('app1/<int:pk>/results/', views.ResultsView.as_view(), name='results'),

Проверяем страницу опроса с результатом голосования:

Страница опроса с результатом голосования

Представление под номером 4

Представление под номером 4 — это страница опроса с обработкой голосования (URL вида http://192.168.1.38:8000/app1/<question_id>/vote/). В этом представлении обрабатываются данные, оправленные формой form (см. Представление под номером 2).

Редактируем файл представлений proj1/app1/views.py. Сверху добавляем код:

from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse

Снизу в файле proj1/app1/views.py добавляем:

def vote(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected_choice = question.choice_set.get(pk=request.POST['choice'])
    except (KeyError, Choice.DoesNotExist):
        return render(request, 'app1_detail.html', {
            'question': question,
            'error_message': "Вы не выбрали ответ.",
        })
    else:
        selected_choice.votes += 1
        selected_choice.save()
        return HttpResponseRedirect(reverse('results', args=(question.id,)))

Функция get_object_or_404() получает объект или вызывает исключение Http404, если объекта не существует.

request.POST[‘choice’] возвращает идентификатор выбранного ответа или вызывает исключение KeyError. Исключение KeyError вызывается при условии, если ответ не был выбран, а кнопка Голосовать была нажата. В случае исключения KeyError повторно отображается страница опроса с формой для голосования и с сообщением «Вы не выбрали ответ.».

У функции render() первый аргумент — это объект запроса, второй аргумент — это шаблон, третий необязательный аргумент — это словарь. Функция загружает шаблон, заполняет контекстом и возвращает объект HttpResponse c результатом визуализации шаблона.

selected_choice — это счетчик выбора. Значение счетчика выбора получается из базы данных, потом значение увеличивается и обратно сохраняется в базу данных.

Примечание: при данной реализации функции vote() и при одновременном голосовании нескольких человек может возникнуть так называемое «состояние гонки». В реальных проектах следует избегать условий гонки.

У функции reverse() первый аргумент — имя представления Django, которому мы хотим передать выполнение, а второй аргумент — чтобы уточнить, для какого именно опроса. Функция reverse() возвращает строку вида:

'/app1/8/results/'

Функция HttpResponseRedirect принимает один аргумент — это URL адрес, на который будет перенаправлен пользователь. Т.е. после того, как пользователь проголосовал в опросе, функция vote() перенаправит пользователя на страницу с результатом голосования по опросу.

Откроем файл proj1/proj1/urls.py и добавим строку:

path('app1/<int:question_id>/vote/', views.vote, name='vote'),

Чтобы проверить работу представления под номером 4, нужно перейти на страницу опроса с формой для голосования и проголосовать.

Выводы

Пример веб-голосовалки на фреймворке Django, который мы разобрали в этой статье, подходит для первого ознакомления с фреймворком Django. Мы научились устанавливать сам фреймворк, запускать веб-сервер для проверки работоспособности веб-приложения, разобрались в основных файлах и каталогах проекта Django и собрали свое первое приложение Django.

Как это может помочь бизнесу?

Лучший способ помочь бизнесу быть более успешным — это использовать практики лидеров рынка. Чтобы использовать эти практики, нужно быть с ними знакомыми. Эта статья знакомит с фреймворком Django, который используется в проектах: YouTube, поиске Google, Instagram, Yahoo Maps и многих других. Фреймворк Django бесплатный и уменьшает стоимость разработки за счет уже готового набора компонентов, которые необходимы практически в любом проекте: аутентификация пользователей (как локальная, так и с аккаунтом социальных сетей), регистрация, управление учетными записями, загрузка и скачивание файлов, работа с облачными хранилищами данных, настраиваемая «админка» со встроенным набором виджетов и т.д. Так что, при возникновении идеи создания веб-приложения для своего бизнеса, вспомните про фреймворк Django!

Все вопросы, по традиции, предлагаю оставлять под статьей в комментариях. Спасибо!

Комментарии

Добавить комментарий

Этот сайт защищен reCAPTCHA, и к нему применяются Google Политика конфиденциальности и Условия использования.

Войти

Зарегистрироваться

Сбросить пароль

Пожалуйста, введите ваше имя пользователя или эл. адрес, вы получите письмо со ссылкой для сброса пароля.