I am trying to register a user into a sqlite database.
My form contains a hidden field with a numerical value.
When I process the form, it returns the following error:
"The browser (or proxy) sent a request that this server could not understand."
Which apparently means a variable is not passed to the function.
How could I address the problem please?
I have tried changing the data type to int() in the backend before sending to the function, I have made the field visible etcetc. Nothing worked.
Funny enough: when I use the "print" function in the backend and disable the "User.regUser(email, username, password, rank)", their values shows in the console... so I would assume the variables contain the info I need to pass to the function.
Here is the code:
Views:
#app.route('/register', methods=['GET', 'POST'])
def register():
#if request.method == 'POST':encrypt
email = request.form['email']
username = request.form['username']
password = generate_password_hash(request.form['pass1'])
rank = int(request.form['rank'])
print(email, password, username, rank)
User.regUser(email, username, password, rank)
# db.session.add(User(email, username, password, "50"))
# db.session.commit()
return render_template('register.html')
Models:
from pjctBB.views import db
class User(db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String, nullable=False)
username = db.Column(db.String, nullable=False)
password = db.Column(db.String, nullable=False)
rank = db.Column(db.Integer, nullable=False)
def __init__(self, email, username, password, rank):
self.email = email
self.username = username
self.password = password
self.rank = rank
def regUser(self, email, username, password, rank):
db.session.add(User(email, username, password, rank))
db.session.commit()
Thanks a bunch!
From what I gather, you're trying to request from a form without first rendering it, meaning there is no form to get or post from. Try this:
#app.route('/register', methods=['GET', 'POST'])
def register():
if request.mthod == 'GET':
return render_template('register.html')
elif request.method == 'POST':
email = request.form['email']
username = request.form['username']
password = generate_password_hash(request.form['pass1'])
rank = int(request.form['rank'])
print(email, password, username, rank)
User.regUser(email, username, password, rank)
#db.session.add(User(email, username, password, "50"))
#db.session.commit()
return render_template('register.html')
That's assuming register.html exists.
Thank you all for your interest in my question. It got me thinking a bit :)
I asked my question slighly differently on SO and 2 users gave me a solution.
I ncase someone runs into a similar problem as mine, please look this thread for a possible solution:
Flask registration error: missing 1 positional argument
Related
I'm new to Flask, and getting an TypeError: Query.filter() got an unexpected keyword argument 'login'.
I'm using flask-login addon. Here is my model.
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
login = db.Column(db.String(128), nullable=False, unique=True)
password = db.Column(db.String(255), nullable=False)
#login_manager.user_loader
def load_user(user_id):
return User.query.get(user_id)
My route:
#app.route('/login', methods=['GET', 'POST'])
def user_login():
login = request.form.get('login')
password = request.form.get('password')
if login and password:
user = User.query.filter(login=login).first() # this line causes an error
if check_password_hash(user.password, password):
login_user(user)
next_page = request.args.get('next_page')
redirect(next_page)
else:
flash("Login or password is incorrect")
else:
flash("Please fill login and password fields")
return render_template('login.html')
What am I doing wrong?
You need to fix your query syntax
use
user = User.query.filter_by(login=login).first()
or
user = User.query.filter_by(login=login).one()
i have been developing a flask app with a sqlite3 database. Now to publish it online i am switching the database from sqlite3 to Sqlalchemy and i am very lost. I implemented a login and registrer but i have problems with login. I have to check that the username entered is indeed registered and that the password match the one in the database
I have already created the table:
class Usuarios(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
hash = db.Column(db.String(120), unique=True, nullable=False)
provincia = db.Column(db.String(80))
mail = db.Column(db.String(80), nullable=False)
def __init__(self, username, hash, provincia, mail):
self.username = username
self.hash = hash
self.provincia = provincia
self.mail = mail
And here is my code:
#app.route("/login", methods=["GET", "POST"])
def login():
"""Log user in"""
# Forget any user_id
session.clear()
# User reached route via POST (as by submitting a form via POST)
if request.method == "POST":
username=request.form.get("username").upper()
# Ensure username was submitted
if not request.form.get("username"):
return apology("Debe ingresar un nombre de usuario.", 403)
# Ensure password was submitted
elif not request.form.get("password"):
return apology("Debe ingresar una contraseña.", 403)
# Query database for username
rowpass = db.session.query.filter_by(Usuarios.username = username).all()
rows = Usuarios.query.filter_by(username=username).first()
# Ensure username exists and password is correct
if rows is None or not check_password_hash(rows[0]["hash"], request.form.get("password")):
return apology("Usuario o contraseña incorrectos", 403)
# Remember which user has logged in
session["user_id"] = rowpass[0]["username"]
# Redirect user to home page
return redirect("/")
# User reached route via GET (as by clicking a link or via redirect)
else:
return render_template("login.html")
With in sqlite3 this code worked perfectly but now i dont know how to translate it properly to sqlalchemy:
rows = db.execute("SELECT * FROM usuarios WHERE username = :username",
username=request.form.get("username").upper())
if len(rows) != 1 or not check_password_hash(rows[0]["hash"], request.form.get("password")):
return apology("Usuario o contraseña incorrectos", 403)
I think the problem is in the password check, where i left the sqlite3's square brackets[] and i am not sure if they re used in alchemy.
If that is the error i am not sure that the line that says:
session["user_id"] = rows[0]["username"] is correct too
What do you think?
I'm trying just to setup a base login model with developed code mostly from Flask-Login.
After my user successfully logs in and I issue a redirect(url_for('index')), the user loses his authentication and returns to the value flask_login.AnonymousUserMixin.
I realize there are some simple workarounds but I'm trying to understand why my code doesn't work like the examples.
I must be missing something simple or a lack understanding of Flask-Login. How can the user remain logged in after a redirect?
__init__.py
...
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = "login"
...
models.py
class User(UserMixin, db.Model):
__tablename__ = 'users'
uid = db.Column(db.Integer, primary_key=True)
firstname = db.Column(db.String(100))
lastname = db.Column(db.String(100))
username = db.Column(db.String(100), unique=True)
email = db.Column(db.String(120), unique=True)
pwdhash = db.Column(db.String(54))
def __init__(self, firstname, lastname, email, username, password):
...
def get_id(self):
return(self.username)
def __repr__(self):
return '<User is:%r>' % (self.username)
routes.py
#login_manager.user_loader
def load_user(user_id):
try:
return User.query.get(user_id)
except:
return None
#app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if request.method == "POST":
if form.validate():
user = User.query.filter_by(username=form.username.data.lower()).first()
login_user(user, remember=False)
assert current_user.is_authenticated
return redirect(url_for('index'))
else:
return render_template('login.html', form=form)
return render_template('login.html', form=form)
#app.route('/index')
#login_required
def index():
return render_template("home.html")
I have reviewed flask-login user is set to anonymous after login but that login method is different than the one above.
Well, I need to answer my own question on a dumb oversight that I should have caught (bleary eyes?)
Simple fix in def load_user(user_id): where I needed to replace the line
Bad: return User.query.get(user_id)
Good: return User.query.filter_by(username=user_id).first()
I suppose the take-away is the importance of def load_user() in preserving session integrity.
Add these functions to your User class.
def is_authenticated(self):
return True
def is_active(self):
return self.active
def is_anonymous(self):
return False
If I remember correctly,Flask-Login requires them in your User class.
self.active is a Boolean field. Trivially, it tells Flask-Login whether the user is active or not. You might want to declare it using active = db.Column(db.Boolean, nullable=False).
Being a newb to python I am not quite sure why I am getting inconsistent results.
I register a user and the password in my table ends up being the hashed version. When the user updates his password, the password in the table ends up being the unhashed version. Obviously, I want the hashed version. What am I doing wrong? (I am using SQLAlchemy and mysql if that matters.)
I have the following:
def hash_password(password):
blah, blah, blah # hash my password here
return hashed_password
class User(Base):
__tablename__ = 'mytable'
email = Column('email')
_password = Column('password')
def _get_password(self):
return self._password
def _set_password(self, password):
self._password = hash_password(password)
password = property(_get_password, _set_password)
password = synonym('_password', descriptor=password)
def __init__(self, password="", email=""):
self.email = email
self.password = password
#classmethod
def register(cls, email, password):
return DBSession.add(User(email=email,password=password)) # this correctly hashes the password
#classmethod
def update(cls, email, password):
return DBSession.query(cls).filter(cls.email == email).update({'password': password}) #password ends up being the unhashed password
The issue here is the way that you are updating the password via your User.update method. This method is skipping the ORM entirely and updating the row directly in the database. It should be obvious that the code to hash the password will not run when you do this. The User model that you pasted is just fine and similar to what I use. You need to use it though. This means that to update a password you should load the user, and set their password.
user = DBSession.query(User).filter_by(email=email).first()
if user:
user.password = new_password
and later when the transaction is committed things will be the way you expect.
You should store password hash in database, so field of your model must contain hash value, not raw password. To set password, you should use methods, that makes hashing and set hash to instance. To check, if password is correct, you should hash user-defined password and compare result with hash stored in your instance. Yo will not be able to decode password from hash - it's unsecure.
class User(Base):
__tablename__ = 'user'
email = Column('email', String(80))
password = Column('password', String(80))
def set_password(raw_password):
self.password = hash(raw_password)
def check_password(raw_password):
return self.password == hash(raw_password)
I'm messing around with Flask and the Flask-SQLAlchemy extension to create a simple registration form. In my User class, I have the attribute "email" set to nullable=False, but when I test the form on the site without including an email, it saves the new user to the db instead of throwing an exception as I expected. Any idea why that's happening? Thanks for looking!
Here's the code:
from flask import Flask, url_for, render_template, request, redirect
from flaskext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/kloubi.db'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(80), unique=True, nullable=False)
fname = db.Column(db.String(80))
lname = db.Column(db.String(80))
def __init__(self, username, email, fname, lname):
self.username = username
self.email = email
self.fname = fname
self.lname = lname
#app.route('/')
def index():
return render_template('index.html')
#app.route('/register/', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
new_user = User(fname = request.form['name'],
lname = request.form['surname'],
email = request.form['email'],
username = request.form['username'])
db.session.add(new_user)
db.session.commit()
return redirect(url_for('index'))
return render_template('register.html')
if __name__ == '__main__':
app.debug = True
app.run(host='0.0.0.0')
The problem is when you submit the webform without entering an email it will contain an empty string "" .. not None... and an empty string is not the same als null and it is ok to store it in the field.
I suggest using something like wtforms to validate the input of the user.
You can add a judgment if email != ''
Option1: If you are defining form by yourself in HTML
Just by using the required attribute in input HTML tag will prompt the user that an input field must be filled out before submitting the form.
<form action="#">
<input type="email" name="email" required>
<input type="submit">
</form>
Option2: If you are using WTforms to define the form
Then by using validators.required() while defining form class you can achieve the same result
class MyForm(Form):
email = EmailField(u'Email', [validators.required()])
you can use html5 attribute email directly in html. See this.