2009-09-28

Pylons, создание модели в SQLAlchemy

Вот как бывает. Стараешься что-то изучить, потом отвлекаешься, а потом, через несколько месяцев снова смотришь на свой код и думаешь - интересно, а как я это сделал?
Чтобы не забыть, опишу последовательность создания модели в Pylons.

1. Создаем новый проект, назовем его newapp.

$ paster create -t pylons newapp
$ cd newapp

2. В файл ./development.ini добавляем расположение файла базы данных, и указываем (опционально) автоматическую конвертацию в юникод.

sqlalchemy.url = sqlite:///%(here)s/newapp.sqlite
sqlalchemy.convert_unicode = true

3. В файл ./newapp/config/environment.py импортируем модуль алхимии и модель, которую создадим чуть позже.

import sqlalchemy as sa
from newapp import model

Там же, в методе load_environment добавим создание алхимического движка для нашей БД и запустим метод init_model

def load_environment(global_conf, app_conf):
____#.....................................#
____engine = sa.engine_from_config(config, "sqlalchemy.")
____model.init_model(engine)

4. В файле ./newapp/websetup.py импортируем модель

from newapp import model

И здесь же, в метод setup_config добавим строки, необходимые для генерирования базы данных из модели.

def setup_config(command, filename, section, vars):
____#...................................#
____log.info("Creating database tables")
____model.meta.create_all(bind=model.engine)
____log.info("Finished setting up")

5. Создаем модель в файле ./newapp/model/__init__.py

# Импортируем модули, которые могут нам понадобиться

from datetime import datetime
from sqlalchemy import Table, Column, Integer, String, DateTime, MetaData, ForeignKey, orm
meta = MetaData()

# Метод, стартуемый в шаге 3: публикуем алхимический движок и сессию, которую
# создаем для работы с БД с нужными нам опциями, и создаем привязки таблиц и
# классов, в т.ч. по внешним ключам.

def init_model(bind):
____global engine, Session
____engine = bind
____Session = orm.scoped_session(orm.sessionmaker(transactional=True, autoflush=True, bind=bind))
____orm.mapper(Sections,sections)
____orm.mapper(Articles,articles,properties={'section':orm.relation(Sections)})

# Описываем таблицы:

sections=Table('sections',meta,
____Column('id',Integer,primary_key=True,autoincrement=True,nullable=False),
____Column('name',String,default=u'',nullable=False)
)
articles=Table('articles',meta,
____Column('id',Integer,primary_key=True,autoincrement=True,nullable=False),
____# А эта колонка - с внешним ключом
____Column('section_id',Integer, ForeignKey('sections.id'),nullable=False,default=0),
____Column('name',String,default=u'',nullable=False),
____Column('body',String,default=u'',nullable=False),
____Column('created_at',DateTime(),nullable=False,default=datetime.now),
____# Обратим внимание, тут мы добавляем триггер на обновление записи
____Column('updated_at',DateTime(),nullable=False,default=datetime.now,onupdate=datetime.now)
)

class Sections(object):
____def __repr__(self):
________ return self.name.encode('utf8')
class Articles(object):
____ def __repr__(self):
________ return self.name.encode('utf8')

6. Реализуем модель в файл базы данных.

$ paster setup-app development.ini

7. Создаем контроллер ./newapp/controllers/index.py.

$ paster controller index

и добавляем в метод index код для добавления данных в наши таблицы и для извлечения.

section=model.Sections()
article.name=u'Раздел 1'
model.Session.add(section)

article=model.Articles()
article.section_id=1
article.name=u'Статья 1'
article.body=u'Много текста'
model.Session.add(article)

model.Session.commit()

sql=model.Session.query(model.Articles).get(1)
return sql.section # Вывод данных, получаемыех по внешнему ключу

Вот как-то так, если вкратце.
P.S. Чтобы было меньше проблем с кодировками, не лишним будет в начало каждого файла добавлять строку

#coding:utf8

2009-09-04

Чужой среди своих: Linux в windows-домене

Об этом много чего написано, но если чисто-конкретно, то:

Указываем IP, маску подсети и шлюз в /etc/network/interfaces (с учетом, что IP статический):
iface eth0 inet static
address 192.168.xx.xx
netmask 255.255.0.0
gateway 192.168.xx.xx
auto eth0

Прописывем DNS сервера в /etc/resolv.conf (можно несколько):
nameserver xxx.xxx.xxx.xxx
nameserver xxx.xxx.xxx.xxx

Устанавливаем samba:
$ sudo apt-get install samba

Прописывем в /etc/samba/smb.conf доменное имя:
workgroup = DOMAIN

Перезапускаем сеть и samba:
$ sudo /etc/init.d/networking restart
$ sudo /etc/init.d/samba restart

Теперь, для удобства перемещения по сети можно установить удобную утилиту pyNeighborhood и smbfs
$ sudo apt-get install smbfs pyneighborhood

Настроить pyNeighborhood: указать папку для монтрования сетевых ресурсов, логин и пароль в сети, опции монтирования (очень актуальна кодировка, см тут). Остальное можно оставить по умолчанию. Программа проста и работает очень быстро. Особенно выручит она пользователей xfce, т.к. гномовский Nautilus умеет перемещаться по сетевым папкам, а Thunar - нет.

2009-09-02

Если FFmpeg при кодировании ругается на нехватку кодеков

На днях решил перекодировать пару видяшек для PSP жены, воспользовавшись ffmpeg, на что последний отреагировал, разведя руками - не знаю, мол, кодека mpeg4.
Стало ясно, что в системе установлен не полный набор кодеков. Чтобы решить эту проблему, делаем так:

Удаляем полностью ffmpeg и обновляем данные репозитариев:
$ sudo apt-get purge ffmpeg
$ sudo apt-get update

Устанавливаем полные библиотеки кодеков, они попросят удалить предыдущие. ОК.
$ sudo apt-get install libavcodec-unstripped-* libavdevice-unstripped-* libavformat-unstripped-* libavutil-unstripped-* libpostproc-unstripped-* libswscale-unstripped-*

Возвращаем ffmpeg:
$ sudo apt-get install ffmpeg

А вот скрипт, чтобы кодировать avi-шки в формат, который переваривает PSP:

#!/bin/bash
[ -d psp ] || mkdir psp
ffmpeg -i "$1" -f psp -s 368x208 -aspect 16:9 -vcodec mpeg4 -b 500k -acodec libfaac -ab 96k -ac 2 "psp/$1.MP4"

В интернетах встречается подобный скрипт, в котором написано "-acodec aac" - не верьте, будет ругаться.