Django Controller Model View.
Установка Python в Ubuntu.
sudo apt-get update
sudo apt-get install python
Установка Django в Ubuntu.
Скачать с сайта архив с Django 1.3 с сайта http://www.djangoproject.com/download/.
Перейти в папку с архивом Django-1.3.5.tar.gz.
cd ~/Downloads/django
tar xfz Django-1.3.5.tar.gz
cd Django-1.3.5
sudo python setup.py install
Проверка правильности установки Django.
django-admin.py --version
Создание проекта.
Перейти в папку, в которой будет храниться папка с созданным проектом.
cd ~/
mkdir django_project
cd ~/django_project
django-admin.py startproject django_bookmarks
В папке django_bookmarks будут созданы файлы вашего проекта Django.
django_bookmarks/
__init__.py
manage.py
settings.py
urls.py
Файл __init__.py - сообщает Python, что в папке находится набор модулей. Данный файл используется для группировки подобных файлов вместе во избежания конфликтов имен.
Файл manage.py - используется, как и django-admin.py, внутри проекта для запуска сервера (runserver), синхронизации базы данных (syncdb), показа кода базы данных (sql), создание папок приложение (startapp).
Файл settings.py - главный конфигурационный файл всего данного проекта Django. В нем указывается выбранная база данных, язык, серверное время, прописываются адреса расположения папок с шаблонами (templates) и адреса расположения папок с приложениями (apps).
Файл urls.py - используется для описания адресов ссылок всего сайта с вызовом соответсвующих методов акшенов из контроллеров приложений (apps).
Настройка файла settings.py для подключения базы данных:
DATABASE_ENGINE = 'sqlite3'
DATABASE_NAME = 'bookmarksdb'
DATABASE_USER = ''
DATABASE_PASSWORD = ''
DATABASE_HOST = ''
DATABASE_PORT = ''
После изменения настроек необходимо синхронизировать базу данных.
python manage.py syncdb
Запускаем сервер и проверяем работу Django в браузере.
python manage.py runserver
Также сервер можно запустить на другом порту:
python manage.py runserver 8001
Переходим в браузере по адресу
http://localhost:8000 или http://127.0.0.1:8000
Выключение сервера производится нажатием сочетания клавиш Ctrl + C или закрытием окна терминала.
Создание приложения Django внутри папки с проектом.
python manage.py startapp bookmarks
В папке bookmarks будут созданы файлы вашего приложения для проекта Django.
django_bookmarks/
bookmarks/
__init__.py
views.py
models.py
Заполним файл контроллера views.py содержимым с методом акшоном.
from django.http import HttpResponse
def main_page(request):
output = '''
<html>
<head>
<title>%s</title>
</head>
<body>
<h1>%s</h1>
<p>%s</p>
</body>
</html>
''' % (
u'Django Bookmarks',
u'Welcome to Django Bookmarks',
u'Where you can store and share bookmarks!'
)
return HttpResponse(output)
Параметр request содержит данные из адресной строки, полученные серверром из браузера.
Внутри request содержатся массивы с данными get, post, cookie:
request.GET
request.POST
request.COOKIES
Соединение метода акшона main_page с адресом url в файле urls.py
from django.conf.urls.defaults import *
from bookmarks.views import main_page
urlpatterns = patterns('',
url(r'^$', main_page)
)
Использующиеся регулярные выражения в URL Django.
Далее при перезагрузке сервера и открытия адреса http://127.0.0.1:8000
И мы увидим созданную нами страницу.
При переходе по адресу http://127.0.0.1:8000/does_not_exist/ страница будет не найдена, так как адресу does_not_exist/ ничего в файле urls.py не соответствует.
Создание модели базы данных в файле bookmarks/models.py
from django.db import models
class Link(models.Model):
url = models.URLField(unique=True)
Типы полей таблицы базы данных.
Более подробно о типах полей таблиц базы данных можно узнать по адресу
http://docs.djangoproject.com/en/dev/ref/models/fields/
В файл settings.py добавим созданное нами приложение для того, чтобы можно было синхронизировать базу данных:
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django_bookmarks.bookmarks',
)
Синхронизируем базу данных для создания таблицы из модели.
python manage.py syncdb
Посмотри код SQL, который в результате был создан
python manage.py sql
BEGIN;
CREATE TABLE "bookmarks_link" (
"id" integer NOT NULL PRIMARY KEY,
"url" varchar(200) NOT NULL UNIQUE
);
COMMIT;
Откроем консоль Django
python manage.py shell
Заполним таблицу базы данных данными из консоли.
from bookmarks.models import *
link1 = Link(uirl=u'http://www.packtppub.com')
link1.save()
link2 = Link(url=u'http://www.example.com')
link2.save()
Выведем данные.
link1.url
link2.url
Изменим данные.
link2.url = u'http://www.google.com'
link2.save()
Без save() данные в таблицу физически добавлены не будут.
Выведем все данные из таблицы.
links = Link.objects.all()
for link in links:
print(link.url)
Выведем дынные, соответствующие конкретному id записи в таблице базы данных.
Link.objects.get(id=1)
Удалим конкретную запись из таблицы базы данных.
link2.delete()
Сосчитаем общее число записей в таблице базы данных.
Link.objects.count()
Модель данных зарегистрированных на сайте пользователей.
Запустите консоль Django.
python manage.py shell
В консоли введите:
from django.contrib.auth.models import User
User.objects.all()
Посмотреть список названий колонок в таблице базы данных.
user = User.objects.get(id=1)
dir(user)
Создадим в файле bookmarks/models.py модель базы данных для таблицы Bookmarks.
from django.contrib.auth.models import User
class Bookmarks(models.Model):
title = models.CharField(max_length=200)
user = models.ForeignKey(User)
link = models.ForeignKet(Link)
Синхронизируем базу данных.
python manage.py syncdb
Посмотри какой SQL код был выполнен.
BEGIN;
CREATE TABLE "bookmarks_link" (
"id" integer NOT NULL PRIMARY KEY,
"url" varchar(200) NOT NULL UNIQUE
);
CREATE TABLE "bookmarks_bookmark" (
"id" integer NOT NULL PRIMARY KEY,
"title" varchar(200) NOT NULL,
"user_id" integer NOT NULL
REFERENCES "auth_user" ("id"),
"link_id" integer NOT NULL
REFERENCES "bookmarks_link" ("id")
);
COMMIT;
Создадим папку templates.
cd ~/django_project/django_bookmarks
mkdir templates
Добавим в файл settings.py адрес расположения шаблонов HTML-страниц (templates).
import os.path
TEMPLATE_DIRS = (
os.path.join(os.path.dirname(__file__), templates)
)
Создадим в папке templates шаблон HTML-страницы main_page.html
<html>
<head>
<title>{{ head_title }}</title>
</head>
<body>
<h1>{{ page_title }}</h1>
<p>{{ page_body }}</p>
</body>
</html>
Изменим акшон метод в файле bookmarks/views.py
from django.http import HttpResponse
from django.template import Context
from django.template.loader import get_template
def main_page(request):
template = get_template('main_page.html')
variables = Context({
'head_title': u'Django Bookmarks',
'page_title': u'Welcome to Django Bookmarks',
'body_title': u'Where you can store and share bookmarks!'
})
output = template.render(variables)
return HttpResponse(output)
Перейдя в браузере по адресу http://127.0.0.1:8000 мы увидим все ту же страницу.
Создадим страницу пользователя.
Добавим адрес url для страницы в файл urls.py
from django.conf.urls.defaults import *
from bookmarks.views import main_page
from bookmarks.views import user_page
urlpatterns = patterns('',
(r'^$', main_page),
(r'^user/(\w+)$'),
)
Добавим в файл bookmarks/views.py метод акшон для страниц пользователя.
from django.http import HttpResponse
from django.http import Http404
from django.contrib.auth.models import User
from django.template import Context
from django.template.loader import get_template
def main_page(request):
template = get_template('main_page.html')
variables = Context({
'head_title': u'Django Bookmarks',
'page_title': u'Welcome to Django Bookmarks',
'body_title': u'Where you can store and share bookmarks!'
})
output = template.render(variables)
return HttpResponse(output)
def user_page(request, username):
try:
username = User.objects.get(username=username)
except:
reise Http404(u'Requested user not found.')
bookmarks = user.bookmark_set.all()
template = get_template('user_page.html')
variables = Context({
'username': username,
'bookmarks': bookmarks
})
output = template.render(variables)
return HttpResponse(output)
Метод user_page(request, username) помимо параметра request принимает дополнительный параметр username, который берется из данных в скобочках (\w+), прописанных в url для этой страницы.
То, что пишется внутри скобочек в url всегда передается как параметр внутрь метода views.py (controller).
Создадим шаблон страницы user_page.html в папке templates.
<html>
<head>
<title>Django Bookmarks - User: {{ username }} </title>
</head>
<body>
<h1>Bookmarks for {{ username }}</h1>
{% if bookmarks %}
<ul>
{% for bookmark in bookmarks %}
<li><a href="{{ bookmark.url }}">{{ bookmark.title }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No bookmarks found.</p>
{% endfor %}
</body>
</html>
Переменная bookmark - это хэш-массив, поэтому внутри шаблона мы можем вывести из нее элементы по ключам url и title.
Теперь перейдем в браузере по адресу http://127.0.0.1:8000/user/dmitriy
и увидим нашу страницу.
Перейдем к консоль Django и заполним таблицу базы данных данными.
python manage.py shell
Заполняем таблицу базу данных пользователя.
from django.cotrib.auth.models import User
from bookmarks.models import *
user = User.objects.get(id=1)
link = Link.objects.get(id=1)
Обратите внимание, что user.bookmark_set пока еще пуст.
user.bookmark_set.all()
Теперь создадим таблицу базы данных.
bookmark = Bookmark(
title = u'Packt Publishing',
user = user,
link = link
)
bookmark.save()
Проверим user.bookmark_set.
user.bookmark_set.all()
Обновим страницу http://localhost:8000/user/dmitriy и увидим нашу запись из базы данных.
Создадим страницу для логина пользователя.
urlpatterns = patterns('',
(r'^$', main_page),
(r'^user/(\w+)/$', user_page),
(r'^login/$', django.contrib.auth.views.login),
)
Создадим папку registration внутри папки templates.
mkdir registration
Создадим в папке templates/registration файл login.html
<html>
<head>
<title>Django Bookmarks - User Login</title>
</head>
<body>
<h1>User Login</h1>
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
<form method="post" action=".">
<p><label for="id_username">Username:</label> {{ form.username }}</p>
<p><label for="id_password">Password:</label> {{ form.password }}</p>
<input type="hidden" name="next" value="/" />
<input type="submit" value="login" />
</form>
</body>
</html>
Перейлем в браузере на страницу http://127.0.0.1:8000/login/ и увидим страницу с нашей формой.
Теперь отредактируем файл templates/main_page.html
<html>
<head>
<title>Django Bookmarks</title>
</head>
<body>
<h1>Welcome to Django Bookmarks</h1>
{% if user.username %}
<p>Welcome {{ user.username }}! Here you can store and share bookmarks!</p>
{% else %}
<p>Welcome anonymous user! You need to <a href="/login/">login</a> before you can store and share bookmarks.</p>
{% endif %}
</body>
</html>
Далее отредактируем соответственно файл bookmarks/views.py
def main_page(request):
template = get_template('main_page.html')
variables = Context({'user': request.user})
output = template.render(variables)
return HttpResponse(output)
Так же можно сделать короче, используя django.shortcuts
from django.shortcuts import render_to_response
def main_page(request):
return render_to_response('main_page.html', {'user', request.user})
Встроенные методы класса user.
is_authenticated() - возвращает Boolean, обозначающий залогинился ли пользователь или нет.
get_full_name() - возвращает имя и фамилию пользователя, разделенные пробелом.
email_user(subject, message, from_email=None) - посылает e-mail пользователю.
set_password(raw_password) - устанавливает пользовательский пароль на переаданное значение.
check_password(raw_password) - возвращает Boolean, обозначающийсовпал пароль или нет.
Откроем консоль Django и проверим пароль пользователя.
from django.contrib.auth.models import User
user = User.objects.get(id=1)
user.password
Добавим функцию Logout.
Добавим код в файл bookmarks/views.py
from django.http import HttpResponseRedirect
from django.contrib.auth import logout
def logout_page(request):
logout(request)
return HttpResponseRedirect('/')
Теперь добавим url для метода logout_page в файл urls.py
urlpatterns = patterns('',
(r'^$', main_page),
(r'^user/(\w+)/$', user_page),
(r'^login/$', django.contrib.auth.views.login),
(r['^logout/$', logout_page),
)
Теперь перейдя по адресу http://127.0.0.1:8000/logout/ вы вернетесь на главную страницу уже в качестве анонимного пользователя.
Усовершенствуем структуру шаблонов.
Создадим в папке templates файл base.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Django Bookmarks | {% block tirle %}{% endblock %}</title>
</head>
<body>
<h1>{% block head %}{% endblock %}</h1>
{% blockcontent %}{% endblock %}
</body>
</html>
В соотвествии с этим отредактируем шаблон templates/main_page.html
{% extends "base.html" %}
{% block title %}
Welcome to Django Bookmarks
{% endblock %}
{% block head %}
Welcome to Django Bookmarks
{% endblock %}
{% block content %}
{% if user.username %}
<p>Welcome {{ user.username }}! Here you can store and share bookmarks!</p>
{% else %}
<p>Welcome anonymous user! You need to <a href="/login/">login</a> before you can store and share bookmarks.</p>
{% endif %}
{% endblock %}
Изменим шаблон в файле templates/user_page.html
{% extends "base.html" %}
{% block title %}
{{ username }}
{% endblock %}
{% block head %}
Bookmarks for {{ username }}
{% endblock %}
{% block content %}
{% if bookmarks %}
<ul>
{% for bookmark in bookmark.link.url %}
<li><a href="{{ bookmark.link.url }}">{{ bookmark.title }}</a></li>
</ul>
{% else %}]
<p>No bookmarks found.</p>
{% end if %}
{% endblock %}
Теперь отредактируем файл templates/registration/login.html
{% extendes "base.html" %}
{% block title %}
User Login
{% endblock %}
{% block head %}
User Login
{% endblock %}
{% block content %}
{% if form.has_errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
<form method="get" action=".">
<p><label for="id_username">Username:</label>{{ form.username }}</p>
<p><label for="id_password">Password:</label>{{ form.password }}</p>
<input type="submit" value="login" />
<input type="hidden" name="text" valuse="/" />
</form>
{% endblock %}
Далее добавим код в файл urls.py
from django.conf.urls.defaults import *
from bookmarks.views import *
import os
site_media = os.path.join(os.path.dirname(__file__), 'site_media')
urlpatterns = patterns('',
(r'^$', main_page),
(r'^/user/(\w+)/$', user_page),
(r'^login/$', 'django.contrib.auth.views.login'),
(r'^logout/$', logout_page),
(r'^site_media/(?<P<path>.*)$', 'django.views.static.serve', ('document_root': site_media)
)
Дале создадим папку site_media в общей папке нашего проекта.
mkdir site_media
Внутри нее создадим файл style.css
#nav {float: right;}
Отредактируем шаблон templates/base.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Django Bookmarks | {% block title %}{% endblock %}</title>
<link rel="stylesheet" href="/site_media/style.css" type="text/css" />
</head>
<body>
<div id="nav">
<a href="/">home</a> |
{% if user.is_authenticated %}
welcome {{ username }}
(<a href="/logout">logout</a>)
{% else %}
<a href="/login/">login</a>
{% endif %}
</div>
<h1>{% block head %}{% endblock %}</h1>
{% block content %}{% endblock %}
</body>
</html>
Отредаутирум файл bookmarks/views.py
from django.template import RequestContext
def main_page(request):
return render_to_response('main_page.html', RequestContext(request))
Теперь нам не нужно передавать request.user, RequestContext(request) обо всем позаботится автоматически.
Продолжим делать аналогичные изменения:
def user_page(request, username):
try:
user = User.objects.get(username=username)
except:
raise Http404(u'Requested user not found.')
bookmarks = user.bookmarks_set.all()
variables = RequestContext(request, {
'username': username,
'bookmarks': bookmarks
})
return render_to_response('user_page.html', variables)
Форма регистрации новых пользователей.
Создадим файл bookmarks/forms.py в котором опишем форму для регистрации пользователей.
from django import forms
class RegistrationForm(forms.Form):
username = forms.CharField(label=u'Username', max_length=30)
email = forms.EmailField(label=u'Email')
password1 = forms.CharField(label=u'Password', widget=forms.PasswordInput())
password2 = forms.CharField(label=u'Password (Again)', widget=forms.PasswordInput())
Параметры форм.
label - создает в HTML коде метку <label for=""></label>
required - параметр по умолчанию установленный в True и требующий обязательного заполнения поль формы input. Чтобы разрешить пустой input требуется добавть параметр required=False.
widget - данный параметр определяет внешний вид поля в форме.
help_text - параметр добавляющий пояснительный текст к полю формы.
Поработаем с формой из консоли Django.
python manage.py shell
Введем следующие команды:
from bookmarks.forms import *
form = RegistrationForm()
print(form.as_table())
print(form.as_ul())
print(form.as_p)
Мы также можем вывести одно поле формы.
print(form['username'])
Теперь введем данные в форму и проверим их.
form = RegistrationForm({
'username': 'test',
'email': 'test@example.com',
'password1': 'test',
'password2': 'test'
})
form.is_valid()
Добавим в файл bookmarks/forms.py свой метод валидации пароля.
def clean_password2(self):
if 'password1' in self.cleaned_data:
password1 = self.cleaned_data['password1']
password2 = self.cleaned_data['password2']
if password1 == password2:
return password2
reise forms.ValidationError('Password do not match.')
В начало файла bookmarks/forms.py добавим:
imort re
from django.cotrib.auth.models import User
Далее добавим метод валидации имени пользователя.
def clean_username(self):
username = self.cleaned_data['username']
if not re.search(r'^\w+$', username):
raise forms.ValidationError('Username can only contain alphanumeric characters and the underscore.')
try:
User.objects.get(username=username)
except User.DoesNotExist:
return username
raise forms.ValidationError('Username is already taken.')
Отредактируем файл bookmarks/views.py для работы с формой.
from bookmarks.forms import *
def register_page(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid:
user = User.objects.create_user(
username = form.cleaned_data['username'],
password = form.cleaned_data['password1'],
email = form.cleaned_data['email']
)
return HttpResponseRedirect('/')
else:
form = RegistrationForm()
variables = RequestContext(request, {
'form': form
})
return render_to_response('registration/register.html', variables)
Создадим шаблон templates/registration/register.html для формы регистрации
{% extends "base.html" %}
{% block title %}
User Registration
{% endblock %}
{% block head %}
User Registrarion
{% endblock %}
{% block content %}
<form metho="post" action=".">
{{ form.as_p }}
<input type="submit" value="register" />
</form>
{% endblock %}
Добавим новый адрес в urls.py
(r'^register/$, register_page)
Добавим новый стиль в файл style.css
input {display: block;}
Перейдем в браузере по ссылке http://127.0.0.1:8000/register/ и увидим наше форму регистрации.
Теперь изменим шаблон templates/base.html
<div id="nav">
<a href="/">home</a> |
{% if user.is_authenticated %}
welcome {{ user.username }}
(<a href="/logout">logout</a>)
{% else %}
<a href="/login/">login</a> |
<a href="/register/">register</a>
{% endif %}
</div>
Создадим шаблон templates/registration/register_success.html
{% extends "base.html" %}
{% block title %}
Registration Successful
{% endblock %}
{% block head %}
Registration Completed Successfully
{% endblock %}
{% block content %}
Thank you for registering. Your information has been saved in the database. Now you can either <a href="/login/">login</a> or go back to the <a href="/">main page</a>.
{% endblock %}
Для прямой ссылки на шаблон добавим ссылку в url в файле urls.py
from django.views.generic.simple import direct_to_template
(r'^register/success/$', direct_to_template, {'template': 'registration/register_success.html'})
В файле bookmarks/views.py заменим в register_page
return HttpResponseRedirect('/')
на
return HttpResponseRedirect('/register/success/')
Про авторизацию пользователей в Djnago подробнее можно прочитать по адресу http://docs.djangoproject.com/en/dev/topics/auth/
Создадим облако тэгов.
Добавим в файл bookmarks/models.py модель базы данных для облака тэгов.
class Tag(models.Model):
name = models.CharField(max_length=64, unique=True)
bookmarks = models.ManyToManyField(Bookmarks)
После этого синхронизируем базу данных:
python manage.py syncdb
И посмотрим SQL-код
python manage.py sql
BEGIN;
CREATE TABLE "bookmarks_link" (
"id" integer NOT NULL PRIMARY KEY,
"url" varchar(200) NOT NULL UNIQUE
);
CREATE TABLE "bookmarks_bookmark" (
"id" integer NOT NULL PRIMARY KEY,
"title" varchar(200) NOT NULL,
"user_id" integer NOT NULL REFERENCES
"auth_user" ("id"),
"link_id" integer NOT NULL REFERENCES
"bookmarks_link" ("id"),
);
CREATE TABLE "bookmarks_tag" (
"id" integer NOT NULL PRIMARY KEY,
"name" varchar(64) NOT NULL UNIQUE
);
CREATE TABLE "bookmarks_tag_bookmarks" (
"id" integer NOT NULL PRIMARY KEY,
"tag_id" integer NOT NULL
REFERENCES "bookmarks_tag" ("id"),
"bookmark_id" integer NOT NULL
REFERENCES "bookmarks_bookmark" ("id"),
UNIQUE ("tag_id", "bookmark_id")
);
COMMIT;
Запустим консоль Django и посмотрим как работает модель многие ко многим.
python manage.py shell
from bookmarks.models import *
bookmark = Bookmark.objects.get(id=1)
bookmark.link.url
tag1 = Tag(name="book")
tag1.save()
bookmark.tag_set.add(tag1)
tag2 = Tag(name="publisher")
tag2.save()
bookmark.tag_set.add(tag2)
tag1.bookmarks.all()
Теперь в файле bookmarks/models.py внесем следующие изменения:
class Tag(models.Model):
name = models.CharField(max_length=64, unique=True)
bookmarks = models.ManyToManyField(Bookmark)
def __unicode__(self):
return self.name
Далее протестируем все это в консоли.
python manage.py shell
from bookmarks.models import *
Tag.objects.all()
Внесем схожие изменения в классы Link и Bookmark в файлу model.py
class Link(models.Model):
url = models.UrlField(unique=true)
def __unicode__(self):
return self.url
class Bookmark(models.Model):
title = models.CharField(max_length=200)
user = models.ForeignKey(User)
link = models.ForeignKey(Link)
def __unicode__(self):
return u'%s, %s' % (self.user.username, self.link.url)
Создадим форму для добавления вкладок в файле bookmarks/forms.py
class BookmarksSaveForm(forms.Form):
url = forms.UrlField(
label = u'Url',
widget = forms.TextInput(attrs = {'size': 64})
)
title = forms.CharField(
label = u'Title',
widget = forms.TextInput(attrs = {'size': 64})
)
tags = forms.CharField(
label = u'Tags',
widget = forms.TextInput(attrs = {'size': 64})
)
Теперь создадим метод контроллера для нашей формы
from bookmarks.models import *
class bookmark.save_page(request):
if request.method == 'POST':
form = BookmarksSaveForm(request.POST)
if form.is_valid():
# Создать или получить link.
link, dummy = Link.objects.get_or_create(url=form.cleaned_data['url'])
# Создать или получить bookmark.
bookmark, created = Bookmark.objects.get_or_create(
user = request.user,
link = link
)
# Обновить bookmark title.
bookmark.title = form.cleaned_data['title']
# Если bookmark обновлена, то очистить старый tag list.
if not created:
bookmark.tag_set.clear()
# Создать новый tag list.
tag_names = form.cleaned_data['tags'].split()
for tag_name in tag_names:
tag, dummy = Tag.objects.get_or_create(name=tag_name)
bookmark.tag_set.add(tag)
# Сохранить bookmark в базу данных.
bookmark.save()
return HttpResponseRedirect('user/%s/' % request.user.username)
else:
form = BookmarkSaveForm()
variables = RequestContext({'form': form})
return render_to_response('bookmark_save.html', variables)
В папке templates создадим файл bookmark_save.html
{% extends "base.html" %}
{% block title %}
Save Bookmark
{% endblock %}
{% block head %}
Save Bookmark
{% endblock %}
{% block content %}
<form method="POST" action=".">
{{ form.as_p }}
<input type="submit" value="save" />
</form>
{% endblock %}
Добавим изменения в файл urls.py
urlpatterns = patterns('',
# Browsing
(r'^$', main_page),
(r'^user/(\w+)/$', user_page),
# Session management
(r'^logon$', django.contrib.auth.views.login),
(r'^logout$', logout_page),
(r'^register$', register_page),
(r'^register/success$', direct_to_template, {'template': 'tegistration/register_success.html'}),
# Account management
(r'^save/$', bookmark_save_page),
# Site media
(r'^site_media/?P<path>.*$', 'django.views.static.serve', {'document_root': site_media}),
)
Запустим сервер
python manage.py startserver
Перейдем в браузере по адресу http://127.0.0.1:8000/save/ и увидим страницу с формой добавления bookmark.
Изменим меню в файле templates/base.html
<div id="nav">
<a href="/">home</a>
{% if user.is_authenticated %}
<a href="/save/">submit</a> |
<a href="/user/{{ user.username }}/">{{ user.username }}</a> |
<a herf="/logout/">logout</a>
{% else %}
<a href="/login/">login</a>
<a href="/register/">register</a>
{% endif %}
</div>
В файле views.py в секцию bookmark_save_page добавим
from djnago.contrib.auth.decorators import login_required
@login_required
def bookmark_save_pager():
Данный код реализует примерно следующую логику:
if request.user.ia_authenticated():
# Обработать данные из формы.
else:
# Перейти на страницу ввода логина и пароля пользователя.
Добавим следующий код в файл settings.py для того, чтобы сохранить там константу с адресом страницы авторизации пользователей
LOGIN_URL = '/login/'
Теперь перейдите в браузере по адресу http://127.0.0.1:8000/save/ и вас перенесет на страницу ввода логина и пароля.
В папке templates создадим новый шаблон bookmark_list.html
{% if bookmarks %}
<ul class="bookmarks">
{% for bookmark in bookmarks %}
<li><a href="{{ bookmark.link.url }}" class="title">{{ bookmark.title }}</a><br />
{% if show_tags %}
Tags:
{% if bookmark.tag_set.all() %}
<ul class="tags">
{% for tag in bookmark.tag_set.all() %}
<li>{{ tag.name }}</li>
{% endfor %}
</ul>
{% else %}
None.
{% endif %}
<br />
{% endif %}
{% if show_user %}
Posted by: <a href="/user/{{ bookmark.user.username }}/" class="username">{{ bookmark.user.username }}</a>
{% endif %}
</li>
{% endfor %}
</ul>
{% else %}
<p>No bookmarks found.</p>
{% endif %}
Теперь модифицируем файл templates/user_page.html
{% extends "base.html" %}
{% block title %}
{{ username }}
{% endblock %}
{% block head %}
Bookmarks fo {{ username }}
{% endblock %}
{% block content %}
{% include "bookmark_list.html" %}
{% endblock %}
Внесем изменения в файл bookmarks/views.py
from django.shortcuts import get_object_or_404
def user_page(request, username):
user = get_object_or_404(User, username=username)
bookmarks = user.bookmark_set.order_by('-id')
variables = RequestContext(reques, {
'bookmarks': bookmarks,
'username': username,
'show_tags': True
})
return render_to_response('user_page.html', variables)
Добавим стили в файл site_media/style.css
ul.tags,
ul.tags li {
display: inline;
margin: 0;
padding: 0;
}
Перейдем в браузере по адресу http://127.0.0.1:8000/user/your_username/ и увидим тэги рядом с гиперссылками.
В файл urls.py добавим url для страницы тэгов.
(r'^tag/([^\s]+)/$', tag_page),
В файле bookmarks/views.py создадим акшон-метод контроллера для страницы с тэгами
def tag_page(request, tag_name):
tag = get_object_or_404(Tag, name=tag_name)
bookmarks = tag.bookmarks.order_by('-id')
variable = RequestContext(request, {
'bookmarks': bookmarks,
'tag_name': tag_name,
'show_tags': True,
'show_user': True
})
return render_to_repsonse('tag_page.html', variables)
Создадим шаблон для страницы с тэгами templates/tag_page.html
{% extends "base.html" %}
{% block title %}
Tag: {{ tag_name }}
{% endblock %}
{% block head %}
Bookmarks for tag: {{ tag_name }}
{% endblock %}
{% block content %}
{% include "bookmark_list.html" %}
{% endblock %}
Модифицируем шаблон bookmark_list.html
<ul class="tags">
{% for tag in bookmark.tag_set.all %}
<li><a href="/tag/{{ tag.name }}">{{ tag.name }}</a></li>
{% endfor %}
</ul>
В браузере перейдем на страницу пользователя и кликнем на гиперссылку с тэгом. В результате мы перейдем на страницу с тэгами.
В файле bookmarks/views.py создадим новый акшон-метод для облака тэгов
def tag_cloud_page(request):
MAX_WEIGHT = 5
tags = Tag.objects.order_by('name')
# Рассчитать вес тэга, минимальное и максимальное значение.
min_count = max_count = tags[0].bookmarks.count()
for tag in tags:
tag.count = tag.bookmarks.count()
if tag.count < min_count:
min_count = tag_count
if max_count < tag.count:
max_count = tag.count
# Рассчитать count range, избегая деления на ноль.
if range = 0.0:
range = 1.0
# Рассчитать вес тэга.
for tag in tags:
tag.weight = int(MAX_WEIGHT * (tag.count - min_count) / range)
variables = RequestContext(request, {
'tags': tags
})
return render_to_response('tag_cloud_page.html', variables)
В папке tamplates создадим шаблон страницы tag_cloud_page.html
{% extends "base.html" %}
{% block title %}
Tag Cloud
{% endblock %}
{% block head %}
Tag Cloud
{% endblock %}
{% block content %}
<div id="tag-cloud">
<a href="/tag/{{ tag.name }}/" class="tag-cloud-{{ tag.weight }}">{{ tag.name }}</a>
</div>
{% endblock %}
Добавим стили для облака тэгов в файл site_media/style.css
#tag-cloud {text-align: center;}
#tag-cloud a {margin: 0 0.2em;}
.tag-cloud-0 {font-size: 100%;}
.tag-cloud-1 {font-size: 120%;}
.tag-cloud-2 {font-size: 140%;}
.tag-cloud-3 {font-size: 160%;}
.tag-cloud-4 {font-size: 180%;}
.tag-cloud-5 {font-size: 200%;}
Добавим url для страницы с облаком тэгов в файл urls.py
(r'^tag/$', tag_cloud_page)
Перейдем в браузере по адресу http://127.0.0.1:8000/tag/ и увидим страницу с облаком тэгов.
Доработаем шаблон templates/bookmark_list.html, добавив фильт urlencode
[...]
{% if show_tags %}
Tags:
{% if bookmark.tag_set.all %}
<ul class="tags">
{% for tag in bookmark.tag_set.all %}
<li><a href="/tag/"{{ tag.name|urlecode }}/>{{ tag.name }}</a></li>
{% endfor %}
</ul>
{% else %}
None.
{% endif %}
<br />
{% endif %}
[...]
Внесем подобные изменения, добавив фильтр urlencode в шаблон templates/tag_cloud_page.html
{% extends "base.html" %}
{% block title %}
Tag Cloud
{% endblock %}
{% block head %}
Tag Cloud
{% endblock %}
{% block content %}
<div id="tag-cloud">
{% for tag in tags %}
<a href="/tag/"{{ tag.name|urlencode }}/" class="tag-cloud-{{ tag.weight }}">{{ tag.name }}</a>
{% endfor %}
</div>
{% endblock %}
Добавим jQuery в основной шаблон templates/base.html
<head>
<title>Django Bookmarks | {% block title %}{% endblock %}</title>
<link rel="stylesheet" href="/site_media/style.css" type="text/css" />
<script type="text/javascript" src="/site_media/jquery.js"></script>
{% block external %} {% endblock %}
</head>
Создадим форму поиска в файле bookmarks/forms.py
class SearchForm(forms.Form):
query = forms.CharField(
label=u'Enter a keyword to search for',
widget=form.TextInput(attrs={'size': 32})
)
Создадим акшон-метод для обработки данных из формы в файле bookmarks/views.py
def search_page(request):
form = SearchForm()
bookmarks = []
shoe_results = False
if 'query' in request.GET:
show_results = True
query = request.GET['query'].strip()
if query:
form = SearchForm({'query': query})
bookmarks = Bookmark.objects.filter(title__icontains=query)[:10]
variables = RequestContext(request, {
'form': form,
'bookmarks': bookmarks,
'show_results': show_results,
'show_tags': True,
'show_user': True
})
return render_to_response('search.html', variables)
Фильтры данных в модели базы данных:
field__operator
__exact - значение соотвествует точно.
__contains - значение является частью поля.
__startswith - поле начинается с этого значения.
__lt - поле меньше, чем значение.
__gt - поле больше, чем значение.
Теперь создадим в папке templates шаблон search.html
{% extends "base.html" %}
{% block title %}
Search Bookmarks
{% endblock %}
{% block head %}
Search Bookmarks
{% endblock %}
{% block content %}
<form id="search-form" method="get" action=".">
{{ form.as_p }}
<input type="submit" value="search" />
</form>
<div id="search-results">
{% if show_results %}
{% include "bookmark_list.html" %}
{% endif %}
</div>
{% endblock %}
Добавим ссылку на страницу поиска в файл urls.py
urlpatterns = patterns('',
(r'^$', main_page),
(r'^user/(\w+)/$', user_page),
(r'^tag/([^\s]+)/$', tag_page),
(r'^tag/$', tag_cloud_page),
(r'^search/$', search_page),
[...]
)
Добавим гиперссылку на страницу поиска в меню шаблона templates/base.html
<div id="nav">
<a href="/">home</a> |
{% if user.is_authenticated %}
<a href="/save/">submit</a> |
<a href="/search/">search</a> |
<a href="/user/{{ user.username }}/">{{ user.username }}</a> |
<a href="/logout/">logout</a>
{% else %}
<a href="/login/">login</a> |
<a href="/register/">register</a>
{% endif %}
</div>
Модифицируем акшон-метод search_page в файле bookmarks/views.py
def search_page(request):
[...]
variables = RequesContext(request, {
'form': form,
'bookmarks': bookmarks,
'show_results': show_results,
'show_tags': True,
'show_user': True
})
if request.GET.has_key('ajax'):
return render_to_response('bookmark_list.html', variables)
else:
return render_to_response('search.html', variables)
В папке site_media создадим файл search.js
function search_submit() {
var query = $("#id_query").val();
$("#search-results").load("/search/?ajax&query=" + encodeURIComponent(query));
return false;
}
$(document).ready(funtion(){
$("#search-form").submit(search_submit);
});
Добавим ссылку на этот файл в шаблон templates/search.html
{% extends "base.html" %}
{% block external %}
<script type="text/javascript" src="/site_media/search.js"></script>
{% endblock %}
{% block title %}
Search Bookmarks
{% endblock %}
{% block content %}
Search Bookmarks
{% endblock %}
[...]
По адресу http://127.0.0.1:8000/search/ перейдем на страницу поиска.
Добавим акшон-метод bookmark_save_page в файл bookmarks/views.py
def bookmark_save(request, form):
# Создать или получить link.
link, dummy = Link.objects.get_or_create(url=form.cleaned_dat['url'])
# Создать или получить bookmark.
bookmark, created = Bookmark.objects.get_or_create(
user=reques.user,
link=link
)
# Обновить bookmark title.
bookmark.title = form.cleaned_data['title']
# Если bookmark обновлен, то очистить старый tag list.
if not created:
bookmark.tag_set_clear()
# Создать новый tag list.
tag_names = form.cleaned_data['tags'].split()
for tag_name in tag_names:
tag, dummy = Tag.objects.get_or_create(name=tag_name)
bookmark.tag_set.add(tag)
# Сохранить bookmark в базу данных и вернуть его.
bookmark.save()
return bookmark
Ниже изменим код следующим образом
@login_required
def bookmark_save_page(request):
if request.method == 'POST':
form = BookmarkSaveForm(request.POST)
if form.is_valid():
bookmark = _bookmark_save(request, form)
return HttpResponseRedirect('/user/%s' % request.user.username)
elif 'url' in request.GET:
url = request.GET['url']
title =''
tags = ''
try:
link = Link.objects.get(url=url)
bookmark = Bookmark.objects.get(
link=link,
user=request.user
)
title = bookmark.title
tags = ' '.join(tag.name for tag in bookmark.tag_set.all())
except (Link.DoesNotExist, Bookmark.DoesNotExist):
pass
form = BookmarkSaveForm({
'url': url,
'title': title,
'tags': tags
})
else:
form = BookmarkSaveForm()
variables = RequestContext(request, {
'form': form
})
return render_to_response('bookmark_save.html', variables)
Внесем изменения в шаблон файла templates/bookmark_list.html
{% if bookmarks %}
<ul class="bookmarks">
{% for bookmark in bookmarks %}
<li><a href="{{ bookmark.link.url }}" class="title">{{ bookmark.title }}</a>
{% if show_edit %}
<a href="/save/?url={{ bookmark.link.url|urlencode }}" class="edit">[edit]</a>
{% endif %}
<br />
{% if show_tags %}
Tags:
{% if bookmarks.tag_set.all %}
<ul class="tags">
{% for tag in bookmark.tag_set.all %}
<li><a href="/tag/{{ tag.name|urlencode }}">{{ tag.name|escape }}</a></li>
{% endfor %}
</ul>
{% else %}
None.
{% endif %}
<br />
[...]
Далее отредактируем акшон-метод user_page в файле bookmarks/views.py
def user_page(request, username):
user = get_object_or_404(User, username=username)
bookmarks = user.bookmark_set.order_by('-id')
variables = RequestContext(request, {
'bookmarks': bookmarks,
'username': username,
'show_tags': True,
'show_edit': username == request.user.username,
})
return render_to_response('user_page.html', variables)
Добавим стиль в файл site_media/style.css
ul.bookmarks .edit {font-size: 70%;}
Теперь создадим шаблон bookmark_save_form.html и переметим в него из шаблона bookmark_save.html следующий код
<form id="save-form" method="post" action=".">
{{ form.as_p }}
<input type="submit" value="save" />
</form>
Теперь подключим новый файл шаблона в файл bookmark_save.html
{% extends "base.html" %}
{% block title %}
Save Bookmark
{% endblock %}
{% block head %}
Save Bookmark
{% endblock %}
{% block content %}
{% include "bookmark_save_form.html" %}
{% endblock %}
Обновим метод bookmark_save_page в файле bookmarks/views.py
@login_required
def bookmark_save_page(request):
ajax = 'ajax' in request.GET
if request.method == 'POST':
form = BookmarkSaveForm(request.POST)
if form.is_valid():
bookmark = _bookmark_save(form)
if ajax:
variables = RequestContext(request, {
'bookmarks': [bookmark],
'show_edit': True,
'show_tags': True
})
return render_to_response('bookmark_list.html', variables)
else:
return HttpResponseRedirect('/user/%s' % request.user.username)
else:
if ajax:
return HttpResponse(u'failure')
elif 'url' in request.GET:
url = request.GETp['url']
title = ''
tags = ''
try:
link = Link.objects.get(url=url)
bookmark = Bookmark.objrcts.get(link=link, user=request.user)
title = bookmark.title
tags = ' '.join(tag.name for tag in bookmark.tag_set.all())
execpt (Link.DoesNotExist, Bookmark.DoesNotExist):
pass
form = BookmarkSaveForm({
'url': url,
'title': title,
'tags': tags
})
else:
form = BookmarkSaveForm()
variables = RequestContext(reques, {
'form': form
})
if ajax:
return render_to_response('bookmark_save_form.html', variables)
else:
return render_to_response('bookmark_save.html', variables)
Далее модифицируем шаблон user_page.html
{% extends "base.html" %}
{% block external %}
<script type="text/javascript" scr="/site_media/bookmark_edit.js"></script>
{% endblock %}
{% block title %}
{{ username }}
{% endblock %}
{% block head %}
Bookmarks for {{ username }}
{% endblock %}
{% block content %}
{% include "bookmark_list.html" %}
{% endblock %}
Запишем пару функций в файл site_media/bookmark_edit.js
function bookmark_edit() {
var item = $(this).parent();
var url = item.find(".title").attr("href");
item.load("/save/?ajax&url=" + encodeURIComponent(url), null, function(){
$("#save-form").submit(bookmark_save);
});
return false;
}
function bookmark_save() {
var item = $(this).parent();
var data = {
url: item.find("#id_url").val(),
title: item.find("#id_title").val(),
tags: item.find("#id_tags").val()
};
$.post("/save/?ajax", data, function(){
if (result != "failure") {
item.before($("li", result).get(0));
item.remove();
$("ul.bookmarks .edit").click(bookmark_edit);
} else {
alert("Failed to validate bookmark before saving.");
}
});
return false;
}
$(document).ready(function(){
$("ul.bookmarks .edit").click(bookmark_edit);
});
Далее скачаем jQuery плагины:
jquery.autocomplete.css
dimensions.js
jquery.bgiframe.min.js
jquery.autocomplete.js
и подключим их к шаблону templates/bookmark_save.html
{% extends "base.html" %}
{% block external %}
<link rel="stylesheet" href="/site_media/jquery.autocomplete.css" type="text/css" />
<script type="text/javascript" src="/site_media/dimensions.js"></script>
<script type="text/javascript" src="/site_media/jquery.bgiframe.min.js"></script>
<script type="text/javascript" src="/site_media/jquery.autocomplete.js"></script>
<script type="text/javascript" src="/site_media/tag_autocomplete.js"></script>
{% endblock %}
{% block title %}
Save Bookmark
{% endblock %}
{% block head %}
Save Bookmark
{% endblock %}
В конец файла bookmarks/views.py добавим следующий код
def ajax_tag_autocomplete(request):
if 'q' in request.GET:
tags = Tag.objects.filter(name__istartswith=request.GET['q'])[:10]
return HttpResponse(u'\n'.join(tag.name for tag in tags))
return HttpResponse()
Добавим url в файл urls.py
urlpatterns = patterns('',
[...]
# Ajax
(r'^ajax/tag/autocomplete/$', ajax_tag_autocomplete )
[...]
)
Далее добавим код в файл site_media/tag_autocomplete.js
$(document).ready(function(){
$("#id_tags").autocomplete("/ajax/tag/autocomplete/", {multiple: true, multipleSeparator:" "});
});
Перейдем в браузере по адресу http://127.0.0.1:8000/save/ и посмотри как работает sugget в форме поиска.
Создадим новую модель базы SharedBookmark данных в файле bookmarks/models.py
class SharedBookmarks(models.Model):
bookmark = models.ForeignKey(Bookmark, unique=True)
date = models.DateTimeField(auto_now_add=True)
votes = models.IntegerField(default=1)
users_voted = models.ManyToManyField(User)
def __unicode__(self):
return u'%s, %s' % (self.bookmark, self.votes)
Синхронизируем базу данных
python manage.py syncdb
И посмотрим SQL
python manage.py sql
Модифицируем форму BookmarkSaveForm в файле bookmarks/forms.py
class BookmarkSaveForm(forms.Form):
url = forms.URLField(
label=u'URL',
widget=form.TextInput(attrs={'size': 64})
)
title = form.CharField(
label=u'Title',
widget=forms.TextInput(attrs={'size': 64})
)
tags = forms.CharField(
label=u'Tags',
widget=forms.TextInput(attrs={'size': 64})
)
share = forms.BooleanField(
label=u'Shared on the main page',
required=False
)
Модифицируем метод _save_bookmark в файле bookmarks/views.py
def _bookmark_save(request, form):
# Создать или получить link.
link, dummy = Link.objects.get_or_create(url=form.cleaned_data['url'])
# Создать или получить bookmark.
bookmark, created = Bookmark.objects.get_or_create(
user=reques.user,
link=link
)
# Обновить bookmark title.
bookmark.title = form.cleaned_data['title']
# Если bookmark обновлено, то очистить старый tag list.
if not created:
bookmark.tag_set.clear()
# Создать новый tag list.
tag_names = form.cleaned_data['tags'].split()
for tag_name in tag_names:
tag, dummy = Tag.objects.get_or_create(name=tag_name)
bookmark.tag_set.add(tag)
# Расшарить на главную страницу, если будет запрос.
if form.cleaned_data['share']:
shared, created = SharesBookmark.objects.get_or_crete(
'bookmark': bookmark
)
if created:
shared.users_voted.add(request.user)
shared.save()
# Сохранить bookmark в базу данных и вернуть его.
bookmark.save()
return bookmark
Модифицируем акшон-метод main_page в файле bookmarks/views.py
def main_page(request):
shared_bookmarks = SharedBookmark.objects.order_by('-date')[:10]
variables = RequestContext(request, {
'shared_bookmarks': shared_bookmarks
})
return render_to_response('main_page.html', variables)
В папке templates создадим новый шаблон shared_bookmark_list.html
{% if shared_bookmarks %}
<ul class="bookmarks">
{% for shared_bookmark in shared_bookmarks %}
<li><a href="{{ shared_bookmark.bookmark.link.url }}" class="title">{{ shared_bookmark.bookmark.title }}</a>
<br />
Posted By:
<a href="/user/{{ shared_bookmark.bookmark.user.username }}/" class="username">{{ shared_bookmark.bookmark.user.username</a> |
<span class="vote-count">Votes:{{ shared_bookmark.votes }}</span>
</li>
{% endfor %}
</ul>
{% else %}
<p>No bookmarks found.</p>
{% endif %}
Включи шаблон shared_bookmark_list.html в файл main_page.html
{% extends "base.html" %}
{% block title %}
Welcome to Django Bookmarks
{% endblock %}
{% block head %}
Welcome to Django Bookmarks
{% endblock %}
{% block content %}
{% if user.username %}
<p>Welcome {{ user.username }}! Here you can store and share bookmarks!</p>
{% else %}
<p>Welcome user! You need to <a href="/login/">login</a> before you can store and share bookmarks.</p>
{% endif %}
<h2>Bookmarks Shared by Users</h2>
{% include "shared_bookmark_list.html" %}
{% endblock %}
Перейдя в браузере по адресу http://127.0.0.1:8000/ вы увидите обновленную главную страницу.
Обновим код в файле bookmarks/views.py
@login_required
def bookmark_vote_page(request):
if 'id' in request.GET:
try:
id = request.GET['id']
shared_bookmark = SharedBookmark.objects.get(id=id)
user_voted = shared_bookmark.users_voted.filter(username=request.user.username)
if no user_voted:
shared_bookmark.votes += 1
shared_bookmark.users_voted.add(request.user)
except SharedBookmark.DoesNotExist:
raise Http404('Bookmark not found.')
if 'HTTP_REFERER' in request.META:
return HttpResponseRedirect(request.META['HTTP_REFERER'])
return HttpResponseRedirect('/')
Добавим url для этого акшон-метода в файл urls.py
urlpatterns = patterns('',
[...]
# Account management
(r'^save/$',bookmark_save_page),
(r'^vote/$', bookmark_vote_page)
)
В шаблон файла shared_bookmark_list.html добавим следующий код
{% if shared_bookmarks %}
<ul class="bookmarks">
{% for shared_bookmark in shared_bookmarks %}
<li>
<a href="/vote/?id={{ shared_bookmark.id }}" class="vote">[+]</a>
<a href="{{ shared_bookmark.bookmark.link.url }}" class="title">{{ shared_bookmark.bookmark.title }}</a>
<br />
Posted By:
<a href="/user/{{ shared_bookmark.bookmark.user.username }}/" class="username">{{ shared_bookmark.bookmark.user.username }}</a> |
<span class="vote-count">Votes: {{ shared_bookmark.votes }}</span>
</li>
{% endfor %}
</ul>
{% else %}
<p>No bookmarks found.</p>
{% endif %}
Добавим новый акшон-метод в файл bookmarks/views.py
from datetime import detetime, timedelta
def popular_page(request):
today = datetime.today()
yesterday = today - timedelta(1)
shared_bookmarks = SharedBookmarks.objects.filter(date__gt=yesterday)
shared_bookmarks = shared_bookmarks.order_by('-votes')[:10]
variables = RequestContext(request, {
'shared_bookmarks': shared_bookmarks
})
return render_to_response('popular_page.html', variables)
Создадим файл шаблона popular_page.html в папке templates
{% extends "base.html" %}
{% block title %}
Popular Bookmarks
{% endblock %}
{% block head %}
Popular Bookmarks
{% endblock %}
{% block content %}
{% include "shared_bookmark_list.html" %}
{% endblock %}
Добавим url на эту страницу в файл urls.py
urlpatterns = patterns('',
# Browsing
(r'^$', main_page),
(r'^popular/$', popular_page),
(r'^user/(\w+)/$', user_page),
(r'^tag/([^\s]+)/$', tag_page),
(r'^tag/$', tag_cloud_page),
(r'^search/$', search_page),
[...]
)
В браузере перейдем по адресу http://127.0.0.1:8000/popular/ и посмотрим на страницу.
В главный шаблон в файле templates/base.html добавим ссылку на эту страницу.
[...]
<div id="nav">
<a href="/">home</a> |
<a href="/popular/">popular</a> |
{% if user.is_authenticated %}
<a href="/save/">submit</a> |
<a href="/search/">search</a> |
<a href="/user/{{ user.username }}/">
{{ user.username }}</a> |
<a href="/logout/">logout</a>
{% else %}
<a href="/login/">login</a> |
<a href="/register/">register</a>
{% endif %}
</div>
[...]
Добавим встроенное в Django приложение для размещения комментариев на сайте.
В файле settings.py добавим строчку 'django.contrib.comments'
INSATALLED_APPS = {
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.comments',
'django_bookmarks.bookmarks'
}
Синхронизируем базу данных
python manage.py syncdb
Посмотри SQL
python manage.py sql
Включим url для комментариев в файл urls.py
urlpatterns = patterns('',
[...]
# Comments
(r'^comments/$', include('django.contrib.comments.urls')),
)
Добавим еще url в файл urls.py
urlpatterns = patterns('',
# Browsing
(r'^$', main_page),
(r'^popular/$', popular_page),
(r'^user/(\w+)/$', user_page),
(r'^tag/([^s]+)$', tag_page),
(r'^tag/$', tag_cloud_page),
(r'^search/$', search_page),
(r'^bookmark/(\d+)/$', bookmark_page),
[...]
)
Добавим акшон-метод bookmark_page в файл bookmarks/views.py
def bookmark_page(request, bookmark_id):
shared_bookmark = get_object_or_404(SharedBookmark, id=bookmark_id)
variables = RequestContext(request, {
'shared_bookmark': shared_bookmark
})
return render_to_response('bookmark_page.html', variables)
Создадим новый шаблон bookmark_page.html в папке templates
{% extends "base.html" %}
{% block title %}
Bookmark: {{ shared_bookmark.bookmark.title }}
{% endblock %}
{% block head %}
<a href="/vote/?id={{ shared_bookmark.id }}" class="vote">[+]</a>
<a href="{{ shared_bookmark.bookmark.link.url }}" class="title">{{ shared_bookmark.bookmark.title }}</a>
{% endblock %}
{% block content %}
Posted By:
<a href="/user/{{ shared_blockmark.user.usernaem }}/" class="username">{{ shared_bookmark.bookmark.user.username }}</a> |
<span class="vote-count">Voted: {{ shared_bookmark.votes }}</span>
{% endblock %}
Специальные тэги для шаблона комментариев:
get_comment_count - возвращает число комментариев для конкретной страницы.
get_comment_list - возвращает список комментариев для конкретной страницы.
render_comment_form - отображает форму для добавления комментариев.
Данные тэги децствуют в шаблоне после добавления команды
{% load comments %}
Каждый комментарий имеет следующий атрибут:
user - объект User пользователя, оставившего комментарий.
submit_date -дата и время добавления комментария.
comment - текст комментария.
ip_address - IP-адрес пользователя, оставившего комментарий.
Обновим код в шаблоне templates/bookmark_page.html
{% render_comment_form for bookmarks.sharedbookmark shared_bookmark.id %}
Добавим код в шаблон templates/bookmark_page.html
{% extends "base.html" %]
{% load comments %}
{% block title %}
Bookmarl: {{ shared_bookmark.bookmark.title }}
{% endblock %}
{% block head %}
<a href="/vote/?id={{ shared_bookmark.id }}" class="vote">[+]</a>
{% endblocl %}
{% block content %}
Posted By:
<a href="/user/{{ shared_bookmark.bookmark.user.username }}/" class="username">{{ shared_bookmark.bookmark.user.username }}</a> |
<span class="vote-count">Votes: {{ shared_bookmark.votes }}</span>
<h2>Comments</h2>
{% get_comment_count for bookmarks.sharedbookmark shared_bookmark.id as comment_count %}
{% get_comment_list for bookmarks.sharedbookmark shared_bookmark.id as comment_list %}
{% for comment in comment_list %}
<div class="comment">
<p><b>{{ comment.user.username }}</b> said:</p>
{{ comment.comment|escape|urlizetrunc:40|linebreaks }}
</div>
{% endfor %}
<p>Number of comments: {{ comment_count }}</p>
{% render_comment_form for bookmarks.sharedbookmark shared_bookmark.id %}
{% endblock %}
Создадим шаблон формы form.html в папке templates/comments/
{% load comments %}
{% if user.is_authenticated %}
<form action="{% comment_form_target %} method="POST">
{% for field in form %}
{% if field.is_hidden %}
{{ field }}
{% endif %}
{% endfor %}
<input type="hidden" name="name" value="{{ user.username }}" />
<input type="text" name="honeypot" size="64" style="display: none;" />
<label for="id_comment">Comment</label>
<textarea id="id_comment" rows="10" cols="40" name="comment"></textarea>
<input type="submit" name="submit" class="submit-post" value="Post" />
</form>
{% else %}
<p>Please <a href="/login/">log in</a> to post comments.</p>
{% endif %}
Далее создадим шаблон posted.html в папке templates/comments/
{% extends "base.html" %}
{% block title %}
Comment Posted Successfully
{% endblock %}
{% block head %}
Comment Posted Successfully
{% endblock %}
{% block content %}
<p>Thank you for contributing.</p>
{% endblock %}
Теперь изменим шаблон templates/shared_bookmark_list.html
{% if shared_bookmarks %}
<ul class="bookmarks">
{% for shared_bookmark in shared_bookmarks %}
<li>
<a href="/vote/?id={{ shared_bookmark.id }}" class="vote">[+]</a>
<a href="{{ shared_bookmark.bookmark.link.url }}" class="title">{{ shared_bookmark.bookmark.title }}</a>
<br />
Posted By:
<a href="/user/{{ shared_bookmark.bookmark.user.username }}/" class="username">{{ shared_bookmark.bookmark.user.username }}</a> |
<span class="vote-count">Votes: {{ shared_bookmark.votes }}</span> |
<a href="/bookmark/{{ shared_bookmark.id }}/">Comments</a>
</li>
{% endfor %}
</ul>
{% else %}
<p>No bookmarks found.</p>
{% endif %}
Добавим новые стили в файл site_media/style.css
textarea {
display: block;
}
.comment {
margin: 1em;
padding: 5px;
border: 1px solid #000;
}
В браузере перейдем на главную страницу по адресу http://127.0.0.1:8000/ и кликнем на гиперссылку Comments.
Попробуем добавить свой комментарий.
Вернемся на страницу bookmarks и увидим там свой комментарий.
Активируем админку Django.
В файл settings.py добавим админку в INSTALLED_APPS.
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.admin',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.comments',
'django_bookmarks.bookmarks',
)
Выполним синхронизацию базы данных для админки.
python manage.py syncdb
Псомотрим получившийся SQL код.
python manage.py sql
В файле urls.py добавим ссылку url на админку Django.
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
[...]
# Admin interface
(r'^admin/(.*)', admin.site.root),
)
Создадим файл с акшон методом bookmarks/admin.py
from django.contrib import admin
from bookmarks.models import *
class LinkAdmin(admin.ModelAdmin):
pass
admin.site.register(Link, LinkAdmin)
В браузе перейдем по адресу http://127.0.0.1:8000/admin/
Введем логин и пароль и попадем на страницу администрирования.
В админке используются только классы базы данных, введенных в файле bookmarks/admin.py
Изменим итерфейс админки.
Добавим в файл bookmarks/admin.py класс BookmarkAdmin
class BookmarkAdmin(admin.ModelAdmin):
list_display = ('title', 'link', 'user')
В скобках указаны имена полей базы данных, которые будут отображаться в списке админки.
Для админки можно определить следующие типы атрибутов в классе.
list_filter - если прописан, то создает сайдбар со ссылками, который может фильтровать объекты по одному или нескольким полям базы данных.
ordering - используется для упорядочивания обектов в списке. Если имя поля представлено со знаком минут, то упорядочивание идет по убыванию, а не по возрастанию.
search_fields - если прописан, то создает поле поиска, которое может быть использована для поиска объектов базы данных.
Дополним класс BookmarkAdmin в файле bookmarks/admin.py
class BookmarkAdmin(admin.ModelAdmin):
list_display = ('title', 'link', 'user')
list_filter = ('user',)
ordering = ('title',)
search_fields = ('title')
list_filter - добавляет фильтрацию bookmarks по имени user
ordering - упорядочивает bookmarks по title
search_fields - позволяет искать bookmarks по title
Обновим страницу админки и увидим внесенные изменения.
Приведем список путей установки Django по умолчанию
Windows: C:\PythonXX\Lib\site-packages\django
UNIX and Linux: /usr/lib/pythonX.X/site-packages/django
Mac OS X: /Library/Python/X.X/site-packages/django
Найдите файл django-admin.py внутри папки bin.
Откройте папку django/contrib/admin/templates/
Найдите там следующие файлы:
admin/base_site.html - это главный шаблон админки. Все страницы админки наследуют из этого шаблона.
admin/change_list.html - этот шаблон генерирует список доступных объектов модели.
admin/change_form.html - этот шаблон генерирует форму для добавления или удаления объектов.
admin/delete_confirmation.html - этот шаблон генерирует страницу подтверждения для удаления объекта.
Изменим один из этих шаблонов.
Создайте в папке templates вашего проекта папку admin, в которую скопируйте файл admin/base_site.html
Измените в скопированном файле все слова Django на Django Bookmarks
{% extends "base.html" %}
{% load il8n %}
{% block title %}
{{ title }} | {% trans 'Django Bookmarks site admin' %}
{% endblock %}
{% block branding %}
<h1 id="site-name">{% trans 'Django Bookmarks administration' %}</h1>
{% endblock %}
{% block nav-global %}
{% endblock %}
Добавим RSS.
Создадим файл feeds.py в папке bookmarks
from django.contrib.syndication.feeds import Feed
from bookmarks.models import Bookmark
class RecentBookmarks(Feed):
title = u'Django Bookmarks | Recent Bookmarks'
link = '/feeds/recent/'
description = u'Recent bookmarks posted to Django Bookmarks'
def items(self):
return Bookmark.objects.order_by('-id')[:10]
Добавим изменения в файл bookmarks/models.py
class Bookmark(models.Model):
title = models.CharField(max_length=200)
user = models.ForeignKey(User)
link = models.ForeignKey(Link)
def __unicode__(self):
return u'%s, %s' % (self.user.username, self.link.url)
def get_absolute_url(self):
return self.link.url
Добавим url для RSS в файл urls.py
import os.path
from django.conf.urls.default import *
from django.views.generic.simple import direct_to_template
from django.contrib import admin
from bookmarks.views import *
from bookmarks.feeds import *
admin.autodiscover()
site_media = os.path.join(os.path.dirname(__file__), 'site_media')
feeds = {'recent': RecentBookmarks}
urlpatterns = patterns('',
[...]
# Feeds
(r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed', {'feed_dict': feeds}),
)
Перейдем в браузере по адресу http://127.0.0.1:8000/feeds/recent/ и увидим наш RSS.
Создадим в папке tamplates папку feeds и в ней создадим файл recent_title.html
{{ obj.title }}
Создадим пустой файл recent_description.html в папке templates/feeds/
Перезагрузим страницу http://127.0.0.1:8000/feeds/recent/ и увидим изменения.
Отредактируем файл bookmarks/feeds.py
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.auth.models import User
class UserBookmarks(Feed):
def get_object(self, bits):
if len(bits) != 1:
raise ObjectDoesNotExist
return User.objects.get(username=bits[0])
def title(self, user):
return (u'Django Bookmarks | Bookmarks for %s' % user.username)
def link(self, user):
return '/feeds/user/%s/' % user.username
def description(self, user):
return u'Recent bookmarks posted by %s' % user.username
def items(self, user):
return user.bookmark_set.order_by('-id')[:10]
Добавим изменение для feeds в файл urls.py
import os.path
from django.conf.urls.defaults import *
from django.views.generic.simple import direct_to_template
from django.contrib import admin
from bookmarks.views import *
from bookmarks.feeds import *
admin.autodiscover()
site_media = os.path.join(os.path.dirname(__file__),'site_media')
feeds = {
'recent': RecentBookmarks,
'user': UserBookmarks
}
Добавим файл user_title.html в папку templates/feeds/
{{ obj.title }}
Перейдем в браузере по адресу http://127.0.0.1:8000/feeds/user/
your_username/
Изменим шаблон в файле templates/main_page.html
{% extend "base.html" %}
{% block title %}
Welcome to Django Bookmarks
{% endblock %}
{% block head %}
Welcome to Django Bookmarks
{% endblock %}
{% block external %}
<link rel="alternate" type="application/rss+xml" title="Django Bookmarks | Recent Bookmarks" href="/feeds/recent/" />
{% endblock %}
[...]
Обновим шаблон в файле templates/user_page.html
{% extends "base.html" %}
{% block external %}
<script type="text/javascript" src="/site_media/bookmark_edit.js"><script>
<link rel="alternate" type="application/rss+xml" title="Django Bookmarks | Bookmarks for {{ username }}" href="/feeds/user/{{ username }}" />
{% endblock %}
Методы выборки данных из базы данных.
.get() - возвращает объект по имени поля.
.all() - возвращает вообще все объекты из таблицы базы данных.
.count() - возвращает общее число объектов в таблице базы данных.
.filter() - используется для отбора объектов по критериям (аналог select из SQL).
.order_by() - позволяет сортировать найденные объекты по порядку возрастания или убывания.
Пример.
Link.objects.filter(url__istartswith='https')
Link.objects.filter(url__istartswith='https', url__iendwith='html')
Bookmark.objects.filter(link_istartswith='http')
Bookmark.objects.filter(link_url_istartswith='https')
Bookmark.objects.filter(tag__name_iexact='JavaScript')
query_set = Bookmark.objects.filter(tag__name__iexact='JavaScript')
bookmarks = query_set.filter(user__username__iexact='dmitriy')
bookmarks = Bookmark.objects.filter(tag__name__iexact='JavaScript').filter(user__username__iexact='dmitriy')
Bookmark.objects.filter(title__icontains='JavaScript').exclude(tag__name__iexact='Web')
Bookmark.objects.filter(user__username__iexacts='dmitriy').order_by('title')
Bookmark.objects.all()[:10]
from django.db.models import Q
q1 = Q(title__icontains='Python')
q2 = Q(title__icontains='JavaScript')
q3 = q1 | q2
Bookmark.objects.filter(q3)
Bookmark.objects.filter(Q(title__icontains='Python') | Q(title__icontains='JavaScript'))
Отредактируем search_page в файле bookmarks/views.py
from django.db.models import Q
def search_page(request):
form = SearchForm()
bookmark = []
show_results = False
if 'query' in reques.GET:
show_results = True
query = reques.GET['query'].strip()
if query:
keywords = query.split()
q = Q()
for keyword in keywords:
q = q & Q(title__icontains=keyword)
form = SearchForm({'query': query})
bookmarks = Bookmark.objects.filter(q)[:10]
variables = RequestContext(request, {
'form': form,
'bookmarks': bookmarks,
'show_results': show_results,
'show_tags': True,
'show_user': True
})
if 'ajax' in request.GET:
return render_to_response('bookmark_list.html', variables)
else:
return render_to_response('search.html', variables)
Поработаем с паджинацией.
from bookmarks.models import *
from django.core.paginator import Paginator
query_set = Bookmark.objects.all()
paginator = Paginator(query_set, 10)
paginator.num_pages
paginator.count
page = paginator.page(1)
page.object_list
page.has_previous()
page.has_next()
Модифицируем user_page в файле bookmarks/views.py
from django.core.paginator import Paginator, InvalidPage
ITEMS_PER_PAGE = 10
def user_page(request, username):
user = get_object_or_404(User, username=username)
query_set = user.bookmark_set.order_by('-id')
paginator = Paginator(query_set, ITEMS_PER_PAGE)
try:
page_number = int(request.GET['page'])
except (KeyError, ValueError):
page_number = 1
try:
page = paginator.page(page_number)
except InvalidPage:
raise Http404
bookmarks = page.object_list
variables = RequestContext(request, {
'bookmarks': bookmarks,
'username': username,
'show_tags': True,
'show_edit': username == request.user.username,
'show_paginator': paginator.num_pages > 1,
'has_prev': page.has_previous(),
'has_next': page.has_next(),
'page': page_number,
'pages': paginator.num_pages,
'next_page': page_number + 1,
})
return render_to_response('user_page.html', variables)
Обновим шаблон templates/bookmark_list.html для использования паджинатора.
{% if bookmarks %}
<ul class="bookmarks">
{% for bookmark in bookmarks %}
[...]
{% endfor %}
</ul>
{% if show_paginator %}
<div class="paginator">
{% if has_prev %}
<a href="?page={{ page_prev }}">« Previous</a>
{% endif %}
{% if has_next %}
<a href="?page={{ next_page }}">Next »</a>
{% endif %}
(Page {{ page }} of {{ pages }})
</div>
{% endif %}
{% else %}
<p>No bookmarks found.</p>
{% endif %}
Перейдем в браузере на страницу со вкладками и увидим паджинацию.
Создадим новую модель базы данных в файле bookmarks/models.py
class Friendship(models.Model):
from_friend = models.ForeignKey(User, related_name='friend_set')
to_friend = models.ForeignKey(User, related_name='to_friend-set')
def __unicode__(self):
return u'%s, %s' % (self.from_friend.username, self.to_friend.username)
class Meta:
unique_together = (('to_friend', 'from_friend'),)
Выполним синхронизацию базы данных.
python manage.py syncdb
Посмотрим код SQL.
python manage.py sql
Потренируемся в командной строке Django.
from bookmarks.models import *
from django.contrib.auth.models import User
user1 = User.objects.get('id=1')
user2 = User.objects.get('id=2')
user3 = User.objects.get('id=3')
friendship1 = Friendship(from_friend=user1, to_friend=user2)
friendship1.save()
friendship2 = Friendship(from_friend=user1, to_friend=user3)
friendship2.save()
user1.friend_set.all()
[friendship.to_friend for friendshipt in user1.friend_set.all()]
user2.friend_set.all()
friendship3 = Friendship(from_friend=user2, to_friend=user1)
friendship3.save()
user2.friend_set.all()
Теперь отредактируем файл bookmarks/views.py
def friends_page(request, username):
user = get_object_or_404(User, username=username)
friends = [friendship.to_friend for friendship in user.friend_set.all()]
friend_bookmarks = Bookmark.objects.filter(user__in=friends).order_by('-id')
variables = RequestContext(request, {
'username': username,
'friends': friends,
'bookmarks': friend_bookmarks[:10],
'show_tags': True,
'show_user': True
})
return render_to_response('friends_page.html', variables)
Создадим шаблон friends_page.html в папке templates
{% extends "base.html" %}
{% block title %}
Friends for {{ username }}
{% endblock %}
{% block head %}
Friends for {{ username }}
{% endblock %}
{% block content %}
<h2>Friend List</h2>
{% if frineds %}
<ul class="friends">
{% for friend in friends %}
<li><a href="/user/{{ friend.username }}/">{{ friend.username }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No friends found.</p>
{% endif %}
<h2>Latest Friend Bookmarks</h2>
{% include "bookmark_list.html" %}
{% endblock %}
Добавим новый url в файл urls.py
urlpatterns = patterns('',
[...]
# Friends
(r'^friends/(\w+)/$', friends_page),
)
Перейдем в браузере по адресу http://127.0.0.1:8000/friends/dmitriy/ и увидим страницу друзей.
Добавим новый акшон-метод в файл bookmarks/views.py
@login_required
def frind_add(request):
if 'username' in request.GET:
friend = get_object_or_404(User, username=request.GET['username'])
friendship = Friendship(from_friend=request.user, to_friend=friend)
friendship.save()
return HttpResponseRedirect('/friends/%s/', request.user.username)
else:
raise Http404
Добавим новый адрес в файл urls.py
urlpatterns = patterns('',
[...]
# Friends
(r'^friend/(\w+)/$', friends_page),
(r'^friend/add/$', friend_add),
)
Изменим метод user_page в файле bookmarks/views.py
def user_page(request, username):
user = get_object_or_404(User, username=username)
query_set = user.bookmark_set.order_by('-id')
paginator = Paginator(query_set, ITEMS_PER_PAGE)
if reques.user.is_authenticated():
is_friend = Friendship.objects.filter(from_friend=request.user, to_friend=user)
else:
is_friend = False
try:
page_number = int(requesr.GET['page'])
except (KeyError, ValueError):
page_number = 1
try:
page = paginator.page(page_number)
except InvalidPage:
raise Http404
bookmarks = page.object_list
variables = RequestContext(request, {
'username': username,
'bookmarks': bookmarks,
'show_tags': True,
'show_edit': username == request.user.username,
'show_paginator': paginator.num_pages > 1,
'has_prev': page.has_previous(),
'has_next': page.has_next(),
'page': page_number,
'pages': paginator.num_pages,
'next_page': page_number + 1,
'prev_page': page_number,
'is_friend': is_friend,
})
Теперь отредактируем шаблон templates/user_page.html
[...]
{% block content %]
{% ifequal user.username usernaem %}
<a href="/friends/{{ username }}/">views your friends</a>
{% else %}
{% if is_friend %}
<a href="/friends/{{ user.username }}/">{{ username }}</a>
{% else %}
<a href="/friend/add/?username={{ username }}">add {{ username }} to your friends</a>
{% endif %}
- <a href="/friends/{{ username }}/">view {{ username }}'s friends</a>
{% endifequal %}
{% include "bookmark_list.html" %}
{% endblock %}
Отредактируем файл settings.py для рассылки e-mail
SITE_HOST = '127.0.0.1:8000'
DEFAULT_FROM_EMAIL = 'Django Bookmarks <django.bookmarks@example.com>'
EMAIL_HOST = 'mail.yourisp.com'
EMAIL_PORT = ''
EMAIL_HOST_USER = 'username'
EMAIL_HOST_PASSWORD = 'password'
Проверил настройки в консоли Django.
from django.core.mail import send_mail
send_mail(mail('Subject', 'Body of the message.', 'from@example.com', ['your_email@example.com'])
Здесь вы можете заменить E-mail свой.
Создадим новый класс базы данных Invitation в файле bookmarks/models.py
class Invitation(models.Model):
name = models.CharField(max_length=50)
email = models.EmailField()
code = models.CharField(max_length=20)
sender = models.ForeignKey(User)
def __unicode__(self):
return u'%s, %s' % (self.sender.username, self.email)
Соответсвенно доработаем файл bookmarks/models.py
from django.core.mail import send_mail
from django.template.loader import get_template
from django.template import Context
from django.conf import settings
class Inaviatation(models.Model):
[...]
def send(self):
subject = u'Invitation to join Django Bookmarks'
link = 'http://%s/friend/accept/%s/' % (settings.SITE_HOST, self.code)
template = get_template('invitation_email.txt')
context = Context({
'name': self.name,
'link': link,
'sender': self.sender.username,
})
message = template.render(context)
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [self.email])
В папке templates создадим файл invitation_email.txt
Hi {{ name }},
{{ sender }} invited you to join Django Bookmarks,
a website where you can post and share your bookmarks with friends!
To accept the invitation, please click the link below:
{{ link }}
-- Django Bookmarks Team
Создадим новую форму в файле bookmarks/forms.py
class FriendInviteForm(form.Form):
name = forms.CharField(label=u'Friend\'s Name')
email = forms.EmailField(label=u'Friend\'s Email')
Отредактируем файл bookmarks/views.py
@login_required
def friend_invite(request):
if request.method == 'POST':
form = FriendInviteForm(request.POST)
if form.is_valid():
invitation = Invitation(
name=form.cleaned_data['name'],
email=form.cleaned_data['email'],
code=User.objects.make_random_password(20),
sender=request.user
)
invitation.save()
invitation.send()
return HttpResponseRedirect('/friend/invite/')
else:
form = FriendInviteForm()
variables = RequestContext(request, {'form': form})
return render_to_response('friend_invite.html', variables)
Добавим новый шаблон friend_invite.html в папку templates
{% extends "base.html" %}
{% block title %}
Invite A Friend
{% endblock %}
{% block head %}
Invite A Friend
{% endblock %}
{% block content %}
Enter your friend name and email below, and click "send invite" to invite your friend to join the site:
<form method="post" action=".">
{{ form.as_p %}
<input type="submit" value="send invite" />
</form>
{% endblock %}
Добавим url в файл urls.py
urlpatterns = patterns('',
[...]
# Friends
(r'^friends/(\w+)/$', friends_page),
(r'^friends/add/$', friend_add),
(r'^friend/invite/$', friend_invite),
)
Перейдем в браузере по адресу http://127.0.0.1:8000/friend/invite/ и увидим форму приглашения друга.
Создадим новую ссылку в файле urls.py
urlpatterns = patterns('',
[...]
# Friends
(r'^friends/(\w+)/$', friends_page),
(r'^friend/add/$', friend_add),
(r'^friend/invite/$', friend_invite),
(r'^friend/accept/(\w+)/$', friend_accept),
)
Изменим файл bookmarks/views.py
def friend_accept(request, code):
invitation = get_object_or_404(Invitation, code__exact=code)
request.session['invitation'] = invitation.id
return HttpResponseRedirect('/register/')
def register_page(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
user = User.objects.create_user(
username = form.cleaned_date['username'],
password = form.cleaned_data['password1'],
email = form.cleaned_data['email']
)
if 'invitation' in request.session:
# Получить invitation object
invitation = Invitation.objects.get(id=request.session['invitation'])
# Создать friendship от user к sender
friendship = Friendship(from_friend=user, to_friend=invitation.sender)
friendship.save()
# Создать friendship от sender к user
friendship = Frindship(from_friend=invitation.sender, to_friend=user)
friendship.save()
# Удалить invitation из базы данных и session
invitation.delete()
del request.session['invitation']
return HttpResponseRedirect('/register/success/')
else:
form = RegistrationForm()
variables = RequestContext(request, {'form': form})
return render_to_response('registration/register.html', variables)
Изменим шаблон в файле templates/friends_page.html
{% extends "base.html" %}
{% block title %}
Friends for {{ user }}
{% endblock %}
{% block head %}
Friends for {{ user }}
{% endblock %}
{% block content %}
<h2>Friend List</h2>
{% if friends %}
<ul class="friends">
{% for friend in friends %}
<li><a href="/user/{{ friend.username }}/">{{ friend.username }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No friends found.</p>
{% endif %}
<a href="/friend/invite/">Invite a friend!</a>
<h2>Latest Friend Bookmarks</h2>
{% include 'bookmark_list.html' %}
{% endblock %}
Изменим базовый шаблон в файле templates/base.html
<body>
<div id="nav">
[...]
</div>
<h1>{% block head %}{% endblock %}</h1>
{% if messges %}
{% for message in message %}
<li>{{ message}}</li>
{% endfor %}
{% endif %}
{% block content %}{% endblock %}
</body>
</html>
Добавим новые стили в файл site_media/style.css
ul.messages {
border: 1px dashed #000;
margin: 1em 4em;
padding: 1em;
}
Изменим метод friend_invite в файле bookmarks/views.py
import smtplib
@login_required
def frind_invite(request):
if request.method == 'POST':
from = FriendInviteForm(request.POST)
if form.is_valid():
invitation = Invitation(
name=form.cleaned_data['name'],
email=form.cleaned_data['email'],
code=User.objects.make_random_password(20),
sender=request.user
)
invitation.save()
try:
invitation.send()
request.user.message_set.create(message=u'An invitation was sent to %s' % invitation.email)
except smtplib.SMTPException:
request.user.message_set.create(message=u'An error happen when sending the invitation')
return HttpResponseRedirect('/friend/invite/')
else:
form = FriendInviteForm()
variables = RequestContext(request, {
'form': form
})
return render_to_response('friend_invite.html', variables)
Перейдем в браузере по адресу http://127.0.0.1:8000/friend/invite/
Внесем изменения в файл bookmarks/views.py
@login_required
def friend_add(request):
if 'username' in request.GET:
friend = get_object_or_404(User, username=request.GET['username'])
friendship = Friendship(from_friend=request.user, to_friend=friend)
try:
friendship.save()
request.user.message_set.create(message=u'%s was added to your friend list.' % friend.username)
except:
request.user.meassge_set.create(message=u'%s is already a friend of yours.' % friend.username)
return HttpResponseRedirect('/friends/%s' % request.user.username)
else:
raise Http404
Теперь сделаем перевод сообщений на другой язык.
Изменим файл bookmarks/views.py
from django.utils.translation import ugetext as _
@login_required
def friend_invite(request):
if request.method == 'POST':
form = FriendInvitationForm(request.POST
if form.is_valid():
invitation = Invitation(
name=form.cleaned_data['name'],
email=form.cleaned_data['email'],
code=User.objects.make_random_password(20),
sender=request.user
)
invitation.save()
try:
invitation.send()
request.user.message_set.create(message=_(u'An invitation was sent to %s' % invitation.email))
except smtplib.SMTPException:
request.user.meassage_set.create(message=_(u'An error happend when sending the invitation.'))
return HttpresponseRedirect('/friend/invite/')
else:
form = FriendInviteForm()
variables = RequestContext(request, {
'form': form
})
return render_to_response('friend_invite.html', variables)
Изменим шаблон friend_invite.html в папке templates
{% extends "base.html" %}
{% load i18n %}
{% block title %}
{% trans 'Invite A Friend' %}
{% endblock %}
{% block head %}
{% trans 'Invite A Friend' %}
{% endblock %}
{% block content %}
{% trans 'Enter your friend name and email below, and click "send invite" to invite your friend to join the site:' %}
<form method="post" action=".">
{{ form.as_p %}
<input type="submit" value="{% trans 'send invite' %}" />
</form>
{% endblock %}
Изменим форму в файле bookmarks/forms.py
from django.ustils.translation import ugettext_lazy as _
class FriendInviteForm(forms.Form):
name=forms.CharField(label=_("Friend's Name"))
email=forms.EmailField(label=_("Friend's Email"))
Управление подключением языков перевода в файле settings.py
USE_I18N = True
LANGUAGES = (
('en': 'English'),
('de': 'German'),
)
LANGUAGE_CODE = 'de'
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.middleware.locale.LocaleMiddleware',
)
Добавим url на перевод в файл urls.py
urlpatterns = patterns('',
[...]
# i18n
(r'i18n/', include('django.conf.urls.i18n')),
)
Изменим основной шаблон templates/base.html
{% load i18n %}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
[...]
</head>
<body>
[...]
<div id="footer">
<form action="/i18n/setlang/" method="post">
<select name="language">
{% for lang in LANGUAGES %}
<option value="{{ lang.0 }}">{{ lang.1 }}</option>
{% endfor %}
</select>
<input type="submit" value="Go" />
</form>
</div>
</body>
</html>
Добавим новые стили в файл site_media/style.css
#footer {
margin-top: 2em;
text-align: center;
}
#footer input {
display: inline;
}
Включим кэширование в файле settings.py
CACHE_BACKEND = 'locmem:///'
Кэшированные данные будут хранится в базе данных.
Создадим таблицу в базе данных для кэширования.
python manage.py createcachetable cache_table
Добавим ссылку на созданную таблицу в файл settings.py
CACHE_BACKEND = 'db://cache_table'
Если мы захотим кэшировать данные в файл, то создадим такую строчку в файле settings.py
CACHE_BACKEND = 'file:///tmp/django_cache'
В виндовсе адрес файла для кэширования будет выглядеть так
С:\tmp\django_cache
Если вы используете фреймворк Memcached, то можете прописать IP-адрес до его сервера.
CACHE_BACKEND = 'memcached://ip:port'
Далее в файле settings.py надо указать время кэширования страниц в секундах.
CACHE_MIDDLEWARE_SECONDS = 60 * 5
Для кэширования всего сайта внесите в файл settings.py следующие изменения
MIDDLEWARE_CLASSES = (
'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware',
)
Для кэширования специфических контроллеров внесем изменения в файл bookmarks/views.py
from django.views.decorators.cache import cache_page
@cache_page(60 * 15)
def tag_cloud_page(request):
[...]
Django содержит класс, который позволяет эмулировать работу браузера. Он может посылать и получать запросы.
Изучим его в консоли Django.
python manage.py shell
from django.test.client import Client
client = Client()
response = client.get('/')
print response
print client.post('/login/', {'username': 'user', 'password': 'password'})
client.login(username='your_username', password='your_password')
Протестируем страницу регистрации.
В папке приложения bookmarks создадим файл tests.py
from django.test import TestCase
from django.test.client import Client
class ViewTest(TestCase):
def setUp(self):
self.client = Client()
def test_register_page(self):
data = {
'username': 'test_user',
'email': 'test_user@example.com',
'password1': 'pass123',
'password2': 'pass123',
}
response = self.client.post('/register/', data)
self.assertRedirects(response, '/register/success/')
Типы утверждений в Django.
assertEqual - ожидает, что второе значение будет эквивалентно первому.
assertNotEquals - ожидает, что второе значение не будет эквивалентно первому.
assertTrue - ожидает, что значение будет равно True.
assertFalse - ожидает, что значени будет равно False.
assertRedirects - ожидает ответ на редирект по заданному URL.
assertContains - ожидает, что ответ содержит часть текста.
Теперь протестируем весь класс bookmarks
python manage.py test bookmarks
Модифицируем метод test_register_page в файле tests.py
def test_register_page(self):
data = {
'username': 'test_user',
'email': 'test_user@example.com',
'password1': '1',
#'password2': '1'
}
response = self.client.post('/register/', data)
self.assertRedirects(response, '/register/success/')
Внесем еще изменения в файл bookmarks/tests.py
class ViewTest(TestCase):
[...]
def test_bookmark_save(self):
response = self.client.login(username='your_username', password='your_password')
self.assertTrue(response, msg='Failed to login.')
data = {
'url': 'http://www.example.com/',
'title': 'Test URL',
'tags': 'test-tag'
}
response = self.client.post('/save/', data)
self.assertRedirects(response, '/user/your_username/')
response = self.client.get('/user/your_username/')
self.assertContains(response, 'http://www.example.com/')
self.assertContains(response, 'Test URL')
self.assertContains(response, 'test-tag')
Скопируем значения из базы данных в текстовый файл
python manage.py dumpdata bookmarks auth > test_data.json
Изменим класс ViewTest в файле bookmarks/tests.py
class ViewTest(TestCase):
fixtures = ['test_data.json']
[...]
Перед размещение Django на реальном сервере выключите режим отладки в файле settings.py
DEBUG = False
Измените переменную администратора
ADMINS = (
('Your Name', 'your_email@domain.com'),
)
Обновите переменные :
EMAIL_HOST
EMAIL_PORT
EMAIL_HOST_USER
EMAIL_HOST_PASSWORD
Создайте шаблоны страниц 404.html и 500.html
Добавим папку templatetags в папку bookmarks и поместите туда пустой файл __init__.py.
Создадим в папке templatetags модуль bookmarks_filters.py
В итоге мы получим такую структуру.
django_bookmarks/
bookmarks/
templatetags/
__init__.py
bookmarks_filters.py
Добавим код в файл bookmarks_filters.py
from django import template
register = template.Library()
@register.filter
def capitalize(value):
return value.capitalize()
Теперь мы можем загрузить наш фильтр в шаблон командой
{% load bookmarks_filters %}
и использовать его так
Hi {{ name|capitalize }}!
Пример создания SQL-запросов
from django.db import connection
Query = '-- SQL code goes here. --'
cursor = connection.cursor()
cursor.execute(query)
rows = cursor.fetchall()
cursor.execute('SELECT * FROM auth_user WHERE username = %s AND password = %s', (username, email))
Внутренние фреймворки Django:
admin - админка Django
auth - система авторизации пользователей сайта
sessions - фреймвор создания сессий и сессионных куки
syndication - генератор RSS
Комментариев нет:
Отправить комментарий