Простой блог с комментариями на Django: разработка и развертывание для самых маленьких

от автора

Данная статья предназначена для новичков в 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/ — поздравляю, это было нелегко, но Вы справились. Теперь у Вас есть собственный уютненький блог, разработанный своими руками на самых современных веб-технологиях!

ссылка на оригинал статьи http://habrahabr.ru/post/181556/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *