Djangologo

Захотелось мне поведать как использовать связь ManyToMany, начал я значит писать пост, но так как я хотел его детализировать то он слишком разросся... И я решил сначала написать пост о том, как создавать первый проект и приложение на Django, чтобы потом ссылаться сюда.

-- начинал я этот пост писать еще в том году, да все руки не доходили его закончить, спасибо vasa_c за терпение

Устанавливаем Django

Заходим на страницу загрузки официального сайта, скачиваем Django 1.1.1 (или выше). Далее, как и в инструкции:

cd /tmp
wget -O Django-1.1.1.tar.gz http://www.djangoproject.com/download/1.1.1/tarball/
tar -xzvf Django-1.1.1.tar.gz
cd Django-1.1.1
sudo python setup.py install

Все, джанго установлен!
Так как мы будем работать с MySQL, то вам надо установить библиотеку py-mysqldb, представляющая собой интерфейс к MySQL.

Для Ubuntu:

apt-get install python-mysqldb 

Для FreeBSD

cd /usr/ports/databases/py-MySQLdb
make install clean

А для Windows можно скачать тут.

Создаем наш первый проект

Допустим, что имя проекта у нас будет "myproject":

cd /www
django-admin.py startproject myproject

Теперь создайте себе новую БД "myproject":

CREATE DATABASE `myproject` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

И отредактируйте "/www/myproject/settings.py", заменив только соответствующие части:

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

...
# Настройки БД
DATABASE_ENGINE = 'mysql'           # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
DATABASE_NAME = 'myproject'             # Or path to database file if using sqlite3.
DATABASE_USER = 'username'             # Not used with sqlite3.
DATABASE_PASSWORD = 'password'         # Not used with sqlite3.
DATABASE_HOST = ''             # Set to empty string for localhost. Not used with sqlite3.
DATABASE_PORT = ''             # Set to empty string for default. Not used with sqlite3.

...
# Путь до каталога, где лежат наши медиа файлы (css, js, images)
MEDIA_ROOT = '/www/myproject/static/'

...
# URL медиа файлов (css, js, images)
MEDIA_URL = '/'

...
# URL медиа файлов админки (css, js, images, etc)
ADMIN_MEDIA_PREFIX = '/admin-media/'

...
# Путь до каталога с шаблонами
TEMPLATE_DIRS = (
    "/www/myproject/blog/templates",
)

...
# Установленные приложения в нашем проекте
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.admin',
    'myproject.blog',
)
# в конец добавлено две строки, первая подключает джанговскую админку,
# а второе наше приложение, которое мы ниже опишем

Для чего я ставлю в начале строки "#~~ coding: utf-8 ~~" читайте тут.

Создаем наше первое приложение

После того, как вы создали проект, надо создать приложение, если у вас проект состоит из одного приложения - можете его назвать "main".

Создаем приложение "blog":

cd /www/myproject
python manage.py startapp blog

Файл модели

Теперь перейдем к разработке модели нашего приложения, отредактируем "/www/myproject/blog/models.py". У нас будет пока одна сущность, это Посты в Блоге:

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

# импортируем класс модели
from django.db import models
# и админки
from django.contrib import admin

'''
Blog posts
'''
class Post(models.Model):
    # название поста
    title = models.CharField(max_length=100)
    # содержимое поста
    text = models.TextField()

    # функция необходима для того, чтобы при выводе объекта Post
    # как строки выводился вместо этого его title
    def __unicode__(self):
        return self.title;

'''
Класс для админки, тут будут дополнительные атрибуты необходимые для админки
'''
class PostAdmin(admin.ModelAdmin):
    # в таблице списка постов выводить только колонку title, если вы добавите еще одно имя поля, то и оно выведется
    list_display = ('title',)

# связываем эту модель с моделью PostAdmin
admin.site.register(Post, PostAdmin)
Вы можете все что связано с админкой вынести в admins.py и импортировать его, чтобы избавится от лишнего кода
После создания файла моделей, вам необходимо запустить синхронизацию с БД, для того чтобы создались структуры данных:
cd /www/myproject
python manage.py syncdb

Для более детального изучения команд manage.py введите:
python manage.py help syncdb

Вы так же можете создавать свои команды, но об этом поговорим не в этот раз.

syncdb создаст таблицы в вашей БД, а также при первой инициализации попросит создать рутовую учетную запись для вашего проекта в django (это будет админский аккаунт):

Creating table auth_permission
Creating table auth_group_permissions
Creating table auth_group
Creating table auth_user_user_permissions
Creating table auth_user_groups
Creating table auth_user
Creating table auth_message
Creating table django_content_type
Creating table django_session
Creating table django_site
Creating table django_admin_log
Creating table blog_post

You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no): yes
Username (Leave blank to use 'root'): 
E-mail address: mail@example.com
Password: 
Password (again): 
Superuser created successfully.
Installing index for auth.Permission model
Installing index for auth.Message model
Installing index for admin.LogEntry model

Когда вы создадите новый класс модели вам будет необходимо вновь запустить syncdb. Если вы внесли изменения в уже синхронизированное приложение, а именно в его модель, то syncdb НЕ внесет их в вашу БД, для этого используйте sqlall и другие sql* комманды:

python manage.py sqlall название_приложения (например: blog)

Или попробуйте расширение для Django Django Evolution (для этого необходимо его установить в вашу систему и добавить в INSTALLED_APPS - "django_evolution").

Файл урлов

Для навигации по вашему проекту вам нужен роутер (URL диспетчер). Отредактируем "/www/myproject/urls.py":

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

# импортируем админку
from django.contrib import admin

# Makes the patterns() function available
from django.conf.urls.defaults import *

# импортируем наши вьюхи (см. ниже описание файла вьюх)
from myproject.blog.views import main_page, get_post

# Above we used admin.autodiscover() to automatically load the INSTALLED_APPS admin.py modules
admin.autodiscover()

urlpatterns = patterns('',
    # Если ничего не введено, то отдаем управление mainpage вьюхе
    (r'^$', main_page),
    # Если передан id поста, то отдаем управление get_post вьюхе
    (r'^post/([0-9]{1,5})', get_post),
    # Если введен /admin/, то идем в админку
    (r'^admin/', include(admin.site.urls)),
)

Вы конечно можете отредактировать локальный для приложения "blog" - urls.py ("/www/myproject/blog/urls.py"), но тогда вам надо будет импортировать "/www/myproject/blog/urls.py" в корневом "urls.py". Либо вы можете его определить в settings.py (ROOT_URLCONF).

Файл вьюхи

Ту роль, которую играет "Controller" в MVC, в Django играет роль View. Почему это так читайте тут. Отредактируем "/www/myproject/blog/views.py":

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

# функция генерирующая 404 страницу
from django.http import Http404

# функция отрисовки страницы, принимающая путь до шаблона и данные помещенные в шаблон
from django.shortcuts import render_to_response

# наша модель
from myproject.blog.models import Post

def main_page (request):
    # Получаем список постов
    posts = Post.objects.all()
    # отрисовываем
    return render_to_response('list.html', {"posts":  posts})

def get_post (request, post_id):
    try:
        # выбираем конкретный пост, pk - primary key
        post = Post.objects.get(pk=post_id)
    except Post.DoesNotExist:
        # если такого поста нет, то генерируем 404
        raise Http404

    # отрисовываем
    return render_to_response('single.html', {"title":  post.title, "text": post.text})

Вывод в шаблоне

В Django очень мощный и гибкий шаблонизатор, у него даже есть аналог на PHP - Twig, что говорит о его удобстве (был бы неудобным - не копировали бы), хотя Twig по слухам сильно хуже. Однако, есть более крутой шаблонизатор для Django - Jinja2, с более высокой производительностью и более гибкими возможностями. Описывать Jinja я не буду, ведь не это цель сего поста, поэтому делюсь только ссылочками:

С более полными возможностями Django Template вы можете познакомится на официальной странице.

В Django Template поддерживается наследование, поэтому мы напишем общий шаблон и будем его использовать base.html:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <title>{% block title %}Default{% endblock %} / MyProject</title>
</head>
<body>
    {% block content %}
    {% endblock %}
</body>
</html>

Шаблон вывода списка постов list.html:

{% extends "base.html" %}

{% block title %}List!{% endblock %}

{% block content %}
<ul style="list-style-type:none">
{% for post in posts %}
<li style="padding-left:10px;{% if forloop.counter0|divisibleby:"4" %}background-color:#E1F3C9{% endif %}">
    <a href="/post/{{ post.id }}/">{{ post.title }}</a>
    <p>{{ post.text }}</p>
</li>
{% endfor %}
</ul>
</div>
{% endblock %}

Шаблон вывода одной записи single.html:

{% extends "base.html" %}

{% block title %}{{ title }}{% endblock %}

{% block content %}
<h1>{{ title }}</h1>

<div>
{{ text }}
</div>
{% endblock %}

Nginx

Теперь настроим Nginx для того, чтобы запуская "manage.py runserver" нам не прописывать порт в URL и чтобы использовать нормальное имя хоста, хотя вы может вполне без это обойтись. Но я очень рекомендую использовать Nginx.


server {
    listen 80;
    server_name myproject.loc;

    location ^~ /admin-media {
        alias /usr/local/lib/python2.6/dist-packages/django/contrib/admin/media;
    }

    location /static/ {
        root /www/myproject/static/;
    }

    location ~* \.(jpg|jpeg|gif|png|ico|css|zip|js|swf)$ {
        root /www/myproject/static/;
        expires 7d;
    }

    location / {
        proxy_pass http://127.0.0.1:8001/;
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Добавить в "/etc/hosts" ваш хост:

127.0.0.1      myproject.loc

И перезагрузить Nginx:


# в новых версиях nginx можно послать сигнал
nginx -s reload

# или для ubuntu/debian через скрипт инициализации
service nginx restart
/etc/init.d/nginx restart

# или для freebsd
/usr/local/etc/rc.d/nginx restart

Запускаем веб-сервер проекта на 8001 порту, так как мы туда будем проксировать из Nginx:


cd /www/myproject
python manage.py runserver 8001

Теперь зайдите в админку (http://myproject.loc/admin/), введите вашу "root" учетку, которую создавали при syncdb.

Вы можете скачать архив с исходниками проекта тут

Вот мы и познакомились с первым приложение на Django, как я и обещал в начале этого поста следующая статья будет о ManyToMany, где мы подключим к нашему "Блогу" возможность создавать и выводить теги, а также расскажу более полно о возможностях моделях и ORM, View и о URL диспетере.

P.S. Пост дописывал в торопях, если найдете любые ошибки - обязательно отпишитесь в комментарии, спасибо!