I was finishing up a simple little user login with Flask and Bcrypt. However, when trying to login with a user that is stored in my database, I keep encountering a runtime error. It looks like some sort of loop that's breaking. Being that I'm pretty new to programming, this has been incredibly challenging to figure out what I'm doing wrong. Hopefully someone here can help out! I'll past the relevant code below:
Here's the issue I'm getting. It just keeps looping this until it exceeds the maximum:
File "C:\Users\desktop\test\app\models.py", line 37, in password
return self.password
File "C:\Users\.virtualenvs\flask\lib\site-packages\sqlalchemy\ext\hybrid.py",
line 742, in get
return self.fget(instance)
File "C:\Users\desktop\test\app\models.py", line 37, in password
Models.py
class User(db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
nickname = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String(120), index=True, unique=True)
password = db.Column(db.String(100))
posts = db.relationship('Post', backref='author', lazy='dynamic',
primaryjoin="User.id==Post.user_id")
about_me = db.Column(db.String(140))
last_seen = db.Column(db.DateTime)
followed = db.relationship('User',
secondary=followers,
primaryjoin=(followers.c.follower_id == id),
secondaryjoin=(followers.c.followed_id == id),
backref=db.backref('followers', lazy='dynamic'),
lazy='dynamic')
#hybrid_property
def password(self):
return self.password
#password.setter
def set_password(self, plaintext):
self.password = bcrypt.generate_password_hash(plaintext)
def is_correct_password(self, plaintext):
return bcrypt.check_password_hash(self.password, plaintext)
Forms.py
class LoginForm(Form):
nickname = TextField('Nickname', validators=[DataRequired()])
password = PasswordField('Password', validators=[DataRequired()])
Views.py Login
#app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(nickname=form.nickname.data).first_or_404()
if user.is_correct_password(form.password.data):
login_user(user)
flash("you've been logged in!, 'success'")
return redirect(url_for('index'))
else:
flash('your email or password doesnt match!', 'error')
return redirect(url_for('login'))
return render_template('login.html',
title='Sign In',
form=form)
Views.py Registration
#app.route('/register', methods=('GET', 'POST'))
def register():
form = forms.RegisterForm()
if form.validate_on_submit():
user = User(nickname=form.nickname.data, emai=form.email.data, password=form.password.data)
db.session.add(user)
db.session.commit()
flash('User successfully registered')
return redirect(url_for('login'))
return render_template('register.html', form=form)
You should use different names for column and property
class User(db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
password_hash = db.Column(db.String(100))
#hybrid_property
def password(self):
return self.password_hash
#password.setter
def set_password(self, plaintext):
self.password_hash = bcrypt.generate_password_hash(plaintext)
Related
I am utilizing a react frontend and a flask backend for my app. I am trying to utilize flask_login to authenticate and track user information throughout my various api calls. I have worked through the flask login docs and cannot for the life of me figure out my user information is not being remembered between route calls.
class User(db.Model, UserMixin):
__tablename__='users'
id= db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(50), unique=True)
email = db.Column(db.String(100), unique=True)
password = db.Column(db.String(50))
date_joined = db.Column(db.Date, default=datetime.utcnow)
# role = db.Column(db.String(50), defualt="user")
def __init__(self, username, email, password):
self.username = username
self.email = email
self.password = password
def to_json(self):
return {
'id' : self.id,
'username' : self.username,
'email' : self.email,
'date_joined' : self.date_joined,
}
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'Login'
login_manager.session_protection = "strong"
login_serializer = URLSafeTimedSerializer(app.secret_key)
#login_manager.user_loader
#cross_origin(supports_credentials=True)
def load_user(user_id):
print(user_id, file=sys.stderr) #This isn't printing anything. I am not sure this route is being hit
return User.query.get(user_id)
#app.route('/Login', methods=['GET', 'POST'])
#cross_origin(supports_credentials=True)
def Login():
if request.method == 'POST':
session.pop('user_id', None)
session['username'] = request.get_json()['username']
session['password'] = request.get_json()['password']
user = db.session.query(User).filter(User.username==session['username']).first()
if user and user.password == session['password']:
session['user_id'] = user.id
login_user(user, remember=True, force=True)
# print(current_user, file=sys.stderr) #This successfully prints out a user
return jsonify(current_user.id)
else:
return jsonify(-99999)
return '''
<form method="post">
<p><input type=text name=username>
<p><input type=submit value=Login>
</form>
'''
Now when I try to access my current_user information with a separate route call, I get nothing. When I test if current_user.is_authenticated:...it is not. I don't know what is happening here. Is the session getting reset? Am I logging out of the user after logging in? I have no idea.
#app.route('/AnswerQuestion/<int:question_id>', methods=['GET', 'POST'])
#cross_origin(supports_credentials=True)
def AnswerQuestion(question_id):
# question = Question.query.get(question_id)
print( current_user.get_id(), file=sys.stderr)
return jsonify(question.to_json())
returns
I have created a registration form with validation but instead of this error Unique Constraint error is coming how can I fix this
Below is the register class
class Registerform(FlaskForm):
username = StringField(label="Username", validators=[
Length(min=3, max=20), DataRequired()])
password1 = PasswordField(label="Password", validators=[
Length(min=6, max=20), DataRequired()])
password2 = PasswordField(label="Confirm Password", validators=[
EqualTo('password1', message='Both password fields must be equal!'), DataRequired()])
Submit = SubmitField(label='Submit')
def validate_existing_user(self, username):
checkexisting = User.query.filter_by(username=username.data).first()
print(checkexisting)
if checkexisting:
raise ValidationError(
"Oops Username already exists please try with a new Username")
Below is the registration route
#app.route("/register", methods=['POST', 'GET'])
def registerpage():
form = Registerform()
if form.validate_on_submit():
usernameinput = form.username.data
userpasswordinput = form.password1.data
hashedpass = bcrypt.generate_password_hash(userpasswordinput)
print(f"Normal pass is {userpasswordinput} & its hash is {hashedpass}")
table_row = User(username=usernameinput,
password_hash=hashedpass, )
db.session.add(table_row)
db.session.commit()
print("User added successfully")
flash('User added successfully you can Login now',
category='success')
return redirect(url_for('login_page'))
return render_template("registration.html", title='Registration', form=form)
Below is the DB model its sqllite
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password_hash = db.Column(db.String(120), nullable=False)
def __repr__(self):
return '<Username %s> <pwd %s>' % (self.username, self.password_hash)
Kindly assist I am new to flask
The Documentation explains how to build a custom validator. The key is to name the validation methode like the attribute of your form.
So instead of using validate_existing_user() you have to name the methode validate_username. That way wtforms will know that it hast to map the custom-validation methode to the username attribute.
I have created ContactForm as a quick WTForm within my HTML templates. When I go through my application and try to use the contact form to add the name and email values in the ContactForm to my User class it doesn't work. When I query User class in DB I just get empty brackets []. Somebody, please help me!
class ContactForm(FlaskForm):
name = StringField('Name', [InputRequired()])
email = StringField('Email Address', [InputRequired()])
submit = SubmitField('Sign Up')
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, unique=False, nullable=False)
email = db.Column(db.String, unique=False, nullable=False)
def __init__(self, name, email):
self.name = name
self.email = email
def __repr__(self, name, email):
return f"{name},{email}"
#app.route('/contact', methods=['GET'])
def contact():
form = ContactForm()
if form.validate_on_submit():
name = form.name.data
email = form.email.data
user = User(name, email)
db.session.add(user)
db.session.commit()
flash('Success')
return redirect(url_for('home'))
else:
return render_template('contact.html', form=form)
return render_template('contact.html', form=form)
Please try with methods POST in your route.
I have this code designed to login users with passwords using Flask. It is somehow always running the exception in the trycatch. Can someone tell me where is the problem?
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.db'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
user = db.Column(db.String(200), nullable=False);
password = db.Column(db.String(20), nullable=False)
date_created = db.Column(db.DateTime, default=datetime.datetime.utcnow)
def __repr__(self):
return '<User %r' % self.id
#app.route('/', methods=['POST','GET'])
def index():
if request.method == 'POST':
user_content = request.form['user']
password_content = request.form['password']
new_user = User(user=user_content)
new_password = User(password=password_content)
try:
db.session.add(new_user)
db.session.add(new_password)
db.session.commit()
return redirect('/')
except:
return ""
else:
users = User.query.order_by(User.date_created).all()
return render_template('index.html', users=users)
if __name__ == "__main__":
app.run(debug=True)
I have the following code. I'm trying to insert user data into a sqlite database using SQLAlchemy it crashes when I give the following command in the python prompt. I'm trying to add the users to the database then once I commit I want to query the database and display the information to verify it got inserted into the database. For now I have it only displaying to the prompt I haven't developed any methods to render it.
from DIRT import db
db.create_all()
from DIRT import User, Post
user_1 = User(username="John Wick", email="jw#gmail.com", password="password")
user_2 = User(username="John Snow", email="js#gmail.com", password="password")
db.session.add(user_1)
db.session.add(user_2)
db.session.commit()
Below is my code for the DIRT.py
from datetime import datetime
from flask import Flask, render_template, url_for, flash, redirect
from flask_sqlalchemy import SQLAlchemy
from MyForms import RegisterForm, LoginForm
app = Flask(__name__)
# creating secret numbers to prevent modified cookie attack, or cross-site attacks
app.config['SECRET_KEY'] = '4b15463cce52d7b99874c9fb2312d580'
# database uri
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///dirt.db'
# database
db = SQLAlchemy(app)
# user model for the sql database
# class User(db.Model):
# id = db.Column(db.Integer, primary_key=True)
# username = db.Column(db.String(25), unique=True, nullable=False)
# email = db.Column(db.String(50), unique=True, nullable=False)
# image_file = db.Column(db.String(25), nullable=False, default='default.jpg')
# password = db.Column(db.String(50), nullable=False)
# posts = db.relationship('Post', backref='author', lazy=True)
# def __repf__(self):
# return f"User('{self.username}', '{self.email}', '{self.image_file}')"
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password = db.Column(db.String(60), nullable=False)
posts = db.relationship('Post', backref='author', lazy=True)
def __repr__(self):
return f"User('{self.username}', '{self.email}')"
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
content = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
def __repr__(self):
return f"Post('{self.title}', '{self.date_posted}')"
posts = [
{
'author': 'Cloud Strife',
'title': 'Where do we find Aeris..',
'content': 'So we are trying to find her',
'date_posted': 'November 12, 2019'
},
{
'author': 'Cecil Paladin',
'title': 'Where is the crystal sword',
'content': 'Trying to find the crystal bridge',
'date_posted': 'July 10, 2019'
}
]
#app.route("/")
#app.route("/home")
def home():
return render_template('home.html', posts=posts)
#app.route("/about")
def about():
return render_template('about.html', title='About')
#app.route("/register", methods=['GET', 'POST'])
def register():
form = RegisterForm()
if form.validate_on_submit():
flash(f'Account created for {form.username.data} successfully!', 'success')
return redirect(url_for('home'))
return render_template('register.html', title='Register', form=form)
# #app.route("/login", methods=['GET', 'POST'])
# def login():
# MyForm = LoginForm()
# return render_template('login.html', title='Login', form=MyForm)
#app.route("/login", methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
if form.email.data == 'onyxbird#hotmail.com' and form.password.data == 'sandman23':
flash(f'{form.email.data} has logged in!', 'success')
return redirect(url_for('home'))
else:
flash('Login Unsuccessful. Please check email and password', 'danger')
return render_template('login.html', title='Login', form=form)
if __name__ == '__main__':
# app.run(host='0.0.0.0', port='8080')
# above is production mode
app.run(debug=True)
This is the errors I'm getting:
*db.session.commit()
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "C:\Users\onyxb\PycharmProjects\DIRT\venv\lib\site-packages\sqlalchemy\orm\scoping.py", line 162, in do
return getattr(self.registry(), name)(*args, **kwargs)
File "C:\Users\onyxb\PycharmProjects\DIRT\venv\lib\site-packages\sqlalchemy\orm\session.py", line 1027, in commit
self.transaction.commit()
File "C:\Users\onyxb\PycharmProjects\DIRT\venv\lib\site-packages\sqlalchemy\orm\session.py", line 492, in commit
self._assert_active(prepared_ok=True)
File "C:\Users\onyxb\PycharmProjects\DIRT\venv\lib\site-packages\sqlalchemy\orm\session.py", line 288, in _assert_active
raise sa_exc.InvalidRequestError(
sqlalchemy.exc.InvalidRequestError: This Session's transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (sqlite3.IntegrityError) NOT NULL constraint failed: user.image_file
[SQL: INSERT INTO user (username, email, password) VALUES (?, ?, ?)]
[parameters: ('John Wick', 'jw#gmail.com', 'password')]
(Background on this error at: http://sqlalche.me/e/gkpj) (Background on this error at: http://sqlalche.me/e/7s2a)*