Django外卖APP多用户类型差异化登录注册实现咨询
多用户类型Django外卖应用实现方案
核心思路
Django仅支持配置一个AUTH_USER_MODEL,因此不能为三类用户分别定义独立的自定义用户模型。最优方案是单主用户模型+一对一关联类型扩展表:
- 主用户模型继承
AbstractUser,通过user_type字段区分顾客、商家、骑手 - 每个用户类型创建一对一关联模型,存储专属字段(如顾客的手机号、商家的企业邮箱)
- 自定义认证后端,适配不同用户类型的登录方式(OTP/邮箱密码)
- 拆分视图、URL和权限控制,实现各类型用户的独立流程
具体实现步骤&代码示例
1. 定义主用户模型
在单独的users应用中创建核心用户模型,取消默认用户名,用邮箱/手机号作为登录标识:
# users/models.py from django.contrib.auth.models import AbstractUser, BaseUserManager from django.db import models from django.utils.translation import gettext_lazy as _ class UserManager(BaseUserManager): def create_user(self, email=None, phone=None, password=None, **extra_fields): if not email and not phone: raise ValueError("必须填写邮箱或手机号") if email: email = self.normalize_email(email) user = self.model(email=email, phone=phone, **extra_fields) if password: user.set_password(password) user.save(using=self._db) return user def create_superuser(self, email, password=None, **extra_fields): extra_fields.setdefault('is_staff', True) extra_fields.setdefault('is_superuser', True) return self.create_user(email=email, password=password, **extra_fields) class User(AbstractUser): class UserType(models.TextChoices): CUSTOMER = 'CUSTOMER', _('顾客') SELLER = 'SELLER', _('商家') DRIVER = 'DRIVER', _('骑手') username = None # 禁用默认用户名字段 email = models.EmailField(_('邮箱'), unique=True, blank=True, null=True) phone = models.CharField(_('手机号'), max_length=15, unique=True, blank=True, null=True) user_type = models.CharField(_('用户类型'), max_length=20, choices=UserType.choices) USERNAME_FIELD = 'email' REQUIRED_FIELDS = [] objects = UserManager() def __str__(self): return self.email or self.phone
2. 各用户类型扩展模型
在拆分的customers、sellers、drivers应用中创建一对一关联模型,存储专属数据:
# customers/models.py from django.db import models from users.models import User class Customer(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True) points = models.IntegerField(default=0) # 顾客专属字段:积分 def __str__(self): return f"顾客: {self.user.phone}"
# sellers/models.py from django.db import models from users.models import User class Seller(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True) company_name = models.CharField(_('企业名称'), max_length=100) business_license = models.CharField(_('营业执照号'), max_length=50) def __str__(self): return f"商家: {self.company_name}"
3. 自定义认证后端
实现支持OTP和邮箱密码的多类型认证:
# users/backends.py from django.contrib.auth.backends import ModelBackend from django.contrib.auth import get_user_model from .utils import verify_otp # 自行实现OTP验证逻辑(如调用短信API) User = get_user_model() class MultiUserAuthBackend(ModelBackend): def authenticate(self, request, username=None, password=None, otp_code=None, **kwargs): # 商家登录:邮箱+密码 if password and username: try: user = User.objects.get(email=username, user_type=User.UserType.SELLER) if user.check_password(password): return user except User.DoesNotExist: return None # 顾客登录:手机号+OTP elif otp_code and username: try: user = User.objects.get(phone=username, user_type=User.UserType.CUSTOMER) if verify_otp(user.phone, otp_code): return user except User.DoesNotExist: return None return None
在settings.py配置认证后端:
AUTHENTICATION_BACKENDS = [ 'users.backends.MultiUserAuthBackend', 'django.contrib.auth.backends.ModelBackend', # 保留默认后端用于后台管理 ] AUTH_USER_MODEL = 'users.User'
4. 独立登录/注册视图
为不同用户类型编写专属视图:
顾客OTP注册/登录
# customers/views.py from django.shortcuts import render, redirect from django.contrib.auth import login from users.models import User from .models import Customer from .utils import send_otp # 自行实现短信发送逻辑 def customer_register(request): if request.method == 'POST': phone = request.POST.get('phone') # 手机号已存在则跳转至OTP登录 if User.objects.filter(phone=phone, user_type=User.UserType.CUSTOMER).exists(): return redirect('customer_otp_login', phone=phone) # 创建用户及顾客关联 user = User.objects.create_user(phone=phone, user_type=User.UserType.CUSTOMER) Customer.objects.create(user=user) send_otp(phone) return redirect('customer_verify_otp', phone=phone) return render(request, 'customers/register.html') def customer_verify_otp(request, phone): if request.method == 'POST': otp_code = request.POST.get('otp') user = User.objects.get(phone=phone, user_type=User.UserType.CUSTOMER) if verify_otp(phone, otp_code): login(request, user) return redirect('customer_dashboard') else: return render(request, 'customers/verify_otp.html', {'error': '验证码无效', 'phone': phone}) return render(request, 'customers/verify_otp.html', {'phone': phone})
商家邮箱密码登录/注册
# sellers/views.py from django.shortcuts import render, redirect from django.contrib.auth import login, authenticate from users.models import User from .models import Seller def seller_register(request): if request.method == 'POST': email = request.POST.get('email') password = request.POST.get('password') company_name = request.POST.get('company_name') business_license = request.POST.get('business_license') # 创建用户及商家关联 user = User.objects.create_user(email=email, password=password, user_type=User.UserType.SELLER) Seller.objects.create(user=user, company_name=company_name, business_license=business_license) login(request, user) return redirect('seller_dashboard') return render(request, 'sellers/register.html') def seller_login(request): if request.method == 'POST': email = request.POST.get('email') password = request.POST.get('password') user = authenticate(request, username=email, password=password) if user and user.user_type == User.UserType.SELLER: login(request, user) return redirect('seller_dashboard') else: return render(request, 'sellers/login.html', {'error': '账号或密码错误'}) return render(request, 'sellers/login.html')
5. 权限控制
编写自定义装饰器,限制页面访问权限:
# users/decorators.py from django.http import HttpResponseForbidden from django.contrib.auth.decorators import login_required def user_type_required(user_type): def decorator(view_func): @login_required def wrapped_view(request, *args, **kwargs): if request.user.user_type == user_type: return view_func(request, *args, **kwargs) else: return HttpResponseForbidden("无访问权限") return wrapped_view return decorator
使用示例:
# customers/views.py from users.decorators import user_type_required from users.models import User @user_type_required(User.UserType.CUSTOMER) def customer_dashboard(request): return render(request, 'customers/dashboard.html')
推荐工具&最佳实践
- OTP简化:使用
django-otp包快速实现OTP生成、验证逻辑,无需手动对接短信API - 权限增强:结合
django-guardian实现对象级权限控制(如商家仅能管理自己的店铺) - 分步注册:商家注册需提交营业执照等资料,用
django-formtools实现分步表单 - API适配:若开发后端API,可基于DRF自定义
OTPAuthentication、EmailPasswordAuthentication类,适配多类型用户的接口认证
内容的提问来源于stack exchange,提问作者Decoder
相关产品推荐
相关产品推荐

