SQLALCHEMY:如何在flask_sqlalchemy-SQLalchemy中使用@ events.listens_for

时间:2016-12-20 18:32:36

标签: python sqlalchemy flask-sqlalchemy

我需要一些帮助来自动化sqlalchemy中的一些任务。 当新用户在我的网站上注册时,我需要添加5个人员。

我想使用sqlalchemy events,因为如果我可以使用它,它将在以后为其他自动化派上用场。

我正在关注Miguel Grinberg先生关于如何制作烧瓶的教程 application 并定义我的模型(db.Model not Base)

我读到要使用@event.listens_for(User.__table__, "after_insert")我必须使用声明性基础。有没有解决的办法?我的模型结构涉及近15个表格!

  class User(db.Model):
        __tablename__ = "user"
        id = db.Column(db.Integer, primary_key=True, autoincrement=True)
        email = db.Column(db.String(64), unique=True, index=True)
        username = db.Column(db.String(64), unique=True, index=True)
        password_hash = db.Column(db.String(128))
        store = db.relationship('Store', uselist=False, backref="user")



@event.listens_for(User.__table__, "after_insert")
def add_personnel(*args, **kwargs):
    for i in range(5):
        db.session.add(Personnel,store_id = User.query.last().id)
    db.session.commit()
    return None

class Personnel(db.Model):
    __tablename__ = "personnel"
    id = db.Column(db.Integer, primary_key=True)
    store_id = db.Column(db.Integer, db.ForeignKey('store.id'))
    first_name = db.Column(db.String(64))
    last_name = db.Column(db.String(64))
    username = db.Column(db.String(64))
    cell_phone = db.Column(db.Integer)
    pin_number = db.Column(db.Integer)
    email = db.Column(db.String(64))
    orders = db.relationship("Order", backref='personnel', lazy='dynamic')

**TRACEBACK**



    Traceback (most recent 
    call last):
      File "manage.py", line 3, in <module>
        from app.models import User
      File "/home/#######/PycharmProjects/#######/app/models.py", line 62, in <module>
        @event.listens_for(User.__table__, "after_insert")
      File "/home/#######/PycharmProjects/#######//venv/local/lib/python2.7/site-packages/sqlalchemy/event/api.py", line 124, in decorate
        listen(target, identifier, fn, *args, **kw)
      File "/home/#######/PycharmProjects/#######/venv/local/lib/python2.7/site-packages/sqlalchemy/event/api.py", line 89, in listen
        _event_key(target, identifier, fn).listen(*args, **kw)
      File "/home/#######/PycharmProjects/#######/venv/local/lib/python2.7/site-packages/sqlalchemy/event/registry.py", line 194, in listen
        dispatch_collection = getattr(target.dispatch, identifier)
      File "/home/#######/PycharmProjects/#######/venv/local/lib/python2.7/site-packages/sqlalchemy/event/base.py", line 95, in __getattr__
        raise AttributeError(name)
    AttributeError: after_insert

3 个答案:

答案 0 :(得分:0)

您实际上可以执行此操作,只需按this answer中所述键入@event.listens_for(User, "after_insert")即可。

请注意,您需要使用SQLAlchemy Connection而不是您在示例事件中使用的会话。检查this answer,它有很好的处理数据库插入的例子。

答案 1 :(得分:0)

我明白了。这里有两种型号。两者都继承db.Model。将数据插入InventoryContents我运行下面定义的事件。现在,如果这不是100%正确使用@db.event.listens_for我道歉。但是现在它按预期工作。

class MenuContentOrderEntry(db.Model):
    __tablename__ = "menu_content_order_entry"
    id = db.Column(db.Integer, primary_key=True)

    store_id = db.Column(db.Integer, db.ForeignKey('store.id'))
    order_id = db.Column(db.Integer, db.ForeignKey('order.id'))
    checkout_id = db.Column(db.Integer, db.ForeignKey('checkout.id'), default=None)

    menu_item_content_id = db.Column(db.Integer, db.ForeignKey('menu_item_content.id'))
    menu_item_id = db.Column(db.Integer, db.ForeignKey('menu_item.id'))
    # Todo 24/3/2017 - add name to the contents in case a user deletes it.
    content_name = db.Column(db.String(64), default=None)

    menu_item_order_id = db.Column(db.Integer, db.ForeignKey('menu_item_order_entry.id'))

    # this indicates whether we will print the order or not.
    # ignore: 0, print: 1, do not print:2
    print_on_pos = db.Column(db.Integer, default=0)

    datetime = db.Column(db.String(64), default=func.now(), nullable=False)

    # help full columns for inventory
    quantity = db.Column(db.Integer, default=0)
    default = db.Column(db.Integer, default=None)
    changed = db.Column(db.Integer, default=None)

class InventoryContents(db.Model):
    """

    This model will show the inventory changes made. Purchases and in-store consumption.
    A payee can be a waiter (in-store) or a supplier.

    """

    # Todo 14/2/2017 - add some sort of order_date and received_date.

    id = db.Column(db.Integer, primary_key=True)
    store_id = db.Column(db.Integer, db.ForeignKey('store.id'))
    order_id = db.Column(db.Integer, db.ForeignKey('order.id'))

    # if an item belongs to a checkout id then it was consumed and money was collected for it.
    checkout_id = db.Column(db.Integer, db.ForeignKey('checkout.id'), default=None)

    name = db.Column(db.String(64))

    datetime = db.Column(db.String(64))  # Todo 14/2/2017 - convert to datetime

    payee = db.Column(db.String(64))

    units = db.Column(db.String(64))  # [-], kg, L, ml

    cost = db.Column(db.Float)  # per unit

    quantity = db.Column(db.Float)  # per unit

    revenue = db.Column(db.Float)


@db.event.listens_for(MenuContentOrderEntry, "after_insert")
def add_content_to_inventory_contents(mapper, connection, target):
    inv = InventoryContents.__table__
    content = MenuItemContent.query.filter_by(id=target.menu_item_content_id).first()
    order = Order.query.filter_by(id=target.order_id).first()
    waiter_id = order.personnel_id
    date_time = order.datetime
    waiter_username = Personnel.query.filter_by(id=waiter_id).first().username
    content_name = content.name


    menu_association = MenuAssociation.query.filter_by(
        menu_content_id=target.menu_item_content_id,
        menu_item_id=target.menu_item_id).first()

    default = target.default
    changed = target.changed

    flag = False
    if (default == 1) and (changed == 1):
        flag = False
    elif (default == 0) and (changed == 0):
        flag = False
    elif (default == 1) and (changed == 0):
        flag = True
    elif (default == 0) and (changed == 1):
        flag = True
    else:
        pass
    print(flag)
    if not flag:
        pass
    else:
        # Todo 24/3/2017 - add those that are used.
        connection.execute(inv.insert().values(store_id=target.store_id,
                                               name=content_name,
                                               order_id=target.order_id,
                                               payee=waiter_username,
                                               datetime=date_time,
                                               cost=menu_association.cost,
                                               quantity=target.quantity))

答案 2 :(得分:0)

我使用参数中的连接就像这样工作。

@db.event.listens_for(Order, "after_insert")
def insert_order_to_printer(mapper, connection, target):
    po = PrinterOrder.__table__
    connection.execute(po.insert().values(store_id=target.store_id, order_id=target.id, scenario=target.order_type))

订单是:

class Order(db.Model):
    #stuff