2012-03-05 20 views
4

私はしばしば、Markdown形式のリッチテキストを保持するText列のモデルを作成します。私のモデルは次のようになります。宣言型SQLAlchemyを使用してコンパウンド列を作成するにはどうすればよいですか?

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

私の編集フォームは、(A)から読み取られ、descriptionに書き込み、その後、(b)はdescription_htmlにマークダウンフォーマットされたバージョンを作成します。 My(Jinja2)ビューテンプレート(c){{ doc.description_html|safe }}でHTMLバージョンを読み込みます。

私はこのように、1つの列定義にこれら三つの定期的な作業を削減したいと思います:

  1. がで2つの列を作り:MarkdownTextは、新しい列の型がある

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

  2. カラムへの書き込み時に、Markdownフォーマットのバージョンをhtmlカラムに書き込み、
  3. html列の内容を返すメソッド__html__()を提供します。これにより、safeフィルタを使用しないで、Jinja2テンプレートから{{ doc.description }}として使用できるようになります。

質問:#1は可能ですか? 2つの列を作成する列を定義できますか?

+0

あなたは本当にソースと結果の両方のテキストをデータベースに保存しますか? ? – plaes

+1

はい、キャッシュしたいと思います。編集ごとに1回だけ生成する必要がある場合は、すべてのビューまたはmemcacheの有効期限が切れるたびにCPU時間を無駄にするのはなぜですか?ディスクはCPUよりも安価です。 –

答えて

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

+3

キャッシュする。 HTMLを再生成するには、CPU時間がかかります。典型的な文書がまれに再編集されることはめったにない場合は、HTMLを一度生成して永久にキャッシュするだけではいかがですか? –

関連する問題