Home > Mobile >  Python - Flask Login - Accessing individual user records
Python - Flask Login - Accessing individual user records

Time:07-14

I've been loosely following the tutorial @ https://www.digitalocean.com/community/tutorials/how-to-add-authentication-to-your-app-with-flask-login

But I am using MongoDB using pymongo and have had to modify my code along the way. I've been good up until Step 10.

The part I am unable to get functioning is where the tutorial (Step 10) is able to access the name, ID, email, etc from the user when logged in. I have tried several methods of trying to access the information from the mongoDB but fall flat any time.

What I would like to do is be able to access, when a user is authenticated, any of the records I so choose.

I am able to get /profile to render - which I suspect means my authentication is working as intended.

from flask import Flask, render_template, redirect, url_for, Blueprint, request, flash
from flask_login import LoginManager
import os

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, EmailField
from wtforms.validators import DataRequired, Email

from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin, LoginManager, login_user, login_required, current_user

import pymongo

myclient = pymongo.MongoClient("properstuff")
mydb = myclient["database"]
mycol = mydb["databasedb"]

app = Flask(__name__)

app.config['SECRET_KEY'] = '12345'


login_manager = LoginManager()
login_manager.login_view = 'auth.login'
login_manager.init_app(app)

@login_manager.user_loader
def load_user(user_id):
    user_json = mycol.find_one({'_id': user_id})
    return User(user_json)

class LoginForm(FlaskForm):
    username = StringField('Username',validators=[DataRequired()])
    password = PasswordField('Password', validators=[DataRequired()])
    submit = SubmitField('Login')
    
class SignUp(FlaskForm):
    username = StringField('Username',validators=[DataRequired()])
    password = PasswordField('Password', validators=[DataRequired()])
    email = EmailField('Email', validators=[DataRequired(), Email()])
    submit = SubmitField('Register')

class User(UserMixin):
    def __init__(self, user_json):
        self.user_json = user_json
    # Overriding get_id is required if you don't have the id property
    # Check the source code for UserMixin for details
    def get_id(self):
        object_id = self.user_json.get('_id')
        return str(object_id)
    

@app.route("/")
def homepage():
    form = LoginForm()
    return render_template('index.html', form=form)

@app.route("/login", methods=['POST'])
def login_post():
    
    username = request.form.get('username')
    password = request.form.get('password')
        
    user = mycol.find_one({"username": username})
    
    if not user or not check_password_hash(user['password'], password):
        flash('Please check your login details and try again.')
        return redirect(url_for('homepage'))
    loginuser = User(user)
    login_user(loginuser, remember=True)
    return redirect(url_for('profile'))
    
@app.route("/register")
def register():
    form = SignUp()
    return render_template('register.html', form=form)

@app.route("/register", methods=["POST"])
def register_post():
    
    email = request.form.get('email')
    username = request.form.get('username')
    password = request.form.get('password')
        
    user = mycol.find_one({"email": email})
    
    if user:
        flash('Email address already exists. Please login below.')
        return redirect(url_for('homepage'))
    
    mycol.insert_one({"username": username, "email": email, "password": generate_password_hash(password, method='sha256')})
    
    return redirect(url_for('homepage'))

@app.route("/profile")
@login_required
def profile():
    return "Logged in successfully"

I tried adding name = user_json['username'] to the init function in the class user and calling it by current_user.name however, it gave me the following error:

Traceback (most recent call last):
  File "C:\Users\David PC\AppData\Roaming\Python\Python37\site-packages\flask\app.py", line 2077, in wsgi_app
    response = self.full_dispatch_request()
  File "C:\Users\David PC\AppData\Roaming\Python\Python37\site-packages\flask\app.py", line 1525, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "C:\Users\David PC\AppData\Roaming\Python\Python37\site-packages\flask\app.py", line 1523, in full_dispatch_request
    rv = self.dispatch_request()
  File "C:\Users\David PC\AppData\Roaming\Python\Python37\site-packages\flask\app.py", line 1509, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
  File "C:\Users\David PC\Desktop\VS Code Python\Flask Site\site.py", line 57, in homepage
    return render_template('index.html', form=form)
  File "C:\Users\David PC\AppData\Roaming\Python\Python37\site-packages\flask\templating.py", line 147, in render_template
    ctx.app.update_template_context(context)
  File "C:\Users\David PC\AppData\Roaming\Python\Python37\site-packages\flask\app.py", line 756, in update_template_context
    context.update(func())
  File "C:\Users\David PC\AppData\Roaming\Python\Python37\site-packages\flask_login\utils.py", line 417, in _user_context_processor
    return dict(current_user=_get_user())
  File "C:\Users\David PC\AppData\Roaming\Python\Python37\site-packages\flask_login\utils.py", line 384, in _get_user
    current_app.login_manager._load_user()
  File "C:\Users\David PC\AppData\Roaming\Python\Python37\site-packages\flask_login\login_manager.py", line 367, in _load_user
    user = self._load_user_from_remember_cookie(cookie)
  File "C:\Users\David PC\AppData\Roaming\Python\Python37\site-packages\flask_login\login_manager.py", line 411, in _load_user_from_remember_cookie
    user = self._user_callback(user_id)
  File "C:\Users\David PC\Desktop\VS Code Python\Flask Site\site.py", line 41, in load_user
    return User(user_json)
  File "C:\Users\David PC\Desktop\VS Code Python\Flask Site\site.py", line 30, in __init__
    name = user_json['username']
TypeError: 'NoneType' object is not subscriptable

CodePudding user response:

you have a syntax error: use brackets instead of parentheses

name = user_json['username']

CodePudding user response:

So it looks like my issue was related to my user_loader.

My database query was always returning None as no record was found. This is because MongoDB defines the "_id" as an objectId, and not a str, I assume.

I imported ObjectId from bson.objectid and modified my user_loader to:

@login_manager.user_loader
def load_user(user_id):
    u = mycol.find_one({"_id": ObjectId(user_id)})
    if not u:
        return None
    return User(u)

I was then able to call individual records using current_user.user_json['key']

  • Related