Краткий учебник Django
Данное
пособие было написано Козловым Михаилом для себя т.к. работаю с довольно
большим количеством совершенно разных технологий, постоянно все вылетает из
головы, выкладываю в общедоступный доступ на своем сайте http://snakeproject.ru/
В данном пособии примеры делались на версии Django 2.1, Python
3.4 и Linux Centos 7
С Python версии 3.4 в состав включается утилита pip, с помощью нее
выполняем установку дополнительных библиотек из штатного репозитория
PyPI
Установка django
pip install django
Создадим новый проект
с именем testsite с помощью утилиты django-admin
mkdir -p /data/www
cd /data/www/
django-admin startproject
testsite
Создастся структура проекта
cd testsite && ls -l &&
ls -l testsite/
testsite/
manage.py
testsite
testsite/testsite
__init__.py
settings.py
urls.py
wsgi.py
manage.py – по сути программная оболочка для
работы с проектом, которая вызывает утилиту django-admin, передавая ей аргументы
testsite
–
папка, содержащая модули проекта и конфигурацию
__init__.py – сообщает python, что папка является полноценным пакетом
settings.py – модуль настроек проекта
urls.py – модуль маршрутизации проекта
wsgi.py – модуль связки проекта с веб-сервером
Запуск
отладочного веб-сервера
Находясь в
папке с проектом
pwd
/data/www/testsite
Наберите (ip
моего тестового сервера - 10.0.2.10)
python3.4 manage.py runserver 10.0.2.10:8000
И
проверьте через браузер:
Вы увидите тестовую страницу проекта
You are seeing this page because DEBUG=True is in your settings file and you have not
configured any URLs.
Расширим функционал нашего проекта с помощью приложений
Находясь в
папке проекта создадим приложение с именем «app1»
python3.4 manage.py startapp app1
Созданная
структура приложения app1
ls -l app1/
admin.py
apps.py
__init__.py
migrations
models.py
tests.py
views.py
admin.py - модуль
административных настроек
apps.py - модуль
настроек приложения
_init_.py -
сообщает python, что папка является полноценным
пакетом
migrations -
директория хранит сгенерированные модули миграций
models.py - модуль
моделей
tests.py - модуль
тестирующих процедур
views.py - модуль
контроллеров
Зарегистрируем
наше приложение в проекте
testsite/settings.py
Добавим
приложение app1 в секцию
INSTALLED_APPS
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app1.apps.App1Config',
]
Теперь
добавим представление, которое по сути является кодом, запускаемым в ответ на
клиентский запрос
Напишем представление-функцию
в нашем приложении app1
app1/views.py
from django.http import HttpResponse
def
index(request) :
return HttpResponse("Тестовый вывод")
Представление-функция с именем index принимает обязательный параметр
экземпляра класса HttpRequest,
который хранит сведения о полученном запросе клиента
Параметр имеет имя request
Внутри функции создается экземпляр класса HttpResponse модуля django.http,
который отправит клиенту ответ
Содержимое указывается параметром конструктора класса, готовый
экземпляр класса возвращается из функции с именем index
Теперь
настроим маршрутизацию на уровне проекта
testsite/urls.py
from django.contrib import admin
from django.urls import path
from app1.views import index
urlpatterns = [
path ( 'app1/',
index),
path ( 'admin/',
admin. site. urls),
]
Тут мы добавили связь запроса
Маршруты описываются в списке urlpatterns
Каждый маршрут - результат, возвращаемый функцией path() модуля django.urls
Функция path() принимает строку с
шаблоном url
и ссылку на функцию-представление
Т.е. новый маршрут связывает шаблон url app1/ и функцию-представление index
Запускаем и
проверяем
python3.4 manage.py runserver 10.0.2.10:8000
Тестовый
вывод
Теперь
настроим маршрутизацию на уровне приложения
В маршрутизации
приложения
app1/urls.py
from django.urls import path
from .views import index
urlpatterns = [
path ('', index),
]
Пустая строка - '' означает корень пути маршрута предыдущего
уровня вложенности
В маршрутизации
проекта
testsite/urls.py
from django.contrib import admin
from django.urls import path,
include
urlpatterns = [
path ('app1/',
include('app1.urls')),
path ( 'admin/', admin.site.urls),
]
include('app1.urls')) - это
список маршрутов, функции path(), представляет результат, возвращаемый
функцией include() из модуля django.urls, ее
параметр - строка с путем до модуля urls
приложения app1, в
котором описан список маршрутов
Запускаем и
проверяем
python3.4 manage.py runserver 10.0.2.10:8000
Тестовый
вывод
Когда сайт получает запрос типа http://10.0.2.10:8000/app1/ ,
маршрутизатор определит, что адрес запроса совпадает с шаблонном app1/ из маршрутизации проекта - testsite/urls.py
Из полученного в запросе адреса удалится префикс, который
соответствует шаблонному адресу, и получится пустая строка
Далее пройдет загрузка вложенного списка маршрутов из модуля urls.py приложения - testsite/urls.py
Полученный адрес, представляющий пустую строку совпадет с первым
маршрутом вложенного списка, запустится функция-представление index() с тестовым выводом
Теперь
поговорим о структуре
Модель –
структура сущности, хранящаяся в базе данных в виде python класса, по
сути представление таблицы, в которой хранится набор сущностей, в каждой из
которых хранятся атрибуты класса, которые описывают поля этой таблицы.
Каждый экземпляр класса модели является отдельной сущностью
Класс модели объявляется на уровне приложения в models.py , а сам класс дает возможность выборки, сортировки, фильтрации
По умолчанию созданный проект настроен использовать базу
данных SQLite (файл db.sqlite3
в папке проекта)
Тестовая модель A1 для приложения app1 (будем описывать товар)
name - тип: CharField, строка длинною 30
символов
description - тип: TextField
price - тип: Float
arrival - тип: DateTimeField, дата и время
(подставлять текущее по дефолту)
Внесем изменения
app1/models.py
from django.db import models
class A1(models.Model):
name = models.CharField(max_length=30)
description = models.TextField(null=True, blank=True)
price = models.FloatField(null=True, blank=True)
arrival = models.DateTimeField(auto_now_add=True,
db_index=True)
Где:
CharField -
строковое поле фиксированной длины (max_length=30 -
30 символов)
TextField -
текстовое поле неограниченной длины, (null=True и blank=True - разрешит поле не заполнять)
FloatField -
вещественных чисел поле
DateTimeField - даты и времени поле (auto_now_add=True - добавление текущей даты и времени, db_index=True - создать индекс)
Теперь нужно
сформировать в базе данных структуру модели
Используем модуль миграция
Запустим миграцию всех
моделей для приложения app1
python3.4
manage.py makemigrations app1
Migrations
for 'app1':
app1/migrations/0001_initial.py
- Create model A1
0001_initial.py – модуль с кодом миграции
Код нашей миграции
cat
app1/migrations/0001_initial.py
# Generated
by Django 2.0.13 on 2019-03-19 15:54
from django.db import migrations, models
class
Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='A1',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True,
serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=30)),
('description', models.TextField(blank=True,
null=True)),
('price', models.FloatField(blank=True,
null=True)),
('arrival', models.DateTimeField(auto_now_add=True, db_index=True)),
],
),
]
Миграции создают SQL код, который будет отправлен СУБД,
просмотрим его
python3.4
manage.py sqlmigrate app1 0001
BEGIN;
--
-- Create
model A1
--
CREATE
TABLE "app1_a1" ("id" integer NOT NULL PRIMARY KEY
AUTOINCREMENT, "name" varchar(30) NOT NULL, "description"
text NULL, "price" real NULL, "arrival" datetime
NOT NULL);
CREATE
INDEX "app1_a1_arrival_42c6d35f" ON "app1_a1"
("arrival");
COMMIT;
Самую первую миграцию
нового проекта рекомендовано производить для всех приложений
python3.4
manage.py migrate
Operations
to perform:
Apply all migrations: admin, app1, auth, contenttypes, sessions
Running
migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying
admin.0002_logentry_remove_auto_add... OK
Applying app1.0001_initial... OK
Applying contenttypes.0002_remove_content_type_name...
OK
Applying
auth.0002_alter_permission_name_max_length... OK
Applying
auth.0003_alter_user_email_max_length... OK
Applying
auth.0004_alter_user_username_opts... OK
Applying
auth.0005_alter_user_last_login_null... OK
Applying
auth.0006_require_contenttypes_0002... OK
Applying
auth.0007_alter_validators_add_error_messages... OK
Applying
auth.0008_alter_user_username_max_length... OK
Applying
auth.0009_alter_user_last_name_max_length... OK
Applying sessions.0001_initial... OK
Теперь познакомимся с консолью python django
Консоль для данного проекта открыть можно так
python3.4 manage.py shell
Теперь вы находитесь в консоли, которая в составе путей поиска модулей имеет ваш проект
Добавим запись в базу
>>>
from app1.models import A1
>>>
a1 = A1 (name='Дрова', description='Березовые, высушенные',
price=300)
>>> a1.save()
Проверим, сохранилась
ли запись, выведя ее ключевое поле
>>> a1.pk
1
Выведем определенные
поля записи
a1.description
'Березовые, высушенные'
>>>
a1.id
1
>>>
a1.arrival
datetime.datetime(2019, 3, 19, 16, 9, 29, 911052, tzinfo=<UTC>)
Второй вариант
создания записи
>>> a2
= A1()
>>>
a2. name='Щепки'
>>>
a2. description='Березовые, сырые'
>>> a2. price=200
>>> a2.save()
Изменим поле записи
>>>
a2.price
200
>>>
a2.price=100
>>>
a2.price
100
>>> a2.save()
Третий вариант создания
записи (атрибут objects класса моделей)
>>>
A1.objects.create(name='Опилки',
description='Влажные', price=50)
<A1:
A1 object (3)>
Наконец сделаем
перебор наших записей из базы
>>>
for a in A1.objects.all():
... print(a.pk, ': ',
a.name)
...
1 :
Дрова
2 :
Щепки
3 : Опилки
Выборка с наложением
фильтра методом filter()
>>>
for a in A1.objects.filter(name='Щепки'):
... print(a.pk, ': ',
a.name)
...
2 : Щепки
Выборка с сортировкой
методом order_by
Тут метод all() – возвращает набор записей из нашей модели
>>>
for a in A1.objects.order_by('name'):
... print(a.pk, ': ',
a.name)
...
1 :
Дрова
3 :
Опилки
2 : Щепки
Сделаем выборку
записи по pk=3
>>>
a=A1.objects.get(pk=3)
>>>
a.name
'Опилки'
>>>
a.price
50.0
Удалим запись
>>>
a.delete()
(1, {'app1.A1': 1})
Выходим из консоли
Use exit() or Ctrl-D
Добавим вывод записей
в django приложении app1
app1/views.py
from django.http import HttpResponse
from
.models import A1
def index(request):
mess = 'Товары:\r\n'
for a in
A1.objects.order_by('-arrival'):
mess += a.name +
'\r\n' + a.description + '\r\n'
return HttpResponse(mess, content_type='text/plain;
charset=utf-8')
Тут метод order_by('-arrival') –
сортирует по убыванию даты
Запускаем и проверяем
python3.4
manage.py runserver 10.0.2.10:8000
Товары:
Щепки
Березовые, сырые
Дрова
Березовые, высушенные
Теперь поговорим о
шаблонах
Шаблонизатор django по умолчанию смотрит в папку templates внутри приложения
Для начала подредактируем вид
app1/views.py
from django.http import HttpResponse
from
.models import A1
from django.template import loader
def index(request):
template=loader.get_template('index.html')
a1v=A1.objects.order_by('-arrival')
context={'a1v': a1v}
return HttpResponse(template.render(context,
request))
Тут мы с
помощью функции get_template() загружаем шаблон из
модуля django.template.loader
('index.html') – путь до шаблона (об этом ниже)
context={'a1v': a1v} – контекст шаблона по сути данные, доступные внутри самого шаблона
template.render(context, request) – рендеринг по сути объединение контекста и шаблона
Создадим для
приложения app1 эту папку и шаблон
mkdir app1/templates
app1/templates/index.html
<html>
<head>
<titlе>Заголовок</titlе>
</head>
<body>
<h2>Список</h2>
{% for a in
a1v %}
<h3>{{ a.name }} </h3>
<р> {{ a.description }} < /р>
<р> {{ a.price }} < /р>
<р>{ { a.arrival:
"d.m. У Н: i:s" }
}</р>
{% endfor %}
</body>
</html>
Тут {% for a in a1v %}…{% endfor
%} – по функционалу цикл for
a1v – данные нашего контекста
Запускаем, проверяем
python3.4
manage.py runserver 10.0.2.10:8000
Заголовок
<р> Березовые,
сырые < /р> <р> 100.0 < /р>
<р>{
{ a.arrival: "d.m. У Н:
i:s" } }
<р>
Березовые, высушенные < /р> <р> 300.0 <
/р> <р>{ { a.arrival: "d.m. У Н: i:s" } }
Более простой вариант
app1/views.py
from django.shortcuts import render
from
.models import A1
def index(request):
a1v=A1.objects.order_by('-arrival')
return
render(request, 'index.html', {'a1v': a1v})
Запускаем, проверяем
python3.4
manage.py runserver 10.0.2.10:8000
Заголовок
<р> Березовые,
сырые < /р> <р> 100.0 < /р>
<р>{
{ a.arrival: "d.m. У Н:
i:s" } }
<р>
Березовые, высушенные < /р> <р> 300.0 <
/р> <р>{ { a.arrival: "d.m. У Н: i:s" } }
Поговорим об админке
Стандартный модуль административной панели django входит в состав по умолчанию
За хранение учетных данных отвечает приложение
django.contrib.auth
За работу админки отвечает приложение
django.contrib.admin
Создадим суперпользователя
python3.4
manage.py createsuperuser
Username
(leave blank to use 'root'): root
Email
address: root@localhost
Password:
Password
(again):
Superuser
created successfully.
Русифицируем админку
testsite/settings.py
...
LANGUAGE_CODE = 'ru-ru'
...
Чтоб приложение app1 отобразилось в админке, его надо
зарегистрировать
app1/admin.py
from django.contrib import admin
from
.models import A1
admin.site.register(A1)
register(A1) – регистрирует наше приложение в админке
Запускаем, проверяем,
вводим логин и пароль
python3.4
manage.py runserver 10.0.2.10:8000
Группы и Пользователи – встроенное по умолчанию приложение django.contrib.auth
Попробуйте самостоятельно добавить пару записей через кнопку «Добавить» и изменить в приложении App1
Поля, параметры,
модель
Давайте дадим в админке «человеческие» названия нашим полям модели
app1/models.py
from django.db import models
class A1(models.Model):
name = models.CharField(max_length=30, verbose_name='Название')
description = models.TextField(null=True, blank=True, verbose_name='Описание')
price = models.FloatField(null=True, blank=True, verbose_name='Цена')
arrival = models.DateTimeField(auto_now_add=True,
db_index=True, verbose_name='Дата')
class Meta:
verbose_name_plural
= 'Товары'
verbose_name = 'Товар'
ordering = [
'-arrival' ]
Где
verbose_name -
название поля, которое выводится на экран
class Meta: - вложенный класс, атрибуты которого зададут параметры
модели
verbose_name_plural - название модели во множественном числе
verbose_name -
название модели в единственном числе
ordering - сортировка записей
Переделаем наше
представление на более простую конструкцию с all()
app1/views.py
from django.shortcuts import render
from
.models import A1
def index(request):
a1v=A1.objects.all()
return
render(request, 'index.html', {'a1v': a1v})
Дополнительно
отобразим по «человечески» сами записи в админке
app1/admin.py
from django.contrib import admin
from
.models import A1
class
A1Admin(admin.ModelAdmin):
list_display =
('name', 'description', 'price', 'arrival')
list_display_links
= ('name', 'description')
search_fields =
('name', 'description')
admin.site.register(A1, A1Admin)
APP1 |
||
Товары |
Добавить |
Изменить |
Конец первой части учебника