I'm trying to add Flask-Login to my Flask-Python app but I'm having this error and I don't know why.
I guess thats my user.loader that isnt correct but the idea is to load the user based on the ID or email.
Any idea what am I doing wrong?
Thanks in advance
Regards
full error :
DataError: (psycopg2.DataError) invalid input syntax for integer:
"t#t.pt" LINE 3: WHERE users.uid = 't#t.pt'
app.py
from flask import Flask, render_template, request, session, redirect, url_for
from models import db, User
from forms import SignupForm, LoginForm
from flask_login import LoginManager, UserMixin, \
login_required, login_user, logout_user
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://localhost/polex'
db.init_app(app)
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = "login"
app.secret_key = "development-key"
#login_manager.user_loader
def user_loader(uid):
"""Given *user_id*, return the associated User object.
:param unicode user_id: user_id (email) user to retrieve
"""
return User.query.get(uid)
#app.route("/")
def index():
return render_template("index.html")
#app.route("/about")
def about():
return render_template("about.html")
#app.route("/signup", methods=["GET", "POST"])
def signup():
if 'email' in session:
return redirect(url_for('home'))
form = SignupForm()
if request.method == "POST":
if form.validate() == False:
return render_template('signup.html', form=form)
else:
newuser = User(form.first_name.data, form.last_name.data, form.email.data, form.password.data)
db.session.add(newuser)
db.session.commit()
session['email'] = newuser.email
return redirect(url_for('home'))
elif request.method == "GET":
return render_template('signup.html', form=form)
#app.route("/login", methods=["GET", "POST"])
def login():
print db
form = LoginForm()
if request.method == "POST":
if form.validate() == False:
return render_template("login.html", form=form)
else:
email = form.email.data
password = form.password.data
user = User.query.filter_by(email=email).first()
if user is not None and user.check_password(password):
login_user(user, remember=True)
return redirect(url_for('home'))
else:
return redirect(url_for('login'))
elif request.method == 'GET':
return render_template('login.html', form=form)
#app.route("/logout")
def logout():
session.pop('email', None)
return redirect(url_for('index'))
#app.route("/home", methods=["GET", "POST"])
def home():
return render_template("home.html")
if __name__ == "__main__":
app.run(debug=True)
models.py
from flask_sqlalchemy import SQLAlchemy
from werkzeug import generate_password_hash, check_password_hash
from flask_login import UserMixin
db = SQLAlchemy()
class User(db.Model):
__tablename__ = 'users'
uid = db.Column(db.Integer, primary_key = True)
firstname = db.Column(db.String(100))
lastname = db.Column(db.String(100))
email = db.Column(db.String(120), unique=True)
pwdhash = db.Column(db.String(54))
#-----login requirements-----
def is_active(self):
#all users are active
return True
def get_id(self):
# returns the user e-mail. not sure who calls this
return self.email
def is_authenticated(self):
return self.authenticated
def is_anonymous(self):
# False as we do not support annonymity
return False
def __init__(self, firstname, lastname, email, password):
self.firstname = firstname.title()
self.lastname = lastname.title()
self.email = email.lower()
self.set_password(password)
def set_password(self, password):
self.pwdhash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.pwdhash, password)
You're using User.query.get(uid) where you need to use filter or filter_by:
#login_manager.user_loader
def user_loader(user_email):
"""Given *user_id*, return the associated User object.
:param unicode user_id: user_id (email) user to retrieve
"""
return User.query.filter_by(email=user_email).first()
get() takes a Primary Key (which would be user id in this case) and returns it, filter is what you need here if you're trying to limit on a column value.
Related
I have a RegisterForm and LoginForm made with Flask and hashed with sha256. The RegisterForm works, but the login page is not returning anything. I stay in the same login page, the only difference is the url returns this:
HTTP/1.1[0m" 304 -INFO:werkzeug:127.0.0.1 - - [27/Nov/2021 04:56:29]
"GET /?username=alex29&password=12345&submit=Login HTTP/1.1" 200 -
And the url change to this:
http://localhost:5000/?username=alex29&password=12345&submit=Login
from flask import Flask, render_template, url_for, redirect, session, flash, request
from flask_sqlalchemy import SQLAlchemy
from flask_login import UserMixin, login_user, LoginManager, login_required, logout_user, current_user
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import InputRequired, Length, ValidationError
from flask_bcrypt import Bcrypt
from werkzeug.security import generate_password_hash, check_password_hash
from flask_wtf.csrf import CSRFProtect
from werkzeug.urls import url_parse
import sqlite3
app = Flask (__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///gestdoc.db'
app.config['SECRET_KEY'] = 'thisisasecretkey'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
USER_LOGIN_URL = '/login'
USER_ENABLE_USERNAME = True
csrf = CSRFProtect(app)
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
#login_manager.user_loader
def load_user(id_user):
return User.query.get(int(id_user))
class User(db.Model, UserMixin):
id_user = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), nullable=False, unique=True)
password = db.Column(db.String(80), nullable=False)
authenticated = db.Column(db.Boolean, default=False)
def set_password(self, password):
self.password = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password, password)
def is_active(self):
return True
def is_authenticated(self):
return True
def is_anonymous(self):
return True
class employee(db.Model):
id_employee = db.Column(db.CHAR(100), primary_key=True)
name = db.Column(db.TEXT(100), nullable=False)
surname = db.Column(db.TEXT(100), nullable=False)
class RegisterForm(FlaskForm):
username = StringField(validators=[InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Usuario"})
password = PasswordField(validators=[InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "ContraseƱa"})
submit = SubmitField("Register")
def validate_username(self, username):
user = User.query.filter_by(username=username.data).first()
if user is not None:
raise ValidationError('Este usuario ya existe. Use otro.')
class EmployeeForm(FlaskForm):
id_employee = StringField(validators=[InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "DNI"})
name = StringField(validators=[InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "NOMBRE"})
surname = StringField(validators=[InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "APELLIDOS"})
submit = SubmitField("Guardar")
def validate_employee(self, employee):
check_id_employee = User.query.filter_by(employee=id_employee.data).first()
if check_id_employee:
raise ValidationError('Este empleado ya existe.')
class LoginForm(FlaskForm):
username = StringField(validators=[InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Username"})
password = PasswordField(validators=[InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Password"})
submit = SubmitField('Login')
#app.route('/', methods=['GET','POST'])
def login():
form = LoginForm(meta={'csrf': False})
if form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first()
if user:
if check_password(user.password, form.password.data):
login_user(user)
flash("Log In")
return redirect(url_for('admin'))
else:
flash('Invalid password')
else:
flash('usuario no existe')
return render_template('login.html', form=form)
#app.route('/admin', methods=['GET','POST'])
#login_required
def showemployee():
con = sqlite3.connect('gestdoc.db')
cur = con.cursor()
cur.execute('SELECT * from employee')
employee = cur.fetchall()
con.close()
return render_template('admin.html', employee=employee)
#app.route('/register', methods=['GET','POST'])
def register():
form = RegisterForm()
if form.validate_on_submit():
user = User(username=form.username.data)
user.set_password(form.password.data)
db.session.add(user)
db.session.commit()
flash('Usuario registrado')
return redirect(url_for('login'))
return render_template('register.html', form=form)
import logging
logging.basicConfig(filename = "sample.log", level = logging.DEBUG,filemode = "w+" )
logging.debug('debug')
logging.info('info')
logging.warning('warning')
logging.error('error')
logging.critical('critical')
if __name__ == '__main__':
app.run(debug=True)
Thank you for the help
I think you forgot to change the login form method to "post"
source
Here you can find an example of how to set the needed form attributes.
Here's my code:
from flask import Flask, render_template, request, redirect
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
app = Flask(__name__)
app._static_folder = 'static/'
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:test#localhost/Scheduling'
db = SQLAlchemy(app)
class CPR_INFO(db.Model):
DEAL_ID = db.Column(db.String(50), primary_key=True)
POG_NUM = db.Column(db.String(50))
OPOG_START_DT = db.Column(db.Date())
OPOG_END_DT = db.Column(db.Date())
def __repr__(self):
return 'Deal_ID ' + str(self.DEAL_ID)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/posts', methods=['GET', 'POST'])
def posts():
if request.method == 'POST':
post_id = request.form['DEAL_ID']
post_title = request.form['POG_NUM']
post_content = request.form['OPOG_START_DT']
new_post = CPR_INFO(DEAL_ID = post_id, POG_NUM=post_title, OPOG_START_DT=post_content)
db.session.add(new_post)
db.session.commit()
return redirect('/posts')
else:
all_posts = CPR_INFO.query.all()
return render_template('posts-2.html', posts=all_posts)
#app.route('/posts/new', methods = ['GET', 'POST'])
def new_post():
if request.method == 'POST':
post_id = request.form['DEAL_ID']
post_title = request.form['POG_NUM']
post_content = request.form['OPOG_START_DT']
new_post = CPR_INFO(DEAL_ID=post_id, POG_NUM=post_title, OPOG_START_DT=post_content)
db.session.add(new_post)
db.session.commit()
return render_template('posts-2.html', posts=all_posts)
else:
return render_template('new_post_2.html')
#app.route('/posts/delete/<string:DEAL_ID>')
def delete(DEAL_ID):
post = CPR_INFO.query.get_or_404(DEAL_ID)
db.session.delete(post)
db.session.commit()
return redirect('/posts')
#app.route('/posts/edit/<string:DEAL_ID>', methods = ['GET', 'POST'])
def edit(DEAL_ID):
post = CPR_INFO.query.get_or_404(DEAL_ID)
if request.method == 'POST':
post.DEAL_ID = request.form['DEAL_ID']
post.POG_NUM = request.form['POG_NUM']
post.OPOG_START_DT = request.form['OPOG_START_DT']
db.session.commit()
return redirect('/posts')
else:
return render_template('edit-2.html', post = post)
if __name__ == "__main__":
app.run(debug=True)
This part of my code fails. The URL is not rendered because the DEAL_ID is not read:
#app.route('/posts/delete/<string:DEAL_ID>')
def delete(DEAL_ID):
post = CPR_INFO.query.get_or_404(DEAL_ID)
db.session.delete(post)
db.session.commit()
return redirect('/posts')
I get the following error message on my HTML page:
Not Found
The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
Add methods parameter at your #app.route('/posts/delete/<string:DEAL_ID>')
I've got this message:
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: user
[SQL: INSERT INTO user (username, email, password) VALUES (?, ?, ?)]
[parameters: ('test', 'test#test.com', 'password')]
(Background on this error at: http://sqlalche.me/e/e3q8)
when I tried: db.session.commit(). I'm following a tutorial and try to personalize the code but with bad results.
What I did so far is:
>>> from lagerut import db
>>> db.create_all()
>>> from models import User
>>> user_1 = User(username='test', email='test#test.com', password='password')
>>> db.session.add(user_1)
>>> db.session.commit()
Here the lagerut.py:
from datetime import datetime
from flask import Flask, render_template, url_for, flash, redirect
from flask_sqlalchemy import SQLAlchemy
from form import RegistrationForm, LoginForm
app = Flask(__name__)
app.config['SECRET_KEY'] = '2a1de6eea4126191912d6e702c6aa8f9'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///lagerut.db'
db = SQLAlchemy(app)
#app.route('/')
#app.route('/home')
def home():
return render_template ('home.html')
#app.route('/how-it-works')
def howitworks():
return render_template ('how-it-works.html', title='How it works')
#app.route('/lager-out')
def lagerout():
return render_template ('lager-out.html', title='Lager out')
#app.route('/lager-in')
def lagerin():
return render_template ('lager-in.html', title='Lager in')
#app.route("/register", methods=['GET', 'POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
flash(f'Account created for {form.username.data}!', 'success')
return redirect(url_for('home'))
return render_template('register.html', title='Register', form=form)
#app.route("/login", methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
if form.email.data == 'admin#blog.com' and form.password.data == 'password':
flash('You have been logged in!', 'success')
return redirect(url_for('home'))
else:
flash('Login Unsuccessful. Please check username and password', 'danger')
return render_template('login.html', title='Login', form=form)
if __name__ == '__main__':
app.run(debug=True)
And here the models.py:
from datetime import datetime
from lagerut import db
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)
def __repr__(self):
return f"User('{self.username}', '{self.email}')"
class Items(db.Model):
item_number = db.Column(db.Integer, primary_key=True)
description = db.Column(db.String(200), nullable=False)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
department = db.Column(db.String(100), nullable=False)
content = db.Column(db.Text, nullable=False)
def __repr__(self):
return f"Items('{self.product}', '{self.date_posted}', '{self.content}', '{self.department}', '{self.content}')"
Should I try to write the code again? I'm just trying to learn how build a little app to my work.
Is a good way to learn programming works also with the shell?
That's because you are not creating the app context while creating the database since you are doing this via python shell you need to add the following line
with app.app_context():
Read more about this here https://flask.palletsprojects.com/en/1.0.x/appcontext/
when I run this in the browser through route /blogs, I am given an internal server error. What does this mean, and how could I potentially fix this error. There is no error returned when I run other routes.
app.py:
from flask import Flask
from flask import render_template
from flask import request
from flask import session
from src.common.database import Database
from src.models.user import User
app = Flask(__name__)
app.secret_key = "Jongbin"
#app.route('/')
def home_template():
return render_template('home.html')
#app.route('/login')
def login_template():
return render_template('login.html')
#app.route('/register')
def register_template():
return render_template('register.html')
#app.before_first_request
def initialise_database():
Database.initialize()
#app.route('/auth/login', methods=['POST'])
def login_user():
email = request.form['email']
password = request.form['password']
if User.login_valid(email, password):
User.login(email)
else:
session['email'] = None
return render_template("profile.html", email=session['email'])
#app.route('/auth/register', methods=['POST'])
def register_user():
email = request.form['email']
password = request.form['password']
User.register(email, password)
return render_template("profile.html", email=session['email'])
#app.route('/blogs/<string:user_id>')
#app.route('/blogs')
def user_blogs(user_id=None):
if user_id is not None:
user = User.get_by_id(user_id)
else:
user = User.get_by_email(session['email'])
blogs = user.get_blogs()
return render_template("user_blogs.html", blogs=blogs, email=user.email)
if __name__ == '__main__':
app.run(port=4995)
user.py:
import uuid
import datetime
from flask import session
from src.common.database import Database
from src.models.blog import Blog
class User(object):
def __init__(self, email, password, _id=None):
self.email = email
self.password = password
self._id = uuid.uuid4().hex if _id is None else _id
#classmethod
def get_by_email(cls, email):
data = Database.find_one("users", {'email': email})
if data is not None:
return cls(**data)
return None
#classmethod
def get_by_id(cls, _id):
data = Database.find_one("users", {'_id': _id})
if data is not None:
return cls(**data)
#staticmethod
def login_valid(email, password):
user = User.get_by_email(email)
if user is not None:
return user.password == password
return False
#classmethod
def register(cls, email, password):
user = cls.get_by_email(email)
if user is None:
new_user = cls(email, password)
new_user.save_to_mongo()
session['email'] = email
return True
else:
return False
#staticmethod
def login(user_email):
session['email'] = user_email
#staticmethod
def logout():
session['email'] = None
def get_blogs(self):
return Blog.find_by_author_id(self._id)
def new_blog(self, title, description):
blog = Blog(author=self.email,
title=title,
description=description,
author_id=self._id)
blog.save_to_mongo()
#staticmethod
def new_post(blog_id, title, content, date=datetime.datetime.utcnow()):
blog = Blog.from_mongo(blog_id)
blog.new_post(title=title,
content=content,
date=date)
def json(self):
return {
"email": self.email,
"_id": self._id,
"password": self.password
}
def save_to_mongo(self):
Database.insert("users", self.json())
I can't figure out why I can't get passed the login page. It doesn't matter if I type in the right or wrong credentials, It reloads the login page, instead of signing me in.
import json
from flask import Flask, render_template, request, url_for, redirect
from flask.ext.bootstrap import Bootstrap
from flask.ext.login import LoginManager, UserMixin, login_required, login_user, current_user
from bson.objectid import ObjectId
from lib.mongo import db
from scripts.twitter_stats import ratio_of_wiki_links
app = Flask(__name__)
app.config["SECRET_KEY"] = ''
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
bootstrap = Bootstrap(app)
class User(UserMixin):
def __init__(self, name, password, id, active=True):
self.name = name
self.password = password
self.id = id
self.active = active
def is_active(self):
account = db.accounts.find_one({ "_id": ObjectId("561c7990e4b060b59d7cbcd1")})
if not account['username'] == self.name and account['password'] == self.password:
self.active = False
return self.active
def is_anonymous(self):
return False
def is_authenticated(self):
return True
def get_id(self):
return str(db.accounts.find_one({'username': self.name})['_id'])
#login_manager.user_loader
def load_user(userid):
user = db.accounts.find_one({'_id': userid})
return user
#app.route('/login', methods=['POST', 'GET'])
def login():
account = db.accounts.find_one({ "_id": ObjectId("561c7990e4b060b59d7cbcd1")})
password = account['password']
user = account['username']
error = None
if request.method == 'POST':
username = request.form['username']
passw = request.form['password']
if username != user or passw != password:
error = 'Invalid Credentials, please try again'
else:
user = User(username, passw, account['_id'])
login_user(user)
return redirect(url_for('home'))
return render_template('login.html', error=error)
#app.route('/')
#login_required
def home():
account = db.accounts.find_one({'account': 'twitter'})
entry = db.tweets.find().sort([['_id', -1]]).limit(1)
entry = list(entry)[0]['post']
# if g.user.is_authenticated():
# g.user = user.name
return render_template('index.html', account=account, entry=entry)
You should call add_routes before run app
if __name__ == '__main__':
add_routes(app)
app.run(debug=True)
For those of you struggling with the same issue, my problem was with the load_user method. I fixed it by changing it to this:
#login_manager.user_loader
def load_user(userid):
user_rec = db.accounts.find_one({'_id': ObjectId(userid)})
user = User(user_rec['username'], user_rec['password'], user_rec['_id'])
return user