Flask self.errors.append() - AttributeError: '

2020-07-13 09:02发布

问题:

My small registration app gives and error when I try to validate the submited data by user and check if the entered e-mail exists.

here is my files:
forms:

from flask.ext.wtf import Form
from wtforms import TextField, BooleanField, PasswordField, TextAreaField, validators
from wtforms.validators import Required
from app import models

class RegisterForm(Form):
"""RegisterForm class needed for retrieving data from user"""
username = TextField('username', [validators.Length(min=3, max=50), validators.Required()])
email = TextField('email', [validators.Length(min=3, max=100), validators.Required()])
password = PasswordField('password', [validators.Required()])
age = TextField('age', [validators.Length(min=1, max=3), validators.Required()])
about_user = TextAreaField('about_user', [validators.Length(max=500)])
img_url = TextField('img_url')


def email_unique(self, email):
    if models.User.query.filter_by(email = email).first() != None:
        self.email.errors.append('This E-mail address is already in use. Please choose another one.') 
        return False

views:

#!flask/bin/python
from app import app, db, lm
from flask import render_template, url_for, flash, g, redirect, session, request
from flask.ext.login import login_user, logout_user, current_user, login_required
from forms import LoginForm, RegisterForm, EditForm
from models import User

@app.route('/register', methods = ['GET', 'POST'])
def register():
    form = RegisterForm()
    #makes the username unique
    u_unique =  form.username.data
    u_unique = User.unique_username(u_unique)

    #validates email adress and checks if it already exists or not 
    form.email_unique(form.email.data)

    if form.validate_on_submit():
        user = User(
            u_unique,
            form.password.data, 
            form.email.data, 
            form.age.data, 
            form.about_user.data,
            form.img_url.data)
        db.session.add(user)
        db.session.commit()
        flash('Thank you for your registration')
        flash('Your username is: ' + str(u_unique))
        return redirect(url_for('login'))
    else:
        for error in form.errors:
            flash(error)

    return render_template('register.html',
        title = 'Registeration',
        form = form)

The error is:

Traceback (most recent call last) File <br> "/home/maksad/Desktop/faskMonkey/flask/lib/python2.7/site-packages/flask/app.py", line 1701, in __call__ return self.wsgi_app(environ, start_response) 
File "/home/maksad/Desktop/faskMonkey/flask/lib/python2.7/site-packages/flask/app.py", line 1689, in wsgi_app response = self.make_response(self.handle_exception(e)) 
File "/home/maksad/Desktop/faskMonkey/flask/lib/python2.7/site-packages/flask/app.py", line 1687, in wsgi_app response = self.full_dispatch_request() 
File "/home/maksad/Desktop/faskMonkey/flask/lib/python2.7/site-packages/flask/app.py", line 1360, in full_dispatch_request rv = self.handle_user_exception(e) 
File "/home/maksad/Desktop/faskMonkey/flask/lib/python2.7/site-packages/flask/app.py", line 1358, in full_dispatch_request rv = self.dispatch_request() 
File "/home/maksad/Desktop/faskMonkey/flask/lib/python2.7/site-packages/flask/app.py", line 1344, in dispatch_request return self.view_functions[rule.endpoint](**req.view_args) 
File "/home/maksad/Desktop/faskMonkey/app/views.py", line 92, in register form.email_unique(form.email.data) 
File "/home/maksad/Desktop/faskMonkey/app/forms.py", line 26, in email_unique
 self.email.errors.append('This E-mail address is already in use. Please choose another one.')
 AttributeError: 'tuple' object has no attribute 'append'

回答1:

The tuple objects cannot append. Instead, convert to a list using list(), and append, and then convert back, as such:

>>> obj1 = (6, 1, 2, 6, 3)
>>> obj2 = list(obj1) #Convert to list
>>> obj2.append(8)
>>> print obj2
[6, 1, 2, 6, 3, 8]
>>> obj1 = tuple(obj2) #Convert back to tuple
>>> print obj1
(6, 1, 2, 6, 3, 8)

Hope this helps!



回答2:

Just came across this myself. I think a better answer to your question is that you should validate the elements before you add errors to them. The validation process sets the error field to a list and if you change it before you validate fields it will be written over when you validate.

So override the validate method of your form, call the parent validate method then run your email_unique method in that.

Then you can remove the email_unique from the view since it will be part of your validate_on_submit



回答3:

tuples are immutable types which means that you cannot splice and assign values to them. If you are going to be working with data types where you need to add values and remove values, use list instead:

>>> a = (1,2,3)
>>> a.append(2)
AttributeError: 'tuple' object has no attribute 'append'
>>> b = [1,2,3]
>>> b.append(2)
[1,2,3,2]


回答4:

The answer is a bit deeper. "errors" is a tuple when Field class created.

class Field(object):
    """
    Field base class
    """
    errors = tuple()

But when method validate called, it convert it to list

def validate(self, form, extra_validators=tuple()):
    self.errors = list(self.process_errors)

So everything you need is just to call your email_unique function right after validate_on_submit, which in turns call validate function of the form and convert errors to list

@app.route('/register', methods = ['GET', 'POST'])
def register():
    form = RegisterForm()
    #makes the username unique
    u_unique =  form.username.data
    u_unique = User.unique_username(u_unique)

    #validates email adress and checks if it already exists or 

    if form.validate_on_submit():
        form.email_unique(form.email.data)
        user = User(
            u_unique,
            form.password.data, 
            form.email.data, 
            form.age.data, 
            form.about_user.data,
            form.img_url.data)
        db.session.add(user)
        db.session.commit()
        flash('Thank you for your registration')
        flash('Your username is: ' + str(u_unique))
        return redirect(url_for('login'))
    else:
        for error in form.errors:
            flash(error)

    return render_template('register.html',
        title = 'Registeration',
        form = form)