Flask / SQLAlchemy: несовместимый тип коллекции: None не похож на список - PullRequest
0 голосов
/ 13 октября 2018

Я в замешательстве.Что не так?

У меня две модели и отношение многие к одному.

Я создал форму 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:

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 голосов
/ 13 октября 2018

Ну, проблема в том, что вы пытаетесь заполнить 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 [])
...