In my Django project I have a user authentication system. Each user has a userprofile:
# Extending main user profile
class UserProfile(models.Model):
# Required
user = models.OneToOneField(User)
# Added fields to main user model
position = models.CharField(max_length=20, null=True, blank=True)
avatar = models.ImageField(upload_to=upload_path_handler, blank=True, default='images/avatar.png')
class Meta:
app_label = 'auth'
# handler -- Create automatically UserProfile foreign key when
# a new user is registered.
def create_user_profile(sender, instance, created, **kwargs):
if created:
# Creating UserProfile
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
Well, I have a context_processor.py which its main function returns something like this:
return {'USER_MEDIA_URL': settings.USER_MEDIA_URL,
'DEBUG': settings.DEBUG,
'SITE_URL': settings.SITE_URL,
'keys_left': keys_left,
'ownRoom': c,
'userThumbnail': request.user.get_profile().avatar,}
All my templates use "userThumbnail" and "request.user.get_profile().avatar" fails randomly without any kind of explication.
The returned error in template is:
Unable to load the profile model, check AUTH_PROFILE_MODULE in your project settings
Sometimes I get this error and sometimes not. It's very annoying.
Any hint?
It's very annoying.
:)
If you don't need to perform other extra tasks on post_save except of creating a profile, maybe you could use AutoOneToOneField from django-annoying instead?
The method get_profile() does not create the profile, if it does not exist.
(django docs)
AutoOneToOneField does.
It's not really an answer, but it may turn out to be a solution for you.
from annoying.fields import AutoOneToOneField
class UserProfile(models.Model):
user = AutoOneToOneField(User, verbose_name=_(u"user"),
on_delete=models.CASCADE,
related_name="profile")
Then you use it with something like that:
return { 'userThumbnail': request.user.profile.avatar, }
Add the following to your settings.py
AUTH_PROFILE_MODULE = 'appname.UserProfile'
That should solve the issue.
Related
I'm trying to use a custom user model in my Django project. After running migrations, the database table is named accounts_listuser while Django appears to be looking for them in accounts_user. How can I change this so Django looks at the correct table (accounts_user) for the user model instead of accounts_listuser?
In my settings.py:
# Auth user models
AUTH_USER_MODEL = 'accounts.User'
AUTHENTICATION_BACKENDS = (
'accounts.authentication.PersonaAuthenticationBackend'
)
The accounts/models.py file:
class User(models.Model):
email = models.EmailField(primary_key=True)
last_login = models.DateTimeField(default=timezone.now)
REQUIRED_FIELDS = ()
USERNAME_FIELD = 'email'
is_authenticated = True
is_anonymous = False
And the file (accounts/authentication.py) where the query fails:
from django.contrib.auth import get_user_model
User = get_user_model()
# .. user's email retrieved ..
def get_user(self, email):
try:
return User.objects.get(email=email)
except User.DoesNotExist:
return None
The full source code can be found here if it helps.
Not sure what you mean by correct table in this case, but this behavior sounds about right since your model is called user and is declared in an app named accounts.
You can overwrite the auto-generated table name using class Meta attribute db_table: https://docs.djangoproject.com/en/1.10/ref/models/options/#db-table
Also just a note, the django docs recommend that your custom user model inherits from AbstractBaseUser, otherwise you will be responsible for implementing quite a few things on your own. https://docs.djangoproject.com/en/1.10/topics/auth/customizing/#specifying-a-custom-user-model
I was working on a Django project and I was trying to do something like this to make sure that my model worked no matter what user model is set.
from django.contrib.auth import get_user_model
class Item(models.Model):
title = models.CharField(max_length=100, )
description = models.TextField()
seller = models.ForeignKey(get_user_model())
However when I did this it resulted in errors telling me the user model couldn't be accessed so I had to change it to this
from django.conf import settings
class Item(models.Model):
title = models.CharField(max_length=100, )
description = models.TextField()
seller = models.ForeignKey(settings.AUTH_USER_MODEL)
This works fine but I thought I have done this in the past using the first method. The only difference that time being that I was using a custom user model. They both seem like they are doing the same thing to me so why do I have to use the second method? And does get_user_model() not work with the default user?
This is the source code of the get_user_model() in django:
def get_user_model():
"""
Returns the User model that is active in this project.
"""
from django.db.models import get_model
try:
app_label, model_name = settings.AUTH_USER_MODEL.split('.')
except ValueError:
raise ImproperlyConfigured("AUTH_USER_MODEL must be of the form 'app_label.model_name'")
user_model = get_model(app_label, model_name)
if user_model is None:
raise ImproperlyConfigured("AUTH_USER_MODEL refers to model '%s' that has not been installed" % settings.AUTH_USER_MODEL)
return user_model
As you can see, it pulls the AUTH_USER_MODEL variable from your settings as you do but extracting the app_label and the user class itself. If it does not work you should see one of the two errors in the terminal when this call is done.
I think your answer lies in the Django source. It depends on your setup what happens. Older versions might do it a bit differently.
I'm trying to use social_auth (omab) for the first time and I'm find that there is no working example how to store basic facebook user data. Authentication works and user is created without problem as it's explained in the social_auth docs but I need to store gender and locale also. Both of them belongs to the basic facebook user data so they are in the facebook response all the time.
I'm use Django 1.4, Python2.7 and latest social_auth. So I was try to use SOCIAL_AUTH_USER_MODEL = 'myapp.UserProfile' in settings.py file and model.py is:
#!/usr/bin/python
#-*- coding: UTF-8 -*-
from django.db import models
from django.contrib.auth.models import User
from django.db.models import signals
import datetime
from datetime import timedelta
from django.db.models.signals import post_save
from social_auth.signals import pre_update
from social_auth.backends.facebook import FacebookBackend
class CustomUserManager(models.Manager):
def create_user(self, username, email):
return self.model._default_manager.create(username=username)
class UserProfile(models.Model):
gender = models.CharField(max_length=150, blank=True)
locale = models.CharField(max_length=150, blank=True)
#social_auth requirements
username = models.CharField(max_length=150)
last_login = models.DateTimeField(blank=True)
is_active = models.BooleanField()
objects = CustomUserManager()
class Meta:
verbose_name_plural = 'Profiles'
def __unicode__(self):
return self.username
def get_absolute_url(self):
return '/profiles/%s/' % self.id
def facebook_extra_values(sender, user,response, details, **kwargs):
profile = user.get_profile()
current_user = user
profile, new = UserProfile.objects.get_or_create(user=current_user)
profile.gender = response.get('gender')
profile.locale = response.get('locale')
profile.save()
return True
pre_update.connect(facebook_extra_values, sender=FacebookBackend, weak = False, dispatch_uid = 'facebook_extra_values_user')
In the settings.py I'm define pipeline
SOCIAL_AUTH_PIPELINE = (
'social_auth.backends.pipeline.social.social_auth_user',
#'social_auth.backends.pipeline.associate.associate_by_email',
'social_auth.backends.pipeline.user.create_user',
'social_auth.backends.pipeline.social.associate_user',
'social_auth.backends.pipeline.social.load_extra_data',
'social_auth.backends.pipeline.user.update_user_details',
'social_auth.backends.pipeline.misc.save_status_to_session',
)
but with above I get error AssertionError: ForeignKey(None) is invalid. First parameter to ForeignKey must be either a model, a model name, or the string 'self'
Also I was try to use AUTH_PROFILE_MODULE = 'myapp.UserProfile' instead as I was do before to extend user.model, which works well but don't understand how to populate needed data when UserProfile is created. Does anyone can place working code for this problem?
Thanks
There are a couple of ways to archive it, what fits better to your project is up to you of course, here's a list of available options:
Define this setting FACEBOOK_EXTRA_DATA = ('gender', 'locale'), the values will be available at the UserSocialAuth instance, to get them just do user.social_auth.get(provider='facebook').extra_data['gender'] or ['locale']. This is possible just because the information is available in the basic user data response.
Use a user profile to store this data (check django doc about it). Then just add a pipeline entry that stores the values in your profile instance.
Create a custom user model, SOCIAL_AUTH_USER_MODEL = 'myapp.CustomUser', and again add a custom pipeline entry that stores the values in your user instance.
Number 1 is not the best solution IMO, since a user can have several Facebook accounts connected and it could create a mess. Number 2 is good for Django 1.4 and lower, but it's deprecated starting from Django 1.5, something to take into account. Number 3 is a bit messy IMO.
I'm trying to configure django_ldap_auth to populate user profile with their region data from LDAP:
I created a model for the profile:
from django.db import models
from django.contrib.auth.models import User
class profile(models.Model):
user = models.ForeignKey(User, unique=True)
region = models.CharField(max_length=128, null=True, blank=True)
def __unicode__(self):
return '{0} profile'.format(self.user.username)
class Meta:
app_label = 'core'
I configured my settings to map to 'l' LDAP attribute (that's how region is marked in LDAP)
AUTH_PROFILE_MODULE = 'core.profile'
AUTH_LDAP_PROFILE_ATTR_MAP = {"region": "l"}
This may be important, the profile class sits inside app/models/UserProfile.py file and models/init.py has from UserProfile import profile statement.
However, I still get the following message in debug and profile won't populate:
search_s('dc=*****,dc=ru', 2, '(sAMAccountName=******)') returned 1 objects: CN=Болотнов Александр,OU=****,OU=****,DC=***,DC=ru
Populating Django user *****
Django user **** does not have a profile to populate
Is there anything I'm missing? userdata such as first/last name and email populate just fine but region won't.
This means that this particular User object does not have an associated profile object. Django does not automatically create profile objects, nor does django-auth-ldap. Typically, you will install a post_save signal handler on the User model to create profiles.
See https://docs.djangoproject.com/en/1.4/topics/auth/#storing-additional-information-about-users.
I am trying to create an intranet/extranet with internal/external user-specific profiles, with a common generic profile. I've looked at several answers on this site, but none specifically address what I'm looking to do. Below are the (stripped down) files I have so far.
What's the best way to create a profile model, with subprofiles for each user type? I'm trying not to require a custom authentication backend if at all possible.
https://gist.github.com/1196077
I have a solution I dont Know if its the best but see it:
models.py
from django.db import models
from django.contrib.auth.models import User
class Pollster(models.Model):
"""docstring for Polister"""
user = models.OneToOneField(User, related_name = 'polister', unique=True)
cedule = models.CharField( max_length = 100 )
class Respondent(models.Model):
""" """
born_date = models.DateField( verbose_name=u'fecha de nacimiento' )
cedule = models.CharField( max_length = 100, verbose_name=u'cedula' )
comunity = models.CharField( max_length = 100, verbose_name=u'comunidad')
phone = models.CharField( max_length = 50, verbose_name=u'telefono')
sanrelation = models.TextField( verbose_name =u'Relacion con SAN')
user = models.OneToOneField( User, related_name = 'respondent')
I create a MiddleWare: so
i create middleware.py
from django.contrib.auth.models import User
from encuestas.models import Pollster, Respondent
class RequestMiddleWare(object):
"""docstring for """
def process_request(self,request):
if isPollster(request.user):
request.user.userprofile = Pollster.objects.get( user = request.user.id)
elif isRespondent(request.user):
request.user.userprofile = Respondent.objects.get(user = request.user.id)
return None
def isPollster(user):
return Pollster.objects.filter(user=user.id).exists()
def isRespondent(user):
return Respondent.objects.filter(user=user.id).exists()
and you need to configure settings.py for the middleware:
add to MIDDLEWARE_CLASSES atribute:
'encuestas.middleware.RequestMiddleWare'
encuestas is my_app name
middleware is the Middleware file
RequestMiddleWare is the middleware class
You need a combination of storing additional information about users and model inheritance.
Basically, you'll need the generic User models we all know and either love or hate, and then you need a generic profile model that is your AUTH_PROFILE_MODULE setting.
That profile model will be a top-level model, with model subclasses for internal and extrernal users. You probably don't want an abstract model in this case since you'll need a common profile table to load user profiles from with User.get_profile().
So...I think the major thing you want to change is to make your Associate, External, etc. models inherit from your Profile model.
Please check this excellent article that describes how to inherit from the User class and add your own information. For me, at least, this clearly seems to be the way to go: http://scottbarnham.com/blog/2008/08/21/extending-the-django-user-model-with-inheritance/
Using this method one should easily be able to add multiple user types to their Django application.