Django. The First Application

I wanted to explain how to use a ManyToMany relationship, so I started writing a post, but since I wanted to go into detail, it grew far too long… So I decided to first write a post about creating your first project and application in Django, so I could link back here later.
-- I started writing this post last year, but never got around to finishing it; thanks to vasa_c for being patient
Installing Django
Go to the download page on the official site and download Django 1.1.1 (or later). Then follow the instructions:
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
That’s it, Django is installed!
Since we’ll be working with MySQL, you need to install the py-mysqldb library, which provides an interface to MySQL.
For Ubuntu:
apt-get install python-mysqldb
For FreeBSD
cd /usr/ports/databases/py-MySQLdb
make install clean
For Windows, you can download it here.
Creating Our First Project
Let’s say our project will be called “myproject”:
cd /www
django-admin.py startproject myproject
Now create a new database called “myproject”:
CREATE DATABASE `myproject` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
And edit “/www/myproject/settings.py”, replacing only the relevant parts:
# ~*~ 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',
)
# в конец добавлено две строки, первая подключает джанговскую админку,
# а второе наше приложение, которое мы ниже опишем
Read here about why I put “#* coding: utf-8 *” at the beginning of the line.
Creating Our First Application
Once you’ve created a project, you need to create an application. If your project consists of just one application, you can call it “main”.
Let’s create an application called “blog”:
cd /www/myproject
python manage.py startapp blog
The Model File
Now let’s move on to developing our application’s model and edit “/www/myproject/blog/models.py”.
For now, we’ll have just one entity: Blog Posts:
# ~*~ 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)
You can move everything related to the admin interface into admins.py and import it to get rid of the extra code
After creating the models file, you need to run database synchronization to create the data structures:
cd /www/myproject
python manage.py syncdb
To explore the manage.py commands in more detail, enter:
python manage.py helpIf you’re interested in a specific command, such as syncdb, then:
python manage.py help syncdbYou can also create your own commands, but we’ll talk about that another time.
syncdb will create tables in your database, and during the first initialization it will also ask you to create a root account for your Django project (this will be the administrator account):
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
When you create a new model class, you’ll need to run syncdb again.
If you make changes to an application that has already been synchronized—specifically, to its model—syncdb will NOT apply them to your database. For that, use sqlall and the other sql* commands:
python manage.py sqlall название_приложения (например: blog)
Or try the Django extension Django Evolution (you’ll need to install it on your system and add “django_evolution” to INSTALLED_APPS).
The URLs File
To navigate your project, you need a router (URL dispatcher).
Let’s edit “/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)),
)
Of course, you can edit the urls.py local to the “blog” application ("/www/myproject/blog/urls.py"), but then you’ll need to import “/www/myproject/blog/urls.py” in the root “urls.py”. Alternatively, you can specify it in settings.py (ROOT_URLCONF).
The View File
The role played by the “Controller” in MVC is played by the View in Django. Read about why that is here.
Let’s edit “/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})
Displaying Data in a Template
Django has a very powerful and flexible template engine. It even has a PHP counterpart—Twig—which speaks to its ease of use (if it weren’t easy to use, they wouldn’t have copied it), although rumor has it that Twig is much worse.
However, there’s an even cooler template engine for Django—Jinja2—with better performance and more flexible capabilities. I won’t describe Jinja, since that’s not the purpose of this post, so I’ll just share a couple of links:
You can learn more about the full capabilities of Django Template on the official page.
Django Template supports inheritance, so we’ll write a common template and use it: 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>
The template for displaying a list of posts, 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 %}
The template for displaying a single post, single.html:
{% extends "base.html" %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<h1>{{ title }}</h1>
<div>
{{ text }}
</div>
{% endblock %}
Nginx
Now let’s configure Nginx so that when we run “manage.py runserver”, we won’t have to specify the port in the URL and can use a proper hostname, although you can certainly do without this.
But I strongly recommend using 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;
}
}
Add your host to “/etc/hosts”:
127.0.0.1 myproject.loc
And restart Nginx:
# в новых версиях nginx можно послать сигнал
nginx -s reload
# или для ubuntu/debian через скрипт инициализации
service nginx restart
/etc/init.d/nginx restart
# или для freebsd
/usr/local/etc/rc.d/nginx restart
Start the project’s web server on port 8001, since that’s where we’ll be proxying requests from Nginx:
cd /www/myproject
python manage.py runserver 8001
Now go to the admin interface (http://myproject.loc/admin/) and enter the credentials for the “root” account you created during syncdb.
You can download an archive of the project’s source code here
So, we’ve now been introduced to our first Django application. As I promised at the beginning of this post, the next article will be about ManyToMany, where we’ll add the ability to create and display tags in our “Blog”. I’ll also go into more detail about the capabilities of models and the ORM, Views, and the URL dispatcher.
P.S. I finished this post in a hurry, so if you find any errors, be sure to let me know in the comments. Thanks!
Comments are closed. Read the original discussion in Russian →