我建议您从 SQLAlchemy 文档的Object Relational Tutorial 部分开始,这将使您更好地理解实现的 OO 概念以及所表示的数据结构。它解释了工作单元(会话)、领域模型和各种类型的关系。如果您只需要阅读一页(尽管相当大),那就是它。
但为了让您入门,请参阅下面的独立运行代码,其中包含您的模型,包括多对多关系、插入、更新和删除数据。根据您的代码示例代码使用 Flask 和 Flask-SQLAlchemy。
另外,我真的会为您的模型对象和关系赋予其他名称:
A -> Category
AItem -> [Category]Item
ACollection -> [Item]Collection
A.a_items -> items (with backref *category*)
下面是代码,用SQLALCHEMY_ECHO 注释[out] 行,以便隐藏/查看已执行的SQL 语句。只需将其保存到某个 python 文件并运行它。
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
_db_uri = 'sqlite:///:memory:'
app.config['SQLALCHEMY_DATABASE_URI'] = _db_uri
app.config['SQLALCHEMY_ECHO'] = True # @TODO: uncomment to see SQL statements
db = SQLAlchemy(app)
# utility to make string representation of objects human-readable
def _repr(self):
from sqlalchemy.orm import class_mapper
attrs = class_mapper(self.__class__).column_attrs # only columns
# attrs = class_mapper(self.__class__).attrs # show also relationships
return u"<{}({})>".format(
self.__class__.__name__,
', '.join(
'%s=%r' % (k.key, getattr(self, k.key))
for k in sorted(attrs)
)
)
db.Model.__repr__ = _repr
# DEFINE THE MODEL
class A(db.Model):
__tablename__ = 'a'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
a_items = db.relationship('AItem', backref='a')
def get_item_by_name(self, item_name):
""" In memory search for the item of this class of given name. """
for item in self.a_items:
if item.name == item_name:
return item
class AItem(db.Model):
__tablename__ = 'a_items'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
A_id = db.Column(db.Integer, db.ForeignKey('a.id'))
# this table contains many-to-many relationship
t_collection_item = db.Table(
'a_collection_item', db.Model.metadata,
db.Column('a_items_id', db.Integer, db.ForeignKey('a_items.id'),
primary_key=True),
db.Column('a_collections_id', db.Integer, db.ForeignKey('a_collections.id'),
primary_key=True)
)
class ACollection(db.Model):
__tablename__ = 'a_collections'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64))
items = db.relationship(AItem,
secondary=t_collection_item,
backref='collections')
def test_model():
with app.app_context():
db.create_all()
# CREATE SOME TEST DATA
# create instance of *A*
colors = A(name='colors')
smells = A(name='smells')
# add some items to them
colors.a_items = [
AItem(name='red'),
AItem(name='green'),
AItem(name='blue'),
AItem(name='yellow'),
AItem(name='black'),
]
smells.a_items = [
AItem(name='superb'),
AItem(name='awful')
]
# this will insert into DB instance of *A* and all their dependents
db.session.add(colors)
db.session.add(smells)
db.session.commit()
# create some collections, but first find colors
red = colors.get_item_by_name('red')
green = colors.get_item_by_name('green')
blue = colors.get_item_by_name('blue')
black = colors.get_item_by_name('black')
yellow = colors.get_item_by_name('yellow')
# create a new one
white = AItem(name='white')
colors.a_items.append(white)
coll1 = ACollection(name='my favorites', items=[red, green, blue])
coll2 = ACollection(name='i hate these', items=[black, yellow])
db.session.add_all([white, coll1, coll2])
db.session.commit()
# SOME QUERIES
# get collections which has blue color
q = (db.session.query(ACollection)
.join(AItem, ACollection.items)
.filter(AItem.name == 'blue')
)
for coll in q.all():
print(coll)
for item in coll.items:
print(" {}".format(item))
# Now I hate blue, so lets remove it from my collection and rename it
mycol = db.session.query(ACollection)\
.filter(ACollection.name == 'my favorites').one()
mycol.name = 'my new favorites'
mycol.items.remove(blue)
db.session.commit()
assert 2 == len(mycol.items)
if __name__ == '__main__':
test_model()