Sqlalchemy:构建一个包含来自另一个类的项集合的类

时间:2014-12-03 14:50:53

标签: oop python-2.7 sqlalchemy flask-sqlalchemy

我有以下三个类:

  1. A
  2. AItem
  3. ACollection
  4. 用户可以添加无限量的对象作为class A的一部分。从A继承的每个对象都可以在class AItem中添加无限量的对象。然后,用户可以根据需要制作这些项目的集合或组合。这些集合仅适用于属于AItem A colors = A red = AI(colors) green = AI(colors) blue = AI(colors) yellow = AI(colors) black = AI(colors) brown = AI(colors) white = AI(colors) Collection_1 = [red, green, blue] Collection_2 = [brown, black] Collection_3 = [red, brown, yellow] 的项目。请注意,并非A中的每个对象都必须具有集合,并且项目可以出现在多个集合中。

    示例:

    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')
    
    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'))
    
    class ACollection(db.model):
        __tablename__ = 'a_collections'
        id = db.Column(db.Integer, primary_key=True)
    

    我的代码到目前为止:

    ACollection

    我的问题:

    如何构建{{1}}类?另外,请随意“重新设计”或重新考虑我的任何代码。

2 个答案:

答案 0 :(得分:3)

我建议您从SQLAlchemy文档的Object Relational Tutorial部分开始,这将使您能够更好地理解所实现的OO概念以及所表示的数据结构。它解释了工作单元(会话),域模型和各种类型的关系。如果你只需要阅读一个页面(虽然非常大),这就是它。

但是为了让您入门,请参阅下面的自包含和运行代码,其中包含您的模型,包括多对多关系,插入,更新和删除数据。根据您的代码示例代码使用Flask和Flask-SQLAlchemy。

另外,我真的会给你的模型对象和关系提供其他名称:

A           -> Category
AItem       -> [Category]Item
ACollection -> [Item]Collection
A.a_items   -> items (with backref *category*)

下面是代码,注释[out] SQLALCHEMY_ECHO行以隐藏/查看已执行的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()

答案 1 :(得分:1)

您是否想要了解如何构建数据或类的建议?由于我不确定,我会给你们两个。

数据:

从数据的角度来看,我建议您在表a_items_collectionsa_items之间创建一个表a_collections,因为您有一个N到N的关系(一个集合可以有很多项目,一个项目可以属于许多集合)。因此,a_items_collections的每一行都会在项目和集合之间建立链接。

<强> OOP:

从OOP的角度来看,您可以定义数据类。您可以在AItem中设置ACollection数组,您可以使用表a_items_collections的另一个集合,...您当然应该使用ORM来帮助您这样做。我不是Python的专家,所以我在这里帮不了多少。另外,我强烈建议您使用SOA(面向服务的体系结构)模式将业务类与数据类分开。更清楚的是,数据库的数据类镜像应该只包含属性,操作这些数据的智能应该在其他类中实现(通常实现为singleton)。如果您必须以与商品相同的方式操纵收藏品,则可以查看composite模式。