Home > Mobile >  Implementing User For Flask Login
Implementing User For Flask Login

Time:10-18

TypeError: User.get_id() takes 0 positional arguments but 1 was given

I'm working with a friend, how would we go about fixing this error in our work from our understanding, user.id has no arguments. We tried using UserMixin and also ran into problems. Our end goal is to retrieve data from our web hosted mongo database.

Relevant Code:

from flask import * from pymongo import * from flask_wtf import * from wtforms import * from wtforms.validators import * from flask_login import * from app import *

app.py

login_manager = LoginManager()
login_manager.init_app(app)

@login_manager.user_loader
def load_user(user_id):
    return User.get(user_id)

login_manager.init_app(app)


class User():

    def __init__(self, email, password):
        self.email = email
        self.password = password

    def is_authenticated():
        return True

    def is_active():
        return True

    def is_anonymous():
        return True

    def get_id():
        return


class LoginForm(FlaskForm):
    username = StringField("username", validators=[InputRequired()] )
    password = PasswordField("password", validators=[InputRequired()])

@app.route("/login", methods = ["get", "post"])
def login():
    user = User("abc", "def")
    form = LoginForm()
    if form.validate_on_submit():
        return login_user(user)
    return render_template("header/login.html", form = form)

login.html

<!-- css bootstrap documentation: https://getbootstrap.com/docs/5.2/getting-started/introduction/  -->
{% import 'partials/macros.html' as macro %}

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>login</title>
    {{macro.imports()}}
    <link rel="stylesheet" href="{{url_for('static', filename='stylesheet/style.css')}}" />
    <script type="text/javascript" src="{{url_for('static', filename='script/login.js')}}"></script>
</head>
  <body>
    {{ macro.header() }}

  <form method = "Post" action = "{{ url_for('login') }}">
      {{ form.csrf_token }}
      {{ form.username.label }}
      {{ form.username }}
      {{ form.password.label }}
      {{ form.password }}

      <input type = "submit" value = "submit">
    </form>
    
    {{ macro.footer() }}

  </body>
</html>

CodePudding user response:

flask-login has a class called UserMixin. Your User class should inherit that class: class User(UserMixin):

The UserMixin doc describes the class. You'll have to remove the functions you defined (is_authenticated, is_active, is_anonymous, get_id) because you'll overwrite the existing functions in the class.

Quote from the docs: "To make implementing a user class easier, you can inherit from UserMixin, which provides default implementations for all of these properties and methods."

CodePudding user response:

When you define an instance method in a class, the first argument that is defined is self. It corresponds to the instance itself.

class User:
    def get_id(self):
        return 'your id here'

Below is a simple example using Flask-Login and Flask-MongoEngine.

The UserMixin is used to implement the user class. This provides the required methods.
In order to load the respective registered user, the search query is implemented using the pk attribute. This consequently serves as the id for the user.

Flask (app.py)
from flask import (
    Flask, 
    redirect, 
    render_template, 
    request, 
    url_for
)
from flask_login import (
    LoginManager, 
    UserMixin, 
    current_user, 
    login_required, 
    login_user, 
    logout_user
)
from flask_mongoengine import MongoEngine
from flask_wtf import FlaskForm
from wtforms import (
    StringField, 
    PasswordField
)
from wtforms.validators import InputRequired
from werkzeug.security import (
    check_password_hash, 
    generate_password_hash
)

app = Flask(__name__)
app.config.from_mapping(
    SECRET_KEY='your secret here', 
    # Database connection configuration.
    MONGODB_SETTINGS={
        'db': 'db', 
        'host': 'localhost', 
        'port': 27017, 
        'username': 'root', 
        'password': 'pass'
    }
)

db = MongoEngine()
login_manager = LoginManager()
login_manager.login_view = '.login'

db.init_app(app)
login_manager.init_app(app)

# Lookup the user by primary key.
@login_manager.user_loader 
def load_user(user_id):
    return User.objects(pk=user_id).first()

# Definition of the user class.
class User(UserMixin, db.Document):
    username = db.StringField(unique=True, required=True)
    password_hash = db.StringField(required=True)

    def check_password(self, password):
        return check_password_hash(self.password_hash, password)

# Create some user objects for development purposes.
try: 
    for i in range(2):
        usr = User(
            username=f'user-{i 1}', 
            password_hash=generate_password_hash('pass'))
        usr.save()
except Exception as exc: 
    pass

class LoginForm(FlaskForm):
    username = StringField('Username', validators=[InputRequired()])
    password = PasswordField('Password', validators=[InputRequired()])

@app.route('/')
def index():
    return '<a href="/logout">Logout</a>' if current_user.is_authenticated \
        else '<a href="/login">Login</a>'

@app.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm(request.form)
    if form.validate_on_submit():
        user = User.objects(username=form.username.data).first()
        if user and user.check_password(form.password.data):
            login_user(user)
            next_url = request.args.get('next')
            return redirect(next_url or url_for('.index'))
    return render_template('login.html', **locals())

@app.route('/logout')
@login_required
def logout():
    logout_user()
    return redirect(url_for('.login'))

@app.route('/secret')
@login_required
def secret():
    return f'Secret access from user: {current_user.username}.'
HTML (templates/login.html)
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Login</title>
</head>
<body>
    <form method="post">
        {{ form.csrf_token }}
        <div>
            {{ form.username.label() }}
            {{ form.username() }}
        </div>
        <div>
            {{ form.password.label() }}
            {{ form.password() }}
        </div>
        <button type="submit">Login</button>
    </form>
</body>
</html>
  • Related