You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于用户组过滤Django中的ManyToManyField选项?

按用户组过滤Django ManyToManyField可选项

要实现按用户所属组过滤Staff模型中websites字段的可选Website实例,核心思路是根据当前用户的组身份,动态修改字段的QuerySet。以下分场景给出具体实现方案:

一、先修复模型的Choices格式(必填前置)

原Website模型中MY_CHOICES的写法不符合Django字段要求,需改成「(存储值, 显示文本)」的元组格式,否则MultiSelectField无法正常工作:

# website/models.py
from django.db import models
from multiselectfield import MultiSelectField

MY_CHOICES = (
    ('chemical', 'Chemical'),
    ('mechnical', 'Mechanical'),
    ('IT', 'IT'),
)

class Website(models.Model):
    title = models.CharField(max_length=100)
    webapps = MultiSelectField(choices=MY_CHOICES, blank=True, null=True)

    def __str__(self):
        return self.title

二、Admin后台场景

如果是在Django Admin中实现过滤,需在Staff的Admin类里重写formfield_for_manytomany方法,根据当前登录用户的组筛选可选项:

# staff/admin.py
from django.contrib import admin
from django.db.models import Q
from .models import Staff
from website.models import Website

class StaffAdmin(admin.ModelAdmin):
    def formfield_for_manytomany(self, db_field, request, **kwargs):
        if db_field.name == 'websites':
            # 获取当前用户所属的所有组名
            user_groups = request.user.groups.values_list('name', flat=True)
            
            # 按组设置过滤规则
            if 'Group1' in user_groups:
                # Group1用户仅能选择webapps包含Chemical或IT的Website
                kwargs['queryset'] = Website.objects.filter(
                    Q(webapps__contains=['chemical']) | 
                    Q(webapps__contains=['IT'])
                )
            elif 'Group2' in user_groups:
                # 示例:Group2用户仅能选择包含Mechanical的Website
                kwargs['queryset'] = Website.objects.filter(webapps__contains=['mechnical'])
            # 其他组用户默认显示全部选项(可根据需求调整)
            else:
                kwargs['queryset'] = Website.objects.all()
        return super().formfield_for_manytomany(db_field, request, **kwargs)

admin.site.register(Staff, StaffAdmin)

三、自定义表单/前端页面场景

如果是在自定义表单中使用,需在表单的__init__方法中接收request对象,根据用户组动态修改字段的可选QuerySet:

# staff/forms.py
from django import forms
from django.db.models import Q
from .models import Staff
from website.models import Website

class StaffForm(forms.ModelForm):
    class Meta:
        model = Staff
        fields = ['name', 'websites']

    def __init__(self, *args, **kwargs):
        # 从参数中取出request对象
        self.request = kwargs.pop('request', None)
        super().__init__(*args, **kwargs)
        
        if self.request and self.request.user.is_authenticated:
            user_groups = self.request.user.groups.values_list('name', flat=True)
            
            # 按组过滤可选选项
            if 'Group1' in user_groups:
                self.fields['websites'].queryset = Website.objects.filter(
                    Q(webapps__contains=['chemical']) | 
                    Q(webapps__contains=['IT'])
                )
            elif 'Group2' in user_groups:
                self.fields['websites'].queryset = Website.objects.filter(webapps__contains=['mechnical'])
            else:
                self.fields['websites'].queryset = Website.objects.all()

在视图中使用该表单时,需要把request传入:

# staff/views.py
from django.shortcuts import render
from .forms import StaffForm

def create_staff(request):
    form = StaffForm(request.POST or None, request=request)
    if request.method == 'POST' and form.is_valid():
        form.save()
        # 处理成功逻辑(如跳转列表页)
    return render(request, 'staff/create_staff.html', {'form': form})

内容的提问来源于stack exchange,提问作者Darwin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 05:55:22