Создание Django-проекта в виртуальном окружении


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

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

Итак, что в идеале хотелось бы получить:

  1. Единый каталог проекта с виртуальным окружением и git-репозиторием для быстрого создания stage и dev-окружений
  2. Скрипт пересоздания виртуального окружения при переносе между рабочими станциями
  3. Скрипты для запуска dev-версии
  4. Скрипты запуска боевого окружения (шаблоны конфигурационных файлов)
  5. Скрипты резервного копирования и восстановления

Создаем виртуальное окружение Django-проекта

Первым делом, создаем корневой каталог (для приложения и его окружения) и для того чтобы не путаться имеет смысл назвать его так же как и будущий проект. Сегодня я начинаю работу над проектом private-vpn-proxy и описываю создание типового окружения именно для этого проекта.

$ mkdir ./private-vpn-proxy
$ cd ./private-vpn-proxy/

В этом каталоге мы создаем каталог deploy который будет содержать скрипт развертывания базового рабочего окружения:

$ mkdir ./deploy
$ touch ./deploy/deploy.sh
$ chmod +x ./deploy/deploy.sh

Сам скрипт имеет следующее содержание:

#!/bin/sh

# Скрипт может быть запущен из любого каталога
DIR=`dirname "$(readlink -f "$0")"`
cd "$DIR"
cd ../

# Устанавливаем необходимые базовые пакеты и dev-пакеты необходимые для создания окружения
sudo apt-get -y install python3-venv python3 python3-pip libjpeg-dev libpng-dev libpq-dev

# Инициализируем виртуальное окружение
if [ -d "./venv" ];
then
    rm -r ./venv/
fi

python3 -m venv ./venv/

Скрипт выполняет переход в каталог на один уровень ниже исполняемого скрипта, устанавливает пакеты python3 и python3-venv, где первый собственно интерпретатор Python, а второй утилита создания рабочего окружения. Дополнительно устанавливаем несколько dev-пакетов необходимых для сборки ряда Python-библиотек и в конце концов инициализируем рабочее виртуальное окружение и эту операцию надо выполнять при каждом переносе окружения на другой сервер или рабочую станцию.

Инициализируем пустой Django-проект и приложение

Устанавливаем в виртуальное окружение пакет Django:

$ ./venv/bin/pip3 install django==2.1.5

Обратите внимание, что мы вызывали pip3 из виртуального окружения и пакет Django установлен не в системное окружение, а в виртуальное. Естественно, что вы можете версию пакета не указывать, но в дальнейшем файл requirements.txt все равно должен будет содержать указание версий пакетов которые устанавливаются в виртуальное окружение.

Создаем наш Django-проект (аналогично вызываем команду из виртуального окружения):

$ ./venv/bin/python3 ./venv/bin/django-admin.py startproject private_vpn_proxy

Создаем первое приложение в проекте:

$ ./venv/bin/python3 ./private_vpn_proxy/manage.py startapp cabinet

Подготавливаем окружение разработчика

В корне свежесозданного приложения размещаем файл requirements.txt который на данный момент имеет только одну запись:

django==2.1.5

Естественно, что в процессе работы над проектом мы будем вписывать туда все используемые Python библиотеки. Следующий файл который размещаем в корне проекта, это .gitignore и лучше всего его взять с github по адресу: https://github.com/github/gitignore/blob/master/Python.gitignore.

На данный момент файл .gitignore имеет вид:

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

Возможно вам имеет смысл привести его к более читаемому виду убрав из него заведомо неиспользуемые элементы:

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
eggs/
.eggs/
*.egg-info/
*.egg

# Translations
*.mo
*.pot

# Project DataBase
db.sqlite3

Переходим к созданию каталогов static и media. Причем media будет символической ссылкой на каталог media в корне проекта, вы конечно можете добавить каталог media в исключения .gitignore, но я пришел к мнению, что это не самый лучший вариант и в дальнейшем я объясню почему.

$ mkdir static
$ mkdir ../media
$ ln -s ../media/ ./media

Для работы со статическими файлами добавьте в конфигурационный файл settings.py следующий параметр:

STATIC_ROOT = os.path.join(BASE_DIR, "static")

Загружаем в каталог static связанные файлы проекта

$ ../venv/bin/python3 ./manage.py collectstatic

Инициализируем базу данных:

$ ../venv/bin/python3 ./manage.py makemigrations
$ ../venv/bin/python3 ./manage.py migrate

Создаем супер-пользователя нашего web-проекта:

$ ../venv/bin/python3 ./manage.py createsuperuser

И наконец, мы инициализируем GIT-репозиторий нашего проекта:

$ git init
$ git add -A
$ git commit -m "Initial commit"

Скрипты обслуживания web-проекта

Как вы понимаете, запускать конструкции вида ../venv/bin/python3 ./manage.py как минимум неудобно и для запуска окружения разработчика я использую специальный скрипт в корне проекта:

#!/bin/sh

./venv/bin/pip3 install -r ./private_vpn_proxy/requirements.txt
./venv/bin/python3 ./private_vpn_proxy/manage.py makemigrations
./venv/bin/python3 ./private_vpn_proxy/manage.py migrate
./venv/bin/python3 ./private_vpn_proxy/manage.py runserver 127.0.0.1:8000

Я этот скрипт обычно называю run_developer_environment.sh. Как вы видите по содержимому этого скрипта, он выполняет все предстартовые операции обслуживания web-проекта и запускает web-сервер для отладки.

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