2016-07-13 2 views
1

TLDR; проблема заключалась в построении наследования, которое я неловко не знал, как сделать без декларативного API.Ввод экземпляра подкласса в SQLAlchemy

Я сделал общую модель Job, которая будет дополнительно сужаться подклассами, такими как DeploymentJob. Каждый Job состоит из нескольких Actions. Если я определяю это отношение Job<->Action, я не могу использовать его в Job экземплярах подкласса.

from sqlalchemy import (Table, Binary, Column as C, String, Integer, 
         ForeignKey, create_engine, MetaData) 
from sqlalchemy.orm import (mapper, relationship, backref, scoped_session, 
          sessionmaker) 


metadata = MetaData() 
db_engine = create_engine('sqlite:////tmp/test.db', convert_unicode=True) 
db_session = scoped_session(sessionmaker(bind=db_engine)) 

class Job(object): 
    pass 

class DeploymentJob(Job): 
    def __init__(self, *args, **kwargs): 
     super(DeploymentJob, self).__init__(*args, **kwargs) 

class Action(object): 
    def __init__(self, unit, job): 
     self.unit = unit 
     self.job = job 

jobs = Table('jobs', metadata, 
      C('id', Integer, primary_key=True), 
      C('type', String, nullable=False) 
) 

deployment_jobs = Table('deployment_jobs', metadata, 
         C('id', ForeignKey('jobs.id'), primary_key=True) 
) 

actions = Table('actions', metadata, 
       C('job_id', ForeignKey('jobs.id'), primary_key=True), 
       C('unit', String, primary_key=True) 
) 

mapper(Job, 
     jobs, 
     polymorphic_on=jobs.c.type, 
     properties = { 
      'actions': relationship(Action, lazy='dynamic', uselist=True, 
            backref=backref('job', uselist=False)), 
    } 
) 

mapper(DeploymentJob, deployment_jobs, polymorphic_identity='deployment') 

mapper(Action, actions) 


metadata.create_all(bind=db_engine) 
unit = 'second-machine' 
job = DeploymentJob() 
action = Action(unit, job) 

print "action.job -> %s is job: %s" % (action.job, isinstance(action.job, Job)) 
# >> action.job -> <__main__.DeploymentJob object at 0x7fe> is job: True 

db_session.add(action) 
db_session.add(job) 

db_session.commit() 

Я ожидаю, что DevelopmentJob принимаются в качестве Job инстанции, но эта ассоциация не будет сделана:

AssertionError: Attribute 'job' on class '<class '__main__.Action'>' doesn't handle objects of type '<class '__main__.DeploymentJob'>' 

ответ

0

Проблема Mapper не будет считать DeploymentJob, как ребенок Job до картографа объекта Job предоставленного mapper объект DeploymentJob как inherit аргумент. Так что это работает:

JobsMapping = mapper(Job, 
     jobs, 
     polymorphic_on=jobs.c.type, 
     properties = { 
      'actions': relationship(Action, lazy='dynamic', uselist=True, 
            backref=backref('job', uselist=False)), 
    } 
) 

mapper(DeploymentJob, deployment_jobs, inherits=JobsMapping, polymorphic_identity='deployment') 
Смежные вопросы