如何在Django自定义用户模型中忽略is_active字段?
I'm trying to create a custom user model in Django, replacing multiple boolean fields (like
is_active,is_staff,is_superuser) with a singlestatusinteger field to manage user permissions. Here's my model code: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)I also added this to
settings.py:AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.AllowAllUsersModelBackend']But when trying to log in, I get the error: "This account is inactive". How can I ignore the
is_activefield in my custom user model?
Let's break down the problem and fix it step by step:
1. Why the Error Happens
Your approach of setting is_active = None in the model doesn't actually remove the is_active field from the database. AbstractUser inherits this field from AbstractBaseUser, and assigning None doesn't properly exclude it. Even with AllowAllUsersModelBackend, Django's authentication flow still checks for the is_active attribute—and if the field exists in the database with a False value (the default might not be what you expect here), you'll get that error.
2. Proper Fix 1: Use AbstractBaseUser for Full Control
For a fully custom user model that replaces the default boolean permission fields, it's better to inherit from AbstractBaseUser (instead of AbstractUser), as it gives you complete control over which fields are included.
Step 1: Create a Custom User Manager
First, define a manager to handle user creation:
from django.db import models from django.contrib.auth.models import AbstractBaseUser, BaseUserManager from django.utils.translation import ugettext_lazy as _ class MyUserManager(BaseUserManager): def create_user(self, email, password=None, **extra_fields): if not email: raise ValueError(_('The Email field must be set')) email = self.normalize_email(email) user = self.model(email=email, **extra_fields) user.set_password(password) user.save(using=self._db) return user def create_superuser(self, email, password=None, **extra_fields): # Use your status field to define superuser permissions (e.g., status=2) extra_fields.setdefault('status', 2) return self.create_user(email, password, **extra_fields)
Step 2: Define the Custom User Model
Now build your model without the default boolean fields, using status instead:
class MyUser(AbstractBaseUser): email = models.EmailField(_('email address'), unique=True) status = models.PositiveSmallIntegerField(default=0, help_text="0: Inactive, 1: Regular User, 2: Admin/Superuser") objects = MyUserManager() # Set email as the unique identifier for authentication USERNAME_FIELD = 'email' REQUIRED_FIELDS = [] # Implement permission checks using the status field def has_perm(self, perm, obj=None): # Allow regular users (status >=1) to have basic permissions return self.status >= 1 def has_module_perms(self, app_label): return self.status >= 1 # Map status to is_staff for admin access (optional but useful) @property def is_staff(self): # Let status=2 users access the Django admin return self.status >= 2
Step 3: Update Settings
Add these to settings.py:
# Point Django to your custom user model AUTH_USER_MODEL = 'your_app_name.MyUser' # Use the default backend (we've handled permissions via our model methods) AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.ModelBackend']
3. Proper Fix 2: Custom Authentication Backend (If You Want to Keep AbstractUser)
If you prefer to stick with AbstractUser, you need to create a custom authentication backend that skips the is_active check entirely, and properly exclude the default boolean fields from your model.
Step 1: Fix the Model (Exclude Default Fields)
Instead of setting fields to None, use Meta.exclude to remove them:
class MyUser(AbstractUser): username = None email = models.EmailField(_('email address'), unique=True) status = models.PositiveSmallIntegerField(default=0) class Meta: exclude = ['is_active', 'is_staff', 'is_superuser'] # Map status to required attributes for Django's auth system @property def is_active(self): # Define active users via status (e.g., status >=1 is active) return self.status >= 1 @property def is_staff(self): return self.status >= 2 @property def is_superuser(self): return self.status == 2
Step 2: Create a Custom Backend
Create a backends.py file in your app:
from django.contrib.auth.backends import ModelBackend class SkipActiveCheckBackend(ModelBackend): def user_can_authenticate(self, user): # Bypass the default is_active check entirely return True
Step 3: Update Settings
AUTH_USER_MODEL = 'your_app_name.MyUser' AUTHENTICATION_BACKENDS = ['your_app_name.backends.SkipActiveCheckBackend']
Final Notes
- Always run
makemigrationsandmigrateafter modifying your user model to apply database changes. - If you're starting a new project, using
AbstractBaseUseris the cleaner approach for full customization. - Make sure your
statusfield values are clearly documented so your team understands what each value represents.
内容的提问来源于stack exchange,提问作者Oto Shavadze

