I'm trying to create a custom user class and I'd like to know the best practice for implementing referencing the new user. After following the Django docs method of implementing the custom user as follows in models.py:
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
And settings.py
AUTH_USER_MODEL = 'myapp.MyUser'
And admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User
admin.site.register(User, UserAdmin)
The Django docs say to use settings.AUTH_USER_MODEL in place of user specifically for ForeignKeys and OnetoOneField, but it's not clear about other instances.
My question is specific to how to refer to the custom user class in views.py. Before defining the user class I was using
from django.contrib.auth.models import User
But after defining a custom class this is no longer correct. I've seen boilerplate code use this method in the beginning of views.py:
from django.contrib.auth import get_user_model
User = get_user_model()
Is this the best practice for referencing the custom user? Or should I just be using settings.AUTH_USER_MODEL in place of where I previously had User?
Using settings.AUTH_USER_MODEL will load the user class lazily after all django apps are loaded. Calling get_user_model() on a module level when your app is initially loaded may result in that the user model app is not loaded and also circular imports.
Update: I read two specific questions:
How to correctly access the user model, contrib or custom.
Djangos get_user_model() is quite simply a call to django.apps get_model() using the settings.AUTH_USER_MODEL. If you are writing apps that might be reused in other projects with other user models, use the get_user_model call. Always. Then it doesn't matter what the user model is.
If you have created your own core.User model and is very confident that your code will only be used in this project, from core.models import User works as well.
When to use the string representation from settings instead of fetching the model.
The string representation will in the end usually call the same django.apps get_model() anyway. By giving a string instead of the class itself in Foreignkeys, OneToOneFields etc you simply don't require the model to be looked up during django app imports, where the user model may not yet be available. So using string representation is simply deferred loading of a model. The same goes for all models.
An also during djangos different major versions this behavior have changed, which is another topic. Notice that get_user_model() have been updated in Django 1.11 for import usage.
https://docs.djangoproject.com/en/1.11/topics/auth/customizing/#referencing-the-user-model
you can go with get_user_model instead User
from django.contrib.auth import get_user_model
User = get_user_model()
get_user_model will Returns the User model that is active in this project.
if you modify(adding new field into it) default User table you need to use get_user_model it will return active User table.
BTW User will return native from django.contrib.auth.models
Related
I want to create a custom user model with some extra fields, among which a contact list of other users. I would like to extend AbstractUser instead of creating a new model with a one-to-one link to User.
from django.contrib.auth import get_user_model
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
a_custom_field = models.IntegerField(default=0)
# per-user contact list
contacts = models.ManyToManyField(get_user_model())
This code doesn't work. Throwing this error during makemigrations.
django.core.exceptions.ImproperlyConfigured: AUTH_USER_MODEL refers to model 'users.CustomUser' that has not been installed
The error totally makes sense, but what's the right way to achieve this?
I found the solution just by digging more into the django docs.
The problem is that I cannot use get_user_model() before the user model has been created.
The solution is using the class name as a string. So, this code works great:
from django.contrib.auth import get_user_model
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
a_custom_field = models.IntegerField(default=0)
# per-user contact list
contacts = models.ManyToManyField('CustomUser')
I'm trying to manage my User table with django.contrib.admin
But during I add the User table in admin, I had an issue that doesn't appear in admin site.
Here is my code.
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
#admin.register(User)
class CustomUserAdmin(UserAdmin):
pass
assert admin.site.is_registered(User) # Fails here
And when I added the other custom model, it works.
Thanks
When you modify or implement the user model, you have to be aware of AUTH_USER_MODEL.
I changed AUTH_USER_MODEL in setting.py, and it starts to work.
Thanks.
When I need to use the current user in a model.
lets say I have a model with a current_user field, something like:
class MyModel(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE,default=None)
my understanding is User can be fetched either:
1)by importing the current user:
from django.contrib.auth.models import User
or
2) setting User to:
from django.contrib.auth import get_user_model
User = get_user_model()
I understand both will work if I am not wrong!!
So What is the main difference between those two methods if there is any?
Thanks
If you are using the default User model, both approaches will work.
However if you are using a custom user model (or are writing a reusable app), then you should use get_user_model() to ensure you get the correct model.
Note that the docs suggest you use settings.AUTH_USER_MODEL in foreign keys.
class MyModel(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE,default=None)
I am using AbstractBaseUser and UserCreationForm with my Django app. When registering users through my app, the password gets saved in hash format and saved in the database. But when I try to do the same thing using Django admin site, the password gets saved in raw format.
You need to make sure that your model admin class knows how to hash passwords. According to the docs, if you are using subclassing AbstractBaseUser, then you might be able to extend UserAdmin.
Assuming your custom user model is called CustomUser, you could try the following.
from django.contrib.auth.admin import UserAdmin
class CustomUserAdmin(UserAdmin):
...
admin.site.register(CustomUser, CustomUserAdmin)
I guess the problem is that you inherited ModelAdmin instead of UserAdmin from django.contrib.auth.admin in your admin.py.
Sample code:
from django.contrib.auth.admin import UserAdmin
from .models import Employee
class EmployeeAdmin(UserAdmin):
pass
admin.site.register(Employee, EmployeeAdmin)
I'm building a website which contains several languages.
Therefore I need to set verbose names of all attributes in all my model classes (with the internationalizaton-helper). Unfortunately I don't find a way to change the verbose names of the user attributes...
And overwriting every single form isn't really a nice way to do it, right?
Thanks for your help!
Ron
It depends on what you need this for. Generally, verbose_name is only used within the context of the admin. If that's what you need to worry about, then you can create a proxy model and then make your user admin use that:
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _
class CustomUser(User):
class Meta:
proxy = True
app_label = 'auth'
verbose_name = _('My Custom User')
Then, in admin.py:
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from .models import CustomUser
admin.site.unregister(User)
admin.site.register(CustomUser, UserAdmin)
Since this is the first answer on google when searching for django verbose name I thought I'd correct Chris Pratt's answer from 2012 to be correct for django 2.0
If you only want to update the model name in the Admin panel you can simply add a Meta class to your user model. Note the slight change from Chris' answer.
class Meta:
verbose_name = 'My Custom User'