我对两个表使用sqlalchemy联接表继承:User和Employee。 我实现了自己的“获取”方法,该方法使用Redis作为缓存将对象存储为泡菜,还实现了自己的序列化方法来创建json响应。当我获取腌制的User对象并尝试对其进行序列化时,会收到“实例未绑定到会话”的错误消息,因为查询返回的是Employee对象而不是User,并且serialize方法尝试查询诸如employee之类的关系属性。 team_id。我无法将对象合并到会话中,因为这是一项昂贵的操作,并且需要依靠我的缓存来提供响应。
我设置了要加载的关系,以便使该对象与所有关系值一起腌制并存储在缓存中(例如,变为Team表的employee.team)。 Employee.get方法及其序列化方法可以正常工作,但是当我尝试使用User.get方法时,由于多态身份,它返回Employee对象而不是User对象,并且由于用户的原因它不会加载Employee属性。表格不包含它们。 如果返回的对象类是Employee,则在序列化时它将尝试获取team属性并抛出erorr“实例未绑定到Session;属性刷新操作无法进行”,因为腌制的对象来自于User查询,但它没有。热情地加载Employee属性。
我的问题是,在查询User表时是否有一种获取User对象的方法,以便我的User.get方法使用它的对应序列化方法?或者,如果该对象在会话中不是持久性的,是否可以阻止该对象获取关系属性(例如employee.team)?
class User(db.Model):
__tablename__ = 'users'
# Basic user data
id = db.Column(db.GUID(), default=uuid.uuid4(), primary_key=True, autoincrement=False)
username = db.Column(db.String(20), index=True)
type_id = db.Column(db.Integer, db.ForeignKey('user_types.id'))
type = db.relationship('UserType', back_populates='users', lazy='subquery')
password = db.Column(db.String(40), default=None)
# Basic contact info
first_name = db.Column(db.String(60), index=True)
last_name = db.Column(db.String(60), index=True)
email = db.Column(db.String(128), index=True)
phone = db.Column(db.String(30), index=True, default=None)
# Personal info
birth_date = db.Column(db.Date(), index=True, default=None)
birth_city = db.Column(db.String(60), index=True, default=None)
rfc = db.Column(db.String(50), index=True, default=None)
curp = db.Column(db.String(30), index=True, default=None)
address_id = db.Column(db.Integer, db.ForeignKey('addresses.id'), default=None)
__mapper_args__ = {
'polymorphic_identity': 1,
'polymorphic_on': type_id
}
class UserType(db.Model):
"""
Create a UserType table
"""
__tablename__ = 'user_types'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(60), unique=True)
users = db.relationship('User', back_populates='type', lazy='select')
@property
def serialize(self):
return {
"id": self.id,
"name": self.name
}
def __repr__(self):
return f'<UserType: {self.id} - {self.name}>'
class Employee(User):
__tablename__ = 'employees'
# Basic employee data
id = db.Column(db.GUID(), db.ForeignKey('users.id'), default=uuid.uuid4(), primary_key=True, autoincrement=False)
# Operation info
goal = db.Column(db.Integer, db.CheckConstraint('goal>=0'), default=0)
team_id = db.Column(db.Integer, db.ForeignKey('teams.id'))
team = db.relationship('Team', back_populates='employees', lazy='subquery')
__mapper_args__ = {
'polymorphic_identity': 2
}
class Team(db.Model):
__tablename__ = 'teams'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(60), unique=True)
type = db.Column(db.String(30))
# eagerly load the team attribute
employees = db.relationship('Employee', back_populates='team', lazy='select')
def __repr__(self):
return '<Team: {}>'.format(self.name)
@classmethod
def list(cls, args):
cache_key = f'{cls.__name__}s:{build_key_from_arguments(**args)}'
cache = redis_db.get(cache_key)
if cache:
return None, cls.pickle_load(cache)
else:
query = cls.query.filter(
cls.visible == True
)
# More filters...
data = query.all()
redis_db.set(cache_key, pickle.dumps(data, protocol=pickle.HIGHEST_PROTOCOL) if data else REDIS_LIST_NONE)
return data
@property
def serialize(self):
obj = {
"id": str(self.id),
"username": self.username,
"type": self.type.serialize,
"status": self.status.serialize,
"role": self.role.serialize,
"first_name": self.first_name,
"last_name": self.last_name,
"email": self.email
}
return obj
@property
def serialize(self):
obj = {
"id": str(self.id),
"username": self.username,
"type": self.type.serialize,
"status": self.status.serialize,
"role": self.role.serialize,
"first_name": self.first_name,
"last_name": self.last_name,
"email": self.email
}
if self.team_id:
obj['team'] = self.team.serialize
return obj
当我执行以下操作时:
users = User.list({})
(用户是Employee对象的列表)
[user.serialize for user in users]
第一次进行实际查询时有效,但是第二次从Redis检索数据时,腌制的对象不在会话中,并引发“实例未绑定到会话;属性刷新操作无法继续”。
预期的输出将是序列化User对象的字典列表。
答案 0 :(得分:0)
我设法通过添加使它起作用
'polymorphic_load': 'inline'
到 mapper_args
中的Employee类