简体   繁体   中英

Python Flask: AttributeError: 'NoneType' object has no attribute 'count'

I'm following a Flask tutorial to do authentication in my app. My user class is like so:

class User(UserMixin, db.Model):  # Here we inherit from two classes
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(64), unique=True, index=True)
    username = db.Column(db.String(64), unique=True, index=True)
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
    password_hash = db.Column(db.String(128))

    # Custom property getter
    @property
    def password(self):
        raise AttributeError('password is not a readable attribute')

    # Custom property setter
    @password.setter
    def password(self, password):
        self.password_hash = generate_password_hash(password)

    def verify_password(self, password):
        return check_password_hash(self.password_hash, password)

    def __repr__(self):
        return '<User %r>' % self.username

My login route is defined like so:

@auth.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm()
    if form.validate_on_submit:
        # Get a user by email and check password matches hash
        user = User.query.filter_by(email=form.email.data).first()
        if user is not None and user.verify_password(form.password.data):
            login_user(user, form.remember_me.data)
        flash('Invalid username or password')
    return render_template('auth/login.html', form=form)

However when I point my browser to the /login endpoint I get the following errors:

File "/Users/kekearif/Documents/Python/FlaskWebDev/flasky/venv/lib/python2.7/site-packages/flask/app.py", line 1994, in __call__
return self.wsgi_app(environ, start_response)
File "/Users/kekearif/Documents/Python/FlaskWebDev/flasky/venv/lib/python2.7/site-packages/flask/app.py", line 1985, in wsgi_app
response = self.handle_exception(e)
File "/Users/kekearif/Documents/Python/FlaskWebDev/flasky/venv/lib/python2.7/site-packages/flask/app.py", line 1540, in handle_exception
reraise(exc_type, exc_value, tb)
File "/Users/kekearif/Documents/Python/FlaskWebDev/flasky/venv/lib/python2.7/site-packages/flask/app.py", line 1982, in wsgi_app
response = self.full_dispatch_request()
File "/Users/kekearif/Documents/Python/FlaskWebDev/flasky/venv/lib/python2.7/site-packages/flask/app.py", line 1614, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/Users/kekearif/Documents/Python/FlaskWebDev/flasky/venv/lib/python2.7/site-packages/flask/app.py", line 1517, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/Users/kekearif/Documents/Python/FlaskWebDev/flasky/venv/lib/python2.7/site-packages/flask/app.py", line 1612, in full_dispatch_request
rv = self.dispatch_request()
File "/Users/kekearif/Documents/Python/FlaskWebDev/flasky/venv/lib/python2.7/site-packages/flask/app.py", line 1598, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/Users/kekearif/Documents/Python/FlaskWebDev/flasky/app/auth/views.py", line 14, in login
if user is not None and user.verify_password(form.password.data):
File "/Users/kekearif/Documents/Python/FlaskWebDev/flasky/app/models.py", line 38, in verify_password
return check_password_hash(self.password_hash, password)
File "/Users/kekearif/Documents/Python/FlaskWebDev/flasky/venv/lib/python2.7/site-packages/werkzeug/security.py", line 245, in check_password_hash
if pwhash.count('$') < 2:
AttributeError: 'NoneType' object has no attribute 'count'

Not sure what is happening here. I'm calling the endpoint from a GET (eg submit has not been tapped so form.validate_on_submit should be false) and there should be no password check done at all. Any ideas what I am doing wrong?

The exception is thrown because the first argument to check_password_hash() is None . In your code that means that self.password_hash is None , as that's the first argument you pass in:

return check_password_hash(self.password_hash, password)

This means that User.password = ... was never executed ( generate_password_hash() can't return None ). There is no password set for your user.

Give the user a password, or code defensively and handle the case where self.password_hash is set to None .

Note that your form test is always true :

if form.validate_on_submit:

because validate_on_submit is a method, not a property. Method objects are non-empty and non-zero, so true. You probably wanted to call the method:

if form.validate_on_submit():

Now the return value determines the outcome.

I am assuming you are following The Flask Mega Tutorial and have a similar code base as I.

The error described can be encountered when the 'password_hash' column for the user you are trying to login with is empty. Use the password method you have defined in the User class to set the password, then commit the changes to the database:

u = User.query.filter(User.username == 'myusername').first()
u.password('thenewpassword')
db.session.add(u)
db.session.commit()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM