Данная статья предназначена для новичков в web-программировании и освещает вопросы разработки блога на Django с использованием Twitter Bootstrap и его развертывания на бесплатном хостинге PythonAnywhere. Я старался написать как можно более проще и понятнее. Более опытным пользователям данное чтиво не расскажет ничего нового, да и некоторые приемы возможно покажутся неэффективными.
Предполагаю, что читатель уже ознакомлен с синтаксисом Python, имеет минимальное представление о Django (для начала неплохо пройти обучение на http://codeacademy.com по соответствующей теме и прочитать туториал по Django), а также владеет приемами работы в командной строке.
Итак, начинаем с организации рабочего окружения на локальном компьютере. В принципе, для наших запросов подойдет любая операционная система в которой вы чувствуете себя уверенно, здесь я описываю процесс для GNU/Linux, а для других систем шаги могут незначительно отличаться. В системе должна быть установлена virtualenv — утилита для создания изолированного рабочего окружения (чтобы библиотеки, которые мы используем не мешались другим программам и проектам).
Cоздаем и активируем окружение:
mkdir ~/projects
cd ~/projects
virtualenv env
source env/bin/activate
В ОС Windows последняя команда должна быть такой:
env/Scripts/activate
Устанавливаем Django с помощью pip — менеджера пакетов Python.
pip install django
Создаем новый проект. Назовем его как-нибудь оригинально — например mysite.
django-admin.py startproject mysite && cd mysite
Скрипт отработает и создаст каталог mysite с еще одним каталогом mysite и несколькими *.py файлами внутри.
Используем скрипт manage.py для создания приложения django с именем blog.
python manage.py startapp blog
Отредактируем настройки в файле mysite/settings.py (обратите внимание: я имею ввиду ~/projects/mysite/mysite/settings.py) добавив туда следующее:
# coding: utf-8
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
В первой строке укажем кодировку в которой работаем, во избежание путаницы и глюков предлагаю указывать ее во всех изменяемых файлах *.py, перекодируя их соответственно в UTF-8.
В BASE_DIR будет храниться полный путь к нашему проекту, что бы использовать относительные пути при дальнейшем конфигурировании
Настроим базу данных, в нашем проекте вполне можно использовать SQLite
DATABASES = { 'default':
{
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
Настроим часовой пояс и язык:
TIME_ZONE = 'Europe/Moscow'
LANGUAGE_CODE = 'ru-ru'
Для того что бы Django узнало о созданном приложении, добавим ‘blog’ в кортеж INSTALLED_APPS, а также раскомментируем строку ‘django.contrib.admin’ для включения встроенной админки:
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.admin',
'blog',
)
Чтобы админка заработала, редактируем mysite/urls.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
admin.autodiscover() #функция автоматического обнаружения файлов admin.py в наших приложениях
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)), #URL админки http://имя_сайта/admin/
)
Cоздаем модель в blog/models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=255) # заголовок поста
datetime = models.DateTimeField(u'Дата публикации') # дата публикации
content = models.TextField(max_length=10000) # текст поста
def __unicode__(self):
return self.title
def get_absolute_url(self):
return "/blog/%i/" % self.id
На основании этой модели Django автоматически создаст таблицы в базе данных.
Регистрируем ее в админке blog\admin.py
from django.contrib import admin
from blog.models import Post # наша модель из blog/models.py
admin.site.register(Post)
Создадим таблицы командой:
python manage.py syncdb
При первом вызове этой команды Django предложит создать суперпользователя, воспользуемся данным предложением.
Запускаем отладочный сервер который предоставляет Django:
python manage.py runserver
Теперь вводим url в браузере
http://localhost:8000/admin/
Если все прошло хорошо, мы должны видеть это:
Заходим с ранее созданным логином\паролем в админку — теперь мы имеем возможность добавлять и удалять посты (кнопки справа от Posts)
Создадим несколько постов для отладки.
Теперь займемся созданием фронтенда, нам требуется всего две шаблонных страницы — одна с перечислением всех постов, вторая — содержание поста.
Редактируем blog/views.py
from blog.models import Post
from django.views.generic import ListView, DetailView
class PostsListView(ListView): # представление в виде списка
model = Post # модель для представления
class PostDetailView(DetailView): # детализированное представление модели
model = Post
Добавим в urlpatterns mysite\urls.py строку
url(r'^blog/', include('blog.urls')),
Для того что бы все URL-ы начинающиеся с /blog/ будут обрабатываться с помощью urls.py из модуля blog, и создаем сам файл urls.py в каталоге blog со следующим содержанием:
#coding: utf-8
from django.conf.urls import patterns, url
from blog.views import PostsListView, PostDetailView
urlpatterns = patterns('',
url(r'^$', PostsListView.as_view(), name='list'), # то есть по URL http://имя_сайта/blog/
# будет выводиться список постов
url(r'^(?P<pk>\d+)/$', PostDetailView.as_view()), # а по URL http://имя_сайта/blog/число/
# будет выводиться пост с определенным номером
)
Теперь нужно создать шаблоны страниц. По умолчанию для класса PostListView Django будет искать шаблон в blog/templates/blog/post_list.html (такой длинный и странный путь связан с логикой работы фреймворка, в силах разработчика поменять это поведение, но в данной статье я этого не касаюсь)
создадим этот файл:
{% block content %}
{% for post in object_list %}
<p>{{ post.datetime }}</p>
<h2><a href="{{ post.get_absolute_url }}">{{ post.title }}</a></h2>
<p>{{ post.content }}</p>
{% empty %}
<p>Нет постов</p>
{% endfor %}
{% endblock %}
Что же, давайте попробуем как все работает, зайдя по URL на http://localhost:8000/blog/. Если ошибок нет, то мы увидим список постов, где заголовок каждого поста является ссылкой.
Пока эти ссылки ведут в никуда, надо это исправить. По умолчанию для класса PostDetailView шаблон находится в blog\templates\blog\post_detail.html.
Создаем его:
{% block content %}
<p>{{ post.datetime }}</p>
<h2>{{ post.title }}</h2>
<p>{{ post.content }}</p>
{% endblock %}
И снова проверяем: http://localhost:8000/blog/1/
Добавим возможность комментирования наших записей, в этих целях мы воспользуемcя услугами DISQUS, который установим с помощью pip
pip install django-disqus
Этот модуль предоставляет функционал комментариев, с защитой от спама, аватарками и прочим, а также берет на себя заботу по их хранению:
Добавляем в post_detail.html перед {% endblock %}
<p>
{% load disqus_tags %}
{% disqus_dev %}
{% disqus_show_comments %}
</p>
В INSTALLED_APPS файла settings.py добавляем ‘disqus’
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.admin',
'blog',
'disqus',
)
А также добавляем в settings.py
DISQUS_API_KEY = '***'
DISQUS_WEBSITE_SHORTNAME = '***'
Два последних значения получаем, зарегистрировавшись на http://disqus.com.
Тестируем проект в браузере. Отлично, функционал нашего приложения внушает, но надо что-то делать с оформлением. Самый простой, и в тоже время современный вариант, использовать Twitter Bootstrap.
Качаем архив http://twitter.github.io/bootstrap/assets/bootstrap.zip и разархивируем его в каталог static нашего проекта (я имею в виду ~/projects/mysite/static — создаем его)
Редактируем settings.py, что бы Django знало где искать статические страницы.
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
Создаем файл blog/templates/blog/base.html следующего содержания
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8" />
<title>MyBlog</title>
<link href="{{STATIC_URL}}bootstrap/css/bootstrap.css" rel="stylesheet">
<style>
body {
padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */
}
</style>
<link href="{{STATIC_URL}}bootstrap/css/bootstrap-responsive.css" rel="stylesheet">
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<script src="{{STATIC_URL}}bootstrap/js/bootstrap.js" type="text/javascript"></script>
{% block extrahead %}
{% endblock %}
<script type="text/javascript">
$(function(){
{% block jquery %}
{% endblock %}
});
</script>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<div class="brand">My Blog</div>
<ul class="nav">
<li><a href="{% url 'list' %}" class="">Список постов</a></li>
</ul>
</div>
</div>
</div>
<div class="container">
{% block content %}Empty page{% endblock %}
</div> <!-- container -->
</body>
</html>
Это основной шаблон для наших страниц, включаем его в post_list.html и post_detail.html дописав первой строкой в них
{% extends 'blog/base.html' %}
Проверяем работоспособность. Вот теперь красота наведена, можно приступить развертыванию приложения на бесплатном облачном хостинге.
Регистрируем бесплатный N00b аккаунт на PythonAnywhere. Мне понравился этот сервис легкостью в установке Django, все происходит практически так же как и на локальном компьютере.
Допустим мы создали пользователя на PythonAnywhere с именем djangotest, тогда наше приложение будет располагаться по адресу djangotest.pythonanywhere.com. Внимание: заменяйте далее по текстк ‘djangotest’ на свой логин в PythonAnywhere.
Меняем в settings.py
DEBUG = False
и дописываем
ALLOWED_HOSTS = ['djangotest.pythonanywhere.com']
Закачиваем файлы на хостинг любым из доступных способов.
На мой взгляд, для неискушенного пользователя, проще всего заархивировать папку проекта, залить архив на сервер (в разделе Files->Upload a file) и разархивировать его на сервере командой в bash — шелле (Раздел Consoles -> bash):
например если мы залили файл mysite.tar.gz то выполняем в консоли PythonAnywhere
tar -zxvf mysite.tar.gz
Теперь настраиваем рабочее окружение на сервере, вводим в консоли PythonAnywhere:
virtualenv env
source env/bin/activate
pip remove django
pip install django django-disqus
Настраиваем статические страницы в разделе Web -> Static files:
В первой строке — место где лежит bootstrap, во второй статические файлы встроенной админки Django.
Настраиваем WSGI (Web -> It is configured via a WSGI file stored at: …):
activate_this = '/home/djangotest/env/bin/activate_this.py'
execfile(activate_this, dict(__file__=activate_this))
import os
import sys
path = '/home/djangotest/mysite'
if path not in sys.path:
sys.path.append(path)
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
Нажимаем кнопку Web -> Reload djangotest.pythonanywhere.com
Заходим на djangotest.pythonanywere.com/blog/ — поздравляю, это было нелегко, но Вы справились. Теперь у Вас есть собственный уютненький блог, разработанный своими руками на самых современных веб-технологиях!