flask - flask wtforms sqlalchemy AttributeError:“str”对象没有属性“_sa_instance_state”
问题描述
我正在尝试在 sqlite 数据库中发送表单数据。有 6 个表,它们之间具有一对多和多对多的关系。
这是我的模型:
class Event(db.Model):
id = db.Column(db.String, default=lambda: uuid.uuid4().hex, primary_key=True)
name = db.Column(db.String(60), nullable=False)
date_created = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
activities = db.relationship('Activity', backref='event', lazy='dynamic')
participants = db.relationship('User', backref='event', lazy='dynamic')
globalweights = db.relationship('Globalw8', backref='event', lazy='dynamic')
relationship_table = db.Table('relationship_table', db.Column('user_id', db.Integer, db.ForeignKey('user.id'), nullable=False), db.Column('activity_id', db.Integer,db.ForeignKey('activity.id'),nullable=False), db.PrimaryKeyConstraint('user_id', 'activity_id'))
class Activity(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(60), nullable=False)
event_id = db.Column(db.Integer, db.ForeignKey('event.id'), nullable=False)
participants = db.relationship('User', secondary=relationship_table, backref='activity')
amounts = db.relationship('Amount', backref='activity', lazy='dynamic')
activityweights = db.relationship('Activityw8', backref='activity', lazy='dynamic')
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(60), nullable=False)
event_id = db.Column(db.Integer, db.ForeignKey('event.id'), nullable=False)
globalw8_id = db.Column(db.Integer, db.ForeignKey('globalw8.id'), nullable=False)
activityweights = db.relationship('Activityw8', backref='participant', lazy='dynamic')
amounts = db.relationship('Amount', backref='participant', lazy='dynamic')
class Amount(db.Model):
id = db.Column(db.Integer, primary_key=True)
amount = db.Column(db.Float, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
activity_id = db.Column(db.Integer, db.ForeignKey('activity.id'), nullable=False)
class Globalw8(db.Model):
id = db.Column(db.Integer, primary_key=True)
weight = db.Column(db.Float, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
event_id = db.Column(db.Integer, db.ForeignKey('event.id'), nullable=False)
class Activityw8(db.Model):
id = db.Column(db.Integer, primary_key=True)
weight = db.Column(db.Float, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
activity_id = db.Column(db.Integer, db.ForeignKey('activity.id'), nullable=False)
这是我的路线:
@app.route('/', methods=['GET', 'POST'])
def home():
form = eveForm()
if form.validate_on_submit():
activity = Activity(name=form.actName.data, event=form.eveName.data)
event = Event(name=form.eveName.data)
user = User(name=form.partName.data, event=form.eveName.data, globalw8=form.partGlobWeight.data, activity=form.actName.data)
globalw8 = Globalw8(weight=form.partGlobWeight.data, participant=form.partName.data, event=form.eveName.data)
amount = Amount(amount=form.amount.data, participant=form.partName.data, activity=form.actName.data)
activityw8 = Activityw8(weight=form.partActWeight.data, participant=form.partName.data, activity=form.actName.data)
db.session.add(activityw8)
db.session.add(activity)
db.session.add(event)
db.session.add(user)
db.session.add(globalw8)
db.session.add(amount)
db.session.commit()
当我提交表单时,我收到错误“AttributeError:'str' object has no attribute '_sa_instance_state'”
我怀疑这是由于我的路线以及我如何尝试收集表单数据,特别是与关系相关的数据 (例如 user = User(name=form.partName.data, event=form.eveName.data, globalw8= form.partGlobWeight.data, 活动=form.actName.data)
例如在上面的例子中,事件是一个反向引用,我没有找到影响它的东西,但是我做了什么,即form.eveName.data
提前致谢
编辑:这是追溯
Traceback (most recent call last):
File "C:\Users\xaray\Anaconda3\envs\Flask\lib\site-packages\flask\app.py", line 2309, in __call__
return self.wsgi_app(environ, start_response)
File "C:\Users\xaray\Anaconda3\envs\Flask\lib\site-packages\flask\app.py", line 2295, in wsgi_app
response = self.handle_exception(e)
File "C:\Users\xaray\Anaconda3\envs\Flask\lib\site-packages\flask\app.py", line 1741, in handle_exception
reraise(exc_type, exc_value, tb)
File "C:\Users\xaray\Anaconda3\envs\Flask\lib\site-packages\flask\_compat.py", line 35, in reraise
raise value
File "C:\Users\xaray\Anaconda3\envs\Flask\lib\site-packages\flask\app.py", line 2292, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\xaray\Anaconda3\envs\Flask\lib\site-packages\flask\app.py", line 1815, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Users\xaray\Anaconda3\envs\Flask\lib\site-packages\flask\app.py", line 1718, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "C:\Users\xaray\Anaconda3\envs\Flask\lib\site-packages\flask\_compat.py", line 35, in reraise
raise value
File "C:\Users\xaray\Anaconda3\envs\Flask\lib\site-packages\flask\app.py", line 1813, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\xaray\Anaconda3\envs\Flask\lib\site-packages\flask\app.py", line 1799, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "C:\Users\xaray\code\Flaskapps\cuentapp\app.py", line 70, in home
activity = Activity(name=form.actName.data, event=form.eveName.data)
File "<string>", line 4, in __init__
File "C:\Users\xaray\Anaconda3\envs\Flask\lib\site-packages\sqlalchemy\orm\state.py", line 441, in _initialize_instance
manager.dispatch.init_failure(self, args, kwargs)
File "C:\Users\xaray\Anaconda3\envs\Flask\lib\site-packages\sqlalchemy\util\langhelpers.py", line 68, in __exit__
compat.reraise(exc_type, exc_value, exc_tb)
File "C:\Users\xaray\Anaconda3\envs\Flask\lib\site-packages\sqlalchemy\util\compat.py", line 129, in reraise
raise value
File "C:\Users\xaray\Anaconda3\envs\Flask\lib\site-packages\sqlalchemy\orm\state.py", line 438, in _initialize_instance
return manager.original_init(*mixed[1:], **kwargs)
File "C:\Users\xaray\Anaconda3\envs\Flask\lib\site-packages\sqlalchemy\ext\declarative\base.py", line 836, in _declarative_constructor
setattr(self, k, kwargs[k])
File "C:\Users\xaray\Anaconda3\envs\Flask\lib\site-packages\sqlalchemy\orm\attributes.py", line 262, in __set__
instance_state(instance), instance_dict(instance), value, None
File "C:\Users\xaray\Anaconda3\envs\Flask\lib\site-packages\sqlalchemy\orm\attributes.py", line 975, in set
value = self.fire_replace_event(state, dict_, value, old, initiator)
File "C:\Users\xaray\Anaconda3\envs\Flask\lib\site-packages\sqlalchemy\orm\attributes.py", line 998, in fire_replace_event
state, value, previous, initiator or self._replace_token
File "C:\Users\xaray\Anaconda3\envs\Flask\lib\site-packages\sqlalchemy\orm\attributes.py", line 1407, in emit_backref_from_scalar_set_event
instance_state(child),
AttributeError: 'str' object has no attribute '_sa_instance_state'
解决方案
第一期
我认为您过度指定了关系(在 SQL 中,两个表可以相互引用吗?):
class User(db.Model):
# ...
globalw8_id = db.Column(db.Integer, db.ForeignKey('globalw8.id'), nullable=False)
class Globalw8(db.Model):
# ...
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
您可以将其替换为关系,从而只需要一个 FK 输入:
class User(db.Model):
# ...
globalw8 = db.relationship('GlobalW8', back_populates='user')
class Globalw8(db.Model):
# ...
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
user = db.relationship('GlobalW8', back_populates='globalw8')
现在,当您创建 SQLAlchemy 对象实体时,它们意味着它们在提交到数据库之前transient
不会从数据库中获取关联。id
但是您不能将它们提交到数据库,因为您将打破nullable=False
约束。因此,您需要添加它们,刷新数据库以“像提交但实际上不提交”,然后重新填充信息,然后提交:
例如。
new_user = User(..)
db.session.add(new_user)
db.session.flush()
new_globalw8 = Globalw8(.., user_id=new_user.id)
db.session.add(new_globalw8)
db.session.commit()
请注意,这可能会破坏某些固有的数据库完整性,将其从原始结构中更改出来,因此您可能需要进行试验。
第 2 期
这实际上是您的特定堆栈跟踪错误:
File "C:\Users\xaray\code\Flaskapps\cuentapp\app.py", line 70, in home
activity = Activity(name=form.actName.data, event=form.eveName.data)
..
**AttributeError: 'str' object has no attribute '_sa_instance_state'**
这是因为这条线:
activities = db.relationship('Activity', backref='event', lazy='dynamic')
然后Activity.event
期望成为一个SQLAlchemy Instance State
. 但是,您从表单中提供了一个字符串:form.eveName.data
,这是完全不兼容的。你真正应该做的是创建第Event
一个:
new_event = Event(name=form.eveName.data)
然后将其填充为活动的事件。
activity = Activity(name=form.actName.data, event=new_event)
请注意,如果您不刷新数据库(类似于上面),您可能会收到一个暂时性错误,但可能不会 - 我这样做已经有一段时间了。
推荐阅读
- django - 无法使用 AWS EC2 在 DJANGO 应用程序中加载静态文件
- c - “print_candidate”功能不起作用。这是逻辑错误吗?
- c# - 切换文档渲染器 - 无法在已刷新的页面上绘制元素
- ios - 我的视图在 SwiftUI 中不断渲染
- python - Pandas DataFrame 从其他 DataFrame 添加两列
- firebase - 我可以使用此快照调用访问文档 ID 吗?
- javascript - jQuery 背景随 id 变化
- swift - 什么是suppressesIncrementalRendering?
- android - 与许多设备的蓝牙连接
- intellij-idea - Intellij 本地历史“贴标签”有什么意义?