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.

Yaroslav
  • 31
  • 3

1 Answers1

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
RushK
  • 525
  • 1
  • 5
  • 13
  • Setting a default value for a `SelectField` with `.data` doesn't seem to work. As discussed elsewhere (https://stackoverflow.com/a/65533281/4204032), it may require `.default` and therefore `form.process()`. Is there a workaround for that? – DSL Dec 30 '21 at 06:35
  • 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. – Alyan Qureshi Mar 24 '22 at 12:51