Flask / SQLAlchemy:不兼容的集合类型:None不类似于列表

时间:2018-10-13 19:27:10

标签: python sqlalchemy flask-sqlalchemy

我很困惑。怎么了?

我有两个模型,以及多对一关系。

我创建了Boss_add表单,用于将老板添加到数据库中。 但是,没有任何效果!

我的模特:

class User(UserMixin, db.Model):
  __tablename__ = 'users'

  id = db.Column(db.Integer, primary_key=True)
  username = db.Column(db.String(20), unique=True, nullable=False)
  boss_id = db.Column(db.Integer, db.ForeignKey('boss.id'))
  boss = db.relationship('Boss', back_populates='users')

class Boss(db.Model):
  __tablename__ = 'boss'

  id = db.Column(db.Integer, primary_key=True)
  short_name = db.Column(db.String(64))
  users = db.relationship('User', back_populates='boss')

我的表单:

from flask_wtf import FlaskForm
from wtforms import IntegerField, StringField, PasswordField, BooleanField, SubmitField, DateField
from wtforms.validators import ValidationError, DataRequired, Email, EqualTo
from wtforms.ext.sqlalchemy.fields import QuerySelectField, QuerySelectMultipleField
from app.models import User, Boss

class Boss_add(FlaskForm):
  short_name = StringField('Short name', validators=[DataRequired()])
  users = QuerySelectMultipleField('Users', query_factory=lambda: db.session.query(User), get_pk=lambda a: a.id, get_label=lambda a: a.username, allow_blank=True)
  button = SubmitField('Add')

我的观点:

@app.route('/boss_add/', methods=['GET', 'POST'])
@login_required
def boss_add():
  form = Boss_add()
  if request.method == 'POST' and form.validate():
    print("FIRST PRINT: ", type(form.users.data))   # DEBUG PRING 1
    print("SECOND PRINT: ", form.data)              # DEBUG PRING 2
    boss = Boss(short_name=form.short_name.data,
                users=form.users.data)
    db.session.add(boss)
    db.session.commit()
  return render_template('boss_edit.html', form=form)

我的模板:

<html><head><title>Boss add</title></head>
<body>
    <form action="" method="post" novalidate>
        {{ form.hidden_tag() }}
<p>
            {{ form.short_name.label }}<br>
            {{ form.short_name }}
        </p>
        <p>
            {{ form.users.label }}<br>
            {{ form.users }}
        </p>
        <p>{{ form.button() }}</p>
</form>
</body></html>

调试打印:

如果我在列表中选择用户

FIRST PRINT: <class 'list'>
SECOND PRINT: {'short_name': '1111', 'users': [<User 1>], 'button': True, 'csrf_token': 'IjYxNDFhYzYyOGNlMGMzYTliNGYxOTA2NDYxYmE1ZDZkZmVjMjVkNDUi.DqPGxg.63Z-bKn8dgRGLNLxgMLUEzKMa15'}

如果我没有在列表中选择用户

FIRST PRINT: <class 'list'>
SECOND PRINT: {'short_name': '1111', 'users': [], 'button': True, 'csrf_token': 'IjYxNDFhYzYyOGNlMGMzYTliNGYxOTA2NDYxYmE1ZDZkZmVjMjVkNDUi.DqPGxg.63Z-bKn8dgRGLNLxgMLUEzKMa15'}

TypeError:不兼容的集合类型:None不类似于列表

这怎么可能?类型:列表,但错误:无。

如果这很重要,我的图书馆:

alembic          1.0.0  
Click            7.0    
Flask            1.0.2  
Flask-Login      0.4.1  
Flask-Migrate    2.2.1  
Flask-SQLAlchemy 2.3.2  
Flask-WTF        0.14.2 
itsdangerous     0.24   
jdcal            1.4    
Jinja2           2.10   
Mako             1.0.7  
MarkupSafe       1.0    
pip              18.1   
pkg-resources    0.0.0  
python-dateutil  2.7.3  
python-editor    1.0.3  
setuptools       40.4.3 
six              1.11.0 
SQLAlchemy       1.2.12 
Werkzeug         0.14.1 
wheel            0.32.1 
WTForms          2.2.1  

跟踪:

Traceback (most recent call last):
  File "/lib/python3.7/site-packages/flask/app.py", line 2292, in wsgi_app
    response = self.full_dispatch_request()
  File "/lib/python3.7/site-packages/flask/app.py", line 1815, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/lib/python3.7/site-packages/flask/app.py", line 1718, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/lib/python3.7/site-packages/flask/_compat.py", line 35, in reraise
    raise value
  File "/lib/python3.7/site-packages/flask/app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
  File "/lib/python3.7/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/lib/python3.7/site-packages/flask_login/utils.py", line 261, in decorated_view
    return func(*args, **kwargs)
  File "/src/app/routes.py", line 313, in client_add
    users=form.users.data)
  File "<string>", line 4, in __init__
  File "/lib/python3.7/site-packages/sqlalchemy/orm/state.py", line 424, in _initialize_instance
    manager.dispatch.init_failure(self, args, kwargs)
  File "/lib/python3.7/site-packages/sqlalchemy/util/langhelpers.py", line 66, in __exit__
    compat.reraise(exc_type, exc_value, exc_tb)
  File "/lib/python3.7/site-packages/sqlalchemy/util/compat.py", line 249, in reraise
    raise value
  File "/lib/python3.7/site-packages/sqlalchemy/orm/state.py", line 421, in _initialize_instance
    return manager.original_init(*mixed[1:], **kwargs)
  File "/lib/python3.7/site-packages/sqlalchemy/ext/declarative/base.py", line 747, in _declarative_constructor
    setattr(self, k, kwargs[k])
  File "/lib/python3.7/site-packages/sqlalchemy/orm/attributes.py", line 229, in __set__
    instance_dict(instance), value, None)
  File "/lib/python3.7/site-packages/sqlalchemy/orm/attributes.py", line 1042, in set
    given, wanted))
TypeError: Incompatible collection type: None is not list-like

1 个答案:

答案 0 :(得分:0)

好吧,问题是您尝试使用users值填充Boss模型上的None

在您的view中尝试一下:

boss = Boss(short_name=form.short_name.data)
if form.users.data:
    for each in form.users.data: boss.users.append(each)
db.session.add(boss)
db.session.commit()

应该很好用

这有可能也起作用

boss = Boss(short_name=form.short_name.data, users=form.users.data if form.users.data else [])