Lors de l'intégration de Simple UI dans Django, il est fréquent de devoir adapter les menus affichés en fonction des rôles et permissions des utilisateurs. Cela permet de masquer les éléments non autorisés, comme les liens ou boutons, en se basant sur une structure de permissions personnalisée.
Définition des modèles
Pour gérer les utilisateurs et les menus, nous définissons d'abord un modèle d'utilisateur personnalisé et un modèle de menu. Notez que cette approche est spécifique et nécessite des ajustements en cas de modification.
class UtilisateurPersonnalise(AbstractBaseUser, PermissionsMixin):
courriel = models.EmailField(verbose_name='Adresse e-mail', max_length=255, unique=True)
telephone = models.CharField('Numéro de téléphone', max_length=20)
date_creation = models.DateTimeField('Date de création', default=timezone.now)
nom_complet = models.CharField('Nom complet', max_length=20)
est_actif = models.BooleanField(default=True)
est_admin = models.BooleanField('Accès à l\'administration', default=False) # Contrôle l'accès au backend
objects = GestionnaireUtilisateur()
USERNAME_FIELD = 'courriel'
REQUIRED_FIELDS = ['nom_complet', 'telephone']
def __str__(self):
return self.nom_complet
@property
def est_personnel(self):
return self.est_admin
class Meta:
verbose_name = 'Utilisateur'
verbose_name_plural = 'Utilisateurs'
permissions = [
("afficher_utilisateur", "Peut afficher la liste des utilisateurs"),
("bloquer_utilisateur", "Peut désactiver un compte utilisateur"),
]
class ElementNavigation(models.Model):
TYPE_CHOICES = (
('api', 'Point d\'accès'),
('menu', 'Menu')
)
intitule = models.CharField(max_length=30, unique=True, db_index=True, verbose_name="Nom de l'élément")
icone = models.CharField(max_length=50, null=True, blank=True, verbose_name="Icône")
lien = models.CharField(max_length=255, null=True, blank=True, verbose_name="URL")
type_element = models.CharField(max_length=30, null=True, blank=True, db_index=True, choices=TYPE_CHOICES,
verbose_name='Type')
visible = models.BooleanField(default=True, db_index=True, verbose_name="Visible dans le menu")
ordre = models.IntegerField(null=True, blank=True, db_index=True, verbose_name="Ordre de tri")
parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.SET_NULL, verbose_name="Élément parent")
def __str__(self):
return self.intitule
class Meta:
verbose_name = 'Élément de navigation'
verbose_name_plural = 'Éléments de navigation'
ordering = ['id']
Configuration de Simple UI
Simple UI utilise une configuration statique ou dynamique pour les menus. Ici, nous désactivons la génération automatique pour utiliser un menu personnalisé basé sur les permissions.
SIMPLEUI_CONFIG = {
'dynamic': False,
'menus': [],
}
Middleware pour le contrôle dynamique des menus
Un middleware inetrcepte chaque requête pour construire la liste des menus autorisés en fonction des permissions de l'utilisateur connecté. Les chemins d'accès sont générés à partir des permissions, en supposant une convention de nommage cohérente dans les modèles Django.
class MenuPermissionMiddleware(MiddlewareMixin):
"""
Génère dynamiquement les menus visibles selon les permissions utilisateur.
"""
def process_request(self, request):
utilisateur = request.user
permissions = utilisateur.get_all_permissions()
chemins_autorises = set() # Format: /admin/app_label/model_name/
for perm in permissions:
parties = perm.split('.')
if len(parties) >= 2:
app_label = parties[0]
module_name = parties[1].split('_')[-1]
chemin = f'/admin/{app_label}/{module_name}/'
chemins_autorises.add(chemin)
from .models import ElementNavigation # Import local pour éviter les imports circulaires
menus_racines = ElementNavigation.objects.filter(
type_element='menu', visible=True
).order_by('ordre')
menu_complet = []
for racine in menus_racines:
sous_elements = racine.elementnavigation_set.filter(
visible=True
).order_by('ordre')
entree_menu = {
'name': racine.intitule,
'icon': racine.icone,
'models': []
}
for sous_elem in sous_elements:
if sous_elem.lien in chemins_autorises:
entree_menu['models'].append({
'name': sous_elem.intitule,
'icon': sous_elem.icone,
'url': sous_elem.lien
})
if entree_menu['models']:
menu_complet.append(entree_menu)
settings.SIMPLEUI_CONFIG['menus'] = menu_complet
return None
Gestion des menus dans l'administration
Les modèles définis peuvent être enregistrés dans l'interface d'administration Django pour permettre la création et la modification des éléments de navigation via l'admin.