How to fix "The CSRF token is missing" in Flask-WTForms
Asked Answered
W

1

3

I'm creating a small corporate web-portal. There will be computers database which contains information about all the computers in a company. I'm creating a WTForm for editing computers' properties. I have a page with a table that contains the computers' properties. There are special buttons on every row. When a user presses one of them, I want to show a page with the form with default values taken from the database. When I edit defaults in a View function, I get an error:

The CSRF token is missing.

My View function:

def edit_computer(computer_id):
    if admin_can() or sysadmin_can():
        computer = models.Computer.query.filter_by(id=computer_id).one()
        user = models.User.query.filter_by(id=computer.user_id).one()
        email = user.email

        form = forms.EditComputerForm()
        form.email.default = user.email
        form.type_.default=computer.type_
        form.model.default = computer.model
        form.cpu.default = computer.cpu
        form.ram.default = computer.ram
        form.rom.default = computer.rom
        form.os.default = computer.os
        form.supplements.default = computer.supplements
        form.process()

        if form.validate_on_submit():
            ...

When I don't set defaults (remove this ↓), the code works fine

form.email.default = user.email
form.type_.default=computer.type_
form.model.default = computer.model
form.cpu.default = computer.cpu
form.ram.default = computer.ram
form.rom.default = computer.rom
form.os.default = computer.os
form.supplements.default = computer.supplements
form.process()

Form:

class EditComputerForm(FlaskForm):    
    email = EmailField("Owner's E-Mail",
                       validators=[DataRequired(), Email()])
    type_ = SelectField('type',
                        choices=[('Notebook', 'Notebook'), ('PC', 'PC')])
    model = StringField('Model')
    cpu = StringField('CPU')
    ram = StringField('RAM')
    rom = StringField('ROM')
    os = StringField('OS')
    supplements = TextAreaField('Supplements')
    submit = SubmitField('Edit')

HTML:

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

{% block app_content %}
<h3>Edit computer's properties {{ add_title }}</h3>
<hr>
{{ wtf.quick_form(form, button_map={'submit': 'primary'}) }}
{% endblock %}

{% block app_windows %}{% endblock %}

How to fix this error? WTForm isn't working now.

Westminster answered 2/8, 2019 at 14:40 Comment(2)
Did to set the SECRET_KEY for the Flask app? It uses that to help generate the CSRF_TOKENFelixfeliza
@Felixfeliza yes. Other forms in my app work properlyWestminster
C
5

It's the form.process() that ruins the csrf process.

To set form values dynamically, I suggest you do use the data attribute, not the default attribute. Then you don't have to call form.process().

form.email.data= user.email
form.type_.data=computer.type_
form.model.data= computer.model
form.cpu.data= computer.cpu
form.ram.data= computer.ram
form.rom.data= computer.rom
form.os.data= computer.os
form.supplements.data= computer.supplements
Coyle answered 1/10, 2020 at 12:42 Comment(2)
Setting a default value for a SelectField with .data doesn't seem to work. As discussed elsewhere (https://mcmap.net/q/804286/-setting-default-value-after-initialization-in-selectfield-flask-wtforms), it may require .default and therefore form.process(). Is there a workaround for that?Stalinsk
Not using default is not the perfect solution. Is there way to retain the csrf token when calling the .process() function? I've been looking for days and days and this is the only place on the internet I've found where someone's having the same issue as me.Belford

© 2022 - 2024 — McMap. All rights reserved.