In an attempt to run a flask project, which uses both wsgi, nginx in a docker configuration, I am facing the following error:
No user_loader has been installed for this LoginManager. Refer to https://flask-login.readthedocs.io/en/latest/#how-it-works for more info. However, if no login is considered, the system works fine.
How could I solve this?
Some more info:
My system files are as follows:
__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate, MigrateCommand
from flask_script import Manager
from flask_bcrypt import Bcrypt
from flask_login import LoginManager
app = Flask(__name__)
app.config.from_object('instance.config')
db = SQLAlchemy(app)
migrate = Migrate(app, db)
flask_bcrypt = Bcrypt(app)
manager = Manager(app)
Code to control the user session:
from instance.config import SECRET_KEY_LOGIN
login_manager = LoginManager(app)
---------------------------------------------------------------------------
login.py
from flask import render_template, request, Blueprint, url_for, redirect
from flask_login import login_user, logout_user, current_user
from app import flask_bcrypt, login_manager
from app.models.login import LoginForm
from app.models.tabelas import Usuario
sign_in = Blueprint('sign_in', __name__)
#login_manager.user_loader
def load_user(id_usuario):
return Usuario.query.filter_by(id_usuario=id_usuario).first()
#login_manager.request_loader
def request_loader(_request):
# print ('using request loader')
# return "load_user_token(_request)"
#sign_in.route('/', methods=['GET', 'POST'])
#sign_in.route('/login', methods=['GET','POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('home'))
else:
error = None
form = LoginForm()
if request.method == 'POST':
if form.validate_on_submit():
usuario = Usuario.query.filter_by(ds_email = form.ds_email.data).first()
if usuario and flask_bcrypt.check_password_hash(usuario.ds_password, form.ds_password.data):
login_user(usuario)
return redirect(url_for('home'))
else:
error = 'Invalid Login .'
else:
error = 'Error'
print(form.errors)
return render_template('admin/login.html', form=form, error=error)
Add in your __init__.py this code below the login_manager instance.
#login_manager.user_loader
def load_user(id):
return User.query.filter_by(user_id=id).first()
After that you can delete the #login_manager decorator and its respect function from login.py
Related
I am trying to build a web app with login and signup in the nav-bar/header. When I open the web app using index.html, the login and signup option shows at the top (in nav-bar) but when I do python -m flask run, it never shows that login/signup option. I will attach a snippet of my app.py
from distutils.log import debug
from operator import imod
from pickle import FALSE
import re
from flask import Flask,render_template,url_for,redirect,flash,request
from flask_sqlalchemy import SQLAlchemy
import os
from flask_login import LoginManager,login_user,login_required,logout_user,current_user
from flask_migrate import Migrate
from forms import RegistrationForm,LoginForm
from models import User
from flask_bcrypt import Bcrypt
from flask_login import LoginManager
app = Flask(__name__)
#* ATTACHING DATABASE TO PROJECT FOR USER CREATION
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///mydb.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
#* ENCRYPTING THE PASSWORD text
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
# GENERATING SECRET-KEY
SECRET_KEY = os.urandom(32)
app.config['SECRET_KEY'] = SECRET_KEY
# CREATING THE MIGRATIONS
migrate = Migrate(app, db)
# login Manager
login_manager = LoginManager()
login_manager.login_view = 'login'
login_manager.init_app(app)
#login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
#app.route('/',methods=['GET'])
def index():
return render_template("index.html",user=current_user)
#app.route('/how_to_play')
#login_required
def how_to_play():
return render_template("how_to_play.html")
#app.route('/play')
def play():
return render_template("play.html")
#app.route('/register', methods = ['POST','GET'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
hashed_password = bcrypt.generate_password_hash(form.password1.data).decode('utf-8')
user = User(username =form.username.data, email = form.email.data,password=hashed_password)
db.session.add(user)
db.session.commit()
return redirect(url_for('login'))
return render_template('registration/registration.html', form=form)
#app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user and bcrypt.check_password_hash(user.password, form.password.data):
login_user(user)
return render_template("index.html",user=current_user)
flash('Invalid email address or Password.')
return render_template('registration/login.html', form=form)
#app.route("/logout")
def logout():
logout_user()
return render_template("index.html",user=current_user)
#app.route('/share/score/', methods = ['GET'])
def share_score():
return render_template('share_score.html')
if __name__ == "__main__":
app.run(debug=True)
Not sure where I am going wrong. Any idea would be appreciated.
Because Flask template doesn't load navbar. Route in Flask doesn't work like route in HTML. In HTML we only need add route like src="/navbar.html", but if the route isn't added in code in Flask, it does not appear when render template.
So you can follow this step https://www.geeksforgeeks.org/navigation-bars-in-flask/
There are a lot of questions regarding this but none of them are using Flask Blueprints.
I am trying to set up a QuerySelectField with a sqlite3 lookup.
But I get then error:
RuntimeError: No application found. Either work inside a view function or push an application context.
Here is my application structure:
My init.py
from flask import Flask, render_template, current_app
from flask_mail import Mail
from flask_login import LoginManager
from flask_bootstrap import Bootstrap
from flask_ckeditor import CKEditor
from instance.config import app_config
from app.views.ticket import ticket as ticket_blueprint
from app.views.users import users as user_blueprint
from app.views.main import main as main_blueprint
from app.models import User, db
login_manager = LoginManager()
def page_not_found(e):
return render_template('404.html'), 404
def register_blueprints_on_app(app):
app.register_blueprint(user_blueprint)
app.register_blueprint(ticket_blueprint)
app.register_blueprint(main_blueprint)
def login_manager_init(app):
login_manager.login_view = 'users.login'
login_manager.init_app(app)
# associate id in the cookie with the User object
#login_manager.user_loader
def load_user(user_id):
print(user_id)
return User.query.get(user_id)
# application factory
def create_app(config):
# create application instance
app = Flask(__name__, instance_relative_config=True)
app.register_error_handler(404, page_not_found)
app.config.from_object(app_config[config])
app.config.from_pyfile('config.py')
Bootstrap(app)
mail = Mail()
mail.init_app(app)
db.init_app(app)
ckeditor = CKEditor()
ckeditor.init_app(app)
login_manager_init(app)
register_blueprints_on_app(app)
return app
And here is the problematic forms.py which is under ticket/views/
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, TextAreaField, FieldList, DateTimeField, SelectField
from wtforms_sqlalchemy.fields import QuerySelectField
from wtforms.fields.html5 import EmailField, TelField
from wtforms.validators import InputRequired, Email
from flask_ckeditor import CKEditorField
from app.models import User
def user_query():
query = User.query()
return query
class TicketForm(FlaskForm):
requested_by = QuerySelectField(label='Requested by',
query_factory=user_query(),
allow_blank=False,
get_label='fullname')
department = SelectField(label='Department')
phone = TelField(label='Phone')
email = EmailField(label='Email', validators=[Email('Enter a valid email address')])
short_desc = StringField(label='Short Description', validators=[InputRequired('Must enter a short description')])
description = CKEditorField(label='Description')
classification = StringField(label='Classification')
priority = StringField(label='Priority')
sla_respond_by = DateTimeField(label='Respond by', render_kw={'readonly': True})
sla_resolve_by = DateTimeField(label='Resolve by', render_kw={'readonly': True})
sla_status = StringField(label='SLA Status', render_kw={'readonly': True})
related_tickets = FieldList(StringField(label='Ticker #'))
client_journal = TextAreaField(label='Client Area')
work_notes = TextAreaField(label='Work Notes')
closed_at = DateTimeField(label='Closed')
closed_by = StringField(label='Closed by')
followed_by = StringField(label='Followed by')
submit = SubmitField('Save')
The problem part is when this runs
def user_query():
query = User.query()
return query
I get the error.
For context here is the routes file under ticket/view
from flask import render_template
from app.views.ticket.forms import TicketForm
from flask_login import login_required
from . import ticket
#ticket.get('/ticket')
#ticket.put('/ticket')
#login_required
def ticket():
form = TicketForm()
return render_template('ticket.html', form=form)
And in ticket/view/init.py
from flask import Blueprint
ticket = Blueprint('ticket', __name__, static_folder='static', template_folder='templates')
from . import routes
I read the doc here but it was no help. https://flask-sqlalchemy.palletsprojects.com/en/2.x/contexts/
I can't work out how to pass the application context so this function works.
I got around this by not using a query_factory in the QuerySelectfield.
I changed the field declaration from this:
class TicketForm(FlaskForm):
requested_by = QuerySelectField(label='Requested by',
query_factory=user_query(),
allow_blank=False,
get_label='full_name')
To this:
class TicketForm(FlaskForm):
requested_by = QuerySelectField(label='Requested by',
allow_blank=False,
get_label='full_name')
(so, just removed query_factory=user_query(),)
I deleted this:
def user_query():
query = User.query()
return query
Then added this to the route in my Blueprint:
#ticket.get('/ticket')
#ticket.put('/ticket')
#login_required
def ticket():
form = TicketForm()
form.requested_by.query = User.query.all() # Added this
print(current_app.app_context())
return render_template('ticket.html', form=form)
I hope that helps someone as it was doing my head in.
I'd still like to know how to do it the other way with a query_factory as I'm sure there is a way. So if anyone knows please share!
I'm coding a simple flask app and I have already done all the login process. I'm not getting errors but the problem appears when I try to log in, somehow the program doesn't recognize me as a user, although I had already sign up correctly and my user data is in the database. So what ends happening is me trying to access to app_home route and, because it is a login_required route and the login doesn't save my data, I fall into a loop in the login page without being able to do anything.
Here is all the code:
server.py:
from flask import Flask
from flask_mongoengine import MongoEngine
from flask_login import LoginManager
from models import User
app = Flask(__name__)
...
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
login_manager.init_app(app)
#login_manager.user_loader
def load_user(email):
return User.objects(email=email).first()
if __name__ == '__main__':
app.run(debug=True)
models.py:
from flask_login import UserMixin
from mongo_setup import db
class User(UserMixin, db.Document):
email = db.StringField()
password = db.StringField()
auth.py:
from flask import Blueprint, render_template, redirect, url_for, request, flash
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import login_user, logout_user, login_required
auth = Blueprint('auth', __name__)
from mongo_setup import db
from models import User
...
#auth.route('/signup', methods=['GET', 'POST'])
def signup():
if request.method == 'POST':
email = request.form.get('email')
password = request.form.get('password')
user_email = User.objects(email=email).first()
if user_email:
flash("Email address already exists")
return redirect(url_for('auth.signup'))
User(email=email,
password=generate_password_hash(password, method='sha256')
).save()
return render_template('signup.html')
#auth.route('/login')
def login_get():
return render_template('login.html')
#auth.route('/login', methods=['POST'])
def login():
email = request.form.get("email")
password = request.form.get("address")
remember = True if request.form.get('remember') else False
user = User.objects(email=email).first()
if not user or not check_password_hash(user.password, password):
flash('Please check your login details and try again.')
return redirect(url_for('auth.login'))
login_user(user, remember=remember)
return redirect(url_for('auth.app_home'))
#auth.route('/app/<address>/<data>/<delete>', methods=['GET', 'POST'])
#login_required
def app_home(address, data, delete):
return render_template('app.html')
#login_manager.user_loader
def load_user(id):
return User.query.get(int(id))
You need to either change your load_user method to find the User object by id or overload the get_id() method on your User model to match your load_user() method to uniquely identify the user by email.
See: https://flask-login.readthedocs.io/en/latest/#how-it-works
So what I did is that I tried to run my flask app but suddenly I got a error which is
TypeError: storage must be a werkzeug.FileStorage
This is the code that I use...
init.py
# IMPORT
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_migrate import Migrate
from flask_login import LoginManager
from flask_uploads import UploadSet, configure_uploads, IMAGES, patch_request_class
from blogapp.config import Config
# INIT
db = SQLAlchemy()
bcrypt = Bcrypt()
login_manager = LoginManager()
migrate = Migrate()
login_manager.login_view = 'users.login'
login_manager.login_message_category = 'info'
photos = UploadSet('photos', IMAGES)
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(Config)
db.init_app(app)
bcrypt.init_app(app)
login_manager.init_app(app)
migrate.init_app(app, db)
configure_uploads(app, photos)
patch_request_class(app)
from blogapp.users.routes import users
from blogapp.posts.routes import posts
from blogapp.main.routes import main
from blogapp.errors.handlers import errors
app.register_blueprint(users)
app.register_blueprint(posts)
app.register_blueprint(main)
app.register_blueprint(errors)
return app
config.py
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config:
SECRET_KEY = os.environ.get('SECRET_KEY')
SQLALCHEMY_DATABASE_URI = os.environ.get('SQLALCHEMY_DATABASE_URI')
UPLOADED_PHOTOS_DEST = os.path.join(basedir, 'uploads')
I have a uploads folder in my parent directory
routes.py
from flask import (render_template, url_for, flash,
redirect, request, abort, Blueprint)
from flask_login import current_user, login_required
from blogapp import db, photos
from blogapp.models import Post
from blogapp.posts.forms import PostForm
posts = Blueprint('posts', __name__)
#posts.route("/post/new", methods=['GET', 'POST'])
#login_required
def new_post():
form = PostForm()
if form.validate_on_submit():
filename = photos.save(form.photo.data)
file_url = photos.url(filename)
else:
file_url = None
if form.validate_on_submit():
post = Post(title=form.title.data, content=form.content.data, image=form.photo.data, author=current_user)
db.session.add(post)
db.session.commit()
flash('Your post has been created!', 'success')
return redirect(url_for('main.home'))
return render_template('create_post.html', title='New Post',
form=form, file_url=file_url, legend="Post")
Can someone help me?
I'm a bit confuse with how I got the error..
Did I do something wrong?
There isn't any thing I could find out there, so for me this is very confusing..
Could it be something wrong with the application factory while using flask upload?
Traceback
When I have a look at your routes.py, I see some possible problems.
new_post does accept both get and post requests, but does not handle them differently.
e.g. usually when there is a get request, you want to just render the empty form, but when there is a post request, you want to e.g. save the file.
You have two if form.validate_on_submit statements. You can simplify them when you move the else to the bottom, just above the return statement. Actually, you do not need an else path as, when the if path is valid, you leave the function with the return redirect already.
About your problem.
The error message clearly says, that form.photo.data is no uploaded file.
Please fix the above suggestions and try it again.
Also make sure you do not send an empty form. Btw - you did not show your form template. Maybe there is no data field?
If you followed all suggestions, but without success, please set a breakpoint just after e.g. form = PostForm() and carefully step through your program and especially inspect what value form.photo.data shows.
All you have to do is in your HTML file, set the FORM "enctype = multipart/form-data"
This is my first post on here, glad i reached as this code is whipping my mental energy, enjoying it all the same :) So I'm trying to build the blog project using PyMongo and flash-login, LoginManager, but its just returning errors. I'm following along with the code from Miguel Grinbergs awesome blog videos. I've been scratching my head on this for a few days now and would really appreciate the input. Thanks and Happy Friday
import os
import env
import model
from model import User
from flask_login import LoginManager, current_user, login_user
from flask import Flask, render_template, url_for, flash, redirect
from flask_pymongo import PyMongo
from forms import LoginForm
from werkzeug.security import generate_password_hash, check_password_hash
app = Flask(__name__)
# SSSSHHHH
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY')
app.config["MONGO_URI"] = os.environ.get("MONGO_URI")
mongo = PyMongo(app)
login = LoginManager(app)
#app.route('/')
def base():
return render_template('base.html')
#app.route('/index')
def home():
return render_template('index.html', title='Home')
#app.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('index'))
form = LoginForm()
# IF ITS RIGHT THE FIRST TIME
if form.validate_on_submit():
user = User.mongo.db.find_one(username=form.username.data).first_or_404()
if user is None or not user.check_password(form.password.data):
flash(f'Invalid username or password')
return redirect(url_for('home'))
#flash('Login success for user {}, remember_me{}'.format(
#form.username.data, form.remember_me.data))
login_user(user, remember=form.remember_me.data)
return redirect(url_for('home'))
return render_template('login.html', title='Log In', form=form)
if __name__ == '__main__':
app.run(host=os.environ.get('IP'),
port=int(os.environ.get('PORT')),
debug=True)
import os
from mini import login
from flask_login import UserMixin, User
#login.user_loader
def load_user(_id):
return User.mongo.db.find(toInt(_id))
class User(UserMixin, db.Document):
_id = ObjectId (primary_key=True)
username = StringField (unique=True)
email = StringField (unique=True)
password = StringField (default=True)
# REPR TELLS PYTHON HOW TO DEAL WITH OBJECTS OF THIS. CLASS
def __repr__(self):
return '<User {}>'.format(self.username)