Flask SQL Alchemy listens_for装饰器

时间:2018-07-23 09:01:23

标签: python-3.x flask sqlalchemy flask-sqlalchemy flask-migrate

我正在尝试在Flask中创建待办事项列表应用程序。我在Python方面有丰富的经验,但是对于Flask框架来说还是一个新手。

我有3个模型-用户,任务和项目,我希望有一个名为Inbox的默认项目,每个用户甚至在自己创建任何项目之前都拥有该默认项目。

用户和项目通过多对多关系关联。

我为此所做的尝试是在创建名为Inbox的新项目的函数上使用以下修饰符。

@event.listens_for(Project.__table__, 'after_create')
def create_inbox(*args, **kwargs):
    inbox = Project(name='Inbox')
    db.session.add(inbox)
    db.session.commit()

然后,当我创建新用户时,我会在__init__函数中将“收件箱”项目添加到他们的项目中。

这是一个仅用于在User和Project之间建立多对多关系的类:

class UserProject(UserMixin, db.Model):
    __tablename__ = 'userprojects'
    project_id = db.Column(db.Integer, db.ForeignKey('projects.id'), primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True)

这里是Project模型和装饰器,用于监听表的创建:

class Project(UserMixin, db.Model):
    __tablename__ = 'projects'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32))
    tasks = db.relationship('Task', backref='project', lazy='dynamic') # one project has many tasks
    users = db.relationship('User', secondary='userprojects', lazy='dynamic', backref=db.backref('user', lazy='dynamic'))

@event.listens_for(Project.__table__, 'after_create')
def create_inbox(*args, **kwargs):
    inbox = Project(name='Inbox')
    db.session.add(inbox)
    db.session.commit()

这是用户模型:

class User(UserMixin, db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=True )
    email = db.Column(db.String(120), unique=True, nullable=True)
    password_hash = db.Column(db.String(128))
    tasks = db.relationship('Task', backref='author', lazy='dynamic') # one user has many tasks
    projects = db.relationship('Project', secondary='userprojects', lazy='dynamic', backref=db.backref('project', lazy='dynamic'))

    def __init__(self, **kwargs):
        super(User, self).__init__(**kwargs)
        p = Project.query.first()
        if p not in self.projects.all():
            self.projects.append(p)

也有一个任务模型,但由于它与问题无关,因此此处未将其包括在内。

出现的问题是当我尝试使用迁移和升级时。我执行flask db初始化,迁移和升级并获得以下输出,因此看起来一切正常,并且迁移文件看起来还不错。

flask db init

Creating directory /Users/Jasmine/projects/flask/tasky/migrations ... done
Creating directory /Users/Jasmine/projects/flask/tasky/migrations/versions ... done
Generating /Users/Jasmine/projects/flask/tasky/migrations/script.py.mako ... done
Generating /Users/Jasmine/projects/flask/tasky/migrations/env.py ... done
Generating /Users/Jasmine/projects/flask/tasky/migrations/README ... done
Generating /Users/Jasmine/projects/flask/tasky/migrations/alembic.ini ... done
Please edit configuration/connection/logging settings in '/Users/Jasmine/projects/flask/tasky/migrations/alembic.ini' before proceeding.

flask db migrate

INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.autogenerate.compare] Detected added table 'projects'
INFO  [alembic.autogenerate.compare] Detected added table 'users'
INFO  [alembic.autogenerate.compare] Detected added table 'tasks'
INFO  [alembic.autogenerate.compare] Detected added index 'ix_tasks_due' on '['due']'
INFO  [alembic.autogenerate.compare] Detected added table 'userprojects'
Generating /Users/Jasmine/projects/flask/tasky/migrations/versions/64311763e16f_creating_the_tables.py ... done

flask db upgrade
INFO  [alembic.runtime.migration] Context impl SQLiteImpl.
INFO  [alembic.runtime.migration] Will assume non-transactional DDL.
INFO  [alembic.runtime.migration] Running upgrade  -> 64311763e16f, creating the tables

但是,当我进入flask shell并键入Project.query.all()时,会得到一个空列表,希望其中包含一个项目的列表-一个名为“收件箱”的项目。

我不确定错误在哪里,因此对此的任何建议将不胜感激。

1 个答案:

答案 0 :(得分:0)

我经常看到有两种不同的方法来处理数据库中初始数据的创建,我想您想到了第三种。

一个选项是创建一个脚本(或flask命令的自定义扩展名),将所有初始值添加到数据库中。例如,完成flask db upgrade后,可以进行flask db initdb添加该收件箱项目。您可以通过多次运行此initdb函数的方式编写此函数,并且该函数只会添加缺少的内容,而不会创建重复项。

另一个选择是编辑迁移脚本以包括添加此数据。 Alembic提供了可用于此目的的execute()bulk_insert()操作。因此,在运行flask db migrate之后,您可以在编辑器中打开迁移脚本并进行手工编辑以包括收件箱条目的创建。仅在进行了这些更改之后,才运行flask db upgrade

我认为您的解决方案有点过大。您正在设置一个事件观察器,以便在应用程序安装的整个生命周期中都会发生一次。考虑到该事件处理程序将在应用程序运行期间处于活动状态,即使在运行时根本不需要它也是如此。我建议您改用以上两种直接方法之一。