пятница, 18 мая 2007 г.

Пишем Tv программу на Django. Часть 1

Ну вот блог создал. Чуть-чуть его покрутил, теперь и наполнять надо...
А наполнять я его по крайней мере по началу буду рассказом о том как я создавал простенькое web приложение на django. В процессе я учусь сам и возможно, кому-то это тоже поможет.

Моим приложением будет Tv программа. Точнее не так, а web2.0Tv программа. :)
Делаю я её в общем-то для себя и для моей не большой сети. Потому что на "внешке" всяких программ и так дополна. Тем не менее я попытаюсь написать тру приложение на django, xml+xlst (хотя в этом пока не уверн, может быть и обычным html'ем обойдусь), с ajax'ом, экспортом в разные форматы и тому подобной мишурой.

И так наверно приступим.


Для начала создаём проект:
django-admin.py startproject mysite


создаём приложение:
cd mysite
python manage.py startapp tv


сразу же подключаем его к проекту, для этого в settings.py в INSTALLED_APPS дописываем:
'mysite.tv',

и настраиваем всё остальное, как Вам надо. Да не забудьте раскомментировать django.contrib.admin.

Отлично, теперь необходимо продумать и создать модель нашего приложения.
Что необходимо Tv программе передач:

  • Каналы
  • Программы
  • Описание некоторых программ
  • И каким-то образом привязать это всё к пользователю.


Для каналов у меня получилась такая моделька:
class Chanal(models.Model):
""" Модель канала """
class Admin: # Сразу же делаем их видимыми в админке
list_display = ('Title',) # отображаем только названия
def __str__(self): # вместа номера объекта будет возвращаться его название
return self.Title
Title = models.CharField(maxlength=50)
Icon = models.ImageField(blank=True, upload_to="tv/images")
Num = models.IntegerField(blank=True, null=True) # номер канала на сервере откуда его берём
Slug = models.SlugField(maxlength=255, editable=False) # название канала в транслите, нужно для нормальных урлов
def save(self):
""" Функция, которая изменяет стандартный метод сохранения для нормального сохранения поля slug """
self.Slug = slugify(self.Title.decode(settings.DEFAULT_CHARSET))
super(Chanal, self).save()


Для программ:
class Program(models.Model):
class Admin: # аналогично делаем видимым в админке
list_display = ('Title', 'Time', 'Chanal') # отображаем название, время и канал в 3 колонки
def __str__(self):
return self.Title
Title = models.CharField(maxlength=150)
Time = models.DateTimeField(blank=True)
Chanal = models.ForeignKey(Chanal) # привязывает программу к каналу


Ну и наконец описание:
class Description(models.Model):
class Admin:
list_display = ('Program', 'Text',)
def __str__(self):
return self.Text[:50]
Text = models.TextField(blank=True)
Program = models.ForeignKey(Program)


Теперь самое сложное. Нужно придумать как привязать это всю к пользователю. Для этого я создал класс setting. Он служит "мостиком" между пользователем и данными приложения.

Для связи этого класса с пользователем было бы логично написать что-то вроде:
Owner = models.ForeignKey(User)
Но тут появляется куча проблем. Где создавать этот класс? При регистрации пользователя? А если они уже есть, то придётся писать какой-то дополнительный скрипт. Короче мороки - куча. Очень красивое решение предложил Иван Сагалаев. У него даже целая статья этому посвящена, советую всем ознакомиться. Не долго думая, тупо копи-пастем его код. :) (как говориться сила OpenSource) После этого у нас появляется замечательное поле AutoOneToOneField. Теперь можно думать дальше. Сразу при планировании я решил, что каналы будут выводится блоками и соответственно было бы неплохо иметь возможность менять их местами. Думал как это сделать попроще довольно долго. Но ничего кроме как создать ещё один класс:
class Place(models.Model):
Chanal = models.ForeignKey(Chanal)
N = models.IntegerField()


ничего придумать не смог. :( Если у кого есть идеи - поделитесь пожалуйста.

В результате для setting у меня получилось вот такая штука:

class Setting(models.Model):
# привязываем класс к пользователю... или наоборот... Не важно.
Owner = AutoOneToOneField(User, related_name='tv_Setting')
# Режим выводить все программы за день или только актуальные. То есть те, которые идут сейчас или начинаются позже
Mode = models.CharField(maxlength=50)
# Список каналов которые пользователь хочет видеть на главной странице c их номерами
Chanals = models.ManyToManyField(Place)
class Admin:
pass # если в админке видить класс хотим, но ничего специфичного нет, можно как в туториале просто написать pass. Тогда будет выводится название объекта, который у нас подменяется именем пользователя.
def __init__(self, *args, **kwargs):
""" Функция вызывается при создании объекта. То есть когда пользователь первый раз обращается к нашему приложению. """
super(Setting, self).__init__(*args, **kwargs)
self.Mode = 'new' # Устанавливаем режим в "только актуальные"
def __str__(self):
return str(self.Owner)


Всё что к этому времени написанно можно взять тут:
svn checkout http://tvwatcher.googlecode.com/svn/tags/post1/ tvwatcher
А последняя версия всегда будет доступна вот тут:
svn checkout http://tvwatcher.googlecode.com/svn/trunk tvwatcher

(если хочется просто посмотреть на код, то можно прямо браузером перейти по этим ссылкам и посмотреть)

Теперь в urls.py раскомментируем строчку
(r'^admin/', include('django.contrib.admin.urls')),


Выполняем в консоли:
python manage.py syncdb
python manage.py runserver


Теперь по адресу http://127.0.0.1:8000/admin/ у вас лежит рабочая админка. Туда можно зайти и убедиться, что все наши классы правильно создались.

На этом пока всё. В следующей части займёмся наполнением базы данных.

P.S чуть не забыл. Я использую сторонний модуль pytils от Pythy. Просто закиньте модуль в директорию с проектом. После этого будет работать import.

Комментариев нет: