如何使用SQLAlchemy声明来创建复合列?

时间:2012-03-05 11:15:58

标签: python sqlalchemy

我经常使用Text列制作包含Markdown格式的richtext的模型。我的模型看起来像这样:

class Document(Base):
    id = Column(Integer, primary_key=True)
    title = Column(Unicode(250))
    description = Column(Text)
    description_html = Column(Text)    

我的编辑表单(a)读取和写入description然后(b)将Markdown格式化版本写入description_html。我的(Jinja2)视图模板(c)使用{{ doc.description_html|safe }}加载HTML版本。

我想将这三个重复操作减少到一个列定义中,如下所示:

class Document(Base):
    id = Column(Integer, primary_key=True)
    title = Column(Unicode(250))
    description = Column(MarkdownText)

MarkdownText是新列类型:

  1. 在数据库表(description和description_html)中创建两列
  2. 写入列后,还会将Markdown格式化版本写入html列,并
  3. 提供返回html列内容的__html__()方法。这样就可以在没有{{ doc.description }}过滤器的情况下使用Jinja2模板safe
  4. 问题:#1可能吗?我可以定义一个包含两列的列吗?

2 个答案:

答案 0 :(得分:3)

我们现在开始使用复合列:

from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, Text
from sqlalchemy.orm import composite, sessionmaker
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite:///')
session = sessionmaker(bind=engine)()
Base = declarative_base()

class MarkdownText(object):

    def __init__(self, text):
        self._text = text
        self._html = "<html>%s</html>" % text

    @classmethod
    def _from_db(cls, text, html):
        mt = MarkdownText(text)
        mt._html = html
        return mt

    def __composite_values__(self):
        return (self._text, self._html)

    def __str__(self):
        return self._text

    @property
    def __html__(self):
        return self._html

class Foo(Base):
    __tablename__ = 'foo'

    id = Column(Integer, primary_key=True)
    a = composite(MarkdownText._from_db,
                     Column('_text', Text),
                     Column('_html', Text))

    def __init__(self, a):
        self.a = MarkdownText(a)

    def __repr__(self):
        return '(%s)' % (self.a)

Base.metadata.create_all(engine)

session.add_all([Foo('test'), Foo('nips')])
session.commit()
x = session.query(Foo).all()
print x
print x[0].a.__html__
print x[0].a

这很好地给了我们:

[(test), (nips)]
<html>test</html>
test

答案 1 :(得分:2)

我最好不要回答你的要点,我最好问你:“你真的想在数据库中存储纯文本和HTML文本吗?”。我就是这样做的:

def text2html(text):
    # TODO: Implement me!
    pass

class Document(Base):
    id = Column(Integer, primary_key=True)
    title = Column(Unicode(250))
    description = Column(Text)

    @property
    def description_html(self):
        return text2html(self.description)

在视图中,可以像document.description_html ...

一样访问html描述