Reputation: 4907
I have a small flask application that I am currently rewriting and changing the directory tree per flask convention. In the previous application, I was able to get flask Bcrypt to work but in this new structure it doesn't seem to work.
Here is a snippet of the code that I have from my models.py
from blackduckflock import app, db, bcrypt
class User(db.Model, flask_login.UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(50))
password = db.Column(db.String(250))
def __init__(self, username='', password=''):
self.username = username
# self.password = password
#------The code below fails while the code above works just fine ------------
#self.password = bcrypt.generate_password_hash(password)
def __repr__(self):
return '<User %r>' % self.username
The bcrypt.generate_password
fails with a (ValueError: Password must be non-empty)
. For some reason, the Create form is not persisting with the request and is not transferring to bcrypt. A code.interact(local=locals())
shows that the default ''
arguments are being passed instead of the actual form value. Without the bcrypt generation, the code works just fine and a User is created.
I'm not exactly sure why that is but does anyone have any ideas?
This is my __init__.py
file within blackduckflock/blackduckflock/__init__.py
import os
from flask import Flask
from flask.ext.bcrypt import Bcrypt
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.script import Manager
from flask.ext.migrate import Migrate, MigrateCommand
app = Flask(__name__)
bcrypt = Bcrypt(app)
db = SQLAlchemy(app)
manager = Manager(app)
migrate = Migrate(app,db)
manager.add_command('db', MigrateCommand)
file_path = os.path.join(os.path.dirname(__file__), 'static/images/')
import blackduckflock.views
import blackduckflock.models
import blackduckflock.forms
import blackduckflock.admin
What could be the problem?
---------------------EDIT (Minimal, Complete, Example)------------------
Tree directory:
blackduckflock/
blackduckflock/
- __init__.py
- models.py
- forms.py
- views.py
- admin.py
- blackduckflock.py
- config.py
blackduckflock.py:
from blackduckflock import app
app.config.from_object('config')
app.run()
init.py
from flask import Flask
from flask.ext.bcrypt import Bcrypt
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
bcrypt = Bcrypt(app)
db = SQLAlchemy(app)
import blackduckflock.admin
import blackduckflock.views
#import blackduckflock.models
#import blackduckflock.forms
admin.py:
class MyAdminIndexView(AdminIndexView):
pass
admin = Admin(app, name='BlackDuck Flock',
index_view=MyAdminIndexView(),
template_mode='bootstrap3')
class UserView(ModelView):
def is_accessible(self):
return flask_login.current_user.is_authenticated
admin.add_view(UserView(User, db.session))
models.py:
from blackduckflock import app, db, bcrypt
import flask.ext.login as flask_login
class User(db.Model, flask_login.UserMixin):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(50))
password = db.Column(db.String(250))
def __init__(self, username='', password=''):
self.username = username
# self.password = password
# code.interact(local=locals())
self.password = bcrypt.generate_password_hash(password)
def __repr__(self):
return '<User %r>' % self.username
views.py:
import flask.ext.login as flask_login
from blackduckflock import db, app
from blackduckflock.models import User
login_manager = flask_login.LoginManager()
login_manager.init_app(app)
@login_manager.user_loader
def load_user(user_id):
return db.session.query(User).get(user_id)
Upvotes: 1
Views: 1303
Reputation: 4907
I solved my dilemma by implementing an event callback shown below.
@listens_for(User, 'before_insert')
def bcrypt_password(mapper, connection, target):
target.password = bcrypt.generate_password_hash(target.password)
Upvotes: 1
Reputation: 2489
You cannot have optional parameters for the User class unless you ensure that empty password is not passed to the generate_password_hash function like:
class User:
def __init__(self, username='', password=''):
self.username = username
if password != '':
self.password = bcrypt.generate_password_hash(password)
or simply remove the optional param and make it obligatory like:
class User:
def __init__(self, password, username=''):
self.username = username
self.password = bcrypt.generate_password_hash(password)
This is important because whenever you try to initialize the class with empty params because they are optional like so:
user = User()
It will fail because it will try to pass password='' to the bcrypt.generate_password_hash(password) and it will raise error.
Upvotes: 1