flask wtforms sqlalchemy AttributeError:“str”对象没有属性“_sa_instance_state”

Posted

技术标签:

【中文标题】flask wtforms sqlalchemy AttributeError:“str”对象没有属性“_sa_instance_state”【英文标题】:flask wtforms sqlalchemy AttributeError: 'str' object has no attribute '_sa_instance_state' 【发布时间】:2019-04-05 13:39:41 【问题描述】:

我正在尝试在 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, activity=form.actName.data)

例如在上面的示例中,event 是一个反向引用,我没有找到影响它的地方,但我已经做了什么,即 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'

【问题讨论】:

请告知这个错误发生在哪个变量上。错误线索的完整副本会更好。 我刚刚用回溯编辑了我的帖子;如果我理解正确,它看起来与 activity = Activity(name=form.actName.data, event=form.eveName.data) 有关 你可以试试这里应用的解决方案***.com/questions/33083772/… 好吧,我已经尝试了所有可以在 *** 或 youtube 上找到的似乎与我的问题相关的教程,但到目前为止没有任何效果。不管怎么说,还是要谢谢你。事实上,我想我很想听听处理过 sqlalchemy 多对多关系 + wtforms 的人的意见,看看他们的代码是什么样的。 【参考方案1】:

问题 1

我认为你过度指定了关系 (In SQL, is it OK for two tables to refer to each other?):

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)

请注意,如果您不刷新数据库(类似于上述),您可能会遇到暂时性错误,但可能不会——我已经有一段时间没有这样做了

【讨论】:

以上是关于flask wtforms sqlalchemy AttributeError:“str”对象没有属性“_sa_instance_state”的主要内容,如果未能解决你的问题,请参考以下文章

Flask-Session SQLAlchemy Script Migrate wtforms

Flask-Session SQLAlchemy Script Migrate wtforms

flask wtforms sqlalchemy AttributeError:“str”对象没有属性“_sa_instance_state”

Flask 插件学习:Flask-WTF 和 WTForms 扩展

Flask-WTF进阶和WTForms扩展

Python 都有哪些好的 Web 框架