2015-10-16 2 views
2

J'ai une application Python Flask en utilisant flask.ext.sqlalchemy et apscheduler.schedulers.background. J'ai créé un JobStore et obtenu une table appelée apscheduler_jobs est a les champs suivants:Comment associer APScheduler JobStore avec SQLAlchemy Models (clé étrangère) - Python Flask

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

Je veux raconter un objet modèle SQLAlchemy à cette table en utilisant quelque chose comme ceci:

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') 

Alors Je veux utiliser la table à partir de APScheduler apscheduler_jobs, puis l'associer à une clé étrangère à mon objet Event. Cette dernière ligne, il y aura essentiellement briser comme « planificateur » n'est pas un modèle SQLAlchmey défini

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. 

Je pense que je besoin d'une classe modèle inbetween appelé « travail » ou quelque chose, se rapportent alors que pour apscheduler_jobs, mais quelque chose Je me sens toujours mal - parce qu'APScheduler fait cette table, je n'ai aucun contrôle sur ce qui se passe là-bas - devrais-je m'inquiéter à ce sujet?

EDIT1: Je créé 2 modèles, un "événement" puis un "Job", le "Job" se rapporte alors à la table 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')) 
problème

il est que quand je laissai tomber la DB et recréé il a jeté l'erreur:

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'

maintenant, je pouvais contourner cela dans mon script de création de base de données, mais encore une fois il se sent encore comme je suis doi ng ce dans le mauvais sens

EDIT2 j'ai réussi à le faire fonctionner, bien que cela se sent assez mal, j'ai maintenant 3 modèles: l'événement, l'emploi et APSchedulerJobsTable. Le modèle final correspond essentiellement à ce à quoi ressemble l'APScheduler apscheduler_jobs. Il doit y avoir une meilleure façon de faire cela.

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) 

Répondre

1

Ok, deux solutions - ni vraiment parfait OMI:

Solution Un, probablement plus propre - ont tout simplement un champ de texte dans la table de travail qui contient aspscheduler_job_ids - ce n'est pas une clé étrangère si mais une fois que l'ID aspscheduler_job est connu, il est possible d'aller de l'avant et le stocker dans la table de travail pour référence ultérieure

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) 

Catch pour celui-ci est pour vous laisser tomber le plein db vous devez exécuter e est d'inclure laisser tomber la table non géré apscheduler_jobs:

db.reflect() 
db.drop_all() 

Solution Deux, ajoutez la table apscheduler au modèle lui-même, puis mis en place la clé étrangère:

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')