如何将APScheduler JobStore与SQLAlchemy Models(外键)联系起来 - Python Flask

时间:2015-10-16 22:43:52

标签: python flask sqlalchemy flask-sqlalchemy apscheduler

我使用flask.ext.sqlalchemyapscheduler.schedulers.background获得了一个Python Flask应用。我创建了一个JobStore并得到一个名为apscheduler_jobs的表,其中包含以下字段:

|id  |next_run_time|job_state|
------------------------------
|TEXT|   REAL      |  TEXT   |

我想使用类似这样的东西将SQLAlchemy Model对象与该表相关联:

from apscheduler.schedulers.background import BackgroundScheduler
scheduler = BackgroundScheduler()
scheduler.add_jobstore('sqlalchemy', url=app.config['SQLALCHEMY_DATABASE_URI'])

class Event(db.Model):

    __tablename__ = "event"

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(255), nullable=False)
    jobs = db.relationship('scheduler', backref='apscheduler_jobs')

所以我想使用APScheduler apscheduler_jobs中的表,然后将它与外键关联到我的Event对象。由于“scheduler”不是定义的SQLAlchmey模型

,因此最后一行基本上会中断
qlalchemy.exc.InvalidRequestError: When initializing mapper Mapper|Event|event, expression 'scheduler' failed to locate a name ("name 'scheduler' is not defined"). If this is a class name, consider adding this relationship() to the <class 'project.models.Event'> class after both dependent classes have been defined.

所以我想我需要一个名为“job”之类的inbetween Model类,然后把它与apscheduler_jobs联系起来,但是这里的东西仍然感觉很糟糕 - 因为APScheduler正在制作这张桌子我无法控制那里发生了什么 - 我应该关注那个吗?

EDIT1: 所以我创建了2个模型,一个是“事件”,然后是一个“作业”,“作业”则与表apscheduler_jobs

相关
class Job(db.Model):

    __tablename__ = "job"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(255), nullable=False)
    apscheduler_job_id = db.Column(db.Integer, db.ForeignKey('apscheduler_jobs.id'))
    event_id = db.Column(db.Integer, db.ForeignKey('event.id'))

问题是,当我删除数据库并重新创建它时,它会抛出错误:

sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'job.apscheduler_job_id' could not find table 'apscheduler_jobs' with which to generate a foreign key to target column 'id'

现在我可以在我的数据库创建脚本中解决这个问题,但是我仍然觉得我这样做是错误的

EDIT2 我设法让它工作,虽然这感觉非常错误,我现在有3个模型:Event,Job和APSchedulerJobsTable。最终模型基本上与APScheduler apscheduler_jobs的外观相匹配。必须有更好的方法来做到这一点。

from project import db


class Event(db.Model):

    __tablename__ = "event"

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(255), nullable=False)
    jobs = db.relationship('Job', backref='job_event')


class Job(db.Model):

    __tablename__ = "job"

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    apscheduler_job_id = db.Column(db.TEXT, db.ForeignKey('apscheduler_jobs.id'))
    event_id = db.Column(db.Integer, db.ForeignKey('event.id'))


class APSchedulerJobsTable(db.Model):
    # TODO: This feels bad man
    __tablename__ = "apscheduler_jobs"

    id = db.Column(db.TEXT, primary_key=True, autoincrement=True)
    next_run_time = db.Column(db.REAL)
    job_state = db.Column(db.TEXT)

1 个答案:

答案 0 :(得分:1)

好的,两个解决方案 - 既不是真正完美的IMO:

解决方案一个,可能更干净 - 只是在作业表中有一个包含aspscheduler_job_ids的文本字段 - 虽然这不是外键但是一旦知道了aspscheduler_job ID就可以了继续将其存储在作业表中供以后参考

class Event(db.Model):

    __tablename__ = "event"

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(255), nullable=False)
    jobs = db.relationship('Job', backref='job_event')


class Job(db.Model):

    __tablename__ = "job"

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    event_id = db.Column(db.Integer, db.ForeignKey('event.id'))
    apscheduler_job_id = db.Column(db.TEXT)

抓住这一个是为了删除完整的数据库,你需要运行它以包括删除非托管表apscheduler_jobs

db.reflect()
db.drop_all()

解决方案二,将apscheduler表添加到模型本身,然后设置外键:

class Event(db.Model):

    __tablename__ = "event"

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(255), nullable=False)
    jobs = db.relationship('Job', backref='job_event')


class Job(db.Model):

    __tablename__ = "job"

    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    event_id = db.Column(db.Integer, db.ForeignKey('event.id'))
    apscheduler_job_id = db.Column(db.TEXT, db.ForeignKey('apscheduler_jobs.id'))


class APSchedulerJobsTable(db.Model):
    # TODO: This feels bad man
    __tablename__ = "apscheduler_jobs"

    id = db.Column(db.TEXT, primary_key=True, autoincrement=True)
    next_run_time = db.Column(db.REAL)
    job_state = db.Column(db.TEXT)
    job = db.relationship('Job', backref='job_event')