2009-09-04 37 views
21

Tôi muốn tải/lưu một dict đến/từ DB sqlite của tôi, nhưng có một số vấn đề tìm ra một cách đơn giản để làm điều đó. Tôi không thực sự cần để có thể lọc, vv, dựa trên các nội dung để chuyển đổi đơn giản đến/từ chuỗi là tốt.Dicts Python trong sqlalchemy

Điều tốt nhất tiếp theo sẽ là khóa ngoại. Xin đừng đăng các liên kết đến các ví dụ rất lớn, đầu tôi sẽ phát nổ nếu tôi đặt mắt vào bất kỳ thứ gì.

Trả lời

4

Bạn có thể tạo một kiểu tùy chỉnh bằng cách subclassing sqlalchemy.types.TypeDecorator để xử lý serialization và deserialization sang văn bản.

An thực hiện có thể trông như

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 

sử dụng Ví dụ:

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

này được nêu trong an example in the SQLAlchemy docs, mà cũng cho thấy làm thế nào để theo dõi những đột biến của từ điển đó.

Cách tiếp cận này sẽ làm việc cho tất cả các phiên bản của Python, trong khi chỉ đơn giản là đi json như giá trị cho pickler đối số của PickleType sẽ không hoạt động chính xác, như AlexGrönholm points out trong bình luận của ông về câu trả lời khác.

+0

Câu trả lời của bạn chưa hoàn chỉnh, vì vậy không thể chấp nhận. Nó cũng có tham chiếu đến "câu trả lời được chấp nhận" làm lệch hướng mọi nỗ lực và thay đổi trạng thái cụ thể đó trên bất kỳ câu trả lời nào. Vui lòng instad bắt đầu với một câu trả lời đúng, và (nếu bạn phải) bao gồm những gì người khác đã làm sai ở cuối. –

+0

@ JonasByström đủ công bằng, tôi đã xóa tham chiếu đến câu trả lời hiện được chấp nhận và mở rộng ví dụ một chút – karlson

+0

Điều này đã hiệu quả khi tôi thiết lập lần đầu tiên. Tuy nhiên sau khi thêm một trường mới vào mô hình của tôi ('product_count = db.Column (db.Integer)') nó cho tôi lỗi sau khi di chuyển các thay đổi sang mysql: 'NameError: name 'TextPickleType' không được định nghĩa' – iamlolz

3

Nếu bạn cần để ánh xạ một 1-N quan và bản đồ nó như dict thay vì sau đó list, sau đó đọc Dictionary Based Collections

Nhưng nếu bạn có nghĩa là một lĩnh vực, sau đó những gì bạn có thể làm điều đó để có một Trường DB của chuỗi kiểu, được ánh xạ tới đối tượng Python của bạn. Nhưng trên cùng một đối tượng python bạn cung cấp một thuộc tính sẽ là loại proxy cho trường chuỗi được ánh xạ kiểu dict() này. Mã ví dụ (không kiểm tra):

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

Ahhh! Lộng lẫy! :) –

+1

Lưu ý rằng SQLAlchemy sẽ không nhìn thấy bạn sửa đổi nội dung của dict, vì vậy bất kỳ thay đổi nào bạn thực hiện cho một dict một khi nó đã được thiết lập sẽ không được tiếp tục tồn tại. – Simon

48

Các SQLAlchemy PickleType có nghĩa là chính xác cho việc này.

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

Bạn có thể thay đổi cơ chế serialization bằng cách thay đổi ra Pickler với cái gì khác mà có dumps()loads() phương pháp. Cơ chế lưu trữ cơ bản bởi subclassing PickleType và trọng attritbute impl:

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: rất đẹp thực sự – van

+0

Đáng yêu! Tôi sẽ thử nó vào thứ hai. –

+0

Tôi có thể làm điều gì đó nghiêm trọng sai khi tôi thử self._properties [k] = v? Tôi nhận được "TypeError: 'Cột' đối tượng không hỗ trợ phân công mục". –

Các vấn đề liên quan