如何在模板中检查用户是否属于一个组

69
如何在模板中检查用户是否属于某个群组?
在生成模板的视图函数中可以实现,但是如果我想在一个继承模板(没有自己的视图函数)中进行检查怎么办?我的所有模板都继承自base.html,所以在每个视图函数中检查这不是好的解决方案。base.html包含上部栏,应该根据登录用户所在的组(客户、卖家)显示相应的按钮。
在我的base.html中包含以下内容:
{% if user.is_authenticated %}

这还不够,因为我必须针对来自客户和来自卖家的用户采取不同的操作。

所以我想要的是:

{% if user.in_group('Customers') %}
 <p>Customer</p>
{% endif %}
{% if user.in_group('Sellers') %}
<p>Seller</p>
{% endif %}
11个回答

113
您需要自定义模板标签:

您需要自定义模板标签:

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() 

在您的模板中:
{% if request.user|has_group:"mygroup" %} 
    <p>User belongs to my group 
{% else %}
    <p>User doesn't belong to mygroup</p>
{% endif %}

来源:http://www.abidibo.net/blog/2014/05/22/check-if-user-belongs-group-django-templates/

文档:https://docs.djangoproject.com/en/dev/howto/custom-template-tags/

这篇文章介绍了如何在Django模板中检查用户是否属于某个组,并提供了一个自定义模板标签的示例。如果你需要更多关于自定义模板标签的信息,可以参考官方文档。

4
混杂,谢谢。我看过那个网页,但我不知道这段代码应该放在哪里。 - Milano
3
你可以通过执行 Group.objects.filter(name=group_name).exists() 来获取一个布尔值。 - Max Lap
4
建议使用return user.groups.filter(name=group_name).exists()以避免多次查询。 - antonagestam
1
这里不需要导入 from django.contrib.auth.models import Group,是正确的吗? - Clement H.
10
你在 HTML 模板中忘记了 {% load has_group %}。 - dzierzak
显示剩余4条评论

35
在你的应用程序中创建一个名为“templatetags”的文件夹,然后在该文件夹中创建两个文件:__init__.pyauth_extras.py
from django import template
from django.contrib.auth.models import Group 

register = template.Library()

@register.filter(name='has_group')
def has_group(user, group_name): 
    group = Group.objects.get(name=group_name) 
    return True if group in user.groups.all() else False

现在它应该看起来像这样:

app/
    __init__.py
    models.py
    templatetags/
        __init__.py
        auth_extras.py
    views.py

添加模板标签模块后,您需要重新启动服务器才能在模板中使用标签或过滤器。

在您的base.html(模板)中使用以下内容:

{% load auth_extras %}

并检查用户是否在组“moderator”中:

{% if request.user|has_group:"moderator" %} 
    <p>moderator</p> 
{% endif %}

文档:https://docs.djangoproject.com/en/1.11/howto/custom-template-tags/


你可以将它添加到项目文件夹中,以便在所有应用程序中使用吗? - AnonymousUser
@匿名用户 是的 - chris Frisina

18

我会说最好的方法是:

yourapp/templatetags/templatetagname.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()

您的应用程序/templates/您的应用程序/您的模板.html:

{% load has_group %}

{% if request.user|has_group:"mygroup" %} 
    <p>User belongs to my group</p>
{% else %}
    <p>User does not belong to my group</p>
{% endif %}

编辑:根据评论建议添加了一个加载模板标签的行。

编辑2:修正了小错误。


3
值得一提的是,在每个你想要使用它的HTML模板的顶部,你需要包含 {% load templatetagname %}。 - pawisoon
@pawisoon 这就是问题所在,也是我不会使用它的原因。因为我有10个模板,而且以后可能还会做更多。 - AnonymousUser

13

请注意,如果数据库中不存在该组,则会出现异常。

自定义模板标签应为:

from django import template
from django.contrib.auth.models import Group

register = template.Library()

@register.filter(name='has_group')
def has_group(user, group_name):
    try:
        group =  Group.objects.get(name=group_name)
    except Group.DoesNotExist:
        return False

    return group in user.groups.all()

您的模板:

{% if request.user|has_group:"mygroup" %} 
    <p>User belongs to my group 
{% else %}
    <p>User doesn't belong to mygroup</p>
{% endif %}

这是一个更好的答案,因为它使用了try/catch块,如果用户不是该组的一部分,它不会在您的模板中出现错误。 - Kalob Taulien

10
在您的模板中:

{% ifequal user.groups.all.0.name "user" %}
  This is User
{% endifequal %}
  


3
如果用户只属于一个组,这个方法非常有效。但是如果一个用户属于多个组,是否有一种简单的方式来修改它,以便我们不只是检查所有.0.name呢? - LNI
@LNI 我正在寻找相同的答案。我不想硬编码任何组名。如果有人决定更改组名,请考虑重新工作的问题。 - Arindam Roychowdhury

6

您可以使用以下方式:

{% for group_for in request.user.groups.all %}
    {% if group_for.name == 'Customers' %}
        Text showed to users in group 'Customers'
    {% elif group_for.name == 'Sellers' %}
        Text showed to users in group 'Sellers'
    {% endif %}
{% endfor %}

这是遍历与请求用户相关的组,并在迭代的组名称等于“Customers”、“Sellers”等时输出文本。


5

我发现最简单的方法是通过使用 context_preprocessor 将所有组名称添加到上下文中。

在你的应用程序中创建一个文件 context_processors.py 并添加以下内容:

def user_groups_processor(request):
    groups = []
    user = request.user
    if user.is_authenticated:
        groups = list(user.groups.values_list('name',flat = True))
    return {'groups': groups}


在您的设置中,添加新的上下文处理器。
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            # ... some options here ...
             "context_processors": [
                "my_app.context_processors.user_groups_processor"
            ],
        },
    },
]

或者如果您更喜欢在settings.py中进行设置

TEMPLATES[0]['OPTIONS']['context_processors'].append("my_app.context_processors.user_groups_processor")

之后在您的模板中,您可以使用以下内容:

{% if 'vip' in groups %}
  <p>Paragraph only visible to VIPs</p>
{% endif %}

这对我来说是最好的答案。之前我使用自定义过滤器来获取当前用户组,但每次在模板中使用标签时都会进行一次数据库请求。对于某些模板,我需要在模板的许多地方检查角色,导致了许多针对相同信息的数据库请求。上下文处理器更符合我的需求。 - Quentin

2
{% if target_group in user.groups.all.0.name %}
    # do your stuff
{% endif %}

你能为你的答案提供一个解释吗? - rassar
2
即使用户属于多个组,此方法也适用。因此,它只检查特定组(target_group)是否在用户的组中。 注意:target_group是组的名称,而不是Group对象! - scorpionipx
你的答案只检查了第一个项目,因为你使用了索引 0。如果你想在模板中完成它,最好遍历相关组对象,然后匹配名称属性。{% for group in user.groups.all %} {%if group.name == target_group %} 做某事 {%endif%} {%endfor%} - Codebender
@Codebender 但是如果你有两个组,你不能使用 if group.name == target_group1 and group.name == target_group2。即使用户拥有这两个组,因为for循环逐一检查,它始终会返回False。 - AnonymousUser

1
虽然mishbah所给的答案是正确的,但对我没有用。
我正在使用Django 2.2.7,我发现register = template.Library()应该替换为from django.template.defaultfilters import register
我希望有人会发现它有用。

1
在我的情况下,问题出在我使用了{% load filter_method_name %}。我不得不改成{% load filename %}
例如:
app/
    __init__.py
    models.py
    templatetags/
        __init__.py
        auth_extras.py
    views.py

在这里,模板标签将是 {% load auth_extras %}

然后我需要重新启动服务器。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接