2009-09-04 20 views
21

dictをロードしてsqlite DBに/から保存したいのですが、簡単な方法で問題を解決しています。内容に基づいてフィルタリングなどができる必要はありませんので、文字列への簡単な変換は問題ありません。sqlalchemyのPython dicts

次善のものは外部キーです。巨大な例へのリンクを投稿しないでください。

答えて

4

あなたはテキストにシリアライズとデシリアライズを処理するためにsqlalchemy.types.TypeDecoratorをサブクラス化してカスタムタイプを作成することができます。これはまた、その辞書の変異を追跡する方法を示しており、an example in the SQLAlchemy docsに概説されている

class SomeModel(Base): 
    __tablename__ = 'the_table' 
    id = Column(Integer, primary_key=True) 
    json_field = Column(TextPickleType()) 

s = SomeEntity(json_field={'baked': 'beans', 'spam': 'ham'}) 
session.add(s) 
session.commit() 

実装は

import json 
import sqlalchemy 
from sqlalchemy.types import TypeDecorator 

SIZE = 256 

class TextPickleType(TypeDecorator): 

    impl = sqlalchemy.Text(SIZE) 

    def process_bind_param(self, value, dialect): 
     if value is not None: 
      value = json.dumps(value) 

     return value 

    def process_result_value(self, value, dialect): 
     if value is not None: 
      value = json.loads(value) 
     return value 

使用例のように見えるかもしれません。

このアプローチは、単に別の答えに彼のコメントにAlexGrönholm points outとして、正常に動作しませんPickleTypepickler引数の値としてjsonを渡すのに対して、Pythonのすべてのバージョンのために働く必要があります。

+0

あなたの答えは完全ではないので受け入れられません。また、「受け入れられた答え」への言及もあり、これはどんな試行をも逸らし、その特定の状態を任意の答えに変えるものです。正しい答えで始めてください。そして、もし必要ならば、他人が最後にやったことを含めてください。 –

+0

@JonasByström私は現在受け入れられている回答への参照を削除し、少し例を拡張しました – karlson

+0

これは最初に設定したときに機能しました。しかし、私のモデルに新しいフィールドを追加した後( 'product_count = db.Column(db.Integer)')、mysqlへの変更をマイグレートするときに次のエラーが表示されます: 'NameError:name 'TextPickleType' is not defined – iamlolz

3

あなたは、1-N 関係をマッピングし、むしろ、その後dictlistとしてそれをマップする必要がある場合は、Dictionary Based Collections

を読んしかし、あなたはフィールドを意味する場合は、あなたが持っている、それを何を行うことができますあなたのPythonオブジェクトにマップされた文字列型のDBフィールド。しかし、同じpythonオブジェクトでは、dict()型のマップされた文字列フィールドのための種類のプロキシであるプロパティを提供します。 コード例(テストされていません):

class MyObject(object): 
    # fields (mapped automatically by sqlalchemy using mapper(...) 
    MyFieldAsString = None 

    def _get_MyFieldAsDict(self): 
     if self.MyFieldAsString: 
      return eval(self.MyFieldAsString) 
     else: 
      return {} # be careful with None and empty dict 

    def _set_MyFieldAsDict(self, value): 
     if value: 
      self.MyFieldAsString = str(value) 
     else: 
      self.MyFieldAsString = None 

    MyFieldAsDict = property(_get_MyFieldAsDict, _set_MyFieldAsDict) 
+0

ああ!素晴らしい! :) –

+1

SQLAlchemyでは、dictの内容を変更することはできません.dictが設定された後に変更を加えると、永続化されません。 – Simon

48

SQLAlchemyのPickleTypeは、このために、正確に意味しています。

class SomeEntity(Base): 
    __tablename__ = 'some_entity' 
    id = Column(Integer, primary_key=True) 
    attributes = Column(PickleType) 

# Just set the attribute to save it 
s = SomeEntity(attributes={'baked': 'beans', 'spam': 'ham'}) 
session.add(s) 
session.commit() 

# If mutable=True on PickleType (the default) SQLAlchemy automatically 
# notices modifications. 
s.attributes['parrot'] = 'dead' 
session.commit() 

あなたはdumps()loads()メソッドを持っている何か他のものとPicklerさんを変更することにより、直列化機構を変更することができます。 PickleTypeをサブクラスとのimplのattritbuteをオーバーライドすることにより、基盤となるストレージ・メカニズム:

class TextPickleType(PickleType): 
    impl = Text 

import json 
class SomeOtherEntity(Base): 
    __tablename__ = 'some_other_entity' 
    id = Column(Integer, primary_key=True) 
    attributes = Column(TextPickleType(pickler=json)) 
+0

+1:本当に素敵な – van

+0

素敵な!私はそれを最初に試してみよう。 –

+0

私はself._properties [k] = vを試してみると、 "TypeError: 'Column'オブジェクトはアイテムの割り当てをサポートしていません。 –

関連する問題