Как написать тег шаблона Django для контроля доступа? - PullRequest
3 голосов
/ 23 сентября 2010

Я тщетно пытаюсь создать простой тег шаблона Django, чтобы показать или скрыть ссылку "удалить" рядом с отправленным комментарием на моем сайте.

Короче говоря, я хочу передать объект комментария в тег шаблона, определить, авторизован ли пользователь, который в данный момент вошел в систему, удалить комментарий, а затем показать или не показать ссылку.

Использование в моем шаблоне будет выглядеть так:

{% load access_tags %}
{% if_authorized comment %}
   <a href="{% url delete_comment comment.id %}">Delete</a>
{% endif_authorized %}

Будьте уверены, что я также проверяю в соответствующем представлении, имеет ли пользователь право удалять комментарий.

Имеет ли этот тип тега конкретное имя? Это, безусловно, поможет мне с поиском в Google, если это будет сделано. Спасибо за вашу помощь!

ОБНОВЛЕНИЕ 1:

Как работает мой сайт, два человека потенциально могут удалить комментарий: 1) создатель комментария и 2) владелец поста, где был оставлен комментарий. Из-за этого мне нужно по каждому комментарию определить, присутствует ли одно из этих условий.

Я не думаю, что могу использовать что-то вроде встроенной системы разрешений Django, так как для этого требуется, чтобы разрешения были установлены глобально для каждого типа объекта, а не для конкретного экземпляра объекта.

В моем случае у пользователя "Боб" могут быть права на удаление комментария (если он написал его или он находится на созданном им посте), но ему также может быть запрещено удалять его (если он смотрит на комментировать чужой пост).

ОБНОВЛЕНИЕ 2:

Похоже, что вы не можете передавать объекты в тег шаблона, только строки: «Хотя вы можете передать любое количество аргументов в тег шаблона с помощью token.split_contents (), все аргументы распаковываются как строки литералы «. Я предполагаю, что передам идентификатор объекта комментария и вытяну его в теге.

Я был неправ по этому поводу, просто должен получить доступ к переданному объекту, как:

self.comment.resolve(context).user 

против

self.comment.user

Ответы [ 3 ]

2 голосов
/ 23 сентября 2010

как насчет этого ... создайте пользовательский тег, который записывает переменную в контексте , затем протестируйте эту переменную, используя {% if %}

это было бы что-то вроде этого:

{% check_access comment %}
{% if has_access %}
    <a href="{% url delete_comment comment.id %}">Delete</a>
{% endif %}

Конечно, тег "check_access" будет писать "has_access" в контексте.

Удачи

2 голосов
/ 23 сентября 2010

ОК, вот как я это сделал ...

Тег используется следующим образом в шаблоне:

   {% load access_tags %}
   {% if_authorized comment.user object.user user %}
      <a href="{% url delete_comment comment.id %}">Delete</a>
   {% endif_authorized %}

Файл тега шаблона называется «access_tag.py» и находится в каталоге «templatetags» моего приложения. Это содержимое файла "access_tag.py":

from django.template import Node, NodeList, TemplateSyntaxError
from django.template import Library, Variable, VariableDoesNotExist

register = Library()

def do_if_authorized(parser, token):
    """
    Outputs the contents of the block if the 'comment owner' or the 
    'page owner' is also the 'authenticated user'. As well, you can use
    an {% else %} tag to show text if the match fails.

    Takes three parameters:
      1) the comment owner
      2) the page owner
      3) the current authenticated user
    """
    bits = token.contents.split()
    if len(bits) != 4:
        raise TemplateSyntaxError("%s tag takes three arguments: \
                                   1) the comment owner \
                                   2) the page owner \
                                   3) the current authenticated user" % bits[0])
    nodelist_true = parser.parse(('else', 'endif_authorized'))
    token = parser.next_token()

    if token.contents == 'else':
        nodelist_false = parser.parse(('endif_authorized',))
        parser.delete_first_token()
    else:
        nodelist_false = NodeList()
    return IfAuthorizedNode(bits[1], bits[2], bits[3], nodelist_true, nodelist_false)

class IfAuthorizedNode(Node):
    def __init__(self, comment_owner, page_owner, authenticated_user, nodelist_true, nodelist_false):
        self.nodelist_true = nodelist_true
        self.nodelist_false = nodelist_false
        self.comment_owner = Variable(comment_owner)
        self.page_owner = Variable(page_owner)
        self.authenticated_user = Variable(authenticated_user)

    def render(self, context):
        try:
            comment_owner = self.comment_owner.resolve(context)
            page_owner = self.page_owner.resolve(context)
            authenticated_user = self.authenticated_user.resolve(context)
        except VariableDoesNotExist:
            return ''

        if comment_owner == authenticated_user or page_owner == authenticated_user:
            return self.nodelist_true.render(context)
        else:
            return self.nodelist_false.render(context)

register.tag('if_authorized', do_if_authorized)

Готово. В конце концов, было бы довольно просто использовать встроенный тег {% if%} для этого сравнения, но, поскольку у меня будут другие полномочия для каждого объекта, я буду продолжать создавать эти пользовательские "access_tags". Плюс, код шаблона выглядит намного аккуратнее:)

2 голосов
/ 23 сентября 2010

Уже существует проект, направленный на то, что вы хотели бы сделать.

django-Authority обеспечивает точный контроль зерна над разрешениями в шаблонах.

Django 1.2 также содержит пользовательские разрешения в шаблонах.

...