I'm trying to import a Flask blueprint into my main file. However, when I do from flask_first.login_user.login import login, I get cannot import name 'login' from partially initialized module 'flask_first.login_user.login' (most likely due to a circular import) (C:\Users\Max\PycharmProjects\python1\flask_first\login_user\login.py). How do I fix this?
flask_first/login_user/login.py:
from flask_first.main import *
from flask import Blueprint
from flask_first.main import users, db
from flask_sqlalchemy import SQLAlchemy
from datetime import timedelta
#login.route('/')
def login():
error = None
if request.method == 'POST': # checking if the method is POST, it means we got a query from button
if request.form['nm'] == 'admin' or request.form['ps'] == 'secret':
flash("You were successfully logged in into the admin's user page")
session.permanent = True
session['user'] = request.form['nm']
password = request.form['ps']
password = session['password']
return redirect(url_for('administrating'))
else: # if we are not admins, continue with this code
flash(f"You were successfully logged in", category='success')
session.permanent = True # setting the bool of session to permanent
session['user'] = request.form[
'nm'] # we are just saying that the session['user']= the name, which we typed into the field
user1 = session['user'] # user1 not a function
session['password'] = request.form['ps'] # session['password']= field, in which we typed our password
password1 = request.form['ps']
found_user = users.query.filter_by(name=user1,
password=password1).first() # we are filtering all the users in the database by the name and password, we typed while logging in
if found_user: # if we have found this user, we say that the email he typed previously is now in the field of email
session[
'email'] = found_user.email # we are saying that the email user typed previously, is now the session['email']
else:
usr = users(user1, '',
password1) # if we haven't found that user by name and password, we create a new one
db.session.add(usr)
db.session.commit()
return redirect(
url_for('user')) # redirecting to the user's page after logging in(using user's name)
else: # below is a standard script, which checks whether we are logged or not
if 'user' in session: # if user is already logged, it will download the user page.
flash('You are already logged in, to log out, type logout')
return redirect(url_for('user'))
else:
flash("You have not logged yet", category='success')
return render_template('login_user.html', error=error) # if it didn't go properly, we force the comeback
# to the login_user page again
flask_first/main.py:
from datetime import timedelta
from flask import Flask, redirect, url_for, render_template, request, session, flash
from flask_sqlalchemy import SQLAlchemy
from flask_first.admin.second import second
from flask_first.login_user.login import login
app = Flask(__name__)
app.secret_key = 'hello world'
app.register_blueprint(second, url_prefix='/test')
app.register_blueprint(login, url_prefix='login_user')
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.sqlite3.html' # access to the SQL
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.permanent_session_lifetime = timedelta(minutes=5) # setting the time for long-lasting session
db = SQLAlchemy(app)
As the error suggests, you have a circular dependency issue. You are importing login from main and main from login. Modules cannot do that.
Check out the "problems" section In this wiki https://en.m.wikipedia.org/wiki/Circular_dependency
Related
I am attempting to create a control panel only using prisma-client-python, flask-login & flask as the primary webserver. I have successfully managed to create the routes, as well as built the registration screen & have also granted prisma access to the database. When I try to use the route,
Here is my code for the login route:
`
from flask import Blueprint, request, render_template
from prisma.models import User
from flask_login import login_user
login_blueprint = Blueprint('login', __name__ , template_folder='../pages/')
#login_blueprint.route('/', methods=['GET','POST'])
def list_create():
if request.method == 'GET':
return render_template('login.html')
if request.method == 'POST':
data = request.form
if data is None:
return
email = data.get('email')
password = data.get('password')
if email is None or password is None:
return {"error": "You need to provide email and password"}
user = User.prisma().find_many(where={'email': email, 'password': password},)
print(user)
return login_user(user)
`
Here is my code for the registration route:
`
from flask import Blueprint, request, render_template
from prisma.models import User
user_blueprint = Blueprint('register', __name__ , template_folder='../pages/')
#user_blueprint.route('/', methods=['GET','POST'])
def list_create():
if request.method == 'POST':
data = request.form
if data is None:
return
name = data.get('username')
email = data.get('email')
password = data.get('password')
if name is None or email is None:
return {"error": "You need to provide name and email"}
user = User.prisma().create(data={'email': email, 'username': name, 'password': password})
return dict(user)
return render_template('register.html')
`
here is my prisma schema:
`
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator db {
provider = "prisma-client-py"
interface = "sync"
}
model User {
id Int #id #default(autoincrement())
createdAt DateTime #default(now())
email String #unique
password String
username String?
admin Boolean #default(false)
is_active Boolean #default(false)
}
`
& here is my main app.py route.
`
from flask import Flask
from prisma import Prisma, register
from routes.register import user_blueprint
from prisma.models import User
from routes.login import login_blueprint
# from routes.post import post_blueprint
db = Prisma()
db.connect()
register(db)
app = Flask(__name__)
#app.route('/', methods=['GET'])
def index():
return {
"ping": "pong"
}
app.register_blueprint(user_blueprint, url_prefix='/register')
app.register_blueprint(login_blueprint, url_prefix='/login')
if __name__ == "__main__":
app.run(debug=True, port=5000, threaded=True)
`
I had tried using login_user(user) as stated in code examples using it. But I keep getting the following error:
AttributeError: 'list' object has no attribute 'is_active'
Does anyone have any idea for what I should to resolve this problem & allow the user to login?
The login route (for which the function is also oddly called list_create) queries the database using find_many - which will return a list of items, not a single item. Flask's login() expects a single user, not a list. The exception makes sense, as the login function is provided with a list of user(s), not a user object.
A simple fix can be:
#login_blueprint.route('/', methods=['GET','POST'])
def list_create():
...
user = User.prisma().find_many(where={'email': email, 'password': password},)
if user and len(user) == 1:
return login_user(user[0])
return {"error": "Authentication error, or user does not exist"}
Alternatively, you can try using find_unique as per Prisma's documentation.
Hi there I'm creating a Flask web app and now I have to create more cruds, so I decided to modularize the app using Blueprints.
I have a Login function on main.py that allows me to enter the app interface:
app.route('/', methods=['GET', 'POST'])
def login():
# Output message if something goes wrong...
msg = ''
# Check if "username" and "password" POST requests exist (user submitted form)
if request.method == 'POST' and 'username' in request.form and 'password' in request.form:
# Create variables for easy access
username = request.form['username']
password = request.form['password']
# Check if account exists using MySQL
cursor = mysql.connection.cursor(MySQLdb.cursors.DictCursor)
cursor.execute(
'SELECT * FROM accounts WHERE username = %s AND password = %s', (username, password,))
# Fetch one record and return result
account = cursor.fetchone()
# If account exists in accounts table in out database
if account:
# Create session data, we can access this data in other routes
session['loggedin'] = True
session['id'] = account['id']
session['username'] = account['username']
# Redirect to home page
return redirect(url_for('client.home'))
else:
# Account doesnt exist or username/password incorrect
msg = 'Incorrect username/password!'
# Show the login form with message (if any)
return render_template('index.html', msg=msg)
It redirects to this Blueprint:
from flask import Blueprint, render_template
from flask import render_template, request, redirect, url_for, session, flash
from flask_mysqldb import MySQL
import MySQLdb.cursors
import re
from extension import mysql
client = Blueprint('client', __name__,
static_folder="../static", template_folder="../templates")
#client.route('/')
def home():
if 'loggedin' in session:
cur = mysql.connection.cursor()
cur.execute('SELECT * FROM cliente')
data = cur.fetchall()
# User is loggedin show them the home page
return render_template('home.html', username=session['username'], cliente=data)
# User is not loggedin redirect to login page
return redirect(url_for('login'))
It works just fine, but with a condition. On my main.py I also have this:
#app.route('/home')
def home():
pass
And this is the problem, I don't know why I should keep this route on my main.py because if I delete it my app crashes and throws me this error:
werkzeug.routing.BuildError
werkzeug.routing.BuildError: Could not build url for endpoint 'home'. Did you mean 'client.home' instead?
I have no idea why does this happens.
Why should I keep this route? or What I'm doing wrong?
Could you please give me a hand?
I've trying to change the redirect to using multiple routes, but if I delete that /home route.. my app crashes anyway.
in url_for look for the name of the function ie url_for('function_name', parameters)
so to avoid the crash better to change the name of main.py home function to something else.
Solved: I had one ref to Home on other file: Layout.html.
Just removed the ref and it's solved
I need to implement a simple login functionality to one of the applications that I a working on using flask-login. The authentication checking is hardcoded if condition and it is validating whether username password equals to a string given. The code is like the following:
#auth_bp.route('/login', methods=["POST"])
def loginHandler():
username = request.form.get('username')
password = request.form.get('password')
if username != 'admin' and password != 'Admin#123':
flash('Please check your login details and try again.')
return redirect(url_for('auth_bp.show_login'))
login_user(username, False)
# if the above check passes, then we know the user has the right credentials
return redirect(url_for('migration_bp.list'))
and in app.py file, I have the following code:
from flask import Flask
from flask_login import LoginManager, login_manager
from auth.auth import auth_bp
from environments.environments import environments_bp
from migration.migration import migration_bp
from logs.logs import logs_bp
UPLOAD_FOLDER = 'static/uploads'
#login_manager.user_loader
def user_loader():
# since the user_id is just the primary key of our user table, use it in the query for the user
return 1
def create_app():
app = Flask(__name__)
login_manager_copy = LoginManager()
login_manager_copy.login_view = 'auth.login'
login_manager_copy.init_app(app)
app.register_blueprint(auth_bp, url_prefix='/auth')
app.register_blueprint(environments_bp, url_prefix='/environments')
app.register_blueprint(migration_bp, url_prefix='/migration')
app.register_blueprint(logs_bp, url_prefix='/logs')
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
return app
if __name__ == '__main__':
create_app().run(debug=True)
But this is showing an error as follows:
AttributeError: module 'flask_login.login_manager' has no attribute 'user_loader'
As I don't need database, I think the User modal given in the examples are not needed. But it is giving errors without it. How can I fix this ?
EDIT:
As per the suggestion below, I have added a User class as shown below:
from flask_login import UserMixin, LoginManager, login_manager
class User(UserMixin):
def is_authenticated(self):
return True
def is_active(self):
return True
def is_anonymous(self):
return False
def get_id(self):
return int(self.id)
def __repr__(self):
return f"User('{self.username}', '{self.email}', '{self.powerlevel}')"
and added following code to app.py file:
#login_manager.user_loader
def load_user(user_id):
# since the user_id is just the primary key of our user table, use it in the query for the user
return User.query.get(int(user_id))
But it is still showing the same error.
app.py you will have this:
from flask_login import UserMixin, login_user, LoginManager, login_required, current_user, logout_user
app = Flask(__name__)
login_manager = LoginManager()
login_manager.init_app(app) #defined above app=Flask(__name__)
login_manager.login_view = 'login' #logged out users will be redirected to this route if attempting to view a route that requires login
#login_manager.user_loader
def load_user(id):
# This sets the callback for reloading a user from the session.
# The function you set should take a user ID and return a user object, or None if the user does not exist.
# id is str or int if the keys in data.USERS are str or int
# "123123" or 123123 (see next section)
try:
return data.USERS.get(str(id))
except:
return None
#app.route("/", methods=["GET","POST"])
def login():
if request.method == "POST":
if request.form["login"]:
id = request.form["id"]
password = request.form["password"]
response = data.confirmUserLogin(id, password)
if response["status"] == True:
# login the user
# Login user, You should pass the actual user object to this.
# If the user’s is_active property is False, they will not be logged in unless force is True
login_user(data.USERS[id])
flash(response["message"])
return redirect(url_for('index'))
else:
flash(response["message"])
return redirect(url_for('login'))
elif request.method == "GET":
return render_template("login.html")
data.py:
#you can use: class User(Usermixin)
"""
UserMixin pre-defines these attributes for your User class:
def is_authenticated():
...
def is_active():
...
def is_anonymous():
...
def get_id():
...
"""
# or you can just define these attributes yourself
class User():
def __init__(self, id, username, active=True):
self.id = id
self.username = username
self.active = active
def is_active(self):
# Here you should write whatever the code is
# that checks the database if your user is active
# return self.active
# for demo i just return True
return True
def is_authenticated(self):
# for demo i just return True
return True
def get_id(self):
# if you do not use Usermixin, this is important
# user_loader load_user(id) uses this get_id attribute to load the id
return self.id
# create local database of sample users
# Key are user id's : Value are User objects
USERS = {
"123123": User("123123", "user1"),
"456456": User("456456", "user2"),
"789789": User("789789", "user3", False),
}
def confirmUserLogin(id, password):
# check local db USERS for the id
if USERS.get(sso):
# get the user object (key's value)
user = USERS.get(id)
# check password
if user.password == password:
# entered password matches database password
response = {"status":True, "message":"Login Successfull!"}
return response
else:
# entered password DOES NOT match database password
response = {"status":False, "message":"Wrong password, please try again."}
return response
else:
# user does not exist
response = {"status":False, "message":"User does not exist, please try again."}
return response
I am quite sure that Flask-Login will not work without a class representing the data storage, because at some point it needs to access the database to know if a user has logged in already and other auth requirements.
Clearly as it does not impose a storage restriction, I think you can cheat the system without a database.
First create the User class as specified in the docs, https://flask-login.readthedocs.io/en/latest/
Define a class as so - all these methods are necessary.
class User:
def is_authenticated():
...
def is_active():
...
def is_anonymous():
...
def get_id():
...
Create a global variable that is of this user type and log users in and do whatever else. You do not necessarily need a database in which this class represents information in.
Let me know if you understood in the comments. Happy to help :)
Forgive me for my lack of knowledge. Am a complete newbie to flask and web technology concept.
I am in the process to build the login part of an app. After searching, I found flask login to be an option to use. After going through SQLAlchemy,Flask-login homepage, some blogs,tutorials,and going through questions on stack-oflow, tried to build a basic login part-code given below. I used SQLAlchemy, and database is POSTGres. This is just a start involving the login through email-password and session handling will involve more functions later.
In the code, I authenticate the user-id and password, and then assign corresponding UUID(primary key in User DB) from the database as a session variable, in order to create a session. Am I right in doing so?. In some 'stack-of' answers, it is mentioned that session-id is to be randomly generated after user authentication, and stored in a separate sessions table in database. Got confused.
I am passing UUID which is my primary key, as an 'id' for 'get_id' method. Is is right??
I tried implementing this code. However in chrome developement console, I see sessions, which dissappear after i logout.
import flask
from flask import Flask,render_template,request,url_for,redirect,session
from flask_sqlalchemy import SQLAlchemy
from flask_login import current_user, UserMixin, LoginManager, login_required, login_user,
logout_user
app = Flask(__name__)
db = SQLAlchemy(app)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:test#localhost/hw'
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
app.config['SECRET_KEY'] = 'thisissecret'
class User(UserMixin,db.Model):
__tablename__ = 'user'
__table_args__ = {'schema': 'logging'}
user_id = db.Column(db.VARCHAR,primary_key = True)
first_name = db.Column(db.VARCHAR)
last_name = db.Column(db.VARCHAR)
email = db.Column(db.VARCHAR)
contact_no = db.Column(db.VARCHAR)
status = db.Column(db.BOOLEAN)
loginpassword = db.Column(db.VARCHAR)
def get_id(self):
return str(self.user_id)
#login_manager.user_loader
def load_user(id):
try:
return User.query.get(id)
except:
return None
#app.route('/logedin',methods=['POST'])
def logedin():
session.pop('id', None)
em = request.form['email']
pwd = request.form['password']
usr = User.query.filter_by(email = em).first()
if usr:
if usr and usr.loginpassword == pwd:
login_user(usr,remember = False)
session['id'] = usr.user_id
return ('you r logged in')
else:
return '<h1>user not found</h1>'
else:
#return render_template('testlogin.html')
return '<h1>user not found</h1>'
#app.before_request
def check_logedin():
if not 'id' in session:
return render_template('testlogin.html')
#app.route('/login')
def login():
if current_user is_authenticated():
return redirect(url_for('home'))
else:
return render_template('testlogin.html')
#app.route('/logout')
#login_required
def logout():
logout_user()
session.pop('id', None)
return 'you are logged out'
#app.route('/home')
#login_required
def home():
return ('The current user is in.')
if __name__ == '__main__':
app.run(debug=True)
Apologies if some silly things. But I am unable to make out this session thing. Appreciate your help. Thanks in advance
You say that you "assign corresponding [user id] as a session variable", but some say "that session-id is to be randomly generated after user authentication, and stored in a separate sessions table in database".
Those two things are not in conflict. A session ID is a value sent to the user. It identifies session data. What is important is that the session data is hidden from the user and that a valid session ID cannot be guessed by a user.
What you are doing with flask.session is fine. You are placing a variable into a session and flask is taking care of the rest (giving only a random session ID to the user).
All you need to do is save user id in the session:
session['id'] = usr.user_id
and later read user id from the session
user_id = session.get('id')
Note that the user_id read this way may be None, meaning the user is not logged in.
This does not keep session data in a database, at least by default, but that probably is not important in your case. A good reason to keep data in a data base would be for example if you have a distributed system in which several servers are serving the same website, so the user might log in in one server, but then access another server.
I am new to Flask and have been working on an existing app for its login module. It has to be delivered asap. The login credentials validates by Active Directory authentication, which is working as expected. I am referring this flask link which says
url_for('main', page=2): return the internal URL /?page=2. All optional keyword arguments are treated as GET parameters.
My index page is loaded from here (working perfectly):
#app.route("/", methods=['GET', 'POST'])
def login():
error = None
if request.method == 'POST':
userName = request.form['username']
pwd = request.form['password']
try:
ldapobject = auth.bind(userName,pwd)
return redirect(url_for('scheduler')) ----> NEED TO PASS USER AND PWD TO scheduler function using post here
except ldap.LDAPError, error_message:
error = 'Invalid Credentials. Please try again'
return render_template('login.html', error=error)
My scheduler function:
#app.route("/home", methods=['POST'])
def scheduler():
# some code here
# WANT TO HAVE USER CREDENTIALS IN THIS FUNCTION FROM login page
return render_template("scheduler.html", scheduler=form)
Problem: How to pass user's credentials to scheduler method as a POST call
If you want to persist user data between your application pages - you will need to store some session data on user side, e.g. cookies.
flask-login module (https://flask-login.readthedocs.org/en/) can do all the dirty work for you.
In short you need to create User class with several required fields and methods (https://flask-login.readthedocs.org/en/latest/#your-user-class) and specify several methods with decorators to load and check users that are being authenticated:
from flask_login import LoginManager
login_manager = LoginManager()
login_manager.init_app(app=app)
#login_manager.user_loader
def load_user(username):
return User(username)
#login_manager.request_loader
def load_from_request(request):
return User.auth_is_valid(request.authorization)
After that you can mark any routes that need user credentials with #login_requied decorator and access logged in user via current_user variable:
from flask_login import login_required, current_user
#app.route("/user_needed")
#login_required
def some_function():
print(current_user)