2010-09-22 2 views
3

J'essaye, en vain, de créer un simple tag de modèle Django pour afficher ou masquer un lien "supprimer" à côté d'un commentaire soumis sur mon site. En un mot, je veux passer l'objet de commentaire à la balise de modèle, déterminer si l'utilisateur actuellement connecté est autorisé à supprimer le commentaire, puis afficher ou ne pas afficher le lien.Comment écrire une balise de modèle Django pour le contrôle d'accès?

L'utilisation de mon modèle serait comme si:

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

Soyez assurés que je vérifie aussi dans la vue appropriée si l'utilisateur est autorisé à supprimer le commentaire.

Ce type d'étiquette a-t-il un nom spécifique? Cela m'aiderait certainement avec mes recherches Google si c'était le cas. Merci de votre aide!

MISE À JOUR 1:

La façon dont mon site fonctionne, deux personnes sont potentiellement autorisés à supprimer un commentaire: 1) le créateur de commentaire et 2) le propriétaire du poste où le commentaire a été laissé. Pour cette raison, je dois déterminer, par commentaire, si l'une de ces conditions est présente. Je ne pense pas que je puisse utiliser quelque chose comme le sytème d'autorisation intégré de Django, car il nécessite que les permissions "soient définies globalement par type d'objet, pas par instance d'objet spécifique". Dans mon cas, l'utilisateur "Bob" peut avoir des permissions pour supprimer un commentaire (s'il l'a écrit ou s'il est sur un post qu'il a créé), mais il peut aussi ne pas être autorisé à le supprimer (s'il regarde un commentaire sur le message de quelqu'un d'autre).

MISE À JOUR 2:

Il semble que vous ne pouvez pas passer des objets à une balise de modèle, seules les chaînes: « Bien que vous puissiez passer un certain nombre d'arguments à une balise de modèle à l'aide token.split_contents(), les arguments sont tous décompressés sous forme de littéraux de chaîne. " Je suppose que je vais passer l'ID de l'objet de commentaire en question et le tirer dans l'étiquette.

j'avais tort à ce sujet, ont juste pour accéder au passé dans l'objet comme:

self.comment.resolve(context).user 

contre

self.comment.user 

Répondre

2

OK, voici comment je l'ai fait ...

La balise est utilisée comme celui-ci dans le modèle:

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

Le fichier d'étiquette de modèle est appelé « access_tag .py "et se trouve dans le répertoire" templatetags "de mon application. Ceci est le contenu de "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) 

Terminé. En fin de compte, il aurait été assez facile d'utiliser simplement la balise intégrée {% if%} pour faire cette comparaison, mais comme je vais avoir d'autres autorisations par objet à faire, je vais continuer à construire ces custom "access_tags". De plus, le code du modèle semble tellement plus ordonné :)

+0

solution cool, je l'ai adapté afin que vous puissiez vérifier la permission de l'utilisateur. vous pouvez aussi les imbriquer, ce qui est très practiacal! Merci –

2

Il existe déjà un projet qui vise à faire ce que vous aimerai faire.

django-authority permet un contrôle précis des autorisations dans les modèles. Django 1.2 contient aussi l'utilisateur permissions dans les templates.

+0

Merci Nick, voir ma mise à jour ci-dessus pour savoir pourquoi les permissions intégrées de Django ne fonctionneront probablement pas dans mon cas. À première vue, aller avec une application à plein régime semble être une exagération, mais je vais tout de même y jeter un coup d'œil. Merci pour votre réponse. – mitchf

2

qu'en pensez-vous ...créer une étiquette personnalisée qui writes a variable in the context, puis tester cette variable à l'aide {% if %}

ce serait quelque chose comme ceci:

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

bien sûr le tag « check_access » écrirait le dans le contexte « has_access ».

Bonne chance

+0

Comment cela fonctionnerait-il s'il y a 10 commentaires sur la page dont l'utilisateur connecté a supprimé les droits sur 3. Est-ce que "has_access" ne remplacera pas et ne passera pas à la dernière valeur? – mitchf

+1

bien vous devez juste appeler le {check _access} sur chaque commentaire ... mais vous trouvez déjà votre solution =) F'm toujours surpris de voir comment un simple test comme celui-ci, devient si difficile à faire en django ... c'est pourquoi php ne mourra jamais! – pleasedontbelong

+0

Merci gladontbelong, j'apprécie l'aide. – mitchf

Questions connexes