2012-03-05 44 views
4

我經常製作帶有Markdown格式的richtext的Text列的模型。我的模型是這樣的:如何用SQLAlchemy聲明式創建複合列?

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

我的編輯形式(一)從讀寫description,然後(B)寫的降價格式的版本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 and description_html),
  2. 在寫入列時,還會將一個Markdown格式的版本寫入html列,並且
  3. 提供返回html列內容的__html__()方法。這將允許從Jinja2模板中使用{{ doc.description }}而不使用safe過濾器。

問題:#1可能嗎?我可以定義製作兩列的列嗎?

+0

你真的想在數據庫中同時存儲源文本和結果html文本? – plaes 2012-03-05 14:29:36

+1

是的,我寧願緩存它。爲什麼要爲每個視圖或每當memcache過期時爲其重新生成CPU時間,如果每次編輯只需要生成一次呢?磁盤比CPU便宜。 – 2012-03-05 17:02:40

回答

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 
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) 

而且在查看HTML描述可以很document.description_html訪問...

+0

+1。爲什麼人人都想要存儲兩個版本? – SingleNegationElimination 2012-03-05 14:44:32

+3

要緩存它。重新生成HTML需要CPU時間。如果典型的文檔很少重新編輯,爲什麼不直接生成一次HTML並永久地緩存呢? – 2012-03-05 17:01:37