4. Запускаем django приложение на сервере

18 февраля 2014 г. 9:45

Цикл статей по развёртыванию сайтов на боевом сервере с нуля по шагам с использованием python + django + uwsgi + nginx + supervisor:

Предыдущий шаг был посвящён настройке конфигураций uwsgi, nginx, supervisor, к тому же мы ещё и настроили DNS. То есть мы выполнили базовую задачу по развёртыванию обычного python приложения. А теперь мы переходим к развёртыванию сайта django nginx uwsgi, который использует базу данных и имеет картинки и другие медиа файлы! На этом шаге мы используем некоторые полезные инструменты. Будем работать почти как профессионалы. Я говорю "почти как профессионалы", потому что, научившись некоторым приёмам процесса разработки и развёртывания приложений, Вам всё равно рано или поздно придётся пополнять свой арсенал используемых инструментов и открывать новые фишечки, а пока приобретённые знания дадут Вам почувствовать себя почти профессионалами!

Настроились на работу и поехали! Сначала давайте создадим на своем компе, который стоит дома или в офисе, Django приложение "Кролики"! Мы будем выводить информацию о кроликах прямо на главной странице. Из командной строки/терминала заходим в папку, где будет лежать проект и собственного стандартной командой создаём тестовый проект. И заодно создадим некоторое приложение main.

#cd /home/vivazzi/tests/
cd d:\tests
django-admin.py startproject rabbits
cd rabbits
python manage.py startapp main

Давайте приложение main будем использовать для отображения главной страницы, в котором будет немного текста и картинка. И заодно в этом приложении реализуем обработку ошибок 404 и 500, чтобы было поинтереснее. И чтобы шибко было интересно используем библиотеку admin-tools для лучшего отображения админки. А чтобы нам было легче работать с изменением структуры БД используем классную библиотеку south. И, конечно же, используем систему контроля ревизий такую как mercurial.

Внимание! Хорошая фишечка: так как у нас будут разные настройки на нашем компе (например, настройки БД), на котором разрабатываем проект, и на боевом сервере, то нужно определить файл settings.py и local_settings.py. Тем самым settings.py будет брать нужные параметры из local_settings.py. Это ещё нужно, например, чтобы пароль к Вашей БД на локальной машине не попал в систему контроля ревизий и не пришлось изменять сам файл настроек на сервере, если пароли на разных машинах разные.

admin-tools - приложение, улучшающее административную часть django (более подробно можно почитать здесь: habrahabr.ru/post/98539/)

south - приложение, упрощающее работу с БД: создаёт и меняет структуру БД и осуществляет миграцию данных из разных полей и таблиц (тоже на хабре можно почитать: habrahabr.ru/post/47004/)

система контроля ревизий (система контроля версий файлов, VCS) - позволяет хранить несколько версий одного и того же документа и проекта в целом, при необходимости возвращаться к более ранним версиям, определять, кто и когда сделал то или иное изменение, и др. (почитать про это: habrahabr.ru/post/108658/)

Чтобы не замарачиваться сразу приведу структуру проекта и весь код, у вас должно быть также.

Структура (обратите внимание, что она изменена в отличии от созданной командой django-admin.py startproject rabbits):

rabbits:
-main:
--|static:
----|main:
------|rabbits.jpg
--|templates:
----|home.html
--|__init__.py
--|models.py
--|urls.py
--|views.py
-__init__.py
-dashboard.py
-local_settings_sample.py
-local_settings.py
-manage.py
-urls.py

# --- rabbits/local_settings_sample.py ---

DEBUG = True

DB_GENERIC = {
    'ENGINE': 'django.db.backends.postgresql_psycopg2',
    'USER': 'user_name',
    'PASSWORD': 'password',
    'HOST': 'localhost',
    'PORT': '',
}

DATABASES = {
    'default': dict(DB_GENERIC),
}

DATABASES['default']['NAME'] = 'db'

SECRET_KEY = 'a-wuz%jy6jq28#4co_ *23fl&0rng6u5i-i+f=$o'

ALLOWED_HOSTS = ['localhost', ]

# --- rabbits/local_settings.py ---

DEBUG = True

DB_GENERIC = {
    'ENGINE': 'django.db.backends.postgresql_psycopg2',
    'USER': 'postgres',
    'PASSWORD': 'postgres',
    'HOST': 'localhost',
    'PORT': '',
}

DATABASES = {
    'default': dict(DB_GENERIC),
}

DATABASES['default']['NAME'] = 'test_db'

SECRET_KEY = 'a-wuz%jy6jq28#4co_ *23fl&0rng6u5i-i+f=$o'

ALLOWED_HOSTS = ['localhost', ]

# --- rabbits/settings.py ---

# -*- coding: utf-8 -*-

import os
try:
    import local_settings
except ImportError:
    import local_settings_sample as local_settings

ROOT_DIR = os.path.dirname(__file__)

DEBUG = local_settings.DEBUG
TEMPLATE_DEBUG = DEBUG

ADMINS = (
    ('name', 'email'),
)


MANAGERS = ADMINS

DATABASES = local_settings.DATABASES

TIME_ZONE = 'Asia/Irkutsk'
LANGUAGE_CODE = 'ru-RU'

LANGUAGES = (
('ru', 'Russian'),
)

SITE_ID = 1

USE_I18N = True
USE_L10N = True
USE_TZ = True

MEDIA_ROOT = os.path.join(ROOT_DIR, 'media')
MEDIA_URL = "/media/"

STATIC_ROOT = os.path.join(ROOT_DIR, 'collect_static')
STATIC_URL = '/static/'

STATICFILES_DIRS = (
os.path.join(ROOT_DIR, 'static'),
)

STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
#    'django.contrib.staticfiles.finders.DefaultStorageFinder',
)

SECRET_KEY = local_settings.SECRET_KEY

TEMPLATE_LOADERS = (
    'django.template.loaders.filesystem.Loader',
    'django.template.loaders.app_directories.Loader',
#     'django.template.loaders.eggs.Loader',
)

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',
    # 'middlewares.AdminSessionMiddleware'
)

ROOT_URLCONF = 'urls'

LOGIN_URL = '/login/'
LOGOUT_URL = '/logout/'

LOGIN_REDIRECT_URL = '/admin/'

WSGI_APPLICATION = 'wsgi.application'

TEMPLATE_DIRS = (
    os.path.join(ROOT_DIR, 'templates'),
)

PROJECT_APPS = (
    'main',
)

INSTALLED_APPS = (
    'admin_tools',
    'admin_tools.theming',
    'admin_tools.menu',
    'admin_tools.dashboard',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.admin',
    'south'
) + PROJECT_APPS


LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse'
        }
    },
    'handlers': {
        'mail_admins': {
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler'
        }
    },
    'loggers': {
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
    }
}

TEMPLATE_CONTEXT_PROCESSORS = (
    'django.contrib.auth.context_processors.auth',
    'django.core.context_processors.request',
    'django.core.context_processors.media',   # MEDIA_URL
    'django.core.context_processors.static',  # STATIC_URL
    'django.contrib.messages.context_processors.messages',
)

ADMIN_TOOLS_INDEX_DASHBOARD = 'dashboard.CustomIndexDashboard'

ALLOWED_HOSTS = getattr(local_settings, 'ALLOWED_HOSTS', ['localhost', ])

# --- rabbits/wsgi.py ---

import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")

from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

# --- rabbits/urls.py (который в корне проекта) ---
from django.conf import settings
from django.conf.urls import patterns, include, url
import main.views as main_views

from django.contrib import admin
admin.autodiscover()


urlpatterns = patterns('',
    url(r'^admin/', include(admin.site.urls)),
    url(r'^admin_tools/', include('admin_tools.urls')),
    url(r'^', include('main.urls')),

    # --- error pages ---
    url(r'^404$', main_views.error_page_404),
    url(r'^500$', main_views.error_page_500),
    # --- error pages ---
)


handler404 = main_views.error_page_404
handler500 = main_views.error_page_500


if settings.DEBUG:
    urlpatterns = patterns(
        '',
        url(r'^media/(?P.*)$', 'django.views.static.serve',
            {'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
        url(r'', include('django.contrib.staticfiles.urls')),
    ) + urlpatterns

# --- rabbits/main/urls.py (в приложении который) ---

# -*- coding: utf-8 -*-
from django.conf.urls import patterns, url
import main.views as main_views


urlpatterns = patterns('',
    url(r'^$', main_views.home),
)

# --- rabbits/main/views.py ---

# -*- coding: utf-8 -*-
from django.shortcuts import render


def home(request):
    rabbits = Rabbit.objects.all()
    return render(request, 'index.html',
                  {'rabbits': rabbits})

# --- rabbits/main/models.py ---

#-*- coding: utf-8 -*-
from django.db import models


class Rabbit(models.Model):
    color = models.CharField(verbose_name=u'Цвет', max_length=100)
    size = models.CharField(verbose_name=u'Размер', max_length=100)

    def __unicode__(self):
        return u'{0} {1}'.format(self.color, self.size)

    class Meta:
        verbose_name = Кролик'
        verbose_name_plural = u'Кролики'

# --- rabbits/main/templates/home.html ---
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Какие бывают разные кролики</title>
</head> 
<body>
<img src="{{ STATIC_URL }}/main/img/rabbits.png" />
<h1>И всё-таки кролики бывают разные:</h1> 
<div>
 {% for rabbit in rabbits %}
   <h3>{{ rabbit.color }} и {{ rabbit.size }}</h3>
 {% endfor %}
</div> 
</body> 
</html> 

На что нужно обратить внимание?

В файле local_settings.py:

1) значение параметра SECRET_KEY вы должны скопировать с settings.py, который автоматически генерируется при запуске django-admin.py startproject rabbits

2) рекомендую использовать настройки бд следующие:

DB_GENERIC = {
    'ENGINE': 'django.db.backends.postgresql_psycopg2',
    'USER': 'postgres',
    'PASSWORD': 'your_password',
    'HOST': 'localhost',
    'PORT': '',
}

DATABASES = {
    'default': dict(DB_GENERIC),
}

DATABASES['default']['NAME'] = 'test_db'

Это позволит задавать несколько баз данных. Чтобы добавить ещё одну, нам нужно добавить ключ, значение в словарь DATABASES и задать имя базы данных. Например:


DATABASES = {
    'default': dict(DB_GENERIC),
    'other_db': dict(DB_GENERIC),
}

DATABASES['default']['NAME'] = 'test_db'
DATABASES['other_db']['NAME'] = 'other_db'

3) Этот файл не добавляем в репозиторий, а создаём его на своей локальной машине и на сервере.

4) Если вдруг Вы забыли создать local_settings.py на сервере, то будет использовано local_settings_sample.py, который храниться в репозитории.

В файле settings.py:

1) Добавляем приложение main в список PROJECT_APPS, который лежит в требуемом для джанги списка INSTALLED_APPS

2) Подключаем admin-tools вот этой строчкой: ADMIN_TOOLS_INDEX_DASHBOARD = 'dashboard.CustomIndexDashboard'

3) В значениях констант WSGI_APPLICATION, ROOT_URLCONF, а также в файле wsgi.py убрали название проекта test_app

4) Константой STATIC_ROOT определили место куда будет собираться вся статика с приложений при вызове команды collectstatic на боевом сервере

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

python manage.py schemamigration main --init
python manage.py migrate

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

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

Создаём структуру папок: для нашего веб-приложения "Кролики"

mkdir -p /home/vivazzi/web/rabbits
cd /home/vivazzi/web/rabbits
mkdir /home/vivazzi/web/rabbits/src  # исходный код проекта
mkdir /home/vivazzi/web/rabbits/logs  # сюда собирать будем логи
mkdir /home/vivazzi/web/rabbits/docs  # здесь будут храниться конфиги

Поставим postgresql для работы с БД:

apt-get install postgresql

Входим под пользователем postgres:

su - postgres

И входим в клиент, который позволяет нам работать с СУБД postgresql:

psql

Создадим владельца базы данных test_user

postgres=# CREATE ROLE test_user WITH NOSUPERUSER LOGIN PASSWORD 'test_pass';
CREATE ROLE

Создадим базу данных test_db, владельцем которой будет test_user

postgres=# CREATE DATABASE test_db OWNER test_user;
CREATE DATABASE

Выходим из редактора postgresql

\q

И разлогинимся с пользователя postgresql:

logout

Ставим mercurial

apt-get install mercurial

А теперь клонируем проект в папку src

cd /home/vivazzi/web/rabbits/src
hg clone https://vivazzi@bitbucket.org/vivazzi/rabbits  # у Вас должен быть свой адрес к проекту на битбаките

И запускаем миграции

cd /home/vivazzi/web/rabbits/src/rabbits/
python manage.py migrate

Пусть у нас будет доменное имя www.happy-rabbits.ru, тогда прописываем DNS записи:

nano /etc/bind/named.conf

# --- /etc/bind/named.conf ---

zone "happy-rabitts.ru" {
        type master;
        file "/etc/bind/happy-rabitts.ru";
};

nano /etc/bind/happy-rabitts.ru

# --- /etc/bind/happy-rabitts.ru ---

$TTL    3600
@  IN      SOA     ns1.happy-rabitts.ru. root.happy-rabitts.ru. (2012000001 10800 3600 604800 86400)

@  IN      NS      ns1
@  IN      NS      ns2

ns1     IN      A       62.109.10.27  # поменяйте на ip вашего сервера (ip-адрес_1)
ns2     IN      A       62.109.7.235  # (ip-адрес_2)

@       IN      A       62.109.10.27  # (ip-адрес_1)
www     IN      A       62.109.10.27  # (ip-адрес_1)

cd /home/vivazzi/web/rabbits/docs/
nano uwsgi.ini

# --- Содержимое файла uwsgi.ini ---

[uwsgi]
# Сокет для передачи данных
socket = /home/vivazzi/web/rabbits/uwsgi.sock

# Путь к виртуальному окружению (пока его не используем)
home = /home/vivazzi/web/rabbits/env

# Нам понадобится включенный python плагин
plugins = python

# Дополнительный python-путь
pythonpath = /home/vivazzi/web/test_app

# Модуль python с определением wsgi приложения
module = wsgi

# Количество процессов
processes = 2

# Максимальное количество соединений для каждого процесса
max-requests = 5000

# Максимальный размер запроса
buffer-size = 32768

# Убивать каждое соединение требующее больше 30 сек для обработки
harakiri = 30

# Включает опцию мастер-процесса uwsgi
master

# Автоматически прибивать воркеры, если умирает мастер-процесс
no-orphans

# Количество секунд, которое дается воркеру uwsgi для корректного перезапуска.
# Если воркер не успевает - по истечении этого времени его принудительно пришибает
reload-mercy = 8

Создаём файл supervisor.conf

root@viva-itstudio:/home/vivazzi/web/rabbits/docs/# nano supervisor.conf

# --- /home/vivazzi/web/rabbits/docs/supervisor.conf ---

[program:rabbits]
command=/usr/bin/uwsgi --ini /home/vivazzi/web/rabbits/docs/uwsgi.ini
user=www-data
stdout_logfile=/home/vivazzi/web/rabbits/logs/uwsgi.log
stderr_logfile=/home/vivazzi/web/rabbits/logs/uwsgi_err.log
directory=/home/vivazzi/web/rabbits/src/rabbits
autostart=true
autorestart=true
redirect_stderr=true
stopsignal=QUIT

Создаём файл nginx.conf

root@viva-itstudio:/home/vivazzi/web/rabbits/docs# nano nginx.conf

# --- /home/vivazzi/web/rabbits/docs/nginx.conf ---
server {

    listen      80;
    server_name happy-rabbits.ru www.happy-rabbits.ru;
    access_log  /home/vivazzi/web/rabbits/docs/nginx_access.log;
    error_log   /home/vivazzi/web/rabbits/docs/nginx_error.log;

    location /static/ {
        alias /home/vivazzi/web/rabbits/src/rabbits/collect_static/;
    }

    location / {
        uwsgi_pass  unix:///home/vivazzi/web/rabbits/uwsgi.sock;
        include     uwsgi_params;
    }
}

Теперь нужно поставить необходимые библиотеки и зависимости

pip install Django==1.5 south django-admin-tools==0.5.1 psycopg2==2.4.1

Если в процессе установки ещё pip ещё что-то просит, то смотрим что он хочет и даём)

Создаём симлинки конфигураций nginx-а и supervisor-а и выдаём права на чтение и запись всей папки с проектом

ln -s /home/vivazzi/web/rabbits/docs/nginx.conf /etc/nginx/sites-enabled/test_app.conf
ln -s /home/vivazzi/web/rabbits/docs/supervisor.conf /etc/supervisor/conf.d/test_app.conf
chmod a+w -R /home/vivazzi/web/rabbits

И перечитаем конфигурацию nginx-а

# если ещё не запущен, то:
cd /usr/local/sbin
./nginx
# либо запуская init-скрипт: /etc/init.d/nginx restart

# и даём команду на перезапуск:
nginx -s reload

Также для supervisor-а нужно выполнить команду перечитывания конфигурации

supervisorctl update  #добавит процесс в свой список

Позже можно управлять проектом командами: supervisorctl start|stop|restart rabbits

Всё! Теперь должно работать. Если это не так, то логи помогут (/home/vivazzi/web/rabbits/logs/)

Если всё заработало, то я Вас поздравляю! Если что-то не так, пишите мне на почту artem@vits.pro. Буду рад помочь!

И в качестве заключения хочу пожелать успехов в работе, в создании клёвых сайтов и, чтоб багов было меньше, а лучше чтоб вообще не было =). Удачи!

Оцените статью

5 из 5 (всего 3 оценки)

captcha
Отмеченные звёздочкой поля ( * ) являются обязательными для заполнения.

Спасибо за ваш отзыв!

После нажатия кнопки "Отправить" ваше сообщение будет доставлено мне на почту.

Автор статьи

Артём Мальцев

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

Права на использование материала, расположенного на этой странице https://vivazzi.pro/ru/deploy-django-site/run-django/:

Разрешается копировать материал с указанием её автора и ссылки на оригинал без использования параметра rel="nofollow" в теге <a>. Использование:

Автор статьи: Артём Мальцев
Ссылка на статью: <a href="https://vivazzi.pro/ru/deploy-django-site/run-django/">https://vivazzi.pro/ru/deploy-django-site/run-django/</a>

Больше: Правила использования сайта

Представляю вашему вниманию книгу, написанную моим близким другом Максимом Макуриным: Секреты эффективного управления ассортиментом.

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

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

Вы можете оставить комментарий как незарегистрированный пользователь.

Но зарегистрировавшись, вы сможете:

  • получать оповещения об ответах
  • просматривать свои комментарии
  • иметь возможность использовать все функции разработанных сервисов

Для комментирования от своего имени войдите или зарегистрируйтесь на сайте Vuspace

Отправить

На данный момент нет специального поиска, поэтому я предлагаю воспользоваться обычной поисковой системой, например, Google, добавив "vivazzi" после своего запроса.

Попробуйте

Выберите валюту для отображения денежных единиц