How do I debug AttributeError: 'list' object has no attribute 'match'
How do I debug AttributeError: 'list' object has no attribute 'match'
我用 flask-wtforms 创建了一个 flask 应用程序,它在点击提交后崩溃了。
错误似乎发生在 Flask-WTF function validate_on_submit
并告诉我我传递的列表对象不包含匹配属性。
现在我假设它一定是像我一样简单地错误地定义了 FormVendor 中的字段 class,但我不确定问题到底是什么。
堆栈跟踪
File ".../webshop/vendor.py", line 38, in vendorsignup_post
if form.validate_on_submit():
...
AttributeError: 'list' object has no attribute 'match'
...
File ".../webshop/venv/lib/python3.6/site-packages/wtforms/validators.py", line 286, in __call__
match = self.regex.match(field.data or '')
我的代码:
vendor.py
from flask import Blueprint, render_template, redirect, url_for, request, flash
from flask_login import login_required, current_user
from flask_wtf import FlaskForm
from wtforms import StringField, IntegerField, FileField, HiddenField, BooleanField
from wtforms.validators import DataRequired, Email, NumberRange, Regexp, InputRequired, AnyOf
vendor = Blueprint('vendor', __name__)
class FormVendor(FlaskForm):
per_email = StringField('Email', validators=[DataRequired(), InputRequired(),Email(message="wrong mail")])
per_first_name = StringField('First Name', validators=[DataRequired(), InputRequired()])
per_last_name = StringField('Last Name', validators=[DataRequired(), InputRequired()])
adr_city = StringField('City', validators=[DataRequired(), InputRequired()])
adr_state = StringField('State', validators=[DataRequired(), InputRequired()])
adr_country = StringField('Country', validators=[DataRequired(), InputRequired()])
adr_line1 = StringField('Address Line 1', validators=[DataRequired(), InputRequired()])
adr_line2 = IntegerField('Address Line 2', validators=[DataRequired()])
adr_postal_code = IntegerField('Postal Code', validators=[DataRequired(), InputRequired(),Regexp(['([1-468][0-9]|[57][0-7]|9[0-6])[0-9]{2}'])])
dob_day = IntegerField('Date of Birth: Day', validators=[DataRequired(), InputRequired()])
dob_month = IntegerField('Date of Birth: Month', validators=[DataRequired(), InputRequired()])
dob_year = IntegerField('Date of Birth: Year', validators=[DataRequired(), InputRequired()])
fin_account_number = StringField('IBAN Account Number', validators=[DataRequired(), InputRequired()])
id_front = FileField('ID Front', validators=[DataRequired(), InputRequired()])
id_back = FileField('ID Back', validators=[DataRequired(), InputRequired()])
address_front = FileField('Address Document', validators=[DataRequired(), InputRequired()])
accept_tos = BooleanField('I accept the TOS', validators=[DataRequired()])
@vendor.route('/vendorsignup')
@login_required
def vendorsignup():
form = FormVendor()
return render_template('vendorsignup.html', user=current_user, form=form)
@vendor.route('/vendorsignup', methods=['POST'])
@login_required
def vendorsignup_post():
form = FormVendor()
if form.validate_on_submit():
print("Successfully registered as vendor")
return redirect(url_for('main.sell'))
print(form.errors)
return render_template('vendorsignup.html', form=form)
vendorsignup.html
{% extends "base.html" %}
{% block content %}
{% if form.errors %}
{{ form.errors }}
{% endif %}
<form method="POST" action="/vendorsignup" enctype="multipart/form-data">
<div class="mb-3">
{{ form.hidden_tag() }}
{{ form.per_email.label(class='form-label') }}
{{ form.per_email(size=20,class="form-control") }}
{{ form.per_first_name.label(class='form-label') }}
{{ form.per_first_name(size=20,class="form-control") }}
{{ form.per_last_name.label(class='form-label') }}
{{ form.per_last_name(size=20,class="form-control") }}
{{ form.adr_city.label(class='form-label') }}
{{ form.adr_city(size=20,class="form-control") }}
{{ form.adr_state.label(class='form-label') }}
{{ form.adr_state(size=20,class="form-control") }}
{{ form.adr_country.label(class='form-label') }}
{{ form.adr_country(size=20,class="form-control") }}
{{ form.adr_line1.label(class='form-label') }}
{{ form.adr_line1(size=20,class="form-control") }}
{{ form.adr_line2.label(class='form-label') }}
{{ form.adr_line2(size=20,class="form-control") }}
{{ form.adr_postal_code.label(class='form-label') }}
{{ form.adr_postal_code(size=20,class="form-control") }}
{{ form.dob_day.label(class='form-label') }}
{{ form.dob_day(size=20,class="form-control") }}
{{ form.dob_month.label(class='form-label') }}
{{ form.dob_month(size=20,class="form-control") }}
{{ form.dob_year.label(class='form-label') }}
{{ form.dob_year(size=20,class="form-control") }}
{{ form.fin_account_number.label(class='form-label') }}
{{ form.fin_account_number(size=20,class="form-control") }}
{{ form.id_front.label(class='form-label') }}
{{ form.id_front(class="form-control") }}
{{ form.id_back.label(class='form-label') }}
{{ form.id_back(class="form-control") }}
{{ form.address_front.label(class='form-label') }}
{{ form.address_front(class="form-control") }}
{{ form.accept_tos.label(class='form-label') }}
{{ form.accept_tos(class="form-control") }}
</div>
<input type="submit" value="Go">
</form>
{% endblock %}
在您的 adr_postal_code
IntegerField 中,您的最后一个验证器如下所示:
Regexp(['([1-468][0-9]|[57][0-7]|9[0-6])[0-9]{2}'])
如果你看一下 Regexp.__init__
source code,你会发现它期望 regex
参数是一个字符串或正则表达式对象,但你传递的是一个列表,其中包含一个字符串。
这是 __init__
的样子:
def __init__(self, regex, flags=0, message=None):
if isinstance(regex, str):
regex = re.compile(regex, flags)
self.regex = regex
self.message = message
然后,就在 __init__
下方,您会找到 __call__
方法,这是您的代码失败的地方。 __call__
假设无论 self.regex
是什么类型,它都必须有一个 match
方法。由于您传入了一个列表,因此 self.regex
将是一个列表,并且没有 match
方法。
因此,您的验证器应该是:
Regexp('([1-468][0-9]|[57][0-7]|9[0-6])[0-9]{2}')
我用 flask-wtforms 创建了一个 flask 应用程序,它在点击提交后崩溃了。
错误似乎发生在 Flask-WTF function validate_on_submit
并告诉我我传递的列表对象不包含匹配属性。
现在我假设它一定是像我一样简单地错误地定义了 FormVendor 中的字段 class,但我不确定问题到底是什么。
堆栈跟踪
File ".../webshop/vendor.py", line 38, in vendorsignup_post
if form.validate_on_submit():
...
AttributeError: 'list' object has no attribute 'match'
...
File ".../webshop/venv/lib/python3.6/site-packages/wtforms/validators.py", line 286, in __call__
match = self.regex.match(field.data or '')
我的代码:
vendor.py
from flask import Blueprint, render_template, redirect, url_for, request, flash
from flask_login import login_required, current_user
from flask_wtf import FlaskForm
from wtforms import StringField, IntegerField, FileField, HiddenField, BooleanField
from wtforms.validators import DataRequired, Email, NumberRange, Regexp, InputRequired, AnyOf
vendor = Blueprint('vendor', __name__)
class FormVendor(FlaskForm):
per_email = StringField('Email', validators=[DataRequired(), InputRequired(),Email(message="wrong mail")])
per_first_name = StringField('First Name', validators=[DataRequired(), InputRequired()])
per_last_name = StringField('Last Name', validators=[DataRequired(), InputRequired()])
adr_city = StringField('City', validators=[DataRequired(), InputRequired()])
adr_state = StringField('State', validators=[DataRequired(), InputRequired()])
adr_country = StringField('Country', validators=[DataRequired(), InputRequired()])
adr_line1 = StringField('Address Line 1', validators=[DataRequired(), InputRequired()])
adr_line2 = IntegerField('Address Line 2', validators=[DataRequired()])
adr_postal_code = IntegerField('Postal Code', validators=[DataRequired(), InputRequired(),Regexp(['([1-468][0-9]|[57][0-7]|9[0-6])[0-9]{2}'])])
dob_day = IntegerField('Date of Birth: Day', validators=[DataRequired(), InputRequired()])
dob_month = IntegerField('Date of Birth: Month', validators=[DataRequired(), InputRequired()])
dob_year = IntegerField('Date of Birth: Year', validators=[DataRequired(), InputRequired()])
fin_account_number = StringField('IBAN Account Number', validators=[DataRequired(), InputRequired()])
id_front = FileField('ID Front', validators=[DataRequired(), InputRequired()])
id_back = FileField('ID Back', validators=[DataRequired(), InputRequired()])
address_front = FileField('Address Document', validators=[DataRequired(), InputRequired()])
accept_tos = BooleanField('I accept the TOS', validators=[DataRequired()])
@vendor.route('/vendorsignup')
@login_required
def vendorsignup():
form = FormVendor()
return render_template('vendorsignup.html', user=current_user, form=form)
@vendor.route('/vendorsignup', methods=['POST'])
@login_required
def vendorsignup_post():
form = FormVendor()
if form.validate_on_submit():
print("Successfully registered as vendor")
return redirect(url_for('main.sell'))
print(form.errors)
return render_template('vendorsignup.html', form=form)
vendorsignup.html
{% extends "base.html" %}
{% block content %}
{% if form.errors %}
{{ form.errors }}
{% endif %}
<form method="POST" action="/vendorsignup" enctype="multipart/form-data">
<div class="mb-3">
{{ form.hidden_tag() }}
{{ form.per_email.label(class='form-label') }}
{{ form.per_email(size=20,class="form-control") }}
{{ form.per_first_name.label(class='form-label') }}
{{ form.per_first_name(size=20,class="form-control") }}
{{ form.per_last_name.label(class='form-label') }}
{{ form.per_last_name(size=20,class="form-control") }}
{{ form.adr_city.label(class='form-label') }}
{{ form.adr_city(size=20,class="form-control") }}
{{ form.adr_state.label(class='form-label') }}
{{ form.adr_state(size=20,class="form-control") }}
{{ form.adr_country.label(class='form-label') }}
{{ form.adr_country(size=20,class="form-control") }}
{{ form.adr_line1.label(class='form-label') }}
{{ form.adr_line1(size=20,class="form-control") }}
{{ form.adr_line2.label(class='form-label') }}
{{ form.adr_line2(size=20,class="form-control") }}
{{ form.adr_postal_code.label(class='form-label') }}
{{ form.adr_postal_code(size=20,class="form-control") }}
{{ form.dob_day.label(class='form-label') }}
{{ form.dob_day(size=20,class="form-control") }}
{{ form.dob_month.label(class='form-label') }}
{{ form.dob_month(size=20,class="form-control") }}
{{ form.dob_year.label(class='form-label') }}
{{ form.dob_year(size=20,class="form-control") }}
{{ form.fin_account_number.label(class='form-label') }}
{{ form.fin_account_number(size=20,class="form-control") }}
{{ form.id_front.label(class='form-label') }}
{{ form.id_front(class="form-control") }}
{{ form.id_back.label(class='form-label') }}
{{ form.id_back(class="form-control") }}
{{ form.address_front.label(class='form-label') }}
{{ form.address_front(class="form-control") }}
{{ form.accept_tos.label(class='form-label') }}
{{ form.accept_tos(class="form-control") }}
</div>
<input type="submit" value="Go">
</form>
{% endblock %}
在您的 adr_postal_code
IntegerField 中,您的最后一个验证器如下所示:
Regexp(['([1-468][0-9]|[57][0-7]|9[0-6])[0-9]{2}'])
如果你看一下 Regexp.__init__
source code,你会发现它期望 regex
参数是一个字符串或正则表达式对象,但你传递的是一个列表,其中包含一个字符串。
这是 __init__
的样子:
def __init__(self, regex, flags=0, message=None):
if isinstance(regex, str):
regex = re.compile(regex, flags)
self.regex = regex
self.message = message
然后,就在 __init__
下方,您会找到 __call__
方法,这是您的代码失败的地方。 __call__
假设无论 self.regex
是什么类型,它都必须有一个 match
方法。由于您传入了一个列表,因此 self.regex
将是一个列表,并且没有 match
方法。
因此,您的验证器应该是:
Regexp('([1-468][0-9]|[57][0-7]|9[0-6])[0-9]{2}')