Django中Admin与Generic视图get_queryset签名不一致,如何避免代码重复?
问题
我想编写一段简单代码,基于请求信息(比如用户所属组织)在视图中过滤记录。
最初为Admin视图实现了如下Mixin:
class OrganizationPermissionMixin: def get_queryset(self, request): query = super().get_queryset(request) if request.user.is_superuser: return query return query.filter( organization__in=request.user.organization_set.all() )
这个Mixin在Admin视图中运行正常,但应用到Generic视图时,会因为get_queryset方法未传入request参数出现签名错误:
TypeError: OrganizationPermissionMixin.get_queryset() missing 1 required positional argument: 'request'
如果把Mixin改成下面这样:
class OrganizationPermissionMixin: def get_queryset(self): query = super().get_queryset() if self.request.user.is_superuser: return query return query.filter( organization__in=self.request.user.organization_set.all() )
它能在ListView等Generic视图中正常工作,但又会导致ModelAdmin视图报错:
OrganizationPermissionMixin.get_queryset() takes 1 positional argument but 2 were given
这种签名不一致的情况很麻烦,难道要因为Admin和Generic视图的请求传递机制不同就重复写代码?我想知道:
- 怎么让这个Mixin同时兼容Admin与Generic视图?
- Django中有没有现成的方案?
- 这种设计是正常的还是欠考虑的选择?
兼容Admin与Generic视图的Mixin实现
可以通过动态处理方法参数的方式,让Mixin同时适配两种视图的get_queryset签名。核心思路是用*args和**kwargs接收所有传入的参数,灵活获取request对象:
class OrganizationPermissionMixin: def get_queryset(self, *args, **kwargs): # 适配两种调用逻辑:Admin传request作为参数,Generic视图从self获取request request = args[0] if len(args) > 0 else self.request # 原样传递参数调用父类方法,保证父类逻辑正常执行 query = super().get_queryset(*args, **kwargs) if request.user.is_superuser: return query return query.filter(organization__in=request.user.organization_set.all())
这段代码的逻辑:
- 用
*args兼容Admin视图传入的request参数,同时适配Generic视图无额外参数的场景 - 优先从
args中取request,否则从self.request获取 - 调用父类方法时完整传递所有参数,不破坏原有视图的逻辑
Django现有方案与设计说明
现成方案:Django官方没有直接提供同时兼容Admin和Generic视图的这类权限过滤Mixin,但可以借助第三方库实现更完善的权限控制,比如
django-guardian(对象级权限管理)或django-rules(规则式权限)。如果仅需要简单的组织过滤,自行实现Mixin是更轻量的选择。设计合理性:这种签名不一致是Django的历史设计产物:
- Admin视图的架构演化早于Generic视图,早期设计中
get_queryset需要显式传入request,因为当时视图实例的request属性并不稳定 - Generic视图是后续类视图重构的产物,将request作为实例属性存储,因此
get_queryset不需要额外参数
这种差异是版本迭代中的设计妥协,属于正常的历史遗留问题,并非欠考虑的选择。
- Admin视图的架构演化早于Generic视图,早期设计中
内容的提问来源于stack exchange,提问作者jlandercy
相关产品推荐
相关产品推荐

