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.
Related
Previously I was using my project with sqlite. Then started a new project copied the data from previous project and made some changes, and I'm using this with mysql.
This is my models.py(not full)
from django.db import models
from django.db.models import CheckConstraint, Q, F
class College(models.Model):
CITY_CHOICES=[('BAN','Bangalore')]
id=models.IntegerField(primary_key=True)
name=models.CharField(max_length=50)
city=models.CharField(choices=CITY_CHOICES,default='BAN',max_length=10)
fest_nos=models.IntegerField()
image=models.ImageField(default='default.jpg',upload_to='college_pics')
class Meta():
db_table='college'
def __str__(self):
return self.name
class Organizer(models.Model):
id=models.IntegerField(primary_key=True)
name=models.CharField(max_length=25)
phone=models.IntegerField()
def __str__(self):
return self.name
class Fest(models.Model):
FEST_CHOICES=[
('CUL','Cultural'),
('TEC','Technical'),
('COL','College'),
('SPO','Sports'),
]
id=models.IntegerField(primary_key=True)
name=models.CharField(max_length=50)
clg_id=models.ForeignKey(College,on_delete=models.CASCADE)
fest_type=models.CharField(choices=FEST_CHOICES,default='COL',max_length=10)
fest_desc=models.TextField(default='This is a fest')
#below two field are not showing up in admin page
start_date=models.DateField(auto_now_add=True)
end_date=models.DateField(auto_now_add=True)
event_nos=models.IntegerField()
org_id=models.ManyToManyField(Organizer)
image=models.ImageField(default='default.jpg',upload_to='fest_pics')
class Meta:
constraints = [
CheckConstraint(
check = Q(end_date__gte=F('start_date')),
name = 'check_start_date',
)
]
db_table='fest'
def __str__(self):
return self.name
The start_date and end_date attributes are the new ones added in this project. It was not there in the old one.
My admin.py file
from django.contrib import admin
from .models import College, Event, Fest, Organizer, Participated
admin.site.register(College)
admin.site.register(Organizer)
admin.site.register(Fest)
admin.site.register(Event)
admin.site.register(Participated)
But in my admin dashboard, while adding new fests I'm not getting the option to add start and end date.
I made migrations once again, fake migrated etc. What to do?
Is check constraint under model fest causing this problem?
They fields won't show up on Django Admin because they have auto_now_add=True so, the user shouldn't touch them.
You can make auto_now_add field display in admin by using readonly_fields in the admin class(this only show the data, you still can't edit it because it's auto_now_add)
#register with a class to use
class FestAdmin(admin.ModelAdmin):
readonly_fields = ('start_date', 'end_date')
admin.site.register(Fest, FestAdmin)
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 have an app that I'm calling Progress. I want to have several different apps throughout my project write to it whenever something happens. But all the different apps are not the same in how they broadcast progress. So I thought that a ContentType solution would work.
The only trick that I'm having a hard time figuring out is that I need to write to the Progress app when an event occurs. Such as when a view renders. I've been trying get_or_create but I'm having trouble getting the right configuration in the queryset. Any suggestions for how to correct this?
I want the get_or_create to sit in the view of an app so that the action I want is what writes to the progress.
My Progress Model.py
from django.db import models
from django.template.defaultfilters import slugify
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from datetime import datetime
class Progress(models.Model):
"""
The page log. Records the user and the object.
"""
user = models.ForeignKey(User, related_name='user_pagelog')
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
stamp = models.DateTimeField(auto_now_add=True)
class Meta:
unique_together = (('user', 'content_type', 'stamp'),)
verbose_name = 'View Log'
verbose_name_plural = 'View Logs'
get_latest_by = 'stamp'
def __str__(self):
return "%s got to %s on %s" % (self.user, self.content_type, self.stamp)
#classmethod
def get_latest_view(cls, user):
"""
Get most recent view log value for a given user.
"""
try:
view_log = cls.objects.filter(user=user).order_by('-stamp')[0]
return view_log.value
except IndexError:
return None
An example of the queryset that I want to write to the Progress app:
Progress.objects.get_or_create(user=request.user, content_type=f.id)
Where f = get_object_or_404(Page, publish=True)
Finally, the error I'm getting:
Cannot assign "1": "Progress.content_type" must be a "ContentType" instance.
Which I think it means the instance isn't getting found? But it exists, so I'm confused.
Thanks.
No, it doesn't mean that at all. It means what it says, that the parameter has to be an instance of the ContentType model, whereas you're passing the ID of the object itself.
You might be able to use content_type along with the actual instance:
Progress.objects.get_or_create(user=request.user, content_object=f)
Otherwise you'll need to get the right ContentType using the get_for_model() method, and pass that along with the object id.
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.
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.