2013-03-13 27 views
10

Tôi muốn tách một phiên bản của một lớp khỏi phiên của tôi nhưng nó vẫn có sẵn để đọc (không phát ra truy vấn). Tôi đã được quét qua các tài liệu trong nhiều ngày nay, nhưng mỗi cách tiếp cận tôi cố gắng dẫn đến thông điệpTách SQLAlchemy dụ để không làm mới xảy ra

DetachedInstanceError: Instance <MyModel at 0x36bb190> is not bound to a Session; 
attribute refresh operation cannot proceed 

tôi đang làm việc với người quản lý zope.sqlalchemy giao dịch trong kim tự tháp. Tôi muốn đối tượng của mình có thể sử dụng được sau giao dịch đã được thực hiện. Tôi chỉ cần nó để đọc giá trị "được lưu trong bộ nhớ cache", tức là những giá trị đã ở trong đó trước khi giao dịch được thực hiện.

Cách duy nhất tôi có thể tìm ra là bằng cách gói lớp (hoặc chính các thuộc tính) và sau đó theo dõi các thay đổi theo cách thủ công (tôi có thể làm điều đó nhưng nó thực sự xấu và không phải ở tất cả pythonic).

Vì vậy, có cách nào tôi có thể ngăn SQLAlchemy cố gắng làm mới các giá trị này không?

Là một fallback Tôi thậm chí sẽ sẵn sàng chỉ trở None, miễn là các lỗi trên không được ném sau khi giao dịch như đã cam kết

+0

Loại thuộc tính nào bạn đang cố gắng đọc? – benselme

+0

Đó là một 'PickleType' được tạo ra bởi hàm' MutableDict.as_mutable() 'của riêng tôi.Nhưng có vẻ như một khi cam kết xảy ra, tất cả dữ liệu sẽ bị xóa khỏi các trạng thái, do đó bạn sẽ phải truy vấn, bất kỳ dữ liệu nào bạn muốn (có thể sai ở đây mặc dù ...) – javex

Trả lời

7

http://docs.sqlalchemy.org/en/latest/orm/session_api.html

Tôi nghĩ rằng bạn đang tìm kiếm expire_on_commit = False

Tôi tin rằng điều này cho phép bạn tách đối tượng và tiếp tục sử dụng nó. Cố gắng sửa đổi nó và cam kết tuy nhiên sẽ dẫn đến DetachedInstanceError.

+0

Đây phải là câu trả lời được chấp nhận. Tuy nhiên, liên kết cần được cập nhật thành: http://docs.sqlalchemy.org/en/latest/orm/session_api.html – shaffooo

3

thử điều này:

DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension(), expire_on_commit=False)) 

Tôi có vấn đề này quá và sử dụng expire_on_commit=False giải quyết vấn đề của tôi.

5

Bạn có thể thực hiện chính xác này (ví dụ cho bộ nhớ đệm) bằng cách thực hiện:

session.expunge(obj) 

Theo tài liệu SQLAlchemy:

http://docs.sqlalchemy.org/en/rel_1_0/orm/session_api.html?highlight=expire#sqlalchemy.orm.session.Session.expunge

này sẽ cung cấp cho bạn phản đối rằng ở trạng thái tách rời mà bạn có thể sử dụng một cách an toàn - bạn cần phải nhớ rằng bạn sẽ không thể đọc các thuộc tính có thể phát ra truy vấn khác do đó bị ràng buộc với mối quan hệ như phiên, điều này sẽ kết thúc với DetachedInstanceError. Theo mặc định, cam kết sẽ phát hành expire_all() có nghĩa là tất cả các đối tượng sẽ làm mới trạng thái của chúng khi đọc, bằng cách xóa chúng, bạn tách chúng ra khỏi phiên sao cho không có truy vấn nào sau khi bạn thực hiện giao dịch của mình.

Tôi khuyên bạn nên vô hiệu hóa chức năng này trên toàn cầu như các ý kiến ​​khác được đề xuất vì Mike Bayer thường đề xuất ý tưởng tốt và mặc định lành mạnh cho hầu hết mọi người có thể giúp bạn giảm đau đầu trong thời gian dài.

Chỉ cần xóa mọi thứ một cách dễ dàng khi bạn cần chúng.

1
@contextmanager 
def make_session_scope(Session): 
    """Provide a transactional scope around a series of operations.""" 
    session = Session() 
    session.expire_on_commit = False 
    try: 
     yield session 
     session.commit() 
    except: 
     session.rollback() 
     raise 
    finally: 
     session.close() 

with make_session_scope(session) as session: 
     query = session.query(model)