如何在Django中不扩展User模型创建独立用户库及Agent独立登录
问题
我正在用Django搭建网站,需要创建users和agents两个独立用户库,Agent不需要关联User就能独立存在,而且两者要有各自独立的登录URL。现在我没法给Agent创建独立登录页面;另外,任何人不用登录/注册成User就能申请成为Agent,满足条件后由超级管理员在后台完成Agent的注册。想问问有没有更优的实现方案?
当前代码实现
models.py
from django.contrib.auth.models import User class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) phonenumber = models.IntegerField() def __str__(self): return f'{self.user.username} Profile' class Agent(models.Model): name = models.CharField(max_length=100) password = models.CharField(max_length=100) image = models.ImageField(upload_to = 'Images/') bio = models.TextField() instagram = models.URLField(max_length=100) twitter = models.URLField(max_length=100) facebook = models.URLField(max_length=100) linkedin = models.URLField(max_length=100) is_featured = models.BooleanField(default = False) slug = models.SlugField(default='') def __str__(self): return f'{self.name} Agent Profile'
forms.py
class AgentSignInForm(AuthenticationForm): username = forms.CharField(max_length=100) password = forms.CharField(max_length=100) def clean(self): cleaned_data = super().clean() username = cleaned_data.get('username') password = cleaned_data.get('password') return cleaned_data
views.py
class AgentLoginView(LoginView): form_class = AgentSignInForm def form_valid(self, form): form.send_email() return super().form_valid(form)
urls.py
urlpatterns = [ path('agent-sign-in/', auth_views.LoginView.as_view(template_name='users/agent_login.html'), name='agent-sign-in'), ]
优化实现方案
一、重构Agent模型,适配Django认证系统
当前Agent模型直接存储明文密码存在严重安全问题,应该基于Django的AbstractBaseUser实现独立的Agent用户模型,既复用Django的认证能力,又保持与默认User模型的独立性。
修改models.py
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin from django.db import models from django.contrib.auth.models import User # 保留原有Profile模型,关联默认User class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) phonenumber = models.IntegerField() def __str__(self): return f'{self.user.username} Profile' # Agent用户管理器,处理账号创建逻辑 class AgentManager(BaseUserManager): def create_user(self, name, password=None, **extra_fields): if not name: raise ValueError('Agent必须填写姓名') agent = self.model(name=name, **extra_fields) agent.set_password(password) # 加密存储密码 agent.save(using=self._db) return agent def create_superuser(self, name, password=None, **extra_fields): extra_fields.setdefault('is_staff', True) extra_fields.setdefault('is_superuser', True) return self.create_user(name, password, **extra_fields) # 独立的Agent用户模型 class Agent(AbstractBaseUser, PermissionsMixin): name = models.CharField(max_length=100, unique=True) # 用姓名作为登录标识,设为唯一 image = models.ImageField(upload_to='Images/', blank=True, null=True) bio = models.TextField(blank=True) instagram = models.URLField(max_length=100, blank=True) twitter = models.URLField(max_length=100, blank=True) facebook = models.URLField(max_length=100, blank=True) linkedin = models.URLField(max_length=100, blank=True) is_featured = models.BooleanField(default=False) slug = models.SlugField(default='', unique=True) is_active = models.BooleanField(default=True) # 控制账号是否可登录 is_staff = models.BooleanField(default=False) # 控制是否能访问后台 objects = AgentManager() USERNAME_FIELD = 'name' # 指定登录用的字段 REQUIRED_FIELDS = [] def __str__(self): return f'{self.name} Agent Profile'
二、配置双用户认证后端
在项目的settings.py中添加自定义认证后端,让Django支持同时识别默认User和Agent两种用户:
settings.py
AUTHENTICATION_BACKENDS = [ 'django.contrib.auth.backends.ModelBackend', # 默认User的认证后端 '你的应用名.backends.AgentBackend', # 自定义Agent认证后端 ]
在应用目录下创建backends.py,编写Agent认证逻辑:
from django.contrib.auth.backends import ModelBackend from .models import Agent class AgentBackend(ModelBackend): def authenticate(self, request, username=None, password=None, **kwargs): try: agent = Agent.objects.get(name=username) if agent.check_password(password) and agent.is_active: return agent except Agent.DoesNotExist: return None def get_user(self, user_id): try: return Agent.objects.get(pk=user_id) except Agent.DoesNotExist: return None
三、实现Agent独立登录流程
修改forms.py
针对Agent模型编写登录表单,增加密码验证逻辑:
from django import forms from django.contrib.auth.forms import AuthenticationForm from .models import Agent class AgentSignInForm(AuthenticationForm): username = forms.CharField(label='姓名', max_length=100) password = forms.CharField(label='密码', widget=forms.PasswordInput) def clean(self): cleaned_data = super().clean() name = cleaned_data.get('username') password = cleaned_data.get('password') try: agent = Agent.objects.get(name=name) if not agent.check_password(password): raise forms.ValidationError('密码错误') if not agent.is_active: raise forms.ValidationError('该账号未激活') except Agent.DoesNotExist: raise forms.ValidationError('不存在该Agent账号') return cleaned_data
修改views.py
自定义Agent登录视图,指定使用Agent认证后端:
from django.contrib.auth import login, authenticate from django.views.generic import FormView from .forms import AgentSignInForm class AgentLoginView(FormView): form_class = AgentSignInForm template_name = 'users/agent_login.html' success_url = '/agent-dashboard/' # Agent登录后的跳转页面 def form_valid(self, form): name = form.cleaned_data.get('username') password = form.cleaned_data.get('password') # 指定使用Agent后端认证 agent = authenticate(self.request, username=name, password=password, backend='你的应用名.backends.AgentBackend') if agent: login(self.request, agent) return super().form_valid(form) else: form.add_error(None, '登录失败,请检查账号密码') return self.form_invalid(form)
修改urls.py
使用自定义的Agent登录视图,替换默认的auth_views:
from django.urls import path from .views import AgentLoginView from django.contrib.auth import views as auth_views urlpatterns = [ # Agent独立登录URL path('agent-sign-in/', AgentLoginView.as_view(), name='agent-sign-in'), # Agent登出URL path('agent-sign-out/', auth_views.LogoutView.as_view(next_page='/'), name='agent-sign-out'), # 保留默认User的登录URL(如果需要) path('user-sign-in/', auth_views.LoginView.as_view(template_name='users/user_login.html'), name='user-sign-in'), ]
四、实现Agent申请与后台审核流程
1. 创建Agent申请模型(存储申请记录)
class AgentApplication(models.Model): name = models.CharField(max_length=100) email = models.EmailField() # 用于联系申请人 phonenumber = models.CharField(max_length=20) bio = models.TextField() instagram = models.URLField(max_length=100, blank=True) twitter = models.URLField(max_length=100, blank=True) facebook = models.URLField(max_length=100, blank=True) linkedin = models.URLField(max_length=100, blank=True) applied_at = models.DateTimeField(auto_now_add=True) is_approved = models.BooleanField(default=False) def __str__(self): return f'{self.name}的Agent申请'
2. 申请表单与视图
# forms.py class AgentApplicationForm(forms.ModelForm): class Meta: model = AgentApplication fields = ['name', 'email', 'phonenumber', 'bio', 'instagram', 'twitter', 'facebook', 'linkedin'] # views.py from django.views.generic.edit import CreateView from .models import AgentApplication class AgentApplyView(CreateView): form_class = AgentApplicationForm template_name = 'users/agent_apply.html' success_url = '/apply-success/' # 申请提交后的跳转页面 def form_valid(self, form): form.save() return super().form_valid(form)
3. 后台配置
在admin.py中注册模型,让超级管理员可以审核申请并创建正式Agent账号:
from django.contrib import admin from .models import Profile, Agent, AgentApplication admin.site.register(Profile) admin.site.register(Agent) admin.site.register(AgentApplication)
审核时,管理员可从申请记录中提取信息,直接创建Agent账号并设置初始密码,再通知申请人。
五、模板适配
在模板中可通过request.user判断用户类型,展示对应内容:
{% if user.is_authenticated %} {% if user.__class__.__name__ == 'Agent' %} <p>欢迎,Agent {{ user.name }}</p> <a href="{% url 'agent-sign-out' %}">登出</a> {% else %} <p>欢迎,用户 {{ user.username }}</p> <a href="{% url 'user-sign-out' %}">登出</a> {% endif %} {% else %} <a href="{% url 'agent-sign-in' %}">Agent登录</a> <a href="{% url 'user-sign-in' %}">用户登录</a> <a href="{% url 'agent-apply' %}">申请成为Agent</a> {% endif %}
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

