Utiliser l’application Django Sites est assez sympatique afin de permettre de placer plusieurs sites différents sur le même projet.
Ainsi dans le cas d’un site multilingue avec un domaine par langue, j’ai un seul projet, un site par langue et tout roule comme en 40
Mais c’est à ce moment que vient la problématique de la gestion des droits (oui. Après l’article sur les ACL dans Rails d’hier, je suis beaucoup dans les problèmes d’autorisation en ce moment).
En effet on veut pouvoir autoriser des utilisateurs à modifier des éléments sur une langue. Mais pas forcément sur une autre.
Alors déjà, mise en contexte :
J’ai un modèle « Language », qui contient toutes mes langues, leur nom et un slug qui les définit pour mettre les chaines appropriées.
class Language(models.Model):
slug = models.SlugField(max_length=4)
name = models.CharField(max_length=200)
site = models.ForeignKey(Site)
group = models.ManyToManyField(Group)
def __unicode__(self):
return self.name
def get_absolute_url(self):
return self.site.get_absolute_url()
Vous constaterez que cette langue est reliée à un site. Ainsi chaque langue a un site.
De même chaque langue peut avoir un ou plusieurs groupes.
J’ai créé un middleware afin de définir le site et la langue appropriés en fonction du domaine.
Je ne rentre pas dans les détails de ce middleware ici. Si ça vous intéresse, merci de le signaler dans les commentaires. Je ferai un autre article.
Maintenant que nous avons une langue qui est en relation avec un ou plusieurs groupes, nous pouvons n’autoriser l’accès que aux utilisateurs étant dans le groupe relatif à cette langue.
Pour la gestion de nos accès, nous allons avoir besoin de deux méthodes :
from django.http import HttpResponse
from app.pages.models import Language
def group_required(func):
def _decorator(request, *args, **kwargs):
if not in_group(request):
return HttpResponse("Access denied")
return func(*args, **kwargs)
return _decorator
def in_group(request):
language = Language.objects.get(site__domain__exact=request.get_host())
for group in language.group.all():
if request.user in group.user_set.all():
return True
return False
La méthode in_group retourne vrai si l’utilisateur est dans l’un des groupes autorisés pour la langue.
Elle retournera faux si ce n’est pas le cas.
la méthode group_required est un décorateur, qui retournera la méthode passée en paramètres si l’utilisateur y a accès. Et un access denied dans le cas contraire.
Deux possibilités d’implémentation maintenant.
Dans une vue
Supposons que vous ayez une méthode de vue bateau :
def single(request, slug):
return object_detail(
request,
queryset = Page.objects.filter(published=True).all(),
slug = slug
)
Nous allons utiliser le décorateur afin de vérifier que notre utilisateur a bien accès à cette langue.
def single(request, slug):
return object_detail(
request,
queryset = Page.objects.filter(published=True).all(),
slug = slug
)
single = group_required(single)
Si l’utilisateur a accès au groupe, la méthode single restera inchangée. Dans le cas contraire, elle retournera un « Access Denied ».
Dans l’admin
Dans l’application django admin, on ne peut redéfinir les méthodes de cette façon. On peut faire la chose de manière bien plus class !
Voici mon admin :
class PageAdmin(admin.ModelAdmin):
list_display = ('title',)
search_fields = ['title']
fieldsets = [
(None, {'fields': ['title', 'slug', 'published']}),
]
def has_add_permission(self, request):
if not in_group(request):
return False
return super(PageAdmin, self).has_add_permission(request)
Toute la partie jusqu’aux fieldsets est basique. La ou ça devient intéressant c’est la méthode has_add_permission.
Méthode normalement définie par ModelAdmin, que l’on redéfinit ici afin de vérifier que notre utilisateur a bien accès à la langue
Si l’utilisateur n’a pas accès à la langue, on retourne directement faux. On ne cherche pas à aller plus loin.
Dans le cas contraire … On fait appel à la classe parente. Si l’utilisateur a le droit de modifier cet élément lui même, il peut le faire !
La méthode has_add_permission n’est bien évidemment pas la seule à réecrire. Il nous faut également redéfinir :
has_change_permission et has_delete_permission
A vous ensuite de définir vos règles d’autorisation en fonction des besoins précis de votre application. Plutôt cool non ?









