Tôi đang cố sử dụng phiên bản SQLAlchemy để lưu trữ các đối tượng của mình trong cơ sở dữ liệu. Tôi có một chức năng save(...)
cho mục đích đó:SQLAlchemy: trình ánh xạ có thay đổi đối tượng của tôi không?
#!/usr/bin/env python
# encoding: utf-8
from sqlalchemy import Column, Integer, MetaData, String, Table, create_engine
from sqlalchemy.orm import mapper, sessionmaker
class MyClass(object):
def __init__(self, title):
self.title = title
def __str__(self):
return '%s' % (self.title)
def save(object_list):
metadata = MetaData()
my_class_table = Table('my_class',
metadata,
Column('id', Integer, primary_key=True),
Column('title', String(255), nullable=False))
# everything is OK here, output:
# some title
# another title
# yet another title
for obj in object_list:
print obj
mapper(MyClass, my_class_table)
# on Linux/SQLAlchemy 0.6.8, this fails with
# Traceback (most recent call last):
# File "./test.py", line 64, in <module>
# save(my_objects)
# File "./test.py", line 57, in save
# print obj
# File "./test.py", line 11, in __str__
# return '%s' % (self.title)
# File "/usr/lib/python2.7/dist-packages/sqlalchemy/orm/attributes.py", line 167, in __get__
# return self.impl.get(instance_state(instance),
# AttributeError: 'NoneType' object has no attribute 'get'
# on Mac OSX/SQLAlchemy 0.7.5, this fails with
# Traceback (most recent call last):
# File "./test.py", line 64, in <module>
# save(my_objects)
# File "./test.py", line 57, in save
# print obj
# File "./test.py", line 11, in __str__
# return '%s' % (self.title)
# File "/Library/Python/2.7/site-packages/sqlalchemy/orm/attributes.py", line 165, in __get__
# if self._supports_population and self.key in dict_:
# File "/Library/Python/2.7/site-packages/sqlalchemy/orm/attributes.py", line 139, in __getattr__
# key)
# AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object has an attribute '_supports_population'
for obj in object_list:
print obj
# (more code to set up engine and session...)
if __name__ == '__main__':
my_objects = [MyClass('some title'), MyClass('another title'), MyClass('yet another title')]
save(my_objects)
Dường như với tôi mapper làm điều gì đó với các đối tượng của tôi mặc nhiên khi tôi tạo ra các ánh xạ và tôi không thể sử dụng chúng nữa. Từ những gì tôi đọc in similar questions, điều này không hoàn toàn không rõ.
Hành vi này có được mong đợi không?
Tôi có gặp phải điều gì đó cơ bản sai ở đây không?
Cách thích hợp để lập bản đồ và lưu trữ các đối tượng của tôi là gì?
Thông tin thêm: Tôi đang sử dụng SQLAlchemy 0.7.5 với hệ thống mặc định Python 2.7.1 trên Mac OSX 10.7.3 Lion và SQLAlchemy 0.6.8 với Python hệ thống mặc định 2.7.2+ trên Kubuntu 11.10 máy ảo.
Cập nhật: Có vẻ như mapper SQLAlchemy là well known to change objects để 'SQLAlchemy cần'. Giải pháp trong bài viết được liên kết là tạo các đối tượng sau khi mapper(...)
được gọi.
Tôi đã có các đối tượng hợp lệ mặc dù - nhưng tôi không thể sử dụng chúng nữa ...
Làm cách nào để lấy SQLAlchemy để lưu trữ các đối tượng của tôi?
Cập nhật 2: Tôi nhận được ấn tượng tôi đang hiểu lầm gì đó cơ bản về ORMs:
Tôi nghĩ khái niệm SQLAlchemy mapper mang lại cho tôi một cách để xác định đối tượng của tôi và làm việc với họ trong ứng dụng của tôi tách rời khỏi cơ sở dữ liệu bất cứ điều gì - và chỉ một lần tôi muốn tồn tại chúng, tôi mang SQLAlchemy và làm cho nó làm tất cả công việc nặng nề của việc ánh xạ một đối tượng lớp tới một bảng cơ sở dữ liệu. Ngoài ra, tôi có thể thấy không có lý do kiến trúc tại sao SQLAlchemy thậm chí nên được đề cập ở bất kỳ nơi nào khác trong mã của tôi hơn là trong các hàm liên tục save(...)
và load(...)
.
Tuy nhiên, khi nhìn vào phản hồi đầu tiên bên dưới, tôi hiểu tôi phải ánh xạ lớp vào bảng cơ sở dữ liệu trước khi tôi sử dụng bất kỳ đối tượng nào của mình; đây sẽ là lúc bắt đầu chương trình của tôi. Có lẽ tôi đang nhận được một cái gì đó sai ở đây, nhưng điều này có vẻ là một hạn chế thiết kế khá mạnh mẽ từ một phần của SQLAlchemy - tất cả các khớp nối lỏng lẻo đã biến mất. Với ý nghĩ đó, tôi cũng không thấy lợi ích của việc có một người lập bản đồ ở nơi đầu tiên như 'khớp nối trễ' mà tôi muốn dường như không thể thực hiện được với SQLAlchemy và tôi cũng có thể làm 'kiểu khai báo' này và trộn và trộn lẫn logic kinh doanh với mã persistency :-(
cập nhật 3: tôi quay trở lại với một hình vuông và đọc lên trên SQLAlchemy một lần nữa Nó nói ngay trên front page:.
SQLAlchemy là nổi tiếng nhất cho trình ánh xạ đối tượng-quan hệ của nó (ORM), một thành phần tùy chọn cung cấp mẫu trình ánh xạ dữ liệu, nơi các lớp có thể được ánh xạ tới cơ sở dữ liệu trong kết thúc mở, theo nhiều cách - cho phép mô hình đối tượng và lược đồ cơ sở dữ liệu phát triển theo cách được tách riêng sạch từ đầu.
Tuy nhiên, dựa trên kinh nghiệm của tôi cho đến nay, SQLAlchemy dường như không cung cấp lời hứa đó vì nó buộc tôi phải ghép nối mô hình đối tượng và lược đồ cơ sở dữ liệu ngay từ đầu.Sau khi tất cả tôi đã nghe nói về SQLAlchemy, tôi thực sự có một thời gian khó tin rằng đây thực sự là trường hợp và tôi thà cho rằng tôi chưa hiểu điều gì đó cơ bản.
Tôi đang làm gì sai?
Cập nhật 4:
Đối với đầy đủ sake, tôi muốn thêm mã mẫu làm việc mà làm tất cả các bản đồ trước khi tạo bất kỳ đối tượng kinh doanh:
#!/usr/bin/env python
# encoding: utf-8
from sqlalchemy import Column, Integer, MetaData, String, Table, create_engine
from sqlalchemy.orm import mapper, sessionmaker
class MyClass(object):
def __init__(self, title):
self.title = title
def __str__(self):
return '%s' % (self.title)
def save(object_list, metadata):
engine = create_engine('sqlite:///:memory:')
metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
for obj in object_list:
try:
session.add(obj)
session.commit()
except Exception as e:
print e
session.rollback()
# query objects to test they're in there
all_objs = session.query(MyClass).all()
for obj in all_objs:
print 'object id :', obj.id
print 'object title:', obj.title
if __name__ == '__main__':
metadata = MetaData()
my_class_table = Table('my_class',
metadata,
Column('id', Integer, primary_key=True),
Column('title', String(255), nullable=False))
mapper(MyClass, my_class_table)
my_objects = [MyClass('some title'), MyClass('another title'), MyClass('yet another title')]
save(my_objects, metadata)
Trong của riêng tôi (không mẫu), tôi nhập MyClass
từ mô-đun riêng của mình và thực hiện ánh xạ trong lớp 'kho lưu trữ đối tượng' riêng biệt tạo ra MetaData
trong phương pháp __init__(...)
và lưu trữ nó trong thành viên, do đó, save(...)
và load(...)
persiste phương pháp ncy có thể truy cập nó theo yêu cầu. Tất cả ứng dụng chính cần làm là tạo đối tượng kho lưu trữ ngay từ đầu; điều này chứa tác động của SQLAlchemy trên thiết kế đến một lớp, nhưng cũng phân phối đối tượng nghiệp vụ và các định nghĩa bảng được ánh xạ tới các vị trí riêng biệt trong mã. Không chắc chắn nếu tôi sẽ đi với điều đó lâu dài, nhưng nó có vẻ làm việc cho thời điểm này.
Gợi ý nhanh cuối cùng cho SQLAlchemy noobs giống như tôi: Bạn phải làm việc với một đối tượng siêu dữ liệu giống nhau, nếu không bạn sẽ nhận được ngoại lệ như no such table
hoặc class not mapped
.
Cảm ơn bạn rất nhiều vì đã giải thích. Tôi đã không nhận thức được một ORM sẽ áp đặt các hạn chế thiết kế mạnh mẽ như vậy trên ứng dụng muốn sử dụng nó. Bây giờ tôi chạy mã mapper trước bất cứ điều gì khác và làm việc với phiên bản cụ thể của các đối tượng kinh doanh của tôi trong suốt. Tôi chắc chắn hy vọng tất cả những hoops trả hết trong thời gian dài ... – ssc
Tôi thực sự không hiểu tại sao bạn đang càu nhàu. Sự bền bỉ của bất kỳ loại nào không phải là tầm thường và sẽ luôn yêu cầu thêm chức năng hoặc áp đặt một giao diện trên các đối tượng bền vững. Ngay cả sự bền bỉ nhất có thể, việc tẩy đơn giản, yêu cầu thêm [nhiều phương pháp ma thuật vào các đối tượng có thể chọn] (http://docs.python.org/library/pickle.html#pickle-protocol). Có thể cho rằng ánh xạ SQLAlchemy áp đặt * ít hơn * đối với các đối tượng kinh doanh hơn cả giao thức pickle! –
Ồ, tôi không có ý nói chuyện càu nhàu: Đây là lần đầu tiên tôi làm việc với SQLAlchemy và tôi đoán tôi đã ở dưới giả định rằng tôi có thể 'thêm vào' sự kiên trì cho các đối tượng của mình với ít nỗ lực hơn. .. – ssc