Wenn Sie mit dem Dekorator @declared_attr einen Index für die Klasse Human definieren, wird der Index an die unterste Klasse gesendet.
joint_ng.py
from sqlalchemy.ext.declarative import *
from sqlalchemy import *
from sqlalchemy_utils import database_exists, drop_database, create_database
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
class Human(object):
age = Column(Integer)
name = Column(String(50))
@declared_attr
def __table_args__(cls):
return(Index('index_name', 'name'),)
class Employee(Human, Base):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
type = Column(String(50))
__mapper_args__ = {
'polymorphic_identity':'employee',
'polymorphic_on':type
}
class Engineer(Employee):
__tablename__ = 'engineer'
id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
engineer_name = Column(String(30))
__mapper_args__ = {
'polymorphic_identity':'engineer',
}
__table_args__ = {
}
class Manager(Employee):
__tablename__ = 'manager'
id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
manager_name = Column(String(30))
__mapper_args__ = {
'polymorphic_identity':'manager',
}
__table_args__ = {
}
engine = create_engine('mysql://user:pass@localhost/dummy?charset=utf8')
if database_exists(engine.url):
drop_database(engine.url)
create_database(engine.url)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
m = Manager(age=10, name = 'foo', manager_name='hoge')
session.add(m)
session.commit()
Beim Indizieren der Namensspalte in einer Manager-Tabelle, die keine Namensspalte definiert, tritt ein Fehler auf.
Traceback (most recent call last):
File "joint.py", line 27, in <module>
class Engineer(Employee):
(Kürzung…)
File "/home/satosi/.pyenv/versions/3.6.1/lib/python3.5/site-packages/sqlalchemy/util/_collections.py", line 194, in __getitem__
return self._data[key]
KeyError: 'name'
Apropos, es scheint, dass die Situation nicht aus der Fehlermeldung verschluckt werden kann, und es hat einige Zeit gedauert, die Ursache einzugrenzen, also werde ich sie veröffentlichen.
Definieren Sie einfach table_args in der Manager-Klasse neu.
joint_ok.py
class Engineer(Employee):
__tablename__ = 'engineer'
id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
engineer_name = Column(String(30))
__mapper_args__ = {
'polymorphic_identity':'engineer',
}
__table_args__ = {
}
class Manager(Employee):
__tablename__ = 'manager'
id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
manager_name = Column(String(30))
__mapper_args__ = {
'polymorphic_identity':'manager',
}
__table_args__ = {
}
Ich möchte die Tabellendefinition und die Modelllogik separat schreiben.
Ich habe versucht, in der Reihenfolge deklarative_Base-> Klasse zu erben, die das Spaltenmitglied (Manager) -> Klasse der Anwendungsschicht (SubManager) angibt, aber der Typ, der der Schlüssel zum Polymorphismus ist, ist nicht angegeben.
joint_ng2.py
import sys
from sqlalchemy.ext.declarative import *
from sqlalchemy import *
from sqlalchemy_utils import database_exists, drop_database, create_database
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
class Employee(Base):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
type = Column(String(50))
__mapper_args__ = {
'polymorphic_identity':'employee',
'polymorphic_on':type
}
class Manager(Employee):
__tablename__ = 'manager'
id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
manager_name = Column(String(30))
__mapper_args__ = {
'polymorphic_identity':'manager',
}
__table_args__ = {
}
def shout(self):
print('Oh')
class SubManager(Manager):
def shout(self):
print('Wah')
engine = create_engine('mysql://user:pass@localhost/dummy?charset=utf8')
if database_exists(engine.url):
drop_database(engine.url)
create_database(engine.url)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
m = SubManager(manager_name='hoge')
m.shout()
session.add(m)
session.commit()
query = session.query(Manager)
print(query)
manager = query.first()
assert manager.type is None
manager.shout()
Ausgabe
Wah
SELECT manager.id AS manager_id, employee.id AS employee_id, employee.type AS employee_type, manager.manager_name AS manager_manager_name
FROM employee INNER JOIN manager ON employee.id = manager.id
Oh
Versuchen Sie also, @declared_attr anzugeben.
joint_ng2.py
class Manager(Employee):
(snip...)
@declared_attr
def __mapper_args__(cls):
return {
'polymorphic_identity':'manager',
}
Es hat funktioniert, aber ich wurde gewarnt, dass es sich um eine doppelte Definition handelt.
Ausgabe
/home/satosi/.pyenv/versions/3.6.1-mtxweb/lib/python3.5/site-packages/sqlalchemy/orm/mapper.py:1034: SAWarning: Reassigning polymorphic association for identity 'manager' from <Mapper at 0x7fb0202ed978; Manager> to <Mapper at 0x7fb0202edbe0; SubManager>: Check for duplicate use of 'manager' as value for polymorphic_identity.
self, self.polymorphic_identity)
Wah
SELECT manager.id AS manager_id, employee.id AS employee_id, employee.type AS employee_type, manager.manager_name AS manager_manager_name
FROM employee INNER JOIN manager ON employee.id = manager.id
Wah
Ändern Sie einfach die Reihenfolge der Vererbung. Solange zwischen der App-Ebene und dem abgeleiteten Typ der gemeinsamen Tabellenvererbung eine Eins-zu-Eins-Entsprechung besteht, sollte es keinen Unterschied in der Funktionalität geben.
joint_ok.py
from sqlalchemy.ext.declarative import *
from sqlalchemy import *
from sqlalchemy_utils import database_exists, drop_database, create_database
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
class _Manager():
def shout(self):
print('Oh')
class Employee(Base):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
type = Column(String(50))
__mapper_args__ = {
'polymorphic_identity':'employee',
'polymorphic_on':type
}
class Manager(Employee, _Manager):
__tablename__ = 'manager'
id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
manager_name = Column(String(30))
__mapper_args__ ={
'polymorphic_identity':'manager',
}
__table_args__ = {
}
def shout(self):
print('Wah')
engine = create_engine('mysql://user:pass@localhost/dummy?charset=utf8')
if database_exists(engine.url):
drop_database(engine.url)
create_database(engine.url)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
m = Manager(manager_name='hoge')
m.shout()
session.add(m)
session.commit()
query = session.query(Manager)
print(query)
manager = query.first()
assert manager.type is not None
manager.shout()
Ausgabe
Wah
SELECT manager.id AS manager_id, employee.id AS employee_id, employee.type AS employee_type, manager.manager_name AS manager_manager_name
FROM employee INNER JOIN manager ON employee.id = manager.id
Wah
Es war arm. Es wäre eine unerwartete Freude, wenn es jemandem helfen würde.
Recommended Posts