SQLAlchemy + json + pylons

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
thelittlebug
User
Beiträge: 188
Registriert: Donnerstag 20. Juli 2006, 20:46
Wohnort: Wien
Kontaktdaten:

Ich ärgerte mich gerade ein wenig mit SQLAlchemy, JSON und Pylons herum denke aber das ich es gar nicht so schlecht gelöst habe. Eventuell kann man ja noch weiter verbessern und würde mich auch über Vorschläge freuen ;)

Das Problem war das sich SQLAlchemy Objekte nicht "jsonifieren" lassen da es keine Routinen dafür gibt oder ich sie nicht gefunden habe. Die Methode zum "jsonifieren" verlang nämlich ein Dict und kein SQLAlchemyobjekt und keine Liste von SQLAlchemyobjekten.

Hier meine Lösung:

Code: Alles auswählen

from sqlalchemy import *
from sqlalchemy.ext.assignmapper import assign_mapper
from pylons.database import create_engine
from pylons.database import session_context as ctx
import datetime

meta = MetaData()

products_table = Table('products', meta,
    Column('id', Integer(), primary_key=True, autoincrement=True),
    Column('manufacturer_id', Integer(), index=True),
    Column('category_id', Integer(), index=True),
    Column('name', Unicode(50)),
    Column('description', Unicode),
    Column('price', Numeric(10,4)),
    Column('created', DateTime()),
    Column('modified', DateTime())
)

pages_table = Table('pages', meta,
    Column('id', Integer(), primary_key=True, autoincrement=True),
    Column('title', Unicode(50)),
    Column('body', Unicode),
    Column('is_home', Boolean),
    Column('created', DateTime()),
    Column('modified', DateTime())
)

def getDict(objlist):
    thelist = []
    for obj in objlist:
        thelist.append(obj.getdict())
    return thelist

class ExtendedModel(object):
    def __str__(self):
        return self.name

    def getdict(self):
        thedict = {}
        for key in self.c.keys():
            element = getattr(self, key)
            if isinstance(element, datetime.datetime):
                thedict[key] = element.__str__()
            else:
                thedict[key] = element
        return thedict

class Product(ExtendedModel):
    pass

class Page(ExtendedModel):
    pass

assign_mapper(ctx, Product, products_table)
assign_mapper(ctx, Page, pages_table)
getDict im ExtendedModel ist für das Umwandeln in ein Dict zuständig und kann natürlich leicht an andere Objekte angepasst werden.

Und so wird es in Pylons verwendet. Ganz praktisch wenn eine JS Application wie das DataGrid von ExtJS JSON Listen braucht. Ich glaube zu wissen das ja SQLAlchemy auch in anderen Frameworks verwendet werden kann, vielleicht ist der Code ja auch für Django oder dergleichen interessant.

Hier wird nun die komplette Tabelle pages ausgelesen, in ein Dict konvertiert und dannach als JSON ausgegeben.

Code: Alles auswählen

    @jsonify
    def adminjson(self):
        return model.getDict(model.Page.select())
Danke im vorraus fürs Ansehen, Zerpflücken und Kritisieren :)
lgherby
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Andere Möglichkeit wäre eine Mixin Klasse:

Code: Alles auswählen

class ExportableModel(object):

    def to_dict(self):
        rv = {}
        for name in self.c:
            value = getattr(self, name)
            if isinstance(value, datetime):
                value = str(value)
            rv[name] = value
        return name

class Page(Model, ExportableModel):
    pass
Die sauberste Lösung wäre natürlich simplejson deine Models und datetime bekannt geben. Aber das geht mit pylons nicht weil jsonify keine custom Encoders erlaubt.
TUFKAB – the user formerly known as blackbird
thelittlebug
User
Beiträge: 188
Registriert: Donnerstag 20. Juli 2006, 20:46
Wohnort: Wien
Kontaktdaten:

blackbird hat geschrieben:Andere Möglichkeit wäre eine Mixin Klasse:
Die sauberste Lösung wäre natürlich simplejson deine Models und datetime bekannt geben. Aber das geht mit pylons nicht weil jsonify keine custom Encoders erlaubt.
Danke für den Tipp auch wenn er (noch) nicht geht. Ich behalte das mal im Hinterkopf, vielleicht bastel ich ja noch weiter.

lgherby
Antworten