RkBlog

Hardware, programming and astronomy tutorials and reviews.

SQLAlchemy i Pylons

SQLAlchemy to bardzo dobry i stabilny ORM baz danych napisany w pythonie i łatwo zastosować go w Pylons. Na początku trzeba załadować i wstępnie "skonfigurować" SQLAlchemy we frameworku. Jeżeli nie masz pojęcia o SQLAlchemy to najpierw poczytaj

Dodaj do modesl/__init__.py:
import sqlalchemy.mods.threadlocal
from sqlalchemy import *

meta = DynamicMetaData()
W tym pliku będziesz mógł później zdefiniować swoje tabele bazy danych. Przy późniejszej instalacji aplikacje definicje z tego pliku zostaną wykorzystane do utworzenia tabel.

Zamień lib/base.py na:
from pylons import Response, c, g, h, cache, request, session
from pylons.controllers import WSGIController
from pylons.decorators import jsonify, rest, validate
from pylons.templating import render, render_response
from pylons.helpers import abort, redirect_to, etag_cache
import NAZWAPROJEKTU.models as model

import sqlalchemy.mods.threadlocal
from sqlalchemy import *

class BaseController(WSGIController):
    def __call__(self, environ, start_response):
        model.meta.connect(
            request.environ['paste.config']['app_conf']['dsn']
        )
        objectstore.clear()
        response = WSGIController.__call__(self, environ, start_response)
        objectstore.flush()
        return response
Wstawiając nazwę twojego projektu
Zastąp websetup.py kodem:
import sqlalchemy.mods.threadlocal
from sqlalchemy import *
from NAZWAPROJEKTU.models import *
from paste.deploy import appconfig

def setup_config(command, filename, section, vars):
    app_conf = appconfig('config:'+filename)
    print "Connecting to database %s"%app_conf['dsn']
    meta.connect(app_conf['dsn'])
    print "Creating tables"
    meta.create_all()
    print "Successfully setup."

Konfiguracja Połączenia z Bazą Danych

Do developement.ini w głównym katalogu projektu dodaj pod [app:main]:
dsn = sqlite://@localhost/termdb
Co jest ścieżką określającą typ bazy danych i dane dostępowe do bazy danych. Format zgodny z dokumentacją SQLAlchemy.

Definiowanie Schematów Tabel

W models/__init__.py załadowaliśmy SQLAlchemy, można tam też dodać schematy tabel i zmapować je na obiekty:
#definicja tabeli
term_table = Table('terms', meta,
    Column('id', Integer, primary_key=True),
    Column('term', String(), default='')
)
#obiekt, na który zmapujemy tabelę
class Term(object):
    def __str__(self):
        return self.term
# mapujemy
term_mapper = mapper(Term, term_table)
Powyższy kod definiuje tabelę posiadającą pole id na numer wiersza i "term" na tekstową frazę.

Instalacja aplikacji - generowanie tabel

W websetup.py znajduje się kod automatycznie wykonujący kod z models/__init__.py - a dokładniej, tworzący tabele tam zdefiniowane. By "zainstalować" aplikację należy z głównego katalogu aplikacji wykonać w konsoli polecenie:
paster setup-app development.ini
Co stworzy tabele (i doda dane jeżeli zdefiniowaliśmy jakieś, o czym później). Teraz nasz projekt jest gotowy do działania we współpracy ze SQLAlchemy

Wykorzystywanie SQLAlchemy w Kontrolerach

Na początek kontrolera trzeba dołożyć ładowanie SQLAlchemy
import sqlalchemy.mods.threadlocal
from sqlalchemy import objectstore
Następnie do klasy dodajemy metodę:
def __before__(self):
         self.query = objectstore.query(model.NazwaZmapowanejKlasy)
Gdzie "NazwaZmapowanejKlasy" w naszym przypadku będzie "Term" jako że tak nazywa się nasza klasa z models/__init__.py. Jeżeli mamy kilka klas to je odpowiednio tutaj wywołujemy stosując "self.cośtam" ale tak by łatwo było odróżnić, o którą tabelę chodzi.

Teraz w metodach można korzystać ze SQLAlchemy. By np. pobrać wszystkie wpisy wystarczy self.query.select(), by pobrać po określonym numerze ID: self.query.get_by(id = 69). By dodać wpis tworzymy nowy obiekt i przypisujemy dane:
terms = model.Term() terms.term = 'Fraza'


Przykład

W poprzednim artykule opisałem jak wykonać prostą wyszukiwarkę opartą o bibliotekę web_search. Kontroler wyglądał tak:
from searchengine.lib.base import *
from searchengine.lib.web_search import *
 
class SearchController(BaseController):
 
    def index(self):
        return render_response('/index.myt')
    def result(self):
        c.result = google(request.params['term'], 10)
        return render_response('/result.myt')
Jak teraz dodać zapis wpisywanych fraz i ich listowanie? Proste:
from searchengine.lib.base import *
from searchengine.lib.web_search import *
import sqlalchemy.mods.threadlocal
from sqlalchemy import objectstore

class SearchController(BaseController):
    def __before__(self):
         self.query = objectstore.query(model.Term)
    def index(self):
        return render_response('/index.myt')
    def result(self):
	#zapisanie frazy
	terms = model.Term()
	terms.term = request.params['term']
        c.result = google(request.params['term'], 10)
	return render_response('/result.myt')
    def list(self):
	#listowanie
	c.terms = [term.term for term in self.query.select()]
	return render_response('/titles.myt')
Gdzie szablon używany przez listowanie zawiera proste for foo in c.terms :)
RkBlog

Pylons, 14 July 2008, Piotr Maliński

Comment article