【问题标题】:Removing csrf_token before inserting into MongoDB在插入 MongoDB 之前删除 csrf_token
【发布时间】:2019-10-07 07:39:04
【问题描述】:

在我的应用程序中,我使用 flask_mongoengine 连接到 MongoDB。我收到错误

“研究”文档中不存在“{'csrf_token'}”字段

插入文档时。

我设法通过在保存之前手动删除 csrf_token 来克服错误(参见下面的代码)。有没有更优雅的方法来克服这个错误?这对于包含 EmbeddedDocument 的模型特别有用,因为所有嵌入的文档都有一个 csrf_token。

app.py

from flask import Flask, render_template, request
from flask_bootstrap import Bootstrap
from flask_mongoengine import MongoEngine
from flask_wtf.csrf import CSRFProtect
from flask_mongoengine.wtf import model_form
from wtforms.meta import DefaultMeta


db = MongoEngine()
bootstrap = Bootstrap()
csrf = CSRFProtect()

app = Flask(__name__)


app.secret_key = 'My secret key'

app.config['MONGODB_HOST'] = 'host'
app.config['MONGODB_PORT'] = 27017
app.config['MONGODB_DB'] = 'database'
app.config['MONGODB_USERNAME'] = 'user'
app.config['MONGODB_PASSWORD'] = 'user'

db.init_app(app)
bootstrap.init_app(app)
csrf.init_app(app)

class Study(db.Document):
    name = db.StringField()

@app.route('/', methods=['GET', 'POST'])
def hello_world():

    StudyForm = model_form(Study, field_args={})

    study_form = StudyForm()

    if request.method == 'POST':
        study_form = StudyForm(request.form)

        if study_form.validate():
            del study_form._fields['csrf_token']
            study_form.save()
            return "Success"

    return render_template('index.html', form=study_form)

if __name__ == '__main__':
    app.run(debug=True,host='0.0.0.0')

index.html

{% extends "bootstrap/base.html" %}
{% import "bootstrap/wtf.html" as wtf %}

{% block content %}

<div class="container">
    <form action="" method="POST">
        {{ form.hidden_tag() }}
        {{ form.name.label() }}
        {{ form.name() }}
         <input type=submit class='btn btn-primary '>
    </form>    
</div>    

{% endblock %

【问题讨论】:

    标签: python-3.x flask flask-wtforms flask-mongoengine


    【解决方案1】:

    这是一个怪癖/错误,可以通过以下方式解决。

    选项 1

    将模型的实例 (Study) 传递给表单构造函数。您可以只传递一个空实例,该实例将在您保存时填充表单值。

    study_form = StudyForm(request.form, instance=Study())
    study_form.save()
    

    选项 2

    自己显式地创建、填充和保存模型实例。要填写表格,请使用Form.populate_obj()。请注意,您必须在模型实例上调用save(),而不是在表单上。

    study = Study()
    study_form.populate_obj(study)
    study.save()
    

    根本原因

    当 Flask-MongoEngine 的 ModelForm.save() 需要创建模型实例时,它会使用来自 Form.data 的值填充它,其中包含 所有 表单字段,包括 csrf_token。相比之下,Form.populate_obj() 区分字段类型,根据需要跳过 CSRFTokenField 实例。

    class ModelForm(FlaskForm):
        """A WTForms mongoengine model form"""
        ...
    
        def save(self, commit=True, **kwargs):
            if self.instance:
                self.populate_obj(self.instance)
            else:
                self.instance = self.model_class(**self.data)
    
            if commit:
                self.instance.save(**kwargs)
            return self.instance
    

    【讨论】:

      猜你喜欢
      • 2016-07-12
      • 2014-04-10
      • 1970-01-01
      • 2019-07-30
      • 2011-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-08
      相关资源
      最近更新 更多