Django: User object's 'email' attribute - python

I'm working on an application where users can log in into my application using their Twitter account credentials which I implemented using the python-social-auth. Now, Django's authentication system provides User objects, with five primary attributes of username, password, email, first_name and last_name as given in the documentation: https://docs.djangoproject.com/en/1.7/topics/auth/default/#user-objects
Now, after the user successfully logs in using his/her Twitter account, I want certain fields of my form, like the user's full name, email address, Twitter account username, etc to be pre-filled. For that purpose, I used something like this for pre-filling user's full name form field:
{% if user and not user.is_anonymous %}
Full Name: <input type = "text" name = "name" value = "{{user.get_full_name}}"">
{% endif %}
This is what the above form field looks like after a user successfully logs in through his/her Twitter account:
Perfect! Works just as intended. Similarly, attributes such as username, last_name, first_name works just fine for the currently logged in User object.
However, when I try to pre-fill the email address field in my form using:
Email Address: <input type = "text" name = "email" value = "{{user.email}}"">
However, the value of {{user.email}} doesn't return anything, and my form field looks something like this:
Why is the email attribute of the User object not returning the email address through which the user logged in using his Twitter credentials? All other User attributes seem to be working just fine. Any reasoning behind this?
EDIT 1:
This is what my database at the admin looks like:
So the email field is empty, hence the User object returns nothing for that attribute value. But why is the email address not stored in the database every time a new user logs in using their Twitter accounts?

The email is stored elsewhere when using python-social-auth. They create a SocialUser table and likely the data you seek is stored in JSON format in the extra_data field - look at the model created by PSA
Pulling the additional info may not be as trivial as before, but you can add functionality that will save the email address to your user's table when the social user is created. See Pipeline

In admin if user_email is not showing probably there is no email added with perticular user.
Just make sure this by checking database again.

It's happening probably because you have nothing in your register process that actually stores the email in the database for the form, so in your view have something like
p = #user object from form.
p.email = request.POST['email']
p.save()

Related

Django - How to differentiate between users in the database?

I'm building a Django server for my company and I'm still unfamiliar with some processes. I'm sure this is super simple, I'm just completely unaware of how this works.
How do I differentiate between user's data so it doesn't get mixed up?
If Jill is a user and she requests a page of her profile data, how do I not send her Jack's profile data, especially if there are multiple models invovled?
For example, the code in the view would look like this:
def display_profile(request)
profile = Profile.objects.get(???) # What do I put in here?
I understand that I can do:
def display_profile(request, user)
profile = Profile.objects.get(user_id=user)
But that's not my design intention.
Thank you in advance.
As documented
Django uses sessions and middleware to hook the authentication system into request objects.
These provide a request.user attribute on every request which
represents the current user. If the current user has not logged in,
this attribute will be set to an instance of AnonymousUser, otherwise
it will be an instance of User.
So in your case (notice field not being called user_id )
profile = Profile.objects.get(user=user)
In your Django view, you can access the current user with request.user.
So if you want to get a Profile instance matching your current logged in user, just do a query as follow:
profile = Profile.objects.get(user=request.user)
This assumes you have a user foreign key field (or OneToOne) in your Profile model.

Django-Differentiate between verified and non verified users in database via email confirmation link

I want to differentiate between the users who signed up and are verified through email confirmation link, and those who signed up but not verified through email confirmation.
I tried is_active and is_authenticated but did not got the desired results.
Adding a new field is an okay solution if you have a custom user model or some secondary model to store addition user information. If you don't have any of this and you are not planning to add them then just use groups.
First create a group called Email Verified. You can do this via django admin or via data migration.
Group.objects.create(name='Email Verified')
Then to mark users as email verified you can do
email_verified_group = Group.objects.get(name='Email Verified')
the_user.groups.add(email_verified_group)
To check if the user is email verified or not
is_email_verified = the_user.groups.filter(name='Email Verified').exists()

django update view password and ForeignKey

i currently use django update/create view and i have some problems:
how can i update/create a password? - i can show the old password but
it doesn't save the new one with the django hash algorithm so the password is
ignored and the user cant log in anymore.
class Update(UpdateView):
model = User
fields = ['username', 'password']
how can i update/create a Foreign Key?
is there a way to custom the fields? i.e. to show them as
radio/checkbox/password?
thx
I can show the old password but it doesn't save the new one with the django hash algorithm so the password is ignored and the user cant log in anymore.
That's because for security, Django doesn't store raw passwords, it stores a hash of the raw password, which is sufficient to tell if a user entered the correct password
To set the password use User.set_password()
user = request.user # or another user source
user.set_password('raw password string')
So instead of changing the field directly, change the password like above to store the hash (not the raw password), and don't bother with "showing old password", a secure system won't be able to
https://docs.djangoproject.com/en/1.8/ref/contrib/auth/#django.contrib.auth.models.User.set_password

Adding a username property to webapp2 User model after entity has been created (with Simpleauth)

I'm currently using Python / App Engine / SimpleAuth to provide OAuth login to my application. The current workflow is that users login with OAuth, and they can later create a unique username for themselves in the app.
I'm having problems creating the unique username after the webapp2 User entity has already been created. I see that in the webapp2 model there is a way to enable a unique username within the application Entity group, but I don't know how to set it for myself. (I'm using SimpleAuth to set everything for other OAuth providers.)
I want to check to see if the user-submitted 'username' exists, and if it doesn't to add it as a property to the currently logged-in user. I'd appreciate any help/pointers on this!
I think you could extend webapp2_extras.appengine.auth.models.User and add username property, e.g.
from webapp2_extras.appengine.auth.models import User as Webapp2User
class User(Webapp2User):
username = ndb.StringProperty(required=True)
Then, to create a webapp2 app you'd need a config which includes this:
APP_CFG = {
'webapp2_extras.auth': {
'user_model': User, # default is webapp2_extras.appengine.auth.models.User
'user_attributes': ['username'] # list of User model properties
}
}
app = webapp2.WSGIApplication(config=APP_CFG)
Havign the above, creating a new user using the following code will ensure username is unique (ensured by Unique model):
auth_id = 'some-auth-id' # e.g. 'google:123456789', see simpleauth example.
ok, props = User.create_user(auth_id, unique_properties=['username'],
username='some-username',
...)
if not ok:
# props list will contain 'username', indicating that
# another entity with the same username already exists
...
Problem is, with this configuration you are bound to set username during the creation time.
If you wanted to make username optional, or let users set/change it later on, you would probably want to change the above code to something like this:
class User(Webapp2User):
username = ndb.StringProperty() # note, there's no required=True
# when creating a new user:
auth_id = 'some-auth-id' # e.g. 'google:123456789', see simpleauth example.
ok, props = User.create_user(auth_id, unique_properties=[], ...)
Basically, unique_properties will be empty list (or you can just skip it). Also, you could temporarily assign username property to something like user.key.id() until the user decides to change their username to something more meaningful. Take, for instance, Google+ profile links: mine is currently https://plus.google.com/114517983826182834234, but if they let me change it, I would try something like https://plus.google.com/+IamNotANumberAnymore
Then, in a "change/set username" form handler, you could check if a username already exists and update User entity (if it doesn't):
def handle_change_username(self):
user = ... # get the user who wants to change their username
username = self.request.get('username')
uniq = 'User.username:%s' % username
ok = User.unique_model.create(uniq)
if ok:
user.username = username
user.put()
else:
# notify them that this username
# is already taken
...
User.unique_model.create(uniq) will create a Unique entity with the given value if it didn't exist. In this case ok will be True. Otherwise, ok will be False which indicates that an entity with that value (a unique username in this case) already exists.
Also, you might want to put User.unique_model.create() and user.put() in the same transaction (it'll be XG because they are in different entity groups).
Hope this helps!

How to update a user's `extra_data` after they have been associated with account?

I've successfully managed to use django-socialauth to associate an account (in this case, an instagram account) with an existing user account. I've also set up my pipeline to collect additional user details:
def update_social_auth(backend, details, response, social_user, uid, user,
*args, **kwargs):
if getattr(backend, 'name', None) in ('instagram', 'tumblr'):
social_user.extra_data['username'] = details.get('username')
social_user.save()
This works great when an account is associated for the first time. However, if the account has already been associated, the username field will not be present in extra_data.
How can I update a user's extra_data after the association has already been made? Is there a way using django-socialauth to do this without disconnecting and reconnecting, or using the account's (e.g Instagram's) API?
If it helps, this is my pipeline at the moment:
SOCIAL_AUTH_PIPELINE = (
'social_auth.backends.pipeline.social.social_auth_user',
'social_auth.backends.pipeline.social.associate_user',
'social_auth.backends.pipeline.social.load_extra_data',
'social_auth.backends.pipeline.user.update_user_details',
'apps.utils.social.utils.update_social_auth'
)
Here is a snippet of code I use to add 'admin' and 'staff' options to an existing Django user; I don't know about django-socialauth or the extra_data field, but I'm guessing something like this might be applicable:
:
userqueryset = User.objects.filter(username=user_name)
if not userqueryset:
print("User %s does not exist"%user_name, file=sys.stderr)
return am_errors.AM_USERNOTEXISTS
# Have all the details - now update the user in the Django user database
# see:
# https://docs.djangoproject.com/en/1.7/ref/contrib/auth/#django.contrib.auth.models.User
# https://docs.djangoproject.c om/en/1.7/ref/contrib/auth/#manager-methods
user = userqueryset[0]
user.is_staff = True
user.is_superuser = True
user.save()
:
FWIW, my app is using 3rd party authentication (specifically atm OpenId Connect via Google+), so I think there's some common goal here. In my case I want to be able to add Django admin privileges to a user that has already been created.
The full module containing the above code is at github.com/gklyne/annalist/blob/develop/src/annalist_root/annalist_manager/am_createuser.py#L231

Categories