如何在Django中为租车系统构建权限差异化的多版本管理员?
Django实现车主专属权限管理方案
别再依赖is_superuser和is_admin了,这俩是给系统级管理员用的。咱们要实现的是基于用户与资源(车辆/订单)关联关系的数据隔离,配合自定义权限控制来打造车主专属管理界面,具体步骤如下:
一、扩展用户模型,标记车主身份
通过一对一关联给普通用户添加车主属性,用来区分普通用户、车主两类角色:
# models.py from django.contrib.auth.models import User from django.db import models class OwnerProfile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='owner_profile') # 可补充车主专属字段,比如联系方式、证件信息等 def __str__(self): return self.user.username
二、给业务模型绑定车主关联
让车辆、订单模型都关联到对应的车主,这是数据隔离的基础:
# models.py class Car(models.Model): owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='cars') plate_number = models.CharField(max_length=20, verbose_name="车牌号") model = models.CharField(max_length=50, verbose_name="车型") # 其他车辆属性字段... class Order(models.Model): car = models.ForeignKey(Car, on_delete=models.CASCADE, related_name='orders') status = models.CharField( max_length=20, choices=[('pending', '待付款'), ('paid', '已完成付款')], verbose_name="订单状态" ) # 其他订单属性字段...
三、自定义权限控制逻辑
1. 函数视图用装饰器控制权限
写一个装饰器,既验证用户是否是车主,又验证操作的资源是否属于当前用户:
# decorators.py from django.http import HttpResponseForbidden def owner_required(func): def wrapper(request, *args, **kwargs): # 验证是否是车主 if not hasattr(request.user, 'owner_profile'): return HttpResponseForbidden("无访问权限") # 验证车辆归属(根据URL参数判断) if 'car_id' in kwargs: from .models import Car try: car = Car.objects.get(id=kwargs['car_id']) if car.owner != request.user: return HttpResponseForbidden("无权访问该车辆") except Car.DoesNotExist: return HttpResponseForbidden("车辆不存在") # 验证订单归属 if 'order_id' in kwargs: from .models import Order try: order = Order.objects.get(id=kwargs['order_id']) if order.car.owner != request.user: return HttpResponseForbidden("无权访问该订单") except Order.DoesNotExist: return HttpResponseForbidden("订单不存在") return func(request, *args, **kwargs) return wrapper
在视图中使用装饰器,同时查询数据时自动过滤当前用户的资源:
# views.py from django.shortcuts import render, redirect from .decorators import owner_required from .models import Car, Order from django.contrib.auth.decorators import login_required @login_required @owner_required def owner_dashboard(request): # 只加载当前车主的车辆和订单 cars = request.user.cars.all() pending_orders = Order.objects.filter(car__owner=request.user, status='pending') paid_orders = Order.objects.filter(car__owner=request.user, status='paid') return render(request, 'owner/dashboard.html', { 'cars': cars, 'pending_orders': pending_orders, 'paid_orders': paid_orders }) @login_required @owner_required def add_car(request): if request.method == 'POST': # 创建车辆时自动绑定当前车主 Car.objects.create( owner=request.user, plate_number=request.POST['plate_number'], model=request.POST['model'] ) return redirect('owner_dashboard') return render(request, 'owner/add_car.html') @login_required @owner_required def delete_car(request, car_id): car = Car.objects.get(id=car_id) car.delete() return redirect('owner_dashboard')
2. 类视图用Mixin控制权限
如果用类视图开发,写一个权限控制Mixin:
# mixins.py from django.http import HttpResponseForbidden from django.views.generic.base import ViewMixin class OwnerAccessMixin(ViewMixin): def dispatch(self, request, *args, **kwargs): # 验证车主身份 if not hasattr(request.user, 'owner_profile'): return HttpResponseForbidden("无访问权限") # 验证资源归属 if hasattr(self, 'get_object'): obj = self.get_object() if hasattr(obj, 'owner') and obj.owner != request.user: return HttpResponseForbidden("无权访问该资源") elif hasattr(obj, 'car') and obj.car.owner != request.user: return HttpResponseForbidden("无权访问该资源") return super().dispatch(request, *args, **kwargs)
在类视图中使用Mixin,同时重写查询集过滤当前用户资源:
# views.py from django.views.generic import ListView, CreateView, DeleteView from .mixins import OwnerAccessMixin from .models import Car from django.urls import reverse_lazy from django.contrib.auth.mixins import LoginRequiredMixin class CarListView(LoginRequiredMixin, OwnerAccessMixin, ListView): model = Car template_name = 'owner/car_list.html' def get_queryset(self): return self.request.user.cars.all() class CarCreateView(LoginRequiredMixin, OwnerAccessMixin, CreateView): model = Car fields = ['plate_number', 'model'] template_name = 'owner/add_car.html' success_url = reverse_lazy('car_list') def form_valid(self, form): form.instance.owner = self.request.user return super().form_valid(form)
四、路由层加固访问权限
给车主专属路由加上login_required,确保只有登录用户能访问,同时原生admin界面保持默认逻辑(仅超级用户可访问,不要给车主设置is_superuser权限):
# urls.py from django.urls import path from .views import owner_dashboard, add_car, delete_car, CarListView urlpatterns = [ path('owner/dashboard/', owner_dashboard, name='owner_dashboard'), path('owner/car/add/', add_car, name='add_car'), path('owner/car/delete/<int:car_id>/', delete_car, name='delete_car'), path('owner/cars/', CarListView.as_view(), name='car_list'), ]
这套方案能实现:
- 车主仅能查看、操作自己的车辆和订单
- 非车主用户无法进入车主管理界面
- 车主无法访问原生admin界面
内容的提问来源于stack exchange,提问作者SIMBA
相关产品推荐
相关产品推荐

