Flask-Admin modelview function - python

I have a flask app with Flask-Admin to manage the users with the /admin/userview modelview.
I wanted it to show the page when a user that is in the DB with the correct group navigates to /admin/userview, and return plain text "not admin" if they are not. Fortunately I got the last part to work, but unfortunately I cannot seem to get the first part (continuing to show the page if they are in the correct group). Here's the relevant code:
class MyView(ModelView):
#expose('/', methods = ['GET', 'POST'])
def index(self):
## grab kerberos username (PROD)
secuser = request.environ.get('REMOTE_USER')
adminresult = User.query.filter_by(usrlevel='admin').all()
adminresult = str(adminresult)
adminresult = adminresult.strip('[]')
managerresult = User.query.filter_by(usrlevel='manager').all()
managerresult = str(managerresult)
managerresult = managerresult.strip('[]')
if secuser in adminresult:
pass <---------------\
elif secuser in managerresult: |- if a user is apart of either, this gives a ValueError
pass <---------------/
else:
return "NOT ADMIN" <--------- This works!
##ADMIN
admin = Admin(flaskapp, index_view=MyHomeView(), name="test APP")
admin.add_view(MyView(User, db.session, "Edit Users"))
Here's the traceback that I get when a user is in adminresult or in managerresult:
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1836, in __call__
return self.wsgi_app(environ, start_response)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1820, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1403, in handle_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1478, in full_dispatch_request
response = self.make_response(rv)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1566, in make_response
raise ValueError('View function did not return a response')
ValueError: View function did not return a response
How do I get the ModelView "User" to display it's contents if the user is in either group, and to just return "not admin" text if they are not? I think I got half of that done, just continuing seems to be an issue...
Thanks!

You should actually put the check in is_accessible:
class MyView(ModelView):
def is_accessible(self):
# grab kerberos username (PROD)
secuser = request.environ.get('REMOTE_USER')
admins_and_managers = User.query
.filter(User.usrlevel.in_('admin', 'manager'))
# Better yet, filter again on `secuser`
# to avoid loading *every* admin and manager
# on *every* request for this resource
# and then use `.first` or `.one`
.all()
return secuser in admins_and_managers

Related

Flask WTF cannot find a value to populate from the provided obj or input data/defaults

I'm using python Flask with WTForm and I'm having serious issues with the populate_obj method:
Traceback (most recent call last):
File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 2088, in __call__
return self.wsgi_app(environ, start_response)
File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 2073, in wsgi_app
response = self.handle_exception(e)
File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 2070, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1515, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1513, in full_dispatch_request
rv = self.dispatch_request()
File "/usr/local/lib/python3.9/site-packages/flask/app.py", line 1499, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
File "/app/my_data/main.py", line 29, in submit
form.populate_obj(demande)
File "/usr/local/lib/python3.9/site-packages/wtforms/form.py", line 95, in populate_obj
field.populate_obj(obj, name)
File "/usr/local/lib/python3.9/site-packages/wtforms/fields/core.py", line 877, in populate_obj
raise TypeError('populate_obj: cannot find a value to populate from the provided obj or input data/defaults')
TypeError: populate_obj: cannot find a value to populate from the provided obj or input data/defaults
Here's my code (nothing fancy):
form = DemandeForm(data=request.form)
if form.validate():
form.populate_obj(demande)
flash('Enregistré', 'success')
return redirect(url_for('main.index'))
I could detail all the forms fields, but this would be tedious. My guess is that this as to do with nested forms I'm using:
class DemandeForm(BaseForm):
AdressePrivee = FormField(AdresseForm)
AdresseProfessionnelle = FormField(AdresseForm)
Prestations = FieldList(FormField(PrestationForm), min_entries=1)
So my questions are:
why is the error rising?
how can I have more explicit error, telling me which fields are raising the issue?
how can I solve this?
I'm completely locked right now :(
Thanks for support
EDIT
So I finally managed to confirm that the issue comes from the FormField(AddressField).
Here's my Demande model extract:
AdressePrivee = db.relationship(AdressePrivee, backref='Demande', lazy=False, uselist=False)
And in DemandeForm:
AdressePrivee = FormField(AdresseForm)
Wtform is not happy because demande.AdressePrivee == None, hence self._obj is None in the code and the error rises.
I tried to add default value:
AdressePrivee = FormField(AdresseForm, default=AdressePrivee())
But then I get an error while saving, as AddressePrivee fields are empty while they shouldn't...
Ain't there a missing option, like nullable: True or something? I'm not sure it makes sense that the error rises, nor how I can handle this situation...
Thanks
Here is the relevant source code for the WTF function, this is where the error is triggered:
def populate_obj(self, obj, name):
candidate = getattr(obj, name, None)
if candidate is None:
if self._obj is None:
raise TypeError('populate_obj: cannot find a value to populate from the provided obj or input data/defaults')
candidate = self._obj
setattr(obj, name, candidate)
self.form.populate_obj(candidate)
Source
self._obj is assigned a value in the routine process.
So it seems that there is something wrong with the variable you are passing. In fact I don't understand why you are passing the equivalent of current_user to your form. Look here for an example of usage.

Routing inside routes - A setup function was called after the first request was handled

I am trying to create routes inside of another route (info_form()). For awhile this was working. I am not sure what exactly caused it, but I may have changed some code and that is what caused it to stop working. This is my code:
#app.route('/Register', methods=["GET", "POST"])
def register():
FormErrMessage = 'Email already taken, or invalid email.'
error = False
if request.method == 'POST':
inp_email = request.form['email']
inp_password = request.form['password']
if User.objects(email=inp_email):
error = True
else:
#app.route('/Register/customer-form', methods=['GET', 'POST'])
def info_form():
msg = None
if request.method == 'POST':
form = request.form
inp_name = form['name']
inp_lastName = form['lastName']
inp_zipCode = form['zipCode']
inp_address = form['address']
inp_phoneNumber = form['phoneNumber']
if User.objects(name=inp_name, lastName=inp_lastName):
msg = '...'
elif User.objects(phoneNumber=inp_phoneNumber):
msg = '...'
else:
#app.route('/Register/customer-form/verify/<send>', methods=['GET', 'POST'])
def verify_email(send):
msg = None
error_msg = None
r = 8
if send == 't':
...
if request.method == 'POST':
inp_code = request.form['code']
if int(inp_code) == r:
try:
User(
email=inp_email,
password=inp_password,
user_id=get_user_id(),
admin=False,
loggedIn=1,
# ip_addresses=ipAddress,
registered=False,
name=inp_name,
lastName=inp_lastName,
zipCode=inp_zipCode,
address=inp_address,
phoneNumber=inp_phoneNumber
).save()
email(...)
except ValidationError as e:
print(e)
error_msg = '...'
else:
session['email'] = inp_email
session["password"] = inp_password
print(session)
return redirect('/')
else:
msg = 'Code invalid, try again.'
return render_template('verify.html', email=inp_email, unk_err=error_msg,
msg=msg)
return redirect('/Register/customer-form/verify/t')
return render_template('customerform.html', msg=msg)
return redirect('/Register/customer-form')
return render_template('register.html', FormErrMessage=FormErrMessage, error=error)
It seems to be raising this because the request was already handled.
Traceback (most recent call last):
File "C:\Users\William\Nickels\venv\lib\site-packages\flask\app.py", line 2463, in __call__
return self.wsgi_app(environ, start_response)
File "C:\Users\William\Nickels\venv\lib\site-packages\flask\app.py", line 2449, in wsgi_app
response = self.handle_exception(e)
File "C:\Users\William\Nickels\venv\lib\site-packages\flask\app.py", line 1866, in handle_exception
reraise(exc_type, exc_value, tb)
File "C:\Users\William\Nickels\venv\lib\site-packages\flask\_compat.py", line 39, in reraise
raise value
File "C:\Users\William\Nickels\venv\lib\site-packages\flask\app.py", line 2446, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\William\Nickels\venv\lib\site-packages\flask\app.py", line 1951, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Users\William\Nickels\venv\lib\site-packages\flask\app.py", line 1820, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "C:\Users\William\Nickels\venv\lib\site-packages\flask\_compat.py", line 39, in reraise
raise value
File "C:\Users\William\Nickels\venv\lib\site-packages\flask\app.py", line 1949, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\William\Nickels\venv\lib\site-packages\flask\app.py", line 1935, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "C:\Users\William\Nickels\app.py", line 55, in register
#app.route('/Register/customer-form', methods=['GET', 'POST'])
File "C:\Users\William\Nickels\venv\lib\site-packages\flask\app.py", line 1314, in decorator
self.add_url_rule(rule, endpoint, f, **options)
File "C:\Users\William\Nickels\venv\lib\site-packages\flask\app.py", line 90, in wrapper_func
"A setup function was called after the "
AssertionError: A setup function was called after the first request was handled. This usually indicates a bug in the application where a module was not imported and decorators or other functionality was called too late.
To fix this make sure to import all your view modules, database models and everything related at a central place before the application starts serving requests.
Can someone tell me how to fix this or get around it. Thanks.
I don't understand this:
import all your view modules, database models and everything related at a central place before the application starts serving requests.
What that error is trying to say is that you can't do setup-y things (like adding routes) after the Flask app has starting running.
You have a deeper problem, which is assuming that nested route functions will retain visibility an data from enclosing routes. E.g., that the /Register/customer-form route will have access to the inf_email set in the enclosing /Register route. The mechanisms here don't work that way.
Since the intent is to hang on to information from one step of a registration workflow to the next, the common mechanisms is to inject state from one route as hidden form elements so that they'll be carried along to the next route. Here, that would mean passing inf_email et al. to be expanded into the "customerform.html" template (and similar for the "verify.html" template).

Populating a list using FieldList, FormField, and populate_obj in WTForms, with adding items client-side

I have an application I am building using Python and Flask. I have a form I am creating using WTForms which will allow the user to edit customer contact details, including a dynamic number of phone numbers. When the form is submitted, I want to save the data from the form back into the Customer object using the form's populate_obj function.
The code for the forms is as follows:
class PhoneNumberFormPart(FlaskForm):
class Meta:
csrf = False # Disable CSRF protection, it will confilct with protection on the parent form
number = StringField("Phone Number", widget=Input('tel'))
label = SelectField('Label', choices=(("Cell", "Cell"), ("Home", "Home"), ("Work", "Work")))
preferred = BooleanField('Preferred', default=False)
class CustomerEditForm(FlaskForm):
name = StringField('Name', validators=[DataRequired()])
name2 = StringField('Contact Person Name')
isBusiness = BooleanField('This is a business client', default=False)
phones = FieldList(FormField(PhoneNumberFormPart), min_entries=1)
address = StringField("Address")
city = StringField("City")
state = StringField("State")
zip = StringField("Zip Code")
email = StringField("Email Address", widget=Input('email'), validators=[Email()])
submit = SubmitField('Save Customer Details')
I have the following javascript to add additional phone number fields on the client side:
/// Called in forms using a FieldList to duplicate the last FieldList-item
function addFieldListItem(fieldList){
let lastField = fieldList.lastElementChild.previousElementSibling;
// Last child is the "add phone" button added in the template, so the last field is the 2nd-to-last item
let newField = lastField.cloneNode(true);
let newInputs = newField.getElementsByTagName('input');
Array.prototype.forEach.call(newInputs, function(input){
// Increment the number that flask assigns to each field name
input.name = input.name.replace(/(\d+)/, function(n){return ++n});
input.id = input.id.replace(/(\d+)/, function(n){return ++n});
// Clear the input values
input.value = null;
input.checked = false;
});
let newSelects = newField.getElementsByTagName('select');
Array.prototype.forEach.call(newSelects, function(select){
// Increment the number that flask assigns to each field name
select.name = select.name.replace(/(\d+)/, function(n){return ++n});
select.id = select.id.replace(/(\d+)/, function(n){return ++n});
});
let newLabels = newField.getElementsByTagName('label');
Array.prototype.forEach.call(newLabels, function(label){
// Increment the number that flask assigns to each field name
label.htmlFor = label.htmlFor.replace(/(\d+)/, function(n){return ++n});
});
fieldList.insertBefore(newField, fieldList.lastElementChild);
}
Everything seems to work as I expect as long as I don't add an additional phone number client-side. However, if I do add another number client-side, when I call populate_obj I get the following exception:
Traceback (most recent call last):
File "c:\python\lib\site-packages\flask\app.py", line 2463, in __call__
return self.wsgi_app(environ, start_response)
File "c:\python\lib\site-packages\flask\app.py", line 2449, in wsgi_app
response = self.handle_exception(e)
File "c:\python\lib\site-packages\flask\app.py", line 1866, in handle_exception
reraise(exc_type, exc_value, tb)
File "c:\python\lib\site-packages\flask\_compat.py", line 39, in reraise
raise value
File "c:\python\lib\site-packages\flask\app.py", line 2446, in wsgi_app
response = self.full_dispatch_request()
File "c:\python\lib\site-packages\flask\app.py", line 1951, in full_dispatch_request
rv = self.handle_user_exception(e)
File "c:\python\lib\site-packages\flask\app.py", line 1820, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "c:\python\lib\site-packages\flask\_compat.py", line 39, in reraise
raise value
File "c:\python\lib\site-packages\flask\app.py", line 1949, in full_dispatch_request
rv = self.dispatch_request()
File "c:\python\lib\site-packages\flask\app.py", line 1935, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "c:\python\lib\site-packages\flask_login\utils.py", line 261, in decorated_view
return func(*args, **kwargs)
File "C:\Users\Techris Design\Project Spiderman\spiderman\spiderman\views\customers.py", line 40, in customer_landing
form.populate_obj(customer)
File "c:\python\lib\site-packages\wtforms\form.py", line 96, in populate_obj
field.populate_obj(obj, name)
File "c:\python\lib\site-packages\wtforms\fields\core.py", line 962, in populate_obj
field.populate_obj(fake_obj, 'data')
File "c:\python\lib\site-packages\wtforms\fields\core.py", line 829, in populate_obj
raise TypeError('populate_obj: cannot find a value to populate from the provided obj or input data/defaults')
TypeError: populate_obj: cannot find a value to populate from the provided obj or input data/defaults
I'm pretty sure it's because the phones property (which is a list of PhoneNumber objects) in the corresponding Customer object doesn't have enough items in it to contain all the form data into the list.
I've looked over the WTForms documentation to see if there is a way to assign a factory function or class to the FormField so that it could create additional PhoneNumber objects to add to customer.phones when I call populate_obj if there are more items in the form data than in the target object. However, so far as I can tell from the documentation there is no such option.
Anyone know the best way to do this?
Okay, I spend some time studying the WTForms source code on Github and figured it out. Pass a class or factory function to the default parameter of the FormField instance, as follows:
phones = FieldList(FormField(PhoneNumberFormPart, default=PhoneNumber), min_entries=1)
It's actually pretty easy, although calling the parameter default made it a little hard for me to find. Never would have even thought to look there...

Oauth2 in Python with Flask gets 302 from API

I am trying to access MeisterTask's API with Python and Flask, and no matter what I do, I seem to always get a 302 code in return from the API, although I can get an access token (or so I think). Here is the code I have so far (I tried reducing it, this is the smallest snippet I could get that replicates the error):
from flask import Flask, redirect, url_for, session, request, jsonify
from flask_oauthlib.client import OAuth
app = Flask(__name__)
app.debug = True
app.secret_key = "development"
oauth = OAuth(app)
meistertask = oauth.remote_app(
'meistertask',
consumer_key= "XXXXXX",
consumer_secret= "XXXXXX",
request_token_params={"scope" : "meistertask"},
base_url='https://www.meistertask.com/api',
request_token_url=None,
access_token_method='GET',
access_token_url='https://www.mindmeister.com/login/oauth2/token',
authorize_url='https://www.mindmeister.com/oauth2/authorize'
)
#app.route('/')
def index():
if 'meistertask_token' in session:
me = meistertask.get('user')
return jsonify(me.data)
return redirect(url_for('login'))
#app.route('/login')
def login():
return meistertask.authorize(callback=url_for('authorized', _external=True))
#app.route('/logout')
def logout():
session.pop('meistertask_token', None)
return redirect(url_for('index'))
#app.route('/login/authorized')
def authorized():
resp = meistertask.authorized_response()
print(resp.get('code'))
if resp is None or resp.get('code') is None:
return 'Access denied: reason=%s error=%s resp=%s' % (
request.args['error'],
request.args['error_description'],
resp
)
session['meistertask_token'] = (resp['code'], '')
return "Hello"
#meistertask.tokengetter
def get_meistertask_oauth_token():
return session.get('meistertask_token')
if __name__ == "__main__":
app.run()
And here is the traceback:
flask_oauthlib.client.OAuthException: Invalid response from meistertask
Traceback (most recent call last):
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask\app.py", line 2309, in __call__ return self.wsgi_app(environ, start_response)
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask\app.py", line 2295, in wsgi_app response = self.handle_exception(e)
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask\app.py", line 1741, in handle_exception reraise(exc_type, exc_value, tb)
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask\_compat.py", line 35, in reraise raise value
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask\app.py", line 2292, in wsgi_app response = self.full_dispatch_request()
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask\app.py", line 1815, in full_dispatch_request rv = self.handle_user_exception(e)
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask\app.py", line 1718, in handle_user_exception reraise(exc_type, exc_value, tb)
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask\_compat.py", line 35, in reraise raise value
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask\app.py", line 1813, in full_dispatch_request rv = self.dispatch_request()
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask\app.py", line 1799, in dispatch_request return self.view_functions[rule.endpoint](**req.view_args)
File "~\Documents\MeisterTaskServer\hello.py", line 49, in authorized resp = meistertask.authorized_response()
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask_oauthlib\client.py", line 707, in authorized_response data = self.handle_oauth2_response(args)
File "~\AppData\Local\Programs\Python\Python37-32\lib\site-packages\flask_oauthlib\client.py", line 692, in handle_oauth2_response
Things I have tried
Tried to modify the method to get the access token from GET to POST. The API clearly states that I should use GET, yet every other example I have seen on flask_oauthlib's GitHub uses POST (the examples are 3 years old, but some still work, namely the GitHub one). Either give the same result.
Tried doing it barebones, without any library. The resulting code was thrice as long and also had more problems.
Used Django instead of Flask. Never even managed to get the hello world example going, it was too much work, and also I have discovered the library flask_oauthlib.
Things worth mentioning
I derived this code from this here GitHub example
There is also code there I omitted in order to keep the snippet short, that establishes that the server should use SSL (as per the request from the API that the redirect_uri should use HTTPS)
The app manages to redirect me over at MeisterTask and asks for my permission. Once I grant it, it redirects to "https://127.0.0.1:5000/login/authorized?code=some_token" where I get the traceback. If I look with Chrome's debugging tools to the requests made and what I receive, I see that I get an 302 from the API, but I also get an access token.
I run Windows 10 with Python 3.7.0
So what's the deal? What's the next step here? I've run out of things to try. Thank you for taking the time to solve this!

TypeError: hash must be unicode or bytes, not None

I am working on Flask project works with mongoengine. Register code hashed to password with passlib.hash when user registered. When I try to read password in login authentication I've got this error.
TypeError: hash must be unicode or bytes, not None
Traceback:
TypeError
TypeError: hash must be unicode or bytes, not appname.models.User
Traceback (most recent call last)
File "/*/**/***/***/appname/env/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__
return self.wsgi_app(environ, start_response)
File "/*/**/***/***/appname/env/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/*/**/***/***/appname/env/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception
reraise(exc_type, exc_value, tb)
File "/*/**/***/***/appname/env/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "/*/**/***/***/appname/env/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/*/**/***/***/appname/env/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/*/**/***/***/appname/env/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/*/**/***/***/appname/env/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/*/**/***/***/appname/views.py", line 207, in login
if sha256_crypt.verify(u''+ passW,user):
File "/*/**/***/***/appname/env/lib/python2.7/site-packages/passlib/utils/handlers.py", line 567, in verify
self = cls.from_string(hash, **context)
File "/*/**/***/***/appname/env/lib/python2.7/site-packages/passlib/handlers/sha2_crypt.py", line 285, in from_string
hash = to_unicode(hash, "ascii", "hash")
File "/*/**/***/***/appname/env/lib/python2.7/site-packages/passlib/utils/__init__.py", line 617, in to_unicode
raise ExpectedStringError(source, param)
TypeError: hash must be unicode or bytes, not appname.models.User
The debugger caught an exception in your WSGI application. You can now look at the traceback which led to the error.
To switch between the interactive traceback and the plaintext one, you can click on the "Traceback" headline. From the text traceback you can also create a paste of it. For code execution mouse-over the frame you want to debug and click on the console icon on the right side.
You can execute arbitrary Python code in the stack frames and there are some extra helpers available for introspection:
dump() shows all variables in the frame
dump(obj) dumps all that's known about the object
Here is my views.py codes:
#app.route("/login", methods=['GET','POST'])
def login():
if current_user.is_authenticated:
flash("You're already registered", "info")
return redirect(url_for('profile')+('/'+current_user.slug))
form = LoginForm()
passW = form.password.data
if request.method == 'POST':
form = LoginForm()
if form.validate_on_submit():
user = User.objects(email=form.email.data, password=str(passW)).first()
if sha256_crypt.verify(passW, user):
login_user(user, form.remember_me.data)
slug = slugify(user.name)
flash('We are glad you came {}.'.format(user.name),'success')
return redirect(request.args.get('next') or url_for('profile', slug=slug))
else:
flash('Wrong username or password.','danger')
return render_template("login.html", form=form, title="Cp-Login")
return render_template("login.html", form=form, title="Cp-Login")
Any help will be appreciated.
I guess the problem is here:
user = User.objects(email=form.email.data, password=str(passW)).first()
If your database can't find any match user, user will be none. So you'd better use if else to tell if the user exist first.
EDIT
From the doc in Passlib,
>>> # import the hash algorithm
>>> from passlib.hash import sha256_crypt
>>> # generate new salt, and hash a password
>>> hash = sha256_crypt.encrypt("toomanysecrets")
>>> hash
'$5$rounds=80000$zvpXD3gCkrt7tw.1$QqeTSolNHEfgryc5oMgiq1o8qCEAcmye3FoMSuvgToC'
>>> # verifying the password
>>> sha256_crypt.verify("toomanysecrets", hash)
True
>>> sha256_crypt.verify("joshua", hash)
False
Your code
if sha256_crypt.verify(passW, user):
should be
if sha256_crypt.verify(passW, user.password):
if you store user's password use Passlib. But usually you should use django build-in authenticating to do something like this.
Just as #aison said above I had to change objects variable with the objects field variable as user.password
if sha256_crypt.verify(passW, user.password):
Also needed to change model queryset itself. I removed the password field in the query, beacuse the password already verifying sha256_crypt statement after the form validation above
before modifying
user = User.objects(email=form.email.data, password=str(passW)).first()
after modifying
user = User.objects(email=form.email.data).first()
Hash verify statement that #aison suggested do the rest
if sha256_crypt.verify(passW, user.password):
in my case (fastAPI) i just make mistake when declare types of class in schemas.py
should be looks like
password: str
instead
password = str

Categories