You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Django中按用户权限筛选模型表单下拉框选项?

解决Django表单下拉列表按权限显示指定选项的问题

作为Django新手,你要实现的「根据用户权限过滤下拉选项」需求,其实可以从表单逻辑层或者模板渲染层来处理,下面给你两种实用方案,推荐优先用第一种,更符合Django的代码规范:


方法1:在表单类中动态过滤选项(推荐)

把权限判断逻辑放在表单里,模板只负责简单渲染,这样代码更清晰易维护。

步骤1:修改你的模型表单

ChangeTaskForm的初始化方法里,根据传入的用户权限,动态修改target字段的可选值:

class ChangeTaskForm(forms.ModelForm):
    class Meta:
        model = GoalStatus
        fields = '__all__'

    def __init__(self, *args, **kwargs):
        # 先取出视图传入的用户对象,记得要在视图里传这个参数
        self.user = kwargs.pop('user', None)
        super().__init__(*args, **kwargs)
        
        # 如果用户属于ADMIN组,只保留'Day'对应的选项
        if self.user and self.user.groups.filter(name='ADMIN').exists():
            # 从原target元组中过滤出符合条件的选项
            self.fields['target'].choices = [item for item in target if item[0] == 'Day']
        # 其他权限用户可以保留默认选项,或者你也可以加其他判断逻辑

步骤2:视图中给表单传递用户对象

在处理表单的视图函数里,实例化表单时要把当前登录用户传进去:

def move_goal(request):
    if request.method == 'POST':
        # POST请求时,传入用户和表单数据
        form = ChangeTaskForm(request.POST, user=request.user)
        if form.is_valid():
            form.save()
            return redirect('your-success-url')
    else:
        # GET请求时,只传入用户
        form = ChangeTaskForm(user=request.user)
    return render(request, 'your-template.html', {'form': form})

步骤3:模板中简化渲染

这时候模板里不用写复杂循环,直接渲染处理好的字段就行:

{% if user.is_authenticated %}
    {% if request.user|has_group:"ADMIN" %}
        <form action="{% url 'myapp:move_goal' %}" method="post">
            {% csrf_token %}
            <!-- 直接渲染过滤后的下拉框 -->
            {{ form.target }}
            <button type="submit">提交</button>
        </form>
    {% endif %}
{% endif %}

方法2:在模板中手动遍历过滤选项

如果暂时不想改表单逻辑,也可以在模板里直接处理(不推荐,因为业务逻辑尽量别放在模板里):

首先要确保你的has_group过滤器是可用的(如果没定义过,需要自己写一个):

# 在你的app下创建templatetags/custom_tags.py文件
from django import template

register = template.Library()

@register.filter(name='has_group')
def has_group(user, group_name):
    return user.groups.filter(name=group_name).exists()

然后在模板开头加载这个过滤器:{% load custom_tags %}

之后在模板里遍历表单字段的原始选项并过滤:

{% if user.is_authenticated %}
    {% if request.user|has_group:"ADMIN" %}
        <form action="{% url 'myapp:move_goal' %}" method="post">
            {% csrf_token %}
            <select name="target">
                {% for value, label in form.target.field.choices %}
                    {% if value == 'Day' %}
                        <option value="{{ value }}">{{ label }}</option>
                    {% endif %}
                {% endfor %}
            </select>
            <button type="submit">提交</button>
        </form>
    {% endif %}
{% endif %}

注意:这里要遍历form.target.field.choices,而不是form.data.target——form.data是用户提交后的数据,不是原始的下拉选项。


小提醒

为什么更推荐方法1?因为把权限过滤逻辑放在表单里,能避免模板里出现过多业务代码,后续要修改权限规则或者选项过滤逻辑时,只需要改表单类就行,不用动模板,维护起来更省心。

内容的提问来源于stack exchange,提问作者A.Sasori

火山引擎 最新活动