I am building an app with multiple roles defined through Django Groups.
I started with a custom user model, defined as below.
I am seeing a weird difference in the groups and permissions use when using a custom user model, like the inheritance is missing something.
I would like to use a custom user model so I don't use username but I also need multiple groups and permissions in my application.
from django.db import models
from django.contrib.auth.models import AbstractUser, AbstractBaseUser, BaseUserManager, PermissionsMixin
import random
import string
from slugify import slugify
# Create your models here.
class MyAccountManager(BaseUserManager):
def create_user(self, email, password=None):
if not email:
raise ValueError("You must have an email address")
user = self.model(
email=self.normalize_email(email),
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password):
user = self.create_user(
email=self.normalize_email(email),
)
user.set_password(password)
user.is_admin=True
user.is_staff=True
user.is_superuser=True
user.save(using=self._db)
return user
#custom user account model
class User_Account(AbstractUser):
email = models.EmailField(verbose_name='email', max_length=60, unique = True)
date_joined = models.DateTimeField(verbose_name="Date Joined", auto_now_add=True)
last_login = models.DateTimeField(verbose_name="Last Login", auto_now=True)
username = models.CharField(max_length=100, null=True)
is_admin = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = MyAccountManager()
def __str__(self):
return self.email
When I create a new group with the custom user model, the group gets automatically assigned to all created users. I reproduced this behavior both programmatically and through the Django Admin.
When I use the default user model the group creation doesn't assign groups to all users automatically.
I also discovered that when using a custom user model the Django Admin for the users is not the same (the group and permission assignment fields are incomplete - screenshots below)
Weird incomplete Django Admin interface with groups and permissions missing the available fields
Normal Django Admin interface with group and permission assignment as expected - default user model
I managed to fix the issue in the Admin panel. It seems that it's a visual rendering problem caused by a wrong Admin class.
The error was caused by the following:
filter_horizontal = ()
list_filter = ()
fieldsets = ()
I have actually added the proper parameters in the class above but forgot to comment out/remove these lines. Works properly after commenting them out.
Try removing
filter_horizontal = (),
It worked for me.
Related
I'm trying to make custom user model, when instead of few boolean columns, I will manage user permissions based on one status filed:
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.utils.translation import ugettext_lazy as _
class MyUser(AbstractUser):
username = None
is_staff = None
is_superuser = None
is_active = None
email = models.EmailField(_('email address'), unique=True)
status = models.PositiveSmallIntegerField(default=0)
In settings.py file added:
AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.AllowAllUsersModelBackend']
Then, when trying to login, getting error: This account is inactive.
How to ignore is_active filed for my custom user model ?
You can replace is_active with a property, so:
class MyUser(AbstractUser):
# …
# no is_active field
# …
#property
def is_active(self):
return self.status > 0
As docs says in https://docs.djangoproject.com/en/3.2/ref/contrib/auth/#django.contrib.auth.models.User.has_perm:
You can use AllowAllUsersModelBackend or AllowAllUsersRemoteUserBackend if you want to allow inactive users to login. In this case, you’ll also want to customize the AuthenticationForm used by the LoginView as it rejects inactive users. Be aware that the permission-checking methods such as has_perm() and the authentication in the Django admin all return False for inactive users.
So you have to override has_perm() method to ignore is_active()
I'm currently taking a custom rest API class that is teaching me to build my own custom REST APIs for authentication, as well as creating custom user models.
Im running into a slight problem with the following code base:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.models import BaseUserManager
# Create your models here.
class UserProfileManager(BaseUserManager):
""" Manager for User Profiles"""
def create_user(self, email, name, password=None):
""" Create a new user profile"""
if not email:
raise ValueError('Users must have an email address')
email = self.normalize_email(email)
user = self.model(email=email, name=name)
""" user.set_password(password) encrypts the passwords as a hash """
user.set_password(password)
""" This allows you to specify which database to use for the user accounts. Django Supports multiple Databases!!! 8D """
user.save(using=self._db)
return user
def create_superusr(self, email, name, password):
""" Create and save a new superuser with given details """
user = self.create_user(email, name, password)
user.is_superuser = True
user.is_staff = True
user.save(using=self._db)
return user
class UserProfile(AbstractBaseUser, PermissionsMixin):
""" Database model for users in system """
email = models.EmailField(max_length=255, unique=True)
name = models.CharField(max_length=255)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
objects = UserProfileManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name']
def get_full_name(self):
""" Retrieve Full Name of User"""
return self.name
def get_short_name(self):
""" Retrieve short name of User"""
return self.name
def __str__(self):
"""Return String representation of our User """
return self.email
The primary issue is in the UserProfileManager section, the issue according to the error output is with the create_superuser section.
The error message is the following:
AttributeError: 'UserProfileManager' object has no attribute 'create_superuser'
I've checked to ensure that in my settings.py file to ensure that using the custom model, as well as Ive checked to confirm that the makemigrations and migrations commands have been run. Ive also tested by deleting the init files, as well as the database and rebuilding them.
Ive also tested to ensure that superuser works, and django admin portal is enabled, all of which without the custom user profile works fine, but with it it breaks, so I know my issue should have something to do with the section of code above, but I cant find anything. Ive checked with the official django docs, but Im at a loss at this point.
I found my error. E for Error, as in the e that was missing in def create_superusEr.
Im good now! This site is awesome! Sometimes just asking the question helps to answer it.
I am trying to allow all active user to login to admin site because as a default just staff and superusers are able to login to admin site.
I've tried to overwrite clean method in my custom crate/change forms but it didn't help
class User(GuardianUserMixin, AbstractUser):
name = models.CharField(_("Name of User"), blank=True, max_length=255)
def get_absolute_url(self):
return reverse("users:detail", kwargs={"username": self.username})
#admin.register(User)
class UserAdmin(GuardedModelAdminMixin, auth_admin.UserAdmin):
form = UserChangeForm
add_form = UserCreationForm
fieldsets = FIELDSETS
list_display = ["username", "name", "is_active", "is_superuser", "is_staff"]
search_fields = ["name", "username"]
class UserChangeForm(forms.UserChangeForm):
class Meta(forms.UserChangeForm.Meta):
model = User
class UserCreationForm(forms.UserCreationForm):
error_message = forms.UserCreationForm.error_messages.update(
{"duplicate_username": _("This username has already been taken.")}
)
class Meta(forms.UserCreationForm.Meta):
model = User
def clean_username(self):
username = self.cleaned_data["username"]
try:
User.objects.get(username=username)
except User.DoesNotExist:
return username
raise
ValidationError(self.error_messages["duplicate_username"])```
There are 2 things that determine whether a user can access the Django Admin:
User.is_staff1 must be set to True
The user will need the appropriate permissions for each model
There are multiple ways to set is_staff to True for all new users. The easiest would probably be to redefine is_staff = models.BooleanField(default=True) on your User model.
If you are not going to use per-model permissions you can also redefine is_superuser = models.BooleanField(default=True) which will give the user all permissions on every model.
Note though that the Django Admin is primarily designed to be used by your developers and site administrators who know what they are doing, and not most regular users.
I'm using a CustomUser in my model. This is the User Manager.
class UserManager(BaseUserManager):
def create_user(self, email, username, password=None, is_staff=False, is_superuser=False, is_active=False,
is_bot=False, is_mobile_verified=False, is_online=True, is_logged_in=True):
logger = logging.getLogger(__name__)
logger.info("REGULAR user created!")
if not email:
raise ValueError('Email is required')
if not username:
raise ValueError('Username is required.')
email = self.normalize_email(email)
user = self.model(email=email, username=username, is_staff=is_staff, is_superuser=is_superuser,
is_active=is_active, is_bot=is_bot, is_mobile_verified=is_mobile_verified,
is_online=is_online, is_logged_in=is_logged_in)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, username, password):
logger = logging.getLogger(__name__)
logger.info("SUPER user created!")
return self.create_user(email, username, password=password, is_staff=True, is_superuser=True, is_active=True,
is_bot=False, is_mobile_verified=False, is_online=True, is_logged_in=True)
This is my definition of the custom user model.
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True, max_length=255)
mobile = PhoneNumberField(null=True)
username = models.CharField(null=False, unique=True, max_length=255)
full_name = models.CharField(max_length=255, blank=True, null=True)
birthday = models.DateField(null=True)
gender = models.CharField(max_length=255, null=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
is_mobile_verified = models.BooleanField(default=False)
is_online = models.BooleanField(default=False)
is_logged_in = models.BooleanField(default=True)
is_bot = models.BooleanField(default=False)
location = models.ForeignKey(Location, on_delete=models.SET_NULL, null=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
#objects = UserManager()
get_user_model().objects.create_user(...)
If I uncomment the line objects = UserManager() then I can run the server but the super users created from the admin backend can't log in.
If I use get_user_model() the code breaks and I get the following error
"AUTH_USER_MODEL refers to model '%s' that has not been installed" % settings.AUTH_USER_MODEL
django.core.exceptions.ImproperlyConfigured: AUTH_USER_MODEL refers to model 'bouncer.User' that has not been installed
But in my settings.py I've define auth user model
AUTH_USER_MODEL = 'bouncer.User'
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
)
What am I doing wrong here?
For anyone reading this in 2020, I suspect the problem is dependency related. I ran into the same error as OP.
Your first two checks should be:
1 - Is the app in the installed apps list in your settings.py?
2 - Is the AUTH_USER_MODEL = "app_name_from_apps_py.model_name" set in settings.py?
This was as far as most of the other responses I read go.
What I didn't realise on reading the docs is that to use get_user_model() you need to have established your model first. Of course, right?!
So above, where OP is using get_user_model(), they are creating a circular dependency.
You cannot use get_user_model() within the class that creates this model.
That error looks like bouncer isn't in your INSTALLED_APPS.
So to clarify, you have to have
bouncer/models.py that contains the User model (or models/__init__.py which imports the model from another file)
'bouncer' in the INSTALLED_APPS list in the settings
AUTH_USER_MODEL = 'bouncer.User' (as you do).
In my case I accidentally pasted in Meta class of my custom user the attribute abstract = True. So it raises this error.
For me this was because I had myapp/models/__init__.py and I tried putting the custom User model definition in myapp/models/user.py, and setting AUTH_USER_MODEL = myapp.User. Moving the custom User model definition into myapp/models/__init__.py fixed it. I was unable to import it in __init__.py; I had to move the definition there.
Make sure that you register your model in admin.py and not in models.py
# admin.py
from django.contrib.auth.admin import UserAdmin
admin.site.register(YourUser, UserAdmin)
This solved the problem for me.
Never put custom user model and additional models containing links to user model in one models.py file in one app. This can be a matter of that error.
Bad idea leading to that error:
# customUserModel/models.py
from django.contrib.auth.models import AbstractUser
from django.conf import settings
class User(AbstractUser):
pass
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
some_field = models.CharField(max_length=25)
This is a good idea:
# customUserModel/models.py
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
# additionalUserProfile/models.py
from django.conf import settings
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
some_field = models.CharField(max_length=25)
#settings.py
AUTH_USER_MODEL = 'customUserModel.User'
Try shifting the position of the bouncer app in your INSTALLED APPS, this worked for me.
For some reason the import from django.contrib.auth.backends import BaseBackend caused this problem. I suspect that BaseBackend tries to use the user model, but can't because it's defined further down the file. However if you define your model BEFORE that import then it'll work just fine.
I'm aware this is an old question but I struggled with this issue for two days before finding my mistake, which was failing to follow the models organization in the Django Models docs.
I would have just commented on #5fec's answer, but I don't have the reputation yet. My answer is similar to his, except importing the model in models/__init__.py worked for me. I had neglected the __init__.py file entirely.
If you have the AUTH_USER_MODEL = <app_name>.<user_model> correctly written, and you have your '<app_name>', in your INSTALLED_APPS list, but you're still getting this error, it's possible that your <custom_user> model (e.g. User) is in the wrong place.
It needs to be defined in either:
<app_name>.models.py
OR
<app_name>/models/<arbitrary_name>.py AND there is an <app_name>/models/__init__.py that contains the line from .<arbitrary_name> import <custom_user>
try importing from django.db import models only after importing from django.contrib.auth.models import AbstractUser
I am creating a custom django user and I get the following error when trying to use it. The error I get is the following
AppRegistryNotReady: Models aren't loaded yet.
My model
class MyCustomUserManager(BaseUserManager):
def create_user(self, username, email, password=None, **kwargs):
if not username:
raise ValueError("Username must be defined for users")
if not kwargs.get('email'):
raise ValueError("Users must have a valid email")
user = self.model(username=username, email=self.normalize_email(email), **kwargs)
user.set_password(password)
user.save()
return user
def create_superuser(self, username, email, password, **kwargs):
user = self.create_user(username, email, password, **kwargs)
user.is_admin = True
user.save()
class MyCustomUser(AbstractBaseUser):
username = models.CharField(max_length=40, unique=True)
email = models.EmailField(max_length=255, unique=True, verbose_name=_('Email Address'))
date_of_birth = models.DateField(auto_now=False, blank=False, null=False, verbose_name=_("Ημ. Γεννήσεως"))
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
first_name = models.CharField(max_length=40, blank=False, null=False, verbose_name=_("Όνομα"))
last_name = models.CharField(max_length=40, blank=False, null=False, verbose_name=_("Επίθετο"))
friends = models.ManyToManyField('self', related_name="friends")
objects = MyCustomUserManager()
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email',]
def get_full_name(self):
return "%s %s" % (self.first_name, self.last_name)
def __unicode__(self):
return self.get_full_name()
class Meta:
verbose_name = _('Χρήστης')
verbose_name_plural = _('Χρήστες')
I have also setup settings file to include my new custom user model.
(inside settings.py)
AUTH_USER_MODEL = 'myapp.MyCustomUserModel'
When logging in the shell trying to use my new user type like this
from django.contrib.auth import get_user_model
user = get_user_model().objects.all()
i get the error above. Is there something wrong with Django 1.7
P.S: I used makemigrations and migrate to make models and I am behind a virtualenv.
Starting in django 1.7 you can't use get_user_model in your models.py files or you'll run into this problem. The details/reason can be seen in referencing the user model
To fix this problem, in your models.py files instead of referencing the custom user model with get_user_model, you need to import the name from settings.
from django.conf import settings
class MyModel(models.Model):
...
user = models.ForeignKey(settings.AUTH_USER_MODEL)
When you fix the problem, it will fix your app as well as your shell.
This post has been here for some time, I have come across this same problem today (using Django shell) and would like to share a quick workaround by writing a custom get_user_model() using import_module.
under one of your models.py:
from django.conf import settings
from importlib import import_module
USER_MODEL = settings.AUTH_USER_MODEL.rsplit('.', 1)
def get_user_model():
models = getattr(import_module(USER_MODEL[0]), 'models')
return getattr(models, USER_MODEL[1])
This works in my local machine (Mac) under Django shell, and I hope this will also work under PyCharm shell.