Django - why cant i retrieve user name? - python

When i log in an user, and attempt to retrieve the username or any details i get the below error. Not sure what it really does mean?
def loginview(request):
message=[]
if request.method=='POST':
if Loginform(request.POST).is_valid():
login_form=Loginform(request.POST)
loginuser=authenticate(username=request.POST['email'],password=request.POST['password'])
if loginuser is not None:
login(request,loginuser)
print("attempted log in")
uname=User.username
print(User.get_full_name)
return render(request,'payrequest/templates/landing.html',{'landing_content':'Well done, you are loged in as'+ str(User.get_username)})
else:
return render(request,'payrequest/templates/landing.html',{'landing_content':'Incorrect details, try again.','okurl':'login'})
else:
message.append("We had some difficulties processing your request, please try again. If the issue persists please contact the systems team.")
return render(request,'payrequest/templates/landing.html',{'landing_content':'invalid data','okurl':'login'})
else:
login_form=Loginform()
return render(request,'payrequest/templates/login.html',{'form':login_form})
Console prints:
<function AbstractUser.get_full_name at 0x04560BB0>

Not sure what is User in your context, but methods (that's a model method, not a property) in Python code should be called with () like user.get_full_name().
In Django templates you can skip it and the templates engine does it instead of you under the hood :)
Usually words starting with upper-cased letter mean Class names, not objects. So normally User is a User model class but user is a User model instance which you created or retrieved from the DB (example, user = User.objects.get(pk=1)).

Maybe you should use the two following lines code replacing yours.
uname=loginuser.username
print(loginuser.get_full_name)

Related

Django not REST - API user registration

I have my first project as junior in my work. It is old (Django 1.8) and it is normal django framework... not REST.
It supports web, and mobile.
I have to create endpoint for mobile to create user.
I think it is not a problem (to create) but I want to make sure it will be save.
First of all I thought that I will create normal ModelForm (RegisterAPIForm based on model=User with full validation (I mean init all fields that are in "backend" not visible for user | cleaned_data for all fields | special overwriten method save() that in addition hashes password, and send email) and in Views I'll add something like this:
class RegistrationAPITestView(View):
def post(self, request):
form = RegistrationAPIForm(
request.POST
)
if form.is_valid():
form.save()
return JsonResponse({})
else:
#check errors and send error code back
Or I should do it other way, by using User object?
class RegistrationAPITestView(View):
def post(self, request):
#check if user does not exist
#password1 and password2 validation
user = User.objects.create()
user.name = request.POST['username']
user.set_password(request.POST['password'])
#init all fields that user can't choose like groups etc
user.save()
What do you think? Do I need ModelForm that I won't even render? It seems to be safer, but maybe I should check it other way? with User object?
Btw. Registration form already exists for web but there is a lot of "web" stuff that I don't need and I don't have to check and there is another method of saving password, so I believe I should create new one.
My code will be revieved in 2 weeks (senior vacations) but now I'm alone and want to do my best.
There is nothing wrong with the second option, but here is the problem that you as a junior should avoid. This line will make the server return a 500 error request.POST['username'] because python will throw a key error if the user doesn't provide the username, to fix just change to request.POST.get('username', 'value if doesn\'t exit') also make sure that everything is ready before create the user or you will have records in the database that wont be useful. Call validators to the password too and try to cover all possible scenario. Remember never trust the user

How would I send an alert or message to a view from a Django model's (overridden) save( ) function?

CONTEXT:
A model object's user_account_granted account indicates if a model object is linked to an non null user account.
When user_account_granted changes from False to True, I detect this in the overridden save() function. Here, I successfully make a User, pulling arguments (email, username, name, etc) from the model object
I create a password and send the new account login info to the object's email
If the email failed, I delete the account
PROBLEM:
I want to alert the current user (who just submitted the form triggering the save() ) that the email was either successful (and the new account now exists) or unsuccessful (and no new account is created). I cannot use the Django Messaging Framework in the save() function, as it requires the request. What can I do?
def save(self, *args, **kwargs):
if self.id:
previous_fields = MyModel(pk=self.id)
if previous_fields.user_account_granted != self.user_account_granted:
title = "Here's your account!"
if previous_fields.user_account_granted == False and self.user_account_granted == True:
user = User(
username=self.first_name + "." + self.last_name,
email=self.email,
first_name=self.first_name,
last_name=self.last_name
)
random_password = User.objects.make_random_password() #this gets hashed on user create
user.set_password(random_password)
user.save()
self.user = user
message = "You have just been given an account! \n\n Here's your account info: \nemail: " + self.user.email + "\npassword: " + random_password
if previous_fields.user_account_granted == True and self.user_account_granted == False:
message = "You no longer have an account. Sorry :( "
try:
sent_success = send_mail(title, message, 'example#email.com', [self.email], fail_silently=False)
if sent_success == 1:
##HERE I WANT TO INDICATE EMAIL SENT SUCCESS TO THE USER'S VIEW AFTER THE FORM IS SUBMITTED
else:
##HERE I WANT TO INDICATE EMAIL SENT FAILURE TO THE USER'S VIEW AFTER THE FORM IS SUBMITTED
user.delete()
self.user_account_granted = False
except:
##HERE I WANT TO INDICATE EMAIL SENT FAILURE TO THE USER'S VIEW AFTER THE FORM IS SUBMITTED
user.delete()
self.user_account_granted = False
super(MyModel, self).save(*args, **kwargs)
You don't send an email in a model's save() function. Ever. That's just not its purpose. Consider:
save() may be called from the shell.
save() may be called from wherever in your project.
The purpose of the save() method is to save the object. End of story.
Now. Let's get back to what you really want to achieve. You are in the process of handling a form submitted by the user. Which means you're dealing with at least to other things here: the form and the view.
Let's have a closer look at what their purpose is:
The Form's basic role is to encapsulate data input and validation. It can be extended so as to encompass the full role of a Command. After all, it only misses an execute() function.
The View's basic role is to take action based on the browser's request (here, the POSTing of a form) and trigger the displaying of the result.
You may choose either. You could have an execute() method on your form, and just call that from you view. Or you could have the view take action after checking that the form is_valid(). I would personnaly choose the form for the actual action, and the view for showing the result.
Thus, in my view, I would customize the form_valid() method to call execute() and do whatever is needed depending on the result. That is:
class MyForm(Form):
# whatever you already have there
def clean(self):
# unrelated to your issue, but just reminding you
# this is the place you make sure everything is right
# This very method MUST raise an error if any input or any
# other condition already known at that point is not fulfilled.
if you_do_not_want_to_grand_an_account:
raise ValidationError('Account not granted, because.')
return self.cleaned_data
def execute(self):
do_whatever()
needs_to_be_done()
if it_failed:
raise AnAppropriateError(_('Descriptive message'))
class MyView(FormView):
form = MyForm
# your other view stuff here
def form_valid(self, form):
try:
form.execute()
except AnAppropriateError as err:
messages.add_message(self.request, messages.ERROR, err.message)
else:
messages.add_message(self.request, messages.INFO, _('It worked'))
AnAppropriateError may just be RuntimeError if you want it quick and dirty, but you should define your own exception class.
Also, you may want to decorate the execute()̀ method with#transaction.atomic()`, depending on its content.
As a final note, remember you cannot be sure the email was actually sent. It's common to have mail systems that accept emails even if there is some error. You'll only know when it bounces, several days later.
First of all it is really not a good idea to send email from model classes. I highly object that. It is better to do that in your form
But you have already implemented that.
There is a way you can access the request inside a model, I wouldn't recommend it though. There is a plugin called CRequest Middlewar, https://pypi.python.org/pypi/django-crequest
You can use this middleware to access the request anywhere new like.
$ python pip install django-crequest
First import the crequest’s middleware:
from crequest.middleware import CrequestMiddleware
Get the current request ;):
current_request = CrequestMiddleware.get_request()
Done. Now you can use the message framework as you wish in that model.

Flask-Login Which Class's user is active

Hello I have Two classes User and ProductOwner
They can be both logged in by Flask-Login
But when you are logged in and the browser revisits the ('/') page I can not redirect them to the user or Productowner page because I don't know the logged in user .if it belongs to User class or ProductOwner class. I think it is using cookie for logging in automatically.
At first I tought it would run #lm.user_loader at each loading. But it seems like it is not.
#lm.user_loader
def load_user(id):
if id[0] == "u":
session['current']='u'
return User.query.get(int(id[1:]))
if id[0] == "b":
session['current']='b'
return ProductOwner.query.get(int(id[1:]))
I think it is not running above code if you are revisiting the page without being logged out.
Because as far as I understood
#app.route('/')
def index():
if current_user.is_authenticated():
if session['current']=='b':
return render_template('b_loggedin.html')
elif session['current']=='u':
return render_template('userloggedin.html')
return render_template('index.html')
returns index.html
Thank you
As a short answer inherit your User and ProductOwner from flask.ext.login.UserMixin, read more here.
But if you like to have a better code you need to make in dynamic. Relying on parts of your id to recognize user type and on another part as user ID is a bad practice and will make you more troubles in future.
Thank you Mehdi. I solved my problem by using is_authenticated method as Mehdi stated.I added code inside is_authenticated method.
Thank you very much.

Google App Engine get_current_user always return None, even if i'm logged

here's my code
def subscribe_current_user(self):
user1 = SocialNodeSubscription(parent=self.key)
user1.subscribed = True
current_user = users.get_current_user()
logging.error(current_user)
if current_user:
user1.user=current_user
else:
raise users.UserNotFoundError
user1.put()
The problem is that get_current_user returns None even if i'm logged in. It stores a None in the field user1.user and it prints a None in the log console.
How can i solve that?
Do you have login: required defined in app.yaml for your handler or have you provided a login url using users.create_login_url() so that the user can explicitly login.
Even if you are logged into google somewhere, users.get_current_user() won't
return a user object.
I have seen a lot of similar questions.
It helps to think of this line differently...
user = users.get_current_user()
This line doesn't search high and low in your browser and cache and retrieve whatever info and put it into a nice user object; it simply checks if an user is logged in to the app using the users class. Which means if you did not have the user logged with the users class, chances are this line of code won't do what you want it to do.
The important codes that should usually follow a get_current_user() method:
if user:
greeting = ('Welcome, %s! (sign out)' %
(user.nickname(), users.create_logout_url('/')))
else:
greeting = ('Sign in or register.' %
users.create_login_url('/'))
self.response.out.write('<html><body>%s</body></html>' % greeting)
I believed, you surely importing this,
from google.appengine.api import users
And also, Are you really authenticating django's 'User' model at the time of login?

How to implement user_loader callback in Flask-Login

I'm attempting to use Flask and the Flask-Login extension to implement user authentication in a Flask app. The goal is to pull user account information from a database and then log in a user, but I'm getting stuck; however, I've narrowed it down to a particular part of Flask-Login behavior.
According to the Flask-Login documentation, I need to create a user_loader "callback" function. The actual purpose and implementation of this function has had me confused for a few days now:
You will need to provide a user_loader callback. This callback is used
to reload the user object from the user ID stored in the session. It
should take the Unicode ID of a user, and return the corresponding
user object. For example:
#login_manager.user_loader
def load_user(userid):
return User.get(userid)
Now, say I want the user to enter a name and password into a form, check against a database, and log in the user. The database stuff works fine and is no problem for me.
This 'callback' function wants to be passed a user ID #, and return the User object (the contents of which I'm loading from a database). But I don't really get what it's supposed to be checking/doing, since the user IDs are all pulled from the same place anyway. I can 'sort-of' get the callback to work, but it seems messy/hackish and it hits the database with every single resource that the browser requests. I really don't want to check my database in order to download favicon.ico with every page refresh, but flask-login seems like it's forcing this.
If I don't check the database again, then I have no way to return a User object from this function. The User object/class gets created in the flask route for logging in, and is thus out of scope of the callback.
What I can't figure out is how to pass a User object into this callback function, without having to hit the database every single time. Or, otherwise figure out how to go about doing this in a more effective way. I must be missing something fundamental, but I've been staring at it for a few days now, throwing all kinds of functions and methods at it, and nothing is working out.
Here are relevant snippets from my test code. The User class:
class UserClass(UserMixin):
def __init__(self, name, id, active=True):
self.name = name
self.id = id
self.active = active
def is_active(self):
return self.active
The function I made to return the user object to Flask-Login's user_loader callback function:
def check_db(userid):
# query database (again), just so we can pass an object to the callback
db_check = users_collection.find_one({ 'userid' : userid })
UserObject = UserClass(db_check['username'], userid, active=True)
if userObject.id == userid:
return UserObject
else:
return None
The 'callback', which I don't totally understand (must return the User object, which gets created after pulling from database):
#login_manager.user_loader
def load_user(id):
return check_db(id)
The login route:
#app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST" and "username" in request.form:
username = request.form["username"]
# check MongoDB for the existence of the entered username
db_result = users_collection.find_one({ 'username' : username })
result_id = int(db_result['userid'])
# create User object/instance
User = UserClass(db_result['username'], result_id, active=True)
# if username entered matches database, log user in
if username == db_result['username']:
# log user in,
login_user(User)
return url_for("index"))
else:
flash("Invalid username.")
else:
flash(u"Invalid login.")
return render_template("login.html")
My code 'kinda' works, I can log in and out, but as I said, it must hit the database for absolutely everything, because I have to provide a User object to the callback function in a different namespace/scope from where the rest of the login action takes place. I'm pretty sure I'm doing it all wrong, but I can't figure out how.
The example code provided by flask-login does it this way, but this only works because it's pulling the User objects from a global hard-coded dictionary, not as in a real-world scenario like a database, where the DB must be checked and User objects created after the user enters their login credentials. And I can't seem to find any other example code that illustrates using a database with flask-login.
What am missing here?
You will need to load the user object from the DB upon every request. The strongest reason for that requirement is that Flask-Login will check the authentication token every time to ensure its continuing validity. The calculation of this token may require parameters stored on the user object.
For example, suppose a user has two concurrent sessions. In one of them, the user changes their password. In subsequent requests, the user must be logged out of the second session and forced to login anew for your application to be secure. Think of the case where the second session is stolen because your user forgot to log out of a computer - you want a password change to immediately fix the situation. You might also want to give your admins the ability to kick a user out.
For such forced logout to happen, the authentication token stored in a cookie must 1) be based in part on the password or something else that changes each time a new password is set; 2) be checked before running any view, against the latest known attributes of the user object - which are stored in the DB.
I do share your concerns Edmond: hitting database each time when one needs to know user's role or name is insane. Best way would be to store your User object in session or even application-wide cache which gets updated from the DB each couple of minutes. I personally use Redis for that (that way website can be run by multiple threads/processes while using single cache entry point). I just make sure Redis is configured with password and non-default port, and any confidential data (like user hashes etc) are stored there in an encrypted form. Cache can be populated by a separate script running on specified interval, or separate thread can be spawned in Flask. Note: Flask-Session can be also configured to use (the same) redis instance to store session data, in that case instance with 'bytes' datatype will be needed, for a regular cache you might often go with instance type which automatically translates bytes into strings (decode_responses=True).
Here is my code, another User as data mapping object provide query_pwd_md5 method.
User login:
#app.route('/users/login', methods=['POST'])
def login():
# check post.
uname = request.form.get('user_name')
request_pwd = request.form.get('password_md5')
user = User()
user.id = uname
try:
user.check_pwd(request_pwd, BacktestUser.query_pwd_md5(
uname, DBSessionMaker.get_session()
))
if user.is_authenticated:
login_user(user)
LOGGER.info('User login, username: {}'.format(user.id))
return utils.serialize({'userName': uname}, msg='login success.')
LOGGER.info('User login failed, username: {}'.format(user.id))
return abort(401)
except (MultipleResultsFound, TypeError):
return abort(401)
User class:
class User(UserMixin):
"""Flask-login user class.
"""
def __init__(self):
self.id = None
self._is_authenticated = False
self._is_active = True
self._is_anoymous = False
#property
def is_authenticated(self):
return self._is_authenticated
#is_authenticated.setter
def is_authenticated(self, val):
self._is_authenticated = val
#property
def is_active(self):
return self._is_active
#is_active.setter
def is_active(self, val):
self._is_active = val
#property
def is_anoymous(self):
return self._is_anoymous
#is_anoymous.setter
def is_anoymous(self, val):
self._is_anoymous = val
def check_pwd(self, request_pwd, pwd):
"""Check user request pwd and update authenticate status.
Args:
request_pwd: (str)
pwd: (unicode)
"""
if request_pwd:
self.is_authenticated = request_pwd == str(pwd)
else:
self.is_authenticated = False

Categories