2009-09-04 81 views
21

我想加載/保存字典到/從我的sqlite數據庫,但我有一些問題找出一個簡單的方法來做到這一點。我根本不需要根據內容進行過濾等,所以簡單地轉換爲/從字符串轉換就可以了。sqlalchemy中的Python字典

次最好的事情是外鍵。請不要張貼大量例子的鏈接,如果我着眼於任何這些例子,我的頭就會爆炸。

回答

4

您可以通過繼承sqlalchemy.types.TypeDecorator處理序列化和反序列化到文本創建一個自定義類型。

的實現可能看起來像

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 

用法示例:

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

這在an example in the SQLAlchemy docs概括,這也說明了如何跟蹤字典的突變。

這種方法應該工作的Python的所有版本,而只是傳遞json作爲價值的PickleTypepickler參數不會在他的另一個答案評論正常工作,爲AlexGrönholm points out

+0

你的答案不完整,所以不能接受。它還提到了「接受的答案」,該答案在任何答案中偏離了任何企圖並改變了該特定狀態。請先從正確的答案開始,並且(如果您必須)包括其他人在最後做錯了什麼。 – 2017-04-25 09:07:01

+0

@JonasByström夠公平的,我已經刪除了對當前接受的答案的引用,並將示例擴展了一下 – karlson 2017-04-25 12:02:51

+0

當我第一次設置它時,這個工作。然而,在我的模型('product_count = db.Column(db.Integer)')中添加一個新字段後,當將更改遷移到mysql時,它給了我以下錯誤:'NameError:name'TextPickleType'未定義' – iamlolz 2017-05-03 05:02:26

3

如果你需要映射1-N 關係,並將其映射爲dict而不是list,然後讀Dictionary Based Collections

但是,如果你說的是,你可以做那麼它有一個字符串類型的數據庫字段,它被映射到您的Python對象。但是在同一個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

啊!燦爛! :) – 2009-09-04 10:24:41

+1

請注意,SQLAlchemy不會看到您修改字典的內容,因此您設置字典後對其進行的任何更改都不會被保留。 – Simon 2012-07-13 07:17:04

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()方法皮克勒序列化機制。底層的存儲機制,通過繼承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 2009-09-04 13:03:56

+0

可愛!我會在星期一做第一件事。 – 2009-09-05 21:51:49

+0

當我嘗試self._properties [k] = v時,我可能會做出嚴重錯誤的事情。我得到「TypeError:'列'對象不支持項目分配」。 – 2009-09-07 07:04:32