How to get name of logged user (Flask, SQLAlchemy) - python

I want to authomaticaly put name to authors blogged from loged in session.
So far I can log user but when he is already logged I cant find way to work with his name on site.
So I am trying to create some way, which will store username after he is logged in memory and flask will then use this username for blog posts and comments or editing profile. Thank you
Base = declarative_base()
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
username = Column(String(64))
password = Column(String(120))
email = Column(String(64))
def __init__(self, username, password, email):
self.username = username
self.password = password
self.email = email
Base.metadata.create_all(engine)
Base2 = declarative_base()
class Blogpost(Base2):
__tablename__ = 'blogpost'
id = Column(Integer, primary_key=True)
title = Column(String(50))
subtitle = Column(String(50))
author = Column(String(20))
date_posted = Column(DateTime)
content = Column(Text)
def __init__(self, title, subtitle, author, date_posted, content):
self.title = title
self.subtitle = subtitle
self.author = author
self.date_posted = date_posted
self.content = content
#app.route('/login', methods=['POST'])
def login():
POST_USERNAME = str(request.form['username'])
POST_PASSWORD = str(request.form['password'])
def check_password(hashed_password, user_password):
password, salt = hashed_password.split(':')
return password == hashlib.sha256(salt.encode() + user_password.encode()).hexdigest()
Session = sessionmaker(bind=engine)
s = Session()
user = s.query(User).filter_by(username=POST_USERNAME).first()
if check_password(user.password, POST_PASSWORD) == True:
session['logged_in'] = True
user_name = POST_USERNAME
else:
flash('wrong password!')
return index()
#app.route('/add')
def add():
return render_template('add.html')
#app.route('/addpost', methods=['POST'])
def addpost():
title = request.form['title']
subtitle = request.form['subtitle']
content = request.form['content']
Session = sessionmaker(bind=engine)
session = Session()
post = Blogpost(title=title, subtitle=subtitle, author=user_name, content=content, date_posted=datetime.now())
session.add(post)
session.commit()

I would encourage you to use an extension like flask-login for user management or flask-security for extended features, meanwhile, you can store the user in flask sessions.
first import session (i will call it login_session to differentiate it with your sql-alchemy session)
from flask import session as login_session
Then once a user logs in you can store the user details like this
login_session['username'] = user.username #user here being the user object you have queried
And to access the user name from session
username = login_session['username']
and once a user logs out, you delete the user details from session like this
del login_session['username']
But as others have mentioned in the comments, for a serious web app, you will want to consider using one of the flask extensions for user management

Related

Sqlalchemy: type object 'Users' has no attribute 'query'

I've been trying for a while to make this code work however my lack of knowledge about sqlalchemy keeps me from making it work.
It should check the username but it gives me an error, wonder if someone here could help me
#auth.route('/login', methods=['GET','POST'])
def login():
if request.method == 'POST':
usrn = request.form.get('username')
password = request.form.get('password')
user = Users.query.filter_by(username=usrn).first()
if user:
/* CODE */
else:
/* CODE */
And this is the model:
engine = db.create_engine('mysql+pymysql://luca:luca#localhost/forum', echo=False)
Session = sessionmaker(bind=engine)
session=Session()
metadata = db.MetaData()
Base = declarative_base()
class Users(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column('name',VARCHAR(25))
surname = Column('surname',VARCHAR(25))
username = Column('username',VARCHAR(20))
mail = Column('mail',VARCHAR(50))
password = Column('password',CHAR(32))
role=Column('role',VARCHAR(10))
threads = relationship("Threads")

python flask simple resetful api not just add 1 record user in sqlite database

i create a simple resetful api with flask and work corrent , but after add 1 record user details , don't add next user or second user in database and give error 500.
my server is: centos 7
python: 3.7.5
from flask import Flask, request, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
import os
app = Flask(__name__)
basedir = os.path.abspath(os.path.dirname(__file__))
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'crud.sqlite')
db = SQLAlchemy(app)
ma = Marshmallow(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(150), unique=True)
userid = db.Column(db.String(120), unique=True)
product = db.Column(db.String(20), unique=True)
licenses = db.Column(db.String(1000), unique=True)
def __init__(self, username, userid , product , licenses):
self.username = username
self.userid = userid
self.product = product
self.licenses = licenses
class UserSchema(ma.Schema):
class Meta:
# Fields to expose
fields = ('username', 'userid', 'product', 'licenses')
user_schema = UserSchema()
users_schema = UserSchema(many=True)
'''
Message list:
- 1x0001 = user created
- 1x0002 = user deleted
- 1x0003 = user updated
- 0x0000 = Error not found customer
- 0x0001 = Error can't add customer
- 0x0003 = Error not found customer for delete
- 0x0004 = Error can't update customer
product list:
- 2x0001 = MoeinWeb
- 2x0002 = MoeinBackup
'''
# endpoint to create new user
#app.route("/api/LicenseService/newcustomer", methods=["POST"])
def add_user():
try:
data = request.get_json()
new_user = User(username=data['username'], userid=data['userid'], product=data['product'], licenses=data['licenses'])
db.session.add(new_user)
db.session.commit()
return jsonify({'Message': '1x0001'})
except:
return jsonify({'Message': '0x0001'})
# endpoint to get user detail by id
#app.route("/api/LicenseService/customer/<userid>", methods=["GET"])
def user_detail(userid):
user = User.query.filter_by(userid=userid).first()
try:
user_data = {}
user_data['username'] = user.username
user_data['userid'] = user.userid
user_data['product'] = user.product
user_data['licenses'] = user.licenses
return jsonify(user_data)
except:
return jsonify({'Message': '0x0000'})
# endpoint to update user
#app.route("/api/LicenseService/customer/<userid>", methods=["PUT"])
def user_update(userid):
try:
user = User.query.filter_by(userid=userid).first()
username = request.json['username']
userid = request.json['userid']
product = request.json['product']
licenses = request.json['licenses']
user.username = username
user.userid = userid
user.product = product
user.licenses = licenses
db.session.commit()
return jsonify({'Message': '1x0003'})
except:
return jsonify({'Message': '0x0004'})
# endpoint to delete user
#app.route("/api/LicenseService/customer/<userid>", methods=["DELETE"])
def user_delete(userid):
try:
user = User.query.filter_by(userid=userid).first()
db.session.delete(user)
db.session.commit()
return jsonify({'Message': '1x0002'})
except:
return jsonify({'Message': '0x0003'})
if __name__ == '__main__':
app.run(host='0.0.0.0',port=7273)
just record 1 can update , delete and show with userid , but can't create record 2 on database ,
add_user()

flask add a new row based on id of other tables

I have two tables, named projects and actions and every project contain several action
class Projet(db.Model):
__tablename__ = 'projets'
id = db.Column(db.Integer, primary_key=True)
nom_projet = db.Column(db.String(100))
description_projet = db.Column(db.String(800))
date_affectation = db.Column(db.DateTime, nullable = False)
statut_projet = db.Column(db.String(100))
admin_id = db.Column(db.Integer, db.ForeignKey('admins.id'))
actions = db.relationship('Action', backref='projet',
lazy='dynamic')
def __repr__(self):
return '<Projet: {}>'.format(self.id)
class Action(db.Model):
__tablename__ = 'actions'
id = db.Column(db.Integer, primary_key=True)
projet_id = db.Column(db.Integer, db.ForeignKey('projets.id'))
description = db.Column(db.String(1000))
statut_action = db.Column(db.String(100))
date_action = db.Column(db.DateTime, nullable = False)
date_execution = db.Column(db.DateTime, nullable = True)
def __repr__(self):
return '<Action: {}>'.format(self.id)
my problem is, I need to create a new action based on an existing project as shown in image,
I need to click on add button and he must redirect me to action form with the name of project auto-selected, and I entre the action details.
this is my first code to add action:
#auth.route('/action/add', methods=['GET', 'POST'])
#login_required
def add_action():
form = ActionForm()
if form.validate_on_submit():
action = Action(
projet = form.projet.data,
description = form.description.data,
statut_action = form.statut_action.data,
date_action = form.date_action.data,
date_execution = form.date_execution.data
)
try:
db.session.add(action)
db.session.commit()
flash('You have successfully added a new action.')
except:
flash('Error: action name already exists.')
return redirect(url_for('auth.list_projets'))
return render_template('admin/actions/action.html', action="Add", form=form,
title="ADD ACTION")
Steps:
Update the URL to include project_id as path param: ex: /project/1/actions/add is meant to load a page with new action form for project with id 1
Update the links to add new action in the previous page(as shown in the screenshot) as per step 1
Remove project field from ActionForm as it is handled using path param
Update "new action form" page to show product name coming in product_name variable
Try,
#auth.route('/project/<project_id>/action/add', methods=['GET', 'POST'])
#login_required
def add_action(project_id):
form = ActionForm()
project = Project.query.get(project_id)
if not project:
flash('Error: invalid project')
abort(404)
if form.validate_on_submit():
action = Action(
project = project,
description = form.description.data,
statut_action = form.statut_action.data,
date_action = form.date_action.data,
date_execution = form.date_execution.data
)
try:
db.session.add(action)
db.session.commit()
flash('You have successfully added a new action.')
except:
flash('Error: action name already exists.')
return redirect(url_for('auth.list_projets'))
return render_template('admin/actions/action.html', action="Add", form=form,
title="ADD ACTION", project_name=project.name)

Flask-SQLAlchemy: '"{0}" is not a valid field for {1}.'.format(key, obj))

I'm trying to create an API with Flask and SQLAlchemy, my function add_user is working perfectly, get_all users too, but i have some issues on my get users (return a specific user ) selected by email (mail is my primary key).
class User(db.Model):
#id = db.Column(db.Integer)
name = db.Column(db.String(30))
badgenum = db.Column(db.String(30))
mail = db.Column(db.String(30), primary_key=True)
status = db.Column(db.String(30))
admin = db.Column(db.String(30))
#borrowed = db.relationship('Borrowing', backref='user', lazy=True)
def __init__(self, name, badgenum, mail, status, admin):
self.name = name
self.badgenum = badgenum
self.mail = mail
self.status = status
self.admin = admin
class UserSchema(ma.Schema):
class Meta:
fields = ('name', 'badgenum', 'mail', 'status', 'admin')
user_schema = UserSchema()
users_schema = UserSchema(many=True)
then , my function that causes problems:
#app.route("/users/<mail>", methods=["GET"])
def user_detail(mail):
user = User.query.filter(User.mail == mail).first()
return user_schema.jsonify(user.name)
I test my API with Postman, i added 2 new users to my database, then when i try the last function i have this error:
line 834, in __filter_fields
'"{0}" is not a valid field for {1}.'.format(key, obj)) AttributeError: "status" is not a valid field for username1.
Try like below.
user = User.query.filter_by(mail=mail).first()
return user_schema.jsonify(user)

Why is check_password_hash always returning False in this login view?

I have a user model with functions to set and check a password using Werkzeug's set_password_hash and check_password_hash functions.
models.py
class User(db.Model):
id = db.Column(db.Integer, primary_key = True)
username = db.Column(db.String(15), unique = True)
password = db.Column(db.String(15))
tasks = db.relationship('Task', backref='author', lazy='dynamic')
def __init__(self, username, password):
self.username = username
self.set_password(password)
def set_password(self, password):
self.password = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password, password)
login.py
def post(self):
username = flask.request.form['username']
passwd = flask.request.form['passwd']
user = User.query.filter_by(username = username).first()
flask.flash(user.check_password(user.password))
if user and user.check_password(user.password):
flask.session['username'] = username
else:
flask.flash("User doesn't exist or password is inccorect.")
return flask.render_template('login.html')
return flask.render_template('index.html')
The flashed result of check_password is always "False". What am I doing wrong?
You've defined User.password to have a length of 15, but the password hash is longer than 15 characters. So when you go to compare it later, it will not be the same value, it will be truncated.
The solution is to either define a longer length to accommodate the length of the hash, or use a database that doesn't care about length (PostgreSQL, SQLite) and don't set a length for the column at all (this is preferable).
password = db.Column(db.String) # no length
# or
password = db.Column(db.String(255)) # some longer length
There's also a second problem: you're calling check_password with the stored hash, not with the user input.
# wrong
user.check_password(user.password)
# should be
user.check_password(passwd)
The following is a small example that demonstrates the password working correctly.
import sqlalchemy as sa
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session
from werkzeug.security import generate_password_hash, check_password_hash
engine = sa.create_engine('sqlite://', echo=True)
session = Session(engine)
Base = declarative_base(engine)
class User(Base):
__tablename__ = 'user'
id = sa.Column(sa.Integer, primary_key=True)
username = sa.Column(sa.String, nullable=False, unique=True)
password = sa.Column('password', sa.String)
def set_password(self, secret):
self.password = generate_password_hash(secret)
def check_password(self, secret):
return check_password_hash(self.password, secret)
Base.metadata.create_all()
u = User(username='davidism')
u.set_password('cabbage')
session.add(u)
session.commit()
u = session.query(User).filter_by(username='davidism').one()
print(u.password)
# pbkdf2:sha1:1000$w9jx4Egp$b420d784ac6ad0575e4a9a908bb4679826e56f5f
print(u.check_password('cabbage'))
# True

Categories

Resources