SQLAlchemy 外键赋值报错 TypeError: Incompatible collection type: Tag is not list-like

flask-sqlalchemy

#1

我想给指定的文章添加一个标签,通过id值找到指定的文章,然后给他的外键tags赋值。但是报错了

modes:

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(60))
    body = db.Column(db.Text)
    timestamp = db.Column(db.DateTime, default=datetime.utcnow, index=True)
    can_comment = db.Column(db.Boolean, default=True)

    # tag_id = db.Column(db.Integer, db.ForeignKey('tag.id'))

    tags = db.relationship('Tag', back_populates='posts',cascade='all, delete-orphan')
    comments = db.relationship('Comment', back_populates='post', cascade='all, delete-orphan')
class Tag(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    body=db.Column(db.String(30))
    post_id = db.Column(db.Integer, db.ForeignKey('post.id'))
    posts=db.relationship('Post',back_populates='tags')

Forms:

class TagForm(FlaskForm):
    name = StringField('Name', validators=[DataRequired(), Length(1, 30)])
    submit = SubmitField()

    def validate_name(self, field):
        if Tag.query.filter_by(name=field.data).first():
            raise ValidationError('Name already in use.')

函数:

@admin_bp.route('/post/<int:post_id>/tag',methods=['POST'])
def add_tag(post_id):
    post=Post.query.get_or_404(post_id)
    form=TagForm()
    if form.validate_on_submit:
        tag=Tag(body=form.name.data)
        db.session.add(tag)
        db.session.commit()
        print(post.tags,post.title,tag.id)
        post.tags=Tag.query.get(tag.id)
        # db.session.add(post)
        db.session.commit()
        flash('添加成功', 'success')
        return redirect_back()
    return redirect_back()

html

<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLabel">添加标签</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
       <form method="post" action="{{ url_for('.add_tag',post_id=post.id,next=request.full_path) }}">
    {{ form.csrf_token }}
    {{ form_field(form.name)}}
           {{ form_field(form.submit)}}

        </form>
      </div>
    </div>
  </div>
</div>

报错:

# TypeError

TypeError: Incompatible collection type: Tag is not list-like

## Traceback  *(most recent call last)*

* #### File "c:\users\17258\.virtualenvs\myblog-7y57whgu\lib\site-packages\flask\app.py", line  *2463* , in  `__call__`

return self.wsgi_app(environ, start_response)

* #### File "c:\users\17258\.virtualenvs\myblog-7y57whgu\lib\site-packages\flask\app.py", line  *2449* , in  `wsgi_app`

response = self.handle_exception(e)

* #### File "c:\users\17258\.virtualenvs\myblog-7y57whgu\lib\site-packages\flask\app.py", line  *1866* , in  `handle_exception`

reraise(exc_type, exc_value, tb)

* #### File "c:\users\17258\.virtualenvs\myblog-7y57whgu\lib\site-packages\flask\_compat.py", line  *39* , in  `reraise`

raise value

* #### File "c:\users\17258\.virtualenvs\myblog-7y57whgu\lib\site-packages\flask\app.py", line  *2446* , in  `wsgi_app`

response = self.full_dispatch_request()

* #### File "c:\users\17258\.virtualenvs\myblog-7y57whgu\lib\site-packages\flask\app.py", line  *1951* , in  `full_dispatch_request`

rv = self.handle_user_exception(e)

* #### File "c:\users\17258\.virtualenvs\myblog-7y57whgu\lib\site-packages\flask\app.py", line  *1820* , in  `handle_user_exception`

reraise(exc_type, exc_value, tb)

* #### File "c:\users\17258\.virtualenvs\myblog-7y57whgu\lib\site-packages\flask\_compat.py", line  *39* , in  `reraise`

raise value

* #### File "c:\users\17258\.virtualenvs\myblog-7y57whgu\lib\site-packages\flask\app.py", line  *1949* , in  `full_dispatch_request`

rv = self.dispatch_request()

* #### File "c:\users\17258\.virtualenvs\myblog-7y57whgu\lib\site-packages\flask\app.py", line  *1935* , in  `dispatch_request`

return self.view_functions[rule.endpoint](**req.view_args)

* #### File "C:\Users\17258\Desktop\python123\myblog\blog\blueprints\admin.py", line  *81* , in  `add_tag`

post.tags=Tag.query.get(tag.id)

* #### File "c:\users\17258\.virtualenvs\myblog-7y57whgu\lib\site-packages\sqlalchemy\orm\attributes.py", line  *271* , in  `__set__`

instance_state(instance), instance_dict(instance), value, None

* #### File "c:\users\17258\.virtualenvs\myblog-7y57whgu\lib\site-packages\sqlalchemy\orm\attributes.py", line  *1297* , in  `set`

![](http://127.0.0.1:5000/admin/post/53/tag?__debugger__=yes&amp;cmd=resource&amp;f=console.png)% (given, wanted)

> TypeError: Incompatible collection type: Tag is not list-like

#2

根据你的模型,Post和Tag是一对多关系, Post.tags应该是一个list类型,所以你应该按list操作方式一样去赋值Post.tags

post.tags.append(Tag.query.get(tag.id))
# 或
post.tags = [Tag.query.get(tag.id)]

#3

应该是指 post.tags=Tag.query.get(tag.id) 中的右值不像list类型。


#4

感谢!!我也试过用list类型,原来是我的写法有问题.


#5

每次添加的值都只能添加到第一个元素上,请问是为什么。(用的bootstrap的模态框)

  {% for post in posts %}
......
......
<button type="button" class="btn btn-primary"  data-toggle="modal" data-target="#myModal"  >+</button>
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLabel">添加标签</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
       <form method="post" action="{{ url_for('.add_tag',post_id=post.id) }}" class="form-inline">
           <div  style="display:block">
     <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
    <label  for="exampleFormControlFile1">{{ post.title }}</label>
     <input id="name" required type="text" name="name" class="form-control" style="Float:left;height:40px;margin-left: 20px" value>
           <button type="submit" class="btn btn-primary mb-2"  style="Float:left;height:40px;margin-left: 20px">确定</button></div>
        </form>
      </div>
    </div>
  </div>
</div>
......
......
  {% endfor %}