воскресенье, 2 июля 2017 г.

Краткий учебник по Django

Не так давно нашёл файл с записями, которые я делал в 2012 году, когда осваивал веб-фреймворк Django. Я подумал, что не стоит зря пропадать этим записям и решил выложить их здесь. Хотя в этом файле есть что дополнить, в процессе подготовки публикации радикальных правок в этот файл я вносить не стал, т.к. фреймворк очень большой и начав раскрывать частности, легко раздуть и без того большой файл до невероятных размеров.

О терминологии веб-фреймворка Django

  • Проект - совокупность приложений, имеющих общие настройки.
  • Приложение - часть проекта, выполняющая определённую логически неделимую функцию. Состоит из представлений (views), шаблонов (templates) и моделей (models).
  • Шаблон - шаблон HTML-страницы. В терминологии MVC шаблону соответствует представление.
  • Модель - средство доступа к данным.
  • Представление - связующий код между моделью и шаблоном. В терминологии MVC представлению соответствует контроллеру.
  • Маршрут - соответствие между URL'ом и представлением (контроллером в терминологии MVC), отвечающим за этот URL.
Программы, написанные с использованием Django, являются совокупностью отдельных приложений, объединённых в один проект. В отличие от многих других веб-фреймворков, в Django не используется архитектура MVC - Модель-Представление-Контроллер, вместо неё используется собственная архитектура MVT - Модель-Представление-Шаблон. Шаблон Django по функциям ближе всего к представлению в MVC, а представление Django по функциям ближе всего к контроллеру в MVC. Представления Django привязываются к определённому URL через маршруты.

Установка Python и Django

В Debian и производных от него дистрибутивах установить Python и Django можно из репозиториев:
# apt-get install python python-django

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

Создаём проект dj:
$ django-admin startproject dj
Переходим в каталог проекта:
$ cd dj
Смотрим содержимое каталога проекта:
$ find .
.
./manage.py
./dj
./dj/wsgi.py
./dj/settings.py
./dj/__init__.py
./dj/urls.py
Создаём в проекте новое приложение app:
$ ./manage.py startapp app
В каталоге проекта появится новый каталог с именем app, созданный специально для размещения приложения:
$ find .
.
./manage.py
./dj
./dj/wsgi.py
./dj/settings.py
./dj/__init__.py
./dj/urls.py
./dj/settings.pyc
./dj/__init__.pyc
./app
./app/tests.py
./app/views.py
./app/models.py
./app/__init__.py

Создание представления

Создадим новое представление hello в приложении app. Представление принимает в качестве аргумента объект HttpRequest и возвращает объект HttpResponse.

Откроем для редактирования файл app/views.py и придадим ему следующий вид:
# -*- coding: UTF-8 -*-
from django.http import HttpResponse

def hello(request):
    return HttpResponse(u'Здравствуй, мир!')

Создание маршрута

Теперь настроим маршрут, вызывающий это представление для url. Для этого откроем файл dj/urls.py и добавим в него пару строчек.

Первую строчку добавим в начало файла, после других строчек импорта. Строчка импортирует представление hello из приложения app:
from app.views import hello
Теперь найдём функцию patterns, возвращаемое значение которой присваивается переменной urlpatterns, и впишем в аргументы функции следующую строчку:
('^hello/$', hello),
В итоге у меня содержимое файла dj/urls.py приняло следующий вид:
from django.conf.urls import patterns, include, url
from app.views import hello

# Uncomment the next two lines to enable the admin:
# from django.contrib import admin
# admin.autodiscover()

urlpatterns = patterns('',
    # Examples:
    # url(r'^$', 'dj.views.home', name='home'),
    # url(r'^dj/', include('dj.foo.urls')),

    # Uncomment the admin/doc line below to enable admin documentation:
    # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),

    # Uncomment the next line to enable the admin:
    # url(r'^admin/', include(admin.site.urls)),
    ('^hello/$', hello),
)
В шаблоне url в конце обязательно должна быть косая черта, т.к. если клиент запросит страницу без косой черты в конце, Django автоматически добавит её и попытается найти представление, соответствующее этому URL. Нужно ли добавлять косую черту, регулируется настройкой APPEND_SLASH. Если установить её в False, то косая черта добавляться не будет. Шаблоном для корня сайта является '^$', то есть соответствие пустой строке.

Включение приложения в проекте

Чтобы в проекте использовалось наше приложение, его нужно подключить к проекту. Для этого закомментируем на время список стандартных приложений в файле dj/settings.py и пропишем наше приложение:
INSTALLED_APPS = (
    #'django.contrib.auth',
    #'django.contrib.contenttypes',
    #'django.contrib.sessions',
    #'django.contrib.sites',
    #'django.contrib.messages',
    #'django.contrib.staticfiles',
    # Uncomment the next line to enable the admin:
    # 'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',
    'app',
)
Также закомментируем в настройках подключение приложений-прослоек:
MIDDLEWARE_CLASSES = (
    #'django.middleware.common.CommonMiddleware',
    #'django.contrib.sessions.middleware.SessionMiddleware',
    #'django.middleware.csrf.CsrfViewMiddleware',
    #'django.contrib.auth.middleware.AuthenticationMiddleware',
    #'django.contrib.messages.middleware.MessageMiddleware',
    # Uncomment the next line for simple clickjacking protection:
    # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

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

Теперь настало время запустить сервер разработчика с только что созданным простейшим приложением:
$ ./manage.py runserver 0.0.0.0:8000
Можно попытаться зайти в браузере на страницу /hello/. У меня ссылка для открытия страницы выглядела так:
http://localhost:8000/hello/
Итак, мы создали наш первый проект на Django, который при обращении к странице /hello/ выводит надпись "Здравствуй, мир!" Возможности Django в этом проекте практически не используются - мы не использовали ни моделей, ни шаблонов, но этот проект даёт общее представление о структуре программ, написанных с использованием Django.

Использование шаблонов

Для начала настроим каталог, в котором будут находиться шаблоны. Для этого отредактируем файл dj/settings.py и впишем в кортеж TEMPLATES_DIRS полный путь к каталогу с шаблонами.

После редактирования файла эта настройка в файле settings.py приняла следующий вид:
TEMPLATE_DIRS = (
    # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
    "/home/stupin/dj/templates",
)
Не забывайте в конце одноэлементного кортежа поставить запятую, чтобы Python мог отличить кортеж от простого выражения в скобках.

Теперь создадим каталог для шаблонов:
$ mkdir templates
И создадим в нём новый шаблон с именем time.tmpl и со следующим содержимым:
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Текущее время</title>
  </head>
  <body>
    <div align="center">
      Сейчас {{ time }}
    </div>
  </body>
</html>
Теперь добавим в файл app/views.py импорт функции для загрузки и отрисовки шаблона:
from django.shortcuts import render_to_response
И создадим представление current_datetime следующим образом:
def current_datetime(request):
    return render_to_response('time.tmpl', {'time' : datetime.now()})
Осталось настроить в файле urls.py маршрут к этому представлению:
('^time/$', current_datetime),
Если сейчас попробовать открыть страницу http://localhost:800/time/, то можно увидеть текущее время на английском языке в часовом поясе Гринвичской обсерватории.

Настройка часового пояса и языка

Чтобы время отображалось правильно - в часовом поясе сервера, пропишем в файл настроек местный часовой пояс. Для этого откроем файл dj/settings.py и пропишем в переменную TIME_ZONE значение 'Asia/Yekaterinburg':
TIME_ZONE = 'Asia/Yekaterinburg'
Чтобы время на странице отображалось в соответствии с правилами, принятыми в России, пропишем в файл настроек язык проекта. Откроем файл dj/settings.py и пропишем в переменную LANGUAGE_CODE значение 'ru-RU':
LANGUAGE_CODE = 'ru-RU'
Теперь текущее время должно отображаться на русском языке в часовом поясе, по которому живёт Уфа :)

Пример более сложного маршрута

Попробуем добавить страницы, которые будут вычитать из текущего времени часы, фигурирующие в URL запрошенной страницы. Для этого в файл dj/urls.py добавим маршруты:
(r'^time/plus/(\d{1,2})$', hours_plus),
(r'^time/minus/(\d{1,2})$', hours_minus),
В каталоге с шаблонами templates разместим два новых шаблона.

Файл templates/time_minus.tmpl со следующим содержимым:
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Прошлое время</title>
  </head>
  <body>
    <div align="center">
      {{ delta }} часов назад было {{ time }}
    </div>
  </body>
</html>
Файл templates/time_plus.tmpl со следующим содержимым:
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Будущее время</title>
  </head>
  <body>
    <div align="center">
      Через {{ delta }} часов будет {{ time }}
    </div>
  </body>
</html>
В файл app/views.py пропишем два представления, которые будут использовать два новых шаблона:
def hours_plus(request, delta):
    try:
      delta = int(delta)
    except ValueError:
      raise Http404()
    time = datetime.now() + timedelta(hours=delta)
    return render_to_response('time_plus.tmpl', {'delta' : delta,
                                                 'time' : time})

def hours_minus(request, delta):
    try:
      delta = int(delta)
    except ValueError:
      raise Http404()
    time = datetime.now() - timedelta(hours=delta)
    return render_to_response('time_minus.tmpl', {'delta' : delta,
                                                  'time' : time})
Файл app/views.py целиком примет следующий вид:
# -*- coding: UTF-8 -*-
from django.http import HttpResponse, Http404
from django.shortcuts import render_to_response
from datetime import datetime, timedelta

def hello(request):
    return HttpResponse(u'Здравствуй, мир!')

def current_datetime(request):
    return render_to_response('time.tmpl', {'time' : datetime.now()})

def hours_plus(request, delta):
    try:
      delta = int(delta)
    except ValueError:
      raise Http404()
    time = datetime.now() + timedelta(hours=delta)
    return render_to_response('time_plus.tmpl', {'delta' : delta,
                                                 'time' : time})

def hours_minus(request, delta):
    try:
      delta = int(delta)
    except ValueError:
      raise Http404()
    time = datetime.now() - timedelta(hours=delta)
    return render_to_response('time_minus.tmpl', {'delta' : delta,
                                                  'time' : time})
Теперь можно перейти по ссылкам http://localhost:8000/time/plus/1 или http://localhost:8000/time/plus/2 и увидеть получающиеся страницы.

Более сложные шаблоны

Условие:
{% if today_is_weekend %}
    <p>Сегодня выходной!</p>
{% endif %}
Условие с двумя вариантами:
{% if today_is_weekend %}
    <p>Сегодня выходной!</p>
{% else %}
    <p>Пора работать.</p>
{% endif %}
Ложным значениями являются: пустой список [], пустой кортеж (), пустой словарь {}, ноль - 0, объект None и объект False.

Можно использовать сочетания условий при помощи and и or, причём and имеет более высокий приоритет. Скобки в условиях не поддерживаются, без них можно обойтись с помощью вложенных условий. Также возможно использовать операторы ==, !=, <, >, >=, <= и in для вычисления условий, по смыслу совпадающих с условными операторами в самом Python. Циклы для перебора значений из списка:
{% for athlete in athlete_list %}
  <li>{{ athlete.name }}</li>
{% endfor %}
Можно перебирать значения из списка в обратном порядке:
{% for athlete in athlete_list reversed %}
...
{% endfor %}
Внутри циклов существуют следующие переменные:
  • {{ forloop.counter }} - номер итерации, начиная с 1,
  • {{ forloop.counter0 }} - номер итерации, начиная с 0,
  • {{ forloop.revcounter }} - количество оставшихся итераций, включая текущую. Внутри первой итерации равно количеству элементов, на последней итерации - 1,
  • {{ forloop.revcounter }} - количество оставшихся итераций. Внутри первой итерации содержит количество элементов за минус единицей, на последней итерации - 0,
  • {% if forloop.first %} - условие выполняется на первой итерации,
  • {% if forloop.last %} - условие выполняется на последней итерации,
  • forloop.parentloop - ссылка на объект родительского цикла.
Комментарии в шаблоне:
{# Это комментарий #}
или
{% comment %}
Многострочный
комментарий.
{% endcomment %}

Включение подшаблонов

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

Включение подшаблона из файла:
{% include "includes/nav.html" %}
Включение подшаблона из переменной:
{% include template_name %}

Наследование шаблонов

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

Продолжим эксперименты с нашим тестовым проектом, добавив в него базовый шаблон.

Базовый шаблон base.tmpl:
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>{% block title %}{% endblock %}</title>
  </head>
  <body>
    <h1>Бесполезный сайт с часами</h1>

    {% block content %}{% endblock %}

    {% block footer %}
    <hr>
    <p>Благодарим за посещение нашего сайта.</p>
    {% endblock %}
  </body>
</html>
В базовом шаблоне помечаются блоки, в которых прописывается часть шаблона, специфичная для этой страницы.

Производный шаблон. Для примера приведу только содержимое шаблона time_plus.tmpl:
{% extends "base.tmpl" %}

{% block title %}Будущее время{% endblock %}

{% block content %}
<p>Через {{ delta }} часов будет {{ time }}</p>
{% endblock %}
В производном шаблоне указывается базовый шаблон и переопределяется содержимое блоков базового шаблона. Шаблоны других страниц можно отредактировать сходным образом, чтобы и они использовали дизайн, общий для всех страниц.

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

После того, как мы рассмотрели шаблоны Django, пришло время заняться моделями Django. Но прежде чем приступить непосредственно к изучению моделей, нужно установить необходимые модули, выставить настройки как в самой СУБД, так и в проекте Django.

Установим модуль для доступа к базе данных MySQL из Python (разработчики фреймворка Django рекомендуют использовать PostgreSQL, но мы воспользуемся MySQL, поддержка которого тоже имеется):
# apt-get install python-mysqldb
Настроим кодировку сервера MySQL и порядок сортировки. Для этого в файле /etc/mysql/my.cnf в секцию [mysqld] впишем следующие настройки:
character_set_server=utf8
collation_server=utf8_unicode_ci
Перезапустим сервер базы данных:
# /etc/init.d/mysql restart
В результате вышеописанных действий должен получиться такой результат:
mysql> show variables like 'coll%';
+----------------------+-----------------+
| Variable_name        | Value           |
+----------------------+-----------------+
| collation_connection | utf8_general_ci |
| collation_database   | utf8_unicode_ci |
| collation_server     | utf8_unicode_ci |
+----------------------+-----------------+
3 rows in set (0.00 sec)

mysql> show variables like 'char%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | utf8                       |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)
Создадим базу данных для проекта:
CREATE USER app@localhost IDENTIFIED BY "app_password";
CREATE DATABASE app;
GRANT ALL ON app.* TO app@localhost;
Пропишем в файл настроек проекта dj/settings.py настройки подключения к базе данных:
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'app',                        # Or path to database file if using sqlite3.
        'USER': 'app',                        # Not used with sqlite3.
        'PASSWORD': 'app_password',           # Not used with sqlite3.
        'HOST': '',                           # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                           # Set to empty string for default. Not used with sqlite3.
    }
}
Проверяем правильность настройки:
$ ./manage.py shell
Если всё правильно, то откроется отладочная оболочка Python. Попробуем ввести следующие команды:
from django.db import connection
cursor = connection.cursor()
Если сообщений об ошибках не было, значит всё настроено правильно.

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

Каждая модель Django описывают одну таблицу в базе данных. В Django имеется система отображения таблиц в объекты - ORM - Object-Relational Mapping - объектно-реляционное отображение. ORM позволяет манипулировать единичными строками таблиц как объектами Python, а также осуществлять операции массовой выборки, обновления и удаления строк.

В качестве примера, рассмотрим адресный справочник домов в городах. Откроем файл app/models.py и приведём его к следующему виду:
# -*- coding: UTF-8 -*-
from django.db import models

class City(models.Model):
    country = models.ForeignKey(Country)
    title = models.CharField(max_length=150)

class Street(models.Model):
    city = models.ForeignKey(City)
    title = models.CharField(max_length=150)

class Area(models.Model):
    city = models.ForeignKey(City)
    title = models.CharField(max_length=150)

class House(models.Model):
    area = models.ForeignKey(Area)
    street = models.ForeignKey(Street)
    house = models.IntegerField()
    frac = models.CharField(max_length=30)
    comment = models.CharField(max_length=100)
Мы описали объекты, составляющие адресный справочник, и описали взаимоотношения между ними через внешние ключи - ForeignKey. В городе имеются улицы и районы, а каждый дом находится на одной улице и принадлежит одному из районов города.

В Django есть не только текстовые поля и внешние ключи. Имеются числовые поля, списковые поля, логические поля, поля для связей один-к-одному и для связей многие-ко-многим. У полей можно прописать значения по умолчанию, разрешить или запретить использовать значение NULL и запретить или разрешить вводить в строковые поля пустые строки. У поля можно прописать его имя в базе данных, выставить признак - нужно ли создавать индекс по этому полю, можно прописать текстовое описание поля, которое будет использоваться в веб-интерфейсе администратора и в объектах форм Django. У классов моделей, в свою очередь, можно тоже указывать их текстовые описания, прописывать составные индексы, ограничения уникальности записей и т.п. Создание моделей - это обширная тема, рассмотреть которую сколь-нибудь подробно в рамках этого небольшого учебника вряд ли получится.

Теперь мы можем проверить правильность синтаксиса и логики моделей:
$ ./manage.py validate
Чтобы увидеть команды SQL для создания структуры базы данных, требуемой для моделей из приложения app, введём следующую команду:
$ ./manage.py sqlall app
Чтобы выполнить эти операторы SQL и создать в базе данных таблицы, соответствующие моделям, нужно выполнить следующую команду:
$ ./manage.py syncdb
Можно войти в базу данных клиентом и увидеть созданную структуру таблиц и их взаимосвязи.

Для входа в базу данных с настройками проекта, можно воспользоваться следующей командой:
$ ./manage.py dbshell

Создание записей в таблицах

Откроем оболочку Python:
$ ./manage.py shell
Импортируем описание моделей:
from address.models import *
Создадим объект "город":
c = City(title=u'Уфа')
И сохраним его в базу данных:
c.save()
Теперь создадим объект "улица" в этом городе:
s = Street(title=u'ул. Карла Маркса', city=c)
И сохраним объект с улицей:
s.save()
Если нужно отредактировать объект, то можно прописать в него новое свойство и сохранить:
c.title = u'г. Уфа'
c.save()
Недостаток такого рода редактирования объектов заключается в том, что в базе данных обновляются все поля в отредактированной строке таблицы, а не только то поле, которое действительно было изменено. Для раздельного редактирования полей строк можно воспользоваться массовым редактированием, о котором будет рассказано далее.

Извлечение записей из таблиц

Откроем оболочку Python:
$ ./manage.py shell
Импортируем описание модели:
from address.models import *
Загрузим все объекты типа "город":
c = City.objects.all()
Загрузим объект "город", имеющий имя "г. Уфа":
c = City.objects.filter(title=u'г. Уфа')
И убедимся, что загрузился именно он:
print c
Выбор списка объектов:
  • Obj.objects.all() - отобрать как список все объекты типа Obj,
  • Obj.objects.filter(field='') - отобрать как список объекты, у которых поле field имеет указанное значение,
  • Obj.objects.filter(field1='', field2='') - отобрать как список объекты, у которых оба поля одновременно имеют указанные значения,
  • Obj.objects.filter(field__contains='') - отобрать как список объекты, у которых в указанном поле содержится указанное значение,
  • Obj.objects.filter(field__icontains='') - отобрать как список объекты, у которых в указанном поле содержится указанное значение без учёта регистра,
  • Obj.objects.filter(field__iexact='') - отобрать как список объекты, у которых указанное поле совпадает с указанным значением без учёта регистра,
  • Obj.objects.filter(field__startswith='') - отобрать как список объекты, у которых указанное поле начинается с указанного значения,
  • Obj.objects.filter(field__istartswith='') - отобрать как список объекты, у которых указанное поле начинается с указанного значения без учёта регистра,
  • Obj.objects.filter(field__endswith='') - отобрать как список объекты, у которых указанное поле заканчивается указанным значением,
  • Obj.objects.filter(field__iendswith='') - отобрать как список объекты, у которых указанное поле заканчивается указанным значением без учёта регистра.
Условия в фильтре можно комбинировать между собой не только указывая их через запятую, но создавая каскады фильтров:
Obj.objects.filter(field1__iendswith='a').filter(field2='b')
Чтобы отобрать объекты, не подходящие под указанное условие, можно воспользоваться методом фильтрации exclude. Например, следующее выражение отберёт те записи, у которых начало первого поля без учёта регистра совпадает с a, а второе поле не равно b:
Obj.objects.filter(field1__iendswith='a').exclude(field2='')
Выбор одного объекта осуществляется точно таким же способом, как выбор списка, за исключением того, что вместо метода filter используется метод get:
Obj.objects.get(field='')
Если ни один объект не был найден, будет сгенерировано исключение Obj.DoesNotExist. Если указанным критериям соответствует несколько записей, то будет сгенерировано исключение Obj.MultipleObjectsReturned.

Как и в случае выборки списка объектов, можно комбинировать фильтры друг с другом. Но для выборки одного объекта последним методом в цепочке должен быть get. Например, вот так:
Obj.objects.filter(field1__iendswith='a').exclude(field2='').get()
Или, что то же самое, вот так:
Obj.objects.exclude(field2='').get(field1__iendswith='a')
В Django версий 1.6 и более поздних имеется метод first(), не принимающий аргументов, который возвращает первую запись из списка, если она есть. В противном случае возвращается None. Стоит учитывать, что этот метод никак не обрабатывает случаи, когда условию соответствует несколько записей сразу.

Сортировка данных:
  • Obj.objects.order_by("field") - сортировка по одному полю,
  • Obj.objects.order_by("-field") - сортировка по одному полю в обратном порядке,
  • Obj.objects.order_by("field1", "field2") - сортировка по двум полям.
Сортировку по умолчанию можно настроить в свойствах объекта модели, добавив вложенный класс со свойством ordering, которому присвоен список полей для сортировки:
    class Meta:
        ordering = ["field"]
Можно комбинировать методы:
Obj.objects.filter(field="").order_by("-field")
Можно выбирать необходимый фрагмент списка объектов. Например, вот этот запрос вернёт два первых объекта:
Obj.objects.filter(field="").order_by("-field")[0:2]
Массовое обновление объектов осуществляется следующим образом:
Obj.objects.filter(id=52).update(field='')
Запрос возвращает количество обновлённых строк таблицы.

Удалить один объект можно следующим образом:
o = Obj.objects.get(field='')
o.delete()
Удалить объекты массово можно так:
Obj.objects.filter(field='').delete()

Активация интерфейса администратора

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

Для включения интерфейса администрирования нужно внести изменения в файл настроек dj/settings.py:
  1. Вписать в INSTALLED_APPS приложения django.contrib.admin, django.contrib.auth, django.contrib.sessions и django.contrib.contenttypes,
  2. Вписать в MIDDLEWARE_CLASSES приложения-прослойки django.middleware.common.CommonMiddleware, django.contrib.sessions.middleware.SessionMiddleware, django.contrib.auth.middleware.AuthenticationMiddleware и django.contrib.messages.middleware.MessageMiddleware.
Вносим изменения в базу данных, чтобы в ней создались таблицы, необходимые для работы интерфейса администрирования:
$ ./manage.py syncdb
Если при этом отказаться от создания суперпользователя, то потом его можно создать с помощью команды:
$ ./manage.py createsuperuser
Теперь в начало файла dj/urls.py добавим использование модуля и его инициализацию:
from django.contrib import admin
admin.autodiscover()
И пропишем маршрут к интерфейсу администрирования:
urlpatterns = patterns('',
    # ...
    (r'^admin', include(admin.site.urls)),
    # ...
)
Для того, чтобы объекты можно было редактировать прямо из интерфейса администратора, нужно создать в каталоге приложения app файл admin.py со следующим содержимым:
from app.models import *
from django.contrib import admin

admin.site.register(City)
admin.site.register(Area)
admin.site.register(Street)
admin.site.register(House)
После этого можно перейти по ссылке http://localhost:8000/admin/, войти под учётными данными, указанными команде createsuperuser, и пользоваться интерфейсом администрирования для добавления, редактирования и удаления записей в таблицах.

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

За рамками этого учебника также остались подробности описания моделей, выражения Q и F для конструирования более сложных запросов, не рассмотрены формы и модельные формы, не рассмотрена миграция структуры базы данных при изменении моделей и многое другое.

Комментариев нет: