Django自定义用户模型注册时account_type为空问题及扩展需求
Solution for Custom User Registration with Flexible Account Types
Hey there! Let's work through your problem to build a flexible, scalable registration system that fits your needs. Here's how to adjust your code step by step:
1. Adjust the User Model for Flexibility
First, let's fix the account_type field to allow empty values (for company accounts) and set up a maintainable way to manage account types for future expansion:
from django.db import models from django.contrib.auth.models import ( BaseUserManager, AbstractBaseUser ) # Define account types as a TextChoices class for easy future expansion class AccountType(models.TextChoices): ADMIN = 'admin', 'Admin' STAFF = 'staff', 'Staff' # Add new types here later, e.g.: # MANAGER = 'manager', 'Manager' # CLIENT = 'client', 'Client' class UserManager(BaseUserManager): def create_user(self, email, first_name, last_name, account_type=None, password=None): if not email: raise ValueError('Email address is required') user = self.model( email=self.normalize_email(email), first_name=first_name, last_name=last_name, account_type=account_type ) user.set_password(password) user.save(using=self._db) return user def create_staffuser(self, email, first_name, last_name, password): # Use the AccountType constant instead of hardcoding 'staff' user = self.create_user( email, first_name=first_name, last_name=last_name, account_type=AccountType.STAFF, password=password ) user.staff = True user.save(using=self._db) return user def create_superuser(self, email, first_name, last_name, password): # Use the AccountType constant for 'admin' user = self.create_user( email, first_name=first_name, last_name=last_name, account_type=AccountType.ADMIN, password=password ) user.staff = True user.admin = True user.save(using=self._db) return user class User(AbstractBaseUser): email = models.CharField(max_length=255, unique=True) first_name = models.CharField(max_length=64) last_name = models.CharField(max_length=64) # Allow empty values for company accounts, use our AccountType for backend validation account_type = models.CharField( max_length=32, choices=AccountType.choices, # This is backend-only, won't force a dropdown in forms blank=True, null=True ) active = models.BooleanField(default=True) staff = models.BooleanField(default=False) admin = models.BooleanField(default=False) objects = UserManager() USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['first_name', 'last_name'] # Keep your existing methods (__str__, get_full_name, has_perm, etc.) def __str__(self): return self.email def get_full_name(self): return "%s %s" % (self.first_name, self.last_name) def get_short_name(self): return self.first_name def has_perm(self, perm, obj=None): return True def has_module_perms(self, app_label): return True @property def is_admin(self): return self.admin @property def is_staff(self): return self.staff @property def is_active(self): return self.active
Why this works:
- The
AccountTypeclass centralizes all account types, making it easy to add new ones later without hunting through code. blank=True, null=Truelets us save empty values for company accounts.- The
choicesparameter is used for backend validation and clarity, but won't force a dropdown in your forms (we'll handle that in the form layer).
2. Update the Registration Form to Hide Account Type
Since you don't want a dropdown for account_type, we'll exclude it from the form so users can't modify it. Here's what your forms.py should look like:
from django import forms from .models import User class RegisterForm(forms.ModelForm): password = forms.CharField(widget=forms.PasswordInput) class Meta: model = User # Exclude account_type from the form fields fields = ['email', 'first_name', 'last_name', 'password']
3. Adjust the View to Set Account Type for Company Accounts
Now, update your view to set account_type to an empty value (as you requested for company accounts) when saving:
from django.shortcuts import render from django.http import HttpResponse from accounts.forms import RegisterForm def register(request): if request.method == 'POST': form = RegisterForm(request.POST) if form.is_valid(): password = form.cleaned_data.get('password') user = form.save(commit=False) # Set account_type to empty for company accounts user.account_type = '' # or None, since we allowed null=True user.set_password(password) user.save() return HttpResponse('Company account created successfully!') else: form = RegisterForm() context = {'form': form} return render(request, 'accounts/form.html', context)
4. Scaling for Future Account Types
When you need to add new account types later:
- Add a new entry to the
AccountTypeclass (e.g.,MANAGER = 'manager', 'Manager'). - Create a dedicated view/form for that account type (e.g.,
StaffRegisterView,ManagerRegisterView) where you set the correspondingaccount_typevalue in the view, just like we did for company accounts. - No need to modify the core model or existing views—this keeps your code clean and maintainable.
内容的提问来源于stack exchange,提问作者Ricky Singh
相关产品推荐
相关产品推荐

