Sith/tutorial/perms/index.html

3561 lines
122 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="fr" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="Le site de l'association des étudiants de l'UTBM">
<link rel="canonical" href="https://ae-utbm.github.io/sith/tutorial/perms/">
<link rel="prev" href="../structure/">
<link rel="next" href="../groups/">
<link rel="icon" href="../../img/favicon.png">
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.5.49">
<title>Gestion des permissions - Site AE UTBM</title>
<link rel="stylesheet" href="../../assets/stylesheets/main.6f8fc17f.min.css">
<link rel="stylesheet" href="../../assets/stylesheets/palette.06af60db.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
<link rel="stylesheet" href="../../assets/_mkdocstrings.css">
<link rel="stylesheet" href="../../stylesheets/extra.css">
<script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
</head>
<body dir="ltr" data-md-color-scheme="default" data-md-color-primary="deeppurple" data-md-color-accent="deeppurple">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#objectifs-du-systeme-de-permissions" class="md-skip">
Aller au contenu
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header md-header--shadow" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="En-tête">
<a href="../.." title="Site AE UTBM" class="md-header__button md-logo" aria-label="Site AE UTBM" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Site AE UTBM
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Gestion des permissions
</span>
</div>
</div>
</div>
<form class="md-header__option" data-md-component="palette">
<input class="md-option" data-md-color-media="(prefers-color-scheme: light)" data-md-color-scheme="default" data-md-color-primary="deeppurple" data-md-color-accent="deeppurple" aria-label="Switch to dark mode" type="radio" name="__palette" id="__palette_0">
<label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_1" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M17 7H7a5 5 0 0 0-5 5 5 5 0 0 0 5 5h10a5 5 0 0 0 5-5 5 5 0 0 0-5-5m0 8a3 3 0 0 1-3-3 3 3 0 0 1 3-3 3 3 0 0 1 3 3 3 3 0 0 1-3 3"/></svg>
</label>
<input class="md-option" data-md-color-media="(prefers-color-scheme: dark)" data-md-color-scheme="slate" data-md-color-primary="blue" data-md-color-accent="blue" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_1">
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_0" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M17 6H7c-3.31 0-6 2.69-6 6s2.69 6 6 6h10c3.31 0 6-2.69 6-6s-2.69-6-6-6m0 10H7c-2.21 0-4-1.79-4-4s1.79-4 4-4h10c2.21 0 4 1.79 4 4s-1.79 4-4 4M7 9c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3"/></svg>
</label>
</form>
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Rechercher" placeholder="Rechercher" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</label>
<nav class="md-search__options" aria-label="Recherche">
<button type="reset" class="md-search__icon md-icon" title="Effacer" aria-label="Effacer" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
</button>
</nav>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initialisation de la recherche
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
<div class="md-header__source">
<a href="https://github.com/ae-utbm/sith" title="Aller au dépôt" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.7.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc.--><path d="M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81"/></svg>
</div>
<div class="md-source__repository">
sith
</div>
</a>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href="../.." title="Site AE UTBM" class="md-nav__button md-logo" aria-label="Site AE UTBM" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
</a>
Site AE UTBM
</label>
<div class="md-nav__source">
<a href="https://github.com/ae-utbm/sith" title="Aller au dépôt" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.7.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc.--><path d="M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81"/></svg>
</div>
<div class="md-source__repository">
sith
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../.." class="md-nav__link">
<span class="md-ellipsis">
Accueil
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2" >
<label class="md-nav__link" for="__nav_2" id="__nav_2_label" tabindex="0">
<span class="md-ellipsis">
Explications
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2">
<span class="md-nav__icon md-icon"></span>
Explications
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../explanation/" class="md-nav__link">
<span class="md-ellipsis">
Accueil
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../explanation/technos/" class="md-nav__link">
<span class="md-ellipsis">
Technologies utilisées
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../explanation/conventions/" class="md-nav__link">
<span class="md-ellipsis">
Conventions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../explanation/archives/" class="md-nav__link">
<span class="md-ellipsis">
Archives
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3" checked>
<label class="md-nav__link" for="__nav_3" id="__nav_3_label" tabindex="0">
<span class="md-ellipsis">
Tutoriels
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_3_label" aria-expanded="true">
<label class="md-nav__title" for="__nav_3">
<span class="md-nav__icon md-icon"></span>
Tutoriels
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../install/" class="md-nav__link">
<span class="md-ellipsis">
Installer le projet
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../install-advanced/" class="md-nav__link">
<span class="md-ellipsis">
Installer le projet (avancé)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../devtools/" class="md-nav__link">
<span class="md-ellipsis">
Configurer son éditeur
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../structure/" class="md-nav__link">
<span class="md-ellipsis">
Structure du projet
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
<span class="md-ellipsis">
Gestion des permissions
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
<span class="md-ellipsis">
Gestion des permissions
</span>
</a>
<nav class="md-nav md-nav--secondary" aria-label="Table des matières">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table des matières
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#objectifs-du-systeme-de-permissions" class="md-nav__link">
<span class="md-ellipsis">
Objectifs du système de permissions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#acces-a-toutes-les-ressources-dune-table" class="md-nav__link">
<span class="md-ellipsis">
Accès à toutes les ressources d'une table
</span>
</a>
<nav class="md-nav" aria-label="Accès à toutes les ressources d'une table">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#permissions-dun-modele" class="md-nav__link">
<span class="md-ellipsis">
Permissions d'un modèle
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#utilisation-des-permissions-dun-modele" class="md-nav__link">
<span class="md-ellipsis">
Utilisation des permissions d'un modèle
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#acces-a-des-elements-en-particulier" class="md-nav__link">
<span class="md-ellipsis">
Accès à des éléments en particulier
</span>
</a>
<nav class="md-nav" aria-label="Accès à des éléments en particulier">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#acces-a-lauteur-de-la-ressource" class="md-nav__link">
<span class="md-ellipsis">
Accès à l'auteur de la ressource
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#acces-en-fonction-de-regles-plus-complexes" class="md-nav__link">
<span class="md-ellipsis">
Accès en fonction de règles plus complexes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#filtrage-des-querysets" class="md-nav__link">
<span class="md-ellipsis">
Filtrage des querysets
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#api" class="md-nav__link">
<span class="md-ellipsis">
API
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../groups/" class="md-nav__link">
<span class="md-ellipsis">
Gestion des groupes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../fragments/" class="md-nav__link">
<span class="md-ellipsis">
Créer des fragments
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../etransaction/" class="md-nav__link">
<span class="md-ellipsis">
Etransactions
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4" >
<label class="md-nav__link" for="__nav_4" id="__nav_4_label" tabindex="0">
<span class="md-ellipsis">
How-to
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4">
<span class="md-nav__icon md-icon"></span>
How-to
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../howto/querysets/" class="md-nav__link">
<span class="md-ellipsis">
L'ORM de Django
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../howto/migrations/" class="md-nav__link">
<span class="md-ellipsis">
Gérer les migrations
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../howto/translation/" class="md-nav__link">
<span class="md-ellipsis">
Gérer les traductions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../howto/statics/" class="md-nav__link">
<span class="md-ellipsis">
Gérer les statics
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../howto/js-import-paths/" class="md-nav__link">
<span class="md-ellipsis">
Ajouter un chemin d'import javascript
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../howto/prod/" class="md-nav__link">
<span class="md-ellipsis">
Configurer pour la production
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../howto/logo/" class="md-nav__link">
<span class="md-ellipsis">
Ajouter un logo de promo
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../howto/subscriptions/" class="md-nav__link">
<span class="md-ellipsis">
Ajouter une cotisation
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../howto/weekmail/" class="md-nav__link">
<span class="md-ellipsis">
Modifier le weekmail
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../howto/terminal/" class="md-nav__link">
<span class="md-ellipsis">
Terminal
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../howto/direnv/" class="md-nav__link">
<span class="md-ellipsis">
Direnv
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5" >
<label class="md-nav__link" for="__nav_5" id="__nav_5_label" tabindex="0">
<span class="md-ellipsis">
Reference
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_5_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5">
<span class="md-nav__icon md-icon"></span>
Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_1" >
<label class="md-nav__link" for="__nav_5_1" id="__nav_5_1_label" tabindex="0">
<span class="md-ellipsis">
accounting
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_1_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_1">
<span class="md-nav__icon md-icon"></span>
accounting
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../reference/accounting/models/" class="md-nav__link">
<span class="md-ellipsis">
Models
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/accounting/views/" class="md-nav__link">
<span class="md-ellipsis">
Views
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_2" >
<label class="md-nav__link" for="__nav_5_2" id="__nav_5_2_label" tabindex="0">
<span class="md-ellipsis">
antispam
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_2">
<span class="md-nav__icon md-icon"></span>
antispam
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../reference/antispam/models/" class="md-nav__link">
<span class="md-ellipsis">
Models
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/antispam/forms/" class="md-nav__link">
<span class="md-ellipsis">
Forms
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_3" >
<label class="md-nav__link" for="__nav_5_3" id="__nav_5_3_label" tabindex="0">
<span class="md-ellipsis">
club
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_3">
<span class="md-nav__icon md-icon"></span>
club
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../reference/club/models/" class="md-nav__link">
<span class="md-ellipsis">
Models
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/club/views/" class="md-nav__link">
<span class="md-ellipsis">
Views
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_4" >
<label class="md-nav__link" for="__nav_5_4" id="__nav_5_4_label" tabindex="0">
<span class="md-ellipsis">
com
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_4">
<span class="md-nav__icon md-icon"></span>
com
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../reference/com/models/" class="md-nav__link">
<span class="md-ellipsis">
Models
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/com/views/" class="md-nav__link">
<span class="md-ellipsis">
Views
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_5" >
<label class="md-nav__link" for="__nav_5_5" id="__nav_5_5_label" tabindex="0">
<span class="md-ellipsis">
core
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_5_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_5">
<span class="md-nav__icon md-icon"></span>
core
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../reference/core/models/" class="md-nav__link">
<span class="md-ellipsis">
Models
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/core/model_fields/" class="md-nav__link">
<span class="md-ellipsis">
Champs de modèle
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/core/views/" class="md-nav__link">
<span class="md-ellipsis">
Views
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/core/schemas/" class="md-nav__link">
<span class="md-ellipsis">
Schemas
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/core/auth/" class="md-nav__link">
<span class="md-ellipsis">
Auth
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_6" >
<label class="md-nav__link" for="__nav_5_6" id="__nav_5_6_label" tabindex="0">
<span class="md-ellipsis">
counter
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_6_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_6">
<span class="md-nav__icon md-icon"></span>
counter
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../reference/counter/models/" class="md-nav__link">
<span class="md-ellipsis">
Models
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/counter/views/" class="md-nav__link">
<span class="md-ellipsis">
Views
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/counter/schemas/" class="md-nav__link">
<span class="md-ellipsis">
Schemas
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_7" >
<label class="md-nav__link" for="__nav_5_7" id="__nav_5_7_label" tabindex="0">
<span class="md-ellipsis">
eboutic
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_7_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_7">
<span class="md-nav__icon md-icon"></span>
eboutic
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../reference/eboutic/models/" class="md-nav__link">
<span class="md-ellipsis">
Models
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/eboutic/views/" class="md-nav__link">
<span class="md-ellipsis">
Views
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_8" >
<label class="md-nav__link" for="__nav_5_8" id="__nav_5_8_label" tabindex="0">
<span class="md-ellipsis">
election
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_8_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_8">
<span class="md-nav__icon md-icon"></span>
election
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../reference/election/models/" class="md-nav__link">
<span class="md-ellipsis">
Models
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/election/views/" class="md-nav__link">
<span class="md-ellipsis">
Views
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_9" >
<label class="md-nav__link" for="__nav_5_9" id="__nav_5_9_label" tabindex="0">
<span class="md-ellipsis">
forum
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_9_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_9">
<span class="md-nav__icon md-icon"></span>
forum
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../reference/forum/models/" class="md-nav__link">
<span class="md-ellipsis">
Models
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/forum/views/" class="md-nav__link">
<span class="md-ellipsis">
Views
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_10" >
<label class="md-nav__link" for="__nav_5_10" id="__nav_5_10_label" tabindex="0">
<span class="md-ellipsis">
galaxy
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_10_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_10">
<span class="md-nav__icon md-icon"></span>
galaxy
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../reference/galaxy/models/" class="md-nav__link">
<span class="md-ellipsis">
Models
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/galaxy/views/" class="md-nav__link">
<span class="md-ellipsis">
Views
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_11" >
<label class="md-nav__link" for="__nav_5_11" id="__nav_5_11_label" tabindex="0">
<span class="md-ellipsis">
launderette
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_11_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_11">
<span class="md-nav__icon md-icon"></span>
launderette
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../reference/launderette/models/" class="md-nav__link">
<span class="md-ellipsis">
Models
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/launderette/views/" class="md-nav__link">
<span class="md-ellipsis">
Views
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_12" >
<label class="md-nav__link" for="__nav_5_12" id="__nav_5_12_label" tabindex="0">
<span class="md-ellipsis">
matmat
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_12_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_12">
<span class="md-nav__icon md-icon"></span>
matmat
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../reference/matmat/models/" class="md-nav__link">
<span class="md-ellipsis">
Models
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/matmat/views/" class="md-nav__link">
<span class="md-ellipsis">
Views
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_13" >
<label class="md-nav__link" for="__nav_5_13" id="__nav_5_13_label" tabindex="0">
<span class="md-ellipsis">
pedagogy
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_13_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_13">
<span class="md-nav__icon md-icon"></span>
pedagogy
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../reference/pedagogy/models/" class="md-nav__link">
<span class="md-ellipsis">
Models
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/pedagogy/views/" class="md-nav__link">
<span class="md-ellipsis">
Views
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/pedagogy/schemas/" class="md-nav__link">
<span class="md-ellipsis">
Schemas
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_14" >
<label class="md-nav__link" for="__nav_5_14" id="__nav_5_14_label" tabindex="0">
<span class="md-ellipsis">
rootplace
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_14_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_14">
<span class="md-nav__icon md-icon"></span>
rootplace
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../reference/rootplace/models/" class="md-nav__link">
<span class="md-ellipsis">
Models
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/rootplace/forms/" class="md-nav__link">
<span class="md-ellipsis">
Forms
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/rootplace/views/" class="md-nav__link">
<span class="md-ellipsis">
Views
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_15" >
<label class="md-nav__link" for="__nav_5_15" id="__nav_5_15_label" tabindex="0">
<span class="md-ellipsis">
sas
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_15_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_15">
<span class="md-nav__icon md-icon"></span>
sas
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../reference/sas/models/" class="md-nav__link">
<span class="md-ellipsis">
Models
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/sas/views/" class="md-nav__link">
<span class="md-ellipsis">
Views
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/sas/schemas/" class="md-nav__link">
<span class="md-ellipsis">
Schemas
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_16" >
<label class="md-nav__link" for="__nav_5_16" id="__nav_5_16_label" tabindex="0">
<span class="md-ellipsis">
staticfiles
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_16_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_16">
<span class="md-nav__icon md-icon"></span>
staticfiles
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../reference/staticfiles/apps/" class="md-nav__link">
<span class="md-ellipsis">
Apps
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/staticfiles/storage/" class="md-nav__link">
<span class="md-ellipsis">
Storage
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/staticfiles/finders/" class="md-nav__link">
<span class="md-ellipsis">
Finders
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/staticfiles/processors/" class="md-nav__link">
<span class="md-ellipsis">
Processors
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_17" >
<label class="md-nav__link" for="__nav_5_17" id="__nav_5_17_label" tabindex="0">
<span class="md-ellipsis">
subscription
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_17_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_17">
<span class="md-nav__icon md-icon"></span>
subscription
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../reference/subscription/models/" class="md-nav__link">
<span class="md-ellipsis">
Models
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/subscription/views/" class="md-nav__link">
<span class="md-ellipsis">
Views
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_18" >
<label class="md-nav__link" for="__nav_5_18" id="__nav_5_18_label" tabindex="0">
<span class="md-ellipsis">
trombi
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_18_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5_18">
<span class="md-nav__icon md-icon"></span>
trombi
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../reference/trombi/models/" class="md-nav__link">
<span class="md-ellipsis">
Models
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../reference/trombi/views/" class="md-nav__link">
<span class="md-ellipsis">
Views
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="Table des matières">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table des matières
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#objectifs-du-systeme-de-permissions" class="md-nav__link">
<span class="md-ellipsis">
Objectifs du système de permissions
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#acces-a-toutes-les-ressources-dune-table" class="md-nav__link">
<span class="md-ellipsis">
Accès à toutes les ressources d'une table
</span>
</a>
<nav class="md-nav" aria-label="Accès à toutes les ressources d'une table">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#permissions-dun-modele" class="md-nav__link">
<span class="md-ellipsis">
Permissions d'un modèle
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#utilisation-des-permissions-dun-modele" class="md-nav__link">
<span class="md-ellipsis">
Utilisation des permissions d'un modèle
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#acces-a-des-elements-en-particulier" class="md-nav__link">
<span class="md-ellipsis">
Accès à des éléments en particulier
</span>
</a>
<nav class="md-nav" aria-label="Accès à des éléments en particulier">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#acces-a-lauteur-de-la-ressource" class="md-nav__link">
<span class="md-ellipsis">
Accès à l'auteur de la ressource
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#acces-en-fonction-de-regles-plus-complexes" class="md-nav__link">
<span class="md-ellipsis">
Accès en fonction de règles plus complexes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#filtrage-des-querysets" class="md-nav__link">
<span class="md-ellipsis">
Filtrage des querysets
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#api" class="md-nav__link">
<span class="md-ellipsis">
API
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<h1>Gestion des permissions</h1>
<h2 id="objectifs-du-systeme-de-permissions">Objectifs du système de permissions<a class="headerlink" href="#objectifs-du-systeme-de-permissions" title="Permanent link">&para;</a></h2>
<p>Les permissions attendues sur le site sont relativement spécifiques.
L'accès à une ressource peut se faire selon un certain nombre
de paramètres différents :</p>
<dl>
<dt><code>L'état de la ressource</code></dt>
<dd>Certaines ressources
sont visibles par tous les cotisants (voire tous les utilisateurs),
à condition qu'elles aient passé une étape de modération.
La visibilité des ressources non-modérées nécessite des permissions
supplémentaires.</dd>
<dt><code>L'appartenance à un groupe</code></dt>
<dd>Les groupes Root, Admin Com, Admin SAS, etc.
sont associés à des jeux de permissions.
Par exemple, les membres du groupe Admin SAS ont tous les droits sur
les ressources liées au SAS : ils peuvent voir,
créer, éditer, supprimer et éventuellement modérer
des images, des albums, des identifications de personnes...
Il en va de même avec les admins Com pour la communication,
les admins pédagogie pour le guide des UEs et ainsi de suite.
Quant aux membres du groupe Root, ils ont tous les droits
sur toutes les ressources du site.</dd>
<dt><code>Le statut de la cotisation</code></dt>
<dd>Les non-cotisants n'ont presque aucun
droit sur les ressources du site (ils peuvent seulement en voir une poignée),
les anciens cotisants peuvent voir un grand nombre de ressources
et les cotisants actuels ont la plupart des droits qui ne sont
pas liés à un club ou à l'administration du site.</dd>
<dt><code>L'appartenance à un club</code></dt>
<dd>Être dans un club donne le droit
de voir la plupart des ressources liées au club dans lequel ils
sont ; être dans le bureau du club donne en outre des droits
d'édition et de création sur ces ressources.</dd>
<dt><code>Être l'auteur ou le possesseur d'une ressource</code></dt>
<dd>Certaines ressources, comme les nouvelles,
enregistrent l'utilisateur qui les a créées ;
ce dernier a les droits de voir, de modifier et éventuellement
de supprimer ses ressources, quand bien même
elles ne seraient pas visibles pour les utilisateurs normaux
(par exemple, parce qu'elles ne sont pas encore modérées.)</dd>
</dl>
<p>Le système de permissions inclus par défaut dans django
permet de modéliser aisément l'accès à des ressources au niveau
de la table.
Ainsi, il n'est pas compliqué de gérer les permissions liées
aux groupes d'administration.</p>
<p>Cependant, une surcouche est nécessaire dès lors que l'on veut
gérer les droits liés à une ligne en particulier
d'une table de la base de données.</p>
<p>Nous essayons le plus possible de nous tenir aux fonctionnalités
de django, sans pour autant hésiter à nous rabattre sur notre
propre surcouche dès lors que les permissions attendues
deviennent trop spécifiques pour être gérées avec juste django.</p>
<div class="admonition info">
<p class="admonition-title">Un peu d'histoire</p>
<p>Les permissions du site n'ont pas toujours été gérées
avec un mélange de fonctionnalités de django et de notre
propre code.
Pendant très longtemps, seule la surcouche était utilisée,
ce qui menait souvent à des vérifications de droits
inefficaces et à une gestion complexe de certaines
parties qui auraient pu être manipulées beaucoup plus simplement.</p>
<p>En plus de ça, les permissions liées à la plupart
des groupes se faisait de manière hardcodée :
plutôt que d'associer un groupe à un jeu de permission
et de faire une jointure en db sur les groupes de l'utilisateur
ayant cette permissions,
on conservait la clef primaire du groupe dans la config
et on vérifiait en dur dans le code que l'utilisateur
était un des groupes voulus.</p>
<p>Ce système possédait le triple désavantage de prendre énormément
de temps, d'être extrêmement limité (de fait, si tout est hardcodé,
on est obligé d'avoir le moins de groupes possibles pour que ça reste
gérable) et d'être désespérément dangereux (par exemple : fin novembre 2024,
une erreur dans le code a donné les accès à la création des cotisations
à tout le monde ; mi-octobre 2019, le calcul des permissions des etickets
pouvait faire tomber le site, cf.
<a href="https://ae.utbm.fr/forum/topic/17943/?page=1msg2277272">ce topic du forum</a>)</p>
</div>
<h2 id="acces-a-toutes-les-ressources-dune-table">Accès à toutes les ressources d'une table<a class="headerlink" href="#acces-a-toutes-les-ressources-dune-table" title="Permanent link">&para;</a></h2>
<p>Gérer ce genre d'accès (par exemple : voir toutes les nouvelles
ou pouvoir supprimer n'importe quelle photo)
est exactement le problème que le système de permissions de django résout.
Nous utilisons donc ce système dans ce genre de situations.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Nous décrivons ci-dessous l'usage que nous faisons du système
de permissions de django,
mais la seule source d'information complète et pleinement fiable
sur le fonctionnement réel de ce système est
<a href="https://docs.djangoproject.com/fr/stable/topics/auth/default/">la documentation de django</a>.</p>
</div>
<h3 id="permissions-dun-modele">Permissions d'un modèle<a class="headerlink" href="#permissions-dun-modele" title="Permanent link">&para;</a></h3>
<p>Par défaut, django crée quatre permissions pour chaque table de la base de données :</p>
<ul>
<li><code>add_&lt;nom de la table&gt;</code> : créer un objet dans cette table</li>
<li><code>view_&lt;nom de la table&gt;</code> : voir le contenu de la table</li>
<li><code>change_&lt;nom de la table&gt;</code> : éditer des objets de la table</li>
<li><code>delete_&lt;nom de la table&gt;</code> : supprimer des objets de la table</li>
</ul>
<p>Ces permissions sont créées au même moment que le modèle.
Si la table existe en base de données, ces permissions existent aussi.</p>
<p>Il est également possible de rajouter nos propres permissions,
directement dans les options Meta du modèle.
Par exemple, prenons le modèle suivant :</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">django.db</span><span class="w"> </span><span class="kn">import</span> <span class="n">models</span>
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a>
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a><span class="k">class</span><span class="w"> </span><span class="nc">News</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
</span><span id="__span-0-4"><a id="__codelineno-0-4" name="__codelineno-0-4" href="#__codelineno-0-4"></a> <span class="c1"># ...</span>
</span><span id="__span-0-5"><a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a>
</span><span id="__span-0-6"><a id="__codelineno-0-6" name="__codelineno-0-6" href="#__codelineno-0-6"></a> <span class="k">class</span><span class="w"> </span><span class="nc">Meta</span><span class="p">:</span>
</span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7" href="#__codelineno-0-7"></a> <span class="n">permissions</span> <span class="o">=</span> <span class="p">[</span>
</span><span id="__span-0-8"><a id="__codelineno-0-8" name="__codelineno-0-8" href="#__codelineno-0-8"></a> <span class="p">(</span><span class="s2">&quot;moderate_news&quot;</span><span class="p">,</span> <span class="s2">&quot;Can moderate news&quot;</span><span class="p">),</span>
</span><span id="__span-0-9"><a id="__codelineno-0-9" name="__codelineno-0-9" href="#__codelineno-0-9"></a> <span class="p">(</span><span class="s2">&quot;view_unmoderated_news&quot;</span><span class="p">,</span> <span class="s2">&quot;Can view non-moderated news&quot;</span><span class="p">),</span>
</span><span id="__span-0-10"><a id="__codelineno-0-10" name="__codelineno-0-10" href="#__codelineno-0-10"></a> <span class="p">]</span>
</span></code></pre></div>
<p>Ce dernier aura les permissions : <code>view_news</code>, <code>add_news</code>, <code>change_news</code>,
<code>delete_news</code>, <code>moderate_news</code> et <code>view_unmoderated_news</code>.</p>
<h3 id="utilisation-des-permissions-dun-modele">Utilisation des permissions d'un modèle<a class="headerlink" href="#utilisation-des-permissions-dun-modele" title="Permanent link">&para;</a></h3>
<p>Pour vérifier qu'un utilisateur a une permission,
on utilise les fonctions suivantes :</p>
<ul>
<li><code>User.has_perm(perm)</code> : retourne <code>True</code> si l'utilisateur
a la permission voulue, sinon <code>False</code></li>
<li><code>User.has_perms([perm_a, perm_b, perm_c])</code> : retourne <code>True</code> si l'utilisateur
a toutes les permissions voulues, sinon <code>False</code>.</li>
</ul>
<p>Ces fonctions attendent un string suivant le format :
<code>&lt;nom de l'application&gt;.&lt;nom de la permission&gt;</code>.
Par exemple, la permission pour vérifier qu'un utilisateur
peut modérer une nouvelle sera : <code>com.moderate_news</code>.</p>
<p>Ces fonctions sont utilisables aussi bien dans les templates Jinja
que dans le code Python :</p>
<div class="tabbed-set tabbed-alternate" data-tabs="1:2"><input checked="checked" id="__tabbed_1_1" name="__tabbed_1" type="radio" /><input id="__tabbed_1_2" name="__tabbed_1" type="radio" /><div class="tabbed-labels"><label for="__tabbed_1_1">Jinja</label><label for="__tabbed_1_2">Python</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
<div class="language-jinja highlight"><pre><span></span><code><span id="__span-1-1"><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a><span class="cp">{%</span> <span class="k">if</span> <span class="nv">user.has_perm</span><span class="o">(</span><span class="s2">&quot;com.moderate_news&quot;</span><span class="o">)</span> <span class="cp">%}</span>
</span><span id="__span-1-2"><a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a><span class="x"> &lt;form method=&quot;post&quot; action=&quot;</span><span class="cp">{{</span> <span class="nv">url</span><span class="o">(</span><span class="s2">&quot;com:news_moderate&quot;</span><span class="o">,</span> <span class="nv">news_id</span><span class="o">=</span><span class="m">387</span><span class="o">)</span> <span class="cp">}}</span><span class="x">&quot;&gt;</span>
</span><span id="__span-1-3"><a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a><span class="x"> &lt;input type=&quot;submit&quot; value=&quot;Modérer&quot; /&gt;</span>
</span><span id="__span-1-4"><a id="__codelineno-1-4" name="__codelineno-1-4" href="#__codelineno-1-4"></a><span class="x"> &lt;/form&gt;</span>
</span><span id="__span-1-5"><a id="__codelineno-1-5" name="__codelineno-1-5" href="#__codelineno-1-5"></a><span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
</span></code></pre></div>
</div>
<div class="tabbed-block">
<div class="language-python highlight"><pre><span></span><code><span id="__span-2-1"><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">com.models</span><span class="w"> </span><span class="kn">import</span> <span class="n">News</span>
</span><span id="__span-2-2"><a id="__codelineno-2-2" name="__codelineno-2-2" href="#__codelineno-2-2"></a><span class="kn">from</span><span class="w"> </span><span class="nn">core.models</span><span class="w"> </span><span class="kn">import</span> <span class="n">User</span>
</span><span id="__span-2-3"><a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a>
</span><span id="__span-2-4"><a id="__codelineno-2-4" name="__codelineno-2-4" href="#__codelineno-2-4"></a>
</span><span id="__span-2-5"><a id="__codelineno-2-5" name="__codelineno-2-5" href="#__codelineno-2-5"></a><span class="n">user</span> <span class="o">=</span> <span class="n">User</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="s2">&quot;bibou&quot;</span><span class="p">)</span>
</span><span id="__span-2-6"><a id="__codelineno-2-6" name="__codelineno-2-6" href="#__codelineno-2-6"></a><span class="n">news</span> <span class="o">=</span> <span class="n">News</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="mi">387</span><span class="p">)</span>
</span><span id="__span-2-7"><a id="__codelineno-2-7" name="__codelineno-2-7" href="#__codelineno-2-7"></a><span class="k">if</span> <span class="n">user</span><span class="o">.</span><span class="n">has_perm</span><span class="p">(</span><span class="s2">&quot;com.moderate_news&quot;</span><span class="p">):</span>
</span><span id="__span-2-8"><a id="__codelineno-2-8" name="__codelineno-2-8" href="#__codelineno-2-8"></a> <span class="n">news</span><span class="o">.</span><span class="n">is_moderated</span> <span class="o">=</span> <span class="kc">True</span>
</span><span id="__span-2-9"><a id="__codelineno-2-9" name="__codelineno-2-9" href="#__codelineno-2-9"></a> <span class="n">news</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
</span><span id="__span-2-10"><a id="__codelineno-2-10" name="__codelineno-2-10" href="#__codelineno-2-10"></a><span class="k">else</span><span class="p">:</span>
</span><span id="__span-2-11"><a id="__codelineno-2-11" name="__codelineno-2-11" href="#__codelineno-2-11"></a> <span class="k">raise</span> <span class="n">PermissionDenied</span>
</span></code></pre></div>
</div>
</div>
</div>
<p>Pour utiliser ce système de permissions dans une class-based view
(c'est-à-dire la plus grande partie de nos vues),
Django met à disposition <code>PermissionRequiredMixin</code>,
qui restreint l'accès à la vue aux utilisateurs ayant
la ou les permissions requises.
Pour les vues sous forme de fonction, il y a le décorateur
<code>permission_required</code>.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="2:2"><input checked="checked" id="__tabbed_2_1" name="__tabbed_2" type="radio" /><input id="__tabbed_2_2" name="__tabbed_2" type="radio" /><div class="tabbed-labels"><label for="__tabbed_2_1">Class-Based View</label><label for="__tabbed_2_2">Function-based view</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
<div class="language-python highlight"><pre><span></span><code><span id="__span-3-1"><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">com.models</span><span class="w"> </span><span class="kn">import</span> <span class="n">News</span>
</span><span id="__span-3-2"><a id="__codelineno-3-2" name="__codelineno-3-2" href="#__codelineno-3-2"></a>
</span><span id="__span-3-3"><a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a><span class="kn">from</span><span class="w"> </span><span class="nn">django.contrib.auth.mixins</span><span class="w"> </span><span class="kn">import</span> <span class="n">PermissionRequiredMixin</span>
</span><span id="__span-3-4"><a id="__codelineno-3-4" name="__codelineno-3-4" href="#__codelineno-3-4"></a><span class="kn">from</span><span class="w"> </span><span class="nn">django.shortcuts</span><span class="w"> </span><span class="kn">import</span> <span class="n">redirect</span>
</span><span id="__span-3-5"><a id="__codelineno-3-5" name="__codelineno-3-5" href="#__codelineno-3-5"></a><span class="kn">from</span><span class="w"> </span><span class="nn">django.urls</span><span class="w"> </span><span class="kn">import</span> <span class="n">reverse</span>
</span><span id="__span-3-6"><a id="__codelineno-3-6" name="__codelineno-3-6" href="#__codelineno-3-6"></a><span class="kn">from</span><span class="w"> </span><span class="nn">django.views</span><span class="w"> </span><span class="kn">import</span> <span class="n">View</span>
</span><span id="__span-3-7"><a id="__codelineno-3-7" name="__codelineno-3-7" href="#__codelineno-3-7"></a><span class="kn">from</span><span class="w"> </span><span class="nn">django.views.generic.detail</span><span class="w"> </span><span class="kn">import</span> <span class="n">SingleObjectMixin</span>
</span><span id="__span-3-8"><a id="__codelineno-3-8" name="__codelineno-3-8" href="#__codelineno-3-8"></a>
</span><span id="__span-3-9"><a id="__codelineno-3-9" name="__codelineno-3-9" href="#__codelineno-3-9"></a><span class="k">class</span><span class="w"> </span><span class="nc">NewsModerateView</span><span class="p">(</span><span class="n">PermissionRequiredMixin</span><span class="p">,</span> <span class="n">SingleObjectMixin</span><span class="p">,</span> <span class="n">View</span><span class="p">):</span>
</span><span id="__span-3-10"><a id="__codelineno-3-10" name="__codelineno-3-10" href="#__codelineno-3-10"></a> <span class="n">model</span> <span class="o">=</span> <span class="n">News</span>
</span><span id="__span-3-11"><a id="__codelineno-3-11" name="__codelineno-3-11" href="#__codelineno-3-11"></a> <span class="n">pk_url_kwarg</span> <span class="o">=</span> <span class="s2">&quot;news_id&quot;</span>
</span><span id="__span-3-12"><a id="__codelineno-3-12" name="__codelineno-3-12" href="#__codelineno-3-12"></a> <span class="n">permission_required</span> <span class="o">=</span> <span class="s2">&quot;com.moderate_news&quot;</span>
</span><span id="__span-3-13"><a id="__codelineno-3-13" name="__codelineno-3-13" href="#__codelineno-3-13"></a> <span class="c1"># On peut aussi fournir plusieurs permissions, par exemple :</span>
</span><span id="__span-3-14"><a id="__codelineno-3-14" name="__codelineno-3-14" href="#__codelineno-3-14"></a> <span class="c1"># permission_required = [&quot;com.moderate_news&quot;, &quot;com.delete_news&quot;]</span>
</span><span id="__span-3-15"><a id="__codelineno-3-15" name="__codelineno-3-15" href="#__codelineno-3-15"></a>
</span><span id="__span-3-16"><a id="__codelineno-3-16" name="__codelineno-3-16" href="#__codelineno-3-16"></a> <span class="k">def</span><span class="w"> </span><span class="nf">post</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
</span><span id="__span-3-17"><a id="__codelineno-3-17" name="__codelineno-3-17" href="#__codelineno-3-17"></a> <span class="c1"># Si nous sommes ici, nous pouvons être certains que l&#39;utilisateur</span>
</span><span id="__span-3-18"><a id="__codelineno-3-18" name="__codelineno-3-18" href="#__codelineno-3-18"></a> <span class="c1"># a la permission requise</span>
</span><span id="__span-3-19"><a id="__codelineno-3-19" name="__codelineno-3-19" href="#__codelineno-3-19"></a> <span class="n">obj</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_object</span><span class="p">()</span>
</span><span id="__span-3-20"><a id="__codelineno-3-20" name="__codelineno-3-20" href="#__codelineno-3-20"></a> <span class="n">obj</span><span class="o">.</span><span class="n">is_moderated</span> <span class="o">=</span> <span class="kc">True</span>
</span><span id="__span-3-21"><a id="__codelineno-3-21" name="__codelineno-3-21" href="#__codelineno-3-21"></a> <span class="n">obj</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
</span><span id="__span-3-22"><a id="__codelineno-3-22" name="__codelineno-3-22" href="#__codelineno-3-22"></a> <span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="n">reverse</span><span class="p">(</span><span class="s2">&quot;com:news_list&quot;</span><span class="p">))</span>
</span></code></pre></div>
</div>
<div class="tabbed-block">
<div class="language-python highlight"><pre><span></span><code><span id="__span-4-1"><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">com.models</span><span class="w"> </span><span class="kn">import</span> <span class="n">News</span>
</span><span id="__span-4-2"><a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a>
</span><span id="__span-4-3"><a id="__codelineno-4-3" name="__codelineno-4-3" href="#__codelineno-4-3"></a><span class="kn">from</span><span class="w"> </span><span class="nn">django.contrib.auth.decorators</span><span class="w"> </span><span class="kn">import</span> <span class="n">permission_required</span>
</span><span id="__span-4-4"><a id="__codelineno-4-4" name="__codelineno-4-4" href="#__codelineno-4-4"></a><span class="kn">from</span><span class="w"> </span><span class="nn">django.shortcuts</span><span class="w"> </span><span class="kn">import</span> <span class="n">get_object_or_404</span><span class="p">,</span> <span class="n">redirect</span>
</span><span id="__span-4-5"><a id="__codelineno-4-5" name="__codelineno-4-5" href="#__codelineno-4-5"></a><span class="kn">from</span><span class="w"> </span><span class="nn">django.urls</span><span class="w"> </span><span class="kn">import</span> <span class="n">reverse</span>
</span><span id="__span-4-6"><a id="__codelineno-4-6" name="__codelineno-4-6" href="#__codelineno-4-6"></a><span class="kn">from</span><span class="w"> </span><span class="nn">django.views.decorators.http</span><span class="w"> </span><span class="kn">import</span> <span class="n">require_POST</span>
</span><span id="__span-4-7"><a id="__codelineno-4-7" name="__codelineno-4-7" href="#__codelineno-4-7"></a>
</span><span id="__span-4-8"><a id="__codelineno-4-8" name="__codelineno-4-8" href="#__codelineno-4-8"></a><span class="nd">@permission_required</span><span class="p">(</span><span class="s2">&quot;com.moderate_news&quot;</span><span class="p">)</span>
</span><span id="__span-4-9"><a id="__codelineno-4-9" name="__codelineno-4-9" href="#__codelineno-4-9"></a><span class="nd">@require_POST</span>
</span><span id="__span-4-10"><a id="__codelineno-4-10" name="__codelineno-4-10" href="#__codelineno-4-10"></a><span class="k">def</span><span class="w"> </span><span class="nf">moderate_news</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">news_id</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
</span><span id="__span-4-11"><a id="__codelineno-4-11" name="__codelineno-4-11" href="#__codelineno-4-11"></a> <span class="c1"># Si nous sommes ici, nous pouvons être certains que l&#39;utilisateur</span>
</span><span id="__span-4-12"><a id="__codelineno-4-12" name="__codelineno-4-12" href="#__codelineno-4-12"></a> <span class="c1"># a la permission requise</span>
</span><span id="__span-4-13"><a id="__codelineno-4-13" name="__codelineno-4-13" href="#__codelineno-4-13"></a> <span class="n">news</span> <span class="o">=</span> <span class="n">get_object_or_404</span><span class="p">(</span><span class="n">News</span><span class="p">,</span> <span class="nb">id</span><span class="o">=</span><span class="n">news_id</span><span class="p">)</span>
</span><span id="__span-4-14"><a id="__codelineno-4-14" name="__codelineno-4-14" href="#__codelineno-4-14"></a> <span class="n">news</span><span class="o">.</span><span class="n">is_moderated</span> <span class="o">=</span> <span class="kc">True</span>
</span><span id="__span-4-15"><a id="__codelineno-4-15" name="__codelineno-4-15" href="#__codelineno-4-15"></a> <span class="n">news</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
</span><span id="__span-4-16"><a id="__codelineno-4-16" name="__codelineno-4-16" href="#__codelineno-4-16"></a> <span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="n">reverse</span><span class="p">(</span><span class="s2">&quot;com:news_list&quot;</span><span class="p">))</span>
</span></code></pre></div>
</div>
</div>
</div>
<h2 id="acces-a-des-elements-en-particulier">Accès à des éléments en particulier<a class="headerlink" href="#acces-a-des-elements-en-particulier" title="Permanent link">&para;</a></h2>
<h3 id="acces-a-lauteur-de-la-ressource">Accès à l'auteur de la ressource<a class="headerlink" href="#acces-a-lauteur-de-la-ressource" title="Permanent link">&para;</a></h3>
<p>Dans ce genre de cas, on peut identifier trois acteurs possibles :</p>
<ul>
<li>les administrateurs peuvent accéder à toutes les ressources,
y compris non-modérées</li>
<li>l'auteur d'une ressource non-modérée peut y accéder</li>
<li>Les autres utilisateurs ne peuvent pas voir les ressources
non-modérées dont ils ne sont pas l'auteur</li>
</ul>
<p>Dans ce genre de cas, on souhaite donc accorder l'accès aux
utilisateurs qui ont la permission globale, selon le système
décrit plus haut, ou bien à l'auteur de la ressource.</p>
<p>Pour cela, nous avons le mixin <code>PermissionOrAuthorRequired</code>.
Ce dernier va effectuer les mêmes vérifications que <code>PermissionRequiredMixin</code>
puis, si l'utilisateur n'a pas la permission requise, vérifier
s'il est l'auteur de la ressource.</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-5-1"><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">com.models</span><span class="w"> </span><span class="kn">import</span> <span class="n">News</span>
</span><span id="__span-5-2"><a id="__codelineno-5-2" name="__codelineno-5-2" href="#__codelineno-5-2"></a><span class="kn">from</span><span class="w"> </span><span class="nn">core.auth.mixins</span><span class="w"> </span><span class="kn">import</span> <span class="n">PermissionOrAuthorRequiredMixin</span>
</span><span id="__span-5-3"><a id="__codelineno-5-3" name="__codelineno-5-3" href="#__codelineno-5-3"></a>
</span><span id="__span-5-4"><a id="__codelineno-5-4" name="__codelineno-5-4" href="#__codelineno-5-4"></a><span class="kn">from</span><span class="w"> </span><span class="nn">django.views.generic</span><span class="w"> </span><span class="kn">import</span> <span class="n">UpdateView</span>
</span><span id="__span-5-5"><a id="__codelineno-5-5" name="__codelineno-5-5" href="#__codelineno-5-5"></a>
</span><span id="__span-5-6"><a id="__codelineno-5-6" name="__codelineno-5-6" href="#__codelineno-5-6"></a><span class="k">class</span><span class="w"> </span><span class="nc">NewsUpdateView</span><span class="p">(</span><span class="n">PermissionOrAuthorRequiredMixin</span><span class="p">,</span> <span class="n">UpdateView</span><span class="p">):</span>
</span><span id="__span-5-7"><a id="__codelineno-5-7" name="__codelineno-5-7" href="#__codelineno-5-7"></a> <span class="n">model</span> <span class="o">=</span> <span class="n">News</span>
</span><span id="__span-5-8"><a id="__codelineno-5-8" name="__codelineno-5-8" href="#__codelineno-5-8"></a> <span class="n">pk_url_kwarg</span> <span class="o">=</span> <span class="s2">&quot;news_id&quot;</span>
</span><span id="__span-5-9"><a id="__codelineno-5-9" name="__codelineno-5-9" href="#__codelineno-5-9"></a> <span class="n">permission_required</span> <span class="o">=</span> <span class="s2">&quot;com.change_news&quot;</span>
</span><span id="__span-5-10"><a id="__codelineno-5-10" name="__codelineno-5-10" href="#__codelineno-5-10"></a> <span class="n">author_field</span> <span class="o">=</span> <span class="s2">&quot;author&quot;</span> <span class="c1"># (1)!</span>
</span></code></pre></div>
<ol>
<li>Nom du champ du modèle utilisé comme clef étrangère vers l'auteur.
Par exemple, ici, la permission sera accordée si
l'utilisateur connecté correspond à l'utilisateur
désigné par <code>News.author</code>.</li>
</ol>
<h3 id="acces-en-fonction-de-regles-plus-complexes">Accès en fonction de règles plus complexes<a class="headerlink" href="#acces-en-fonction-de-regles-plus-complexes" title="Permanent link">&para;</a></h3>
<p>Tout ce que nous avons décrit précédemment permet de couvrir
la plupart des cas simples.
Cependant, il arrivera souvent que les permissions attendues soient
plus complexes.
Dans ce genre de cas, on rentre entièrement dans notre surcouche.</p>
<h4 id="implementation-dans-les-modeles">Implémentation dans les modèles<a class="headerlink" href="#implementation-dans-les-modeles" title="Permanent link">&para;</a></h4>
<p>La gestion de ce type de permissions se fait directement par modèle.
Il en existe trois niveaux :</p>
<ul>
<li>Éditer des propriétés de l'objet</li>
<li>Éditer certaines valeurs l'objet</li>
<li>Voir l'objet</li>
</ul>
<p>Chacune de ces permissions est vérifiée par une méthode
dédiée de la classe <a class="autorefs autorefs-internal" href="../../reference/core/models/#core.models.User">User</a> :</p>
<ul>
<li>Editer les propriéts : <a class="autorefs autorefs-internal" href="../../reference/core/models/#core.models.User.is_owner">User.is_owner(obj)</a></li>
<li>Editer les valeurs : <a class="autorefs autorefs-internal" href="../../reference/core/models/#core.models.User.can_edit">User.can_edit(obj)</a></li>
<li>Voir : <a class="autorefs autorefs-internal" href="../../reference/core/models/#core.models.User.can_view">User.can_view(obj)</a></li>
</ul>
<p>Ces méthodes vont alors résoudre les permissions
dans cet ordre :</p>
<ol>
<li>Si l'objet possède une méthode <code>can_be_viewed_by(user)</code>
(ou <code>can_be_edited_by(user)</code>, ou <code>is_owned_by(user)</code>)
et que son appel renvoie <code>True</code>, l'utilisateur a la permission requise.</li>
<li>Sinon, si le modèle de l'objet possède un attribut <code>view_groups</code>
(ou <code>edit_groups</code>, ou <code>owner_group</code>) et que l'utilisateur
est dans l'un des groupes indiqués, il a la permission requise.</li>
<li>Sinon, on regarde si l'utilisateur a la permission de niveau supérieur
(les droits <code>owner</code> impliquent les droits d'édition, et les droits
d'édition impliquent les droits de vue).</li>
<li>Si aucune des étapes si dessus ne permet d'établir que l'utilisateur
n'a la permission requise, c'est qu'il ne l'a pas.</li>
</ol>
<p>Voici un exemple d'implémentation de ce système :</p>
<div class="tabbed-set tabbed-alternate" data-tabs="3:2"><input checked="checked" id="__tabbed_3_1" name="__tabbed_3" type="radio" /><input id="__tabbed_3_2" name="__tabbed_3" type="radio" /><div class="tabbed-labels"><label for="__tabbed_3_1">Avec les méthodes</label><label for="__tabbed_3_2">Avec les groupes de permission</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
<div class="language-python highlight"><pre><span></span><code><span id="__span-6-1"><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">django.db</span><span class="w"> </span><span class="kn">import</span> <span class="n">models</span>
</span><span id="__span-6-2"><a id="__codelineno-6-2" name="__codelineno-6-2" href="#__codelineno-6-2"></a><span class="kn">from</span><span class="w"> </span><span class="nn">django.utils.translation</span><span class="w"> </span><span class="kn">import</span> <span class="n">gettext_lazy</span> <span class="k">as</span> <span class="n">_</span>
</span><span id="__span-6-3"><a id="__codelineno-6-3" name="__codelineno-6-3" href="#__codelineno-6-3"></a>
</span><span id="__span-6-4"><a id="__codelineno-6-4" name="__codelineno-6-4" href="#__codelineno-6-4"></a><span class="kn">from</span><span class="w"> </span><span class="nn">core.models</span><span class="w"> </span><span class="kn">import</span> <span class="n">User</span><span class="p">,</span> <span class="n">Group</span>
</span><span id="__span-6-5"><a id="__codelineno-6-5" name="__codelineno-6-5" href="#__codelineno-6-5"></a>
</span><span id="__span-6-6"><a id="__codelineno-6-6" name="__codelineno-6-6" href="#__codelineno-6-6"></a><span class="k">class</span><span class="w"> </span><span class="nc">Article</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
</span><span id="__span-6-7"><a id="__codelineno-6-7" name="__codelineno-6-7" href="#__codelineno-6-7"></a>
</span><span id="__span-6-8"><a id="__codelineno-6-8" name="__codelineno-6-8" href="#__codelineno-6-8"></a> <span class="n">title</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">_</span><span class="p">(</span><span class="s2">&quot;title&quot;</span><span class="p">),</span> <span class="n">max_length</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span>
</span><span id="__span-6-9"><a id="__codelineno-6-9" name="__codelineno-6-9" href="#__codelineno-6-9"></a> <span class="n">content</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">TextField</span><span class="p">(</span><span class="n">_</span><span class="p">(</span><span class="s2">&quot;content&quot;</span><span class="p">))</span>
</span><span id="__span-6-10"><a id="__codelineno-6-10" name="__codelineno-6-10" href="#__codelineno-6-10"></a>
</span><span id="__span-6-11"><a id="__codelineno-6-11" name="__codelineno-6-11" href="#__codelineno-6-11"></a> <span class="k">def</span><span class="w"> </span><span class="nf">is_owned_by</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">user</span><span class="p">):</span> <span class="c1"># (1)!</span>
</span><span id="__span-6-12"><a id="__codelineno-6-12" name="__codelineno-6-12" href="#__codelineno-6-12"></a> <span class="k">return</span> <span class="n">user</span><span class="o">.</span><span class="n">is_board_member</span>
</span><span id="__span-6-13"><a id="__codelineno-6-13" name="__codelineno-6-13" href="#__codelineno-6-13"></a>
</span><span id="__span-6-14"><a id="__codelineno-6-14" name="__codelineno-6-14" href="#__codelineno-6-14"></a> <span class="k">def</span><span class="w"> </span><span class="nf">can_be_edited_by</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">user</span><span class="p">):</span> <span class="c1"># (2)!</span>
</span><span id="__span-6-15"><a id="__codelineno-6-15" name="__codelineno-6-15" href="#__codelineno-6-15"></a> <span class="k">return</span> <span class="n">user</span><span class="o">.</span><span class="n">is_subscribed</span>
</span><span id="__span-6-16"><a id="__codelineno-6-16" name="__codelineno-6-16" href="#__codelineno-6-16"></a>
</span><span id="__span-6-17"><a id="__codelineno-6-17" name="__codelineno-6-17" href="#__codelineno-6-17"></a> <span class="k">def</span><span class="w"> </span><span class="nf">can_be_viewed_by</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">user</span><span class="p">):</span> <span class="c1"># (3)!</span>
</span><span id="__span-6-18"><a id="__codelineno-6-18" name="__codelineno-6-18" href="#__codelineno-6-18"></a> <span class="k">return</span> <span class="ow">not</span> <span class="n">user</span><span class="o">.</span><span class="n">is_anonymous</span>
</span></code></pre></div>
<ol>
<li>Donne ou non les droits d'édition des propriétés de l'objet.
Ici, un utilisateur dans le bureau AE aura tous les droits sur cet objet</li>
<li>Donne ou non les droits d'édition de l'objet
Ici, l'objet ne sera modifiable que par un utilisateur cotisant</li>
<li>Donne ou non les droits de vue de l'objet
Ici, l'objet n'est visible que par un utilisateur connecté</li>
</ol>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Dans cet exemple, nous utilisons des permissions très simples
pour que vous puissiez constater le squelette de ce système,
plutôt que la logique de validation dans ce cas particulier.</p>
<p>En réalité, il serait ici beaucoup plus approprié de
donner les permissions <code>com.delete_article</code> et
<code>com.change_article_properties</code> (en créant ce dernier
s'il n'existe pas encore) au groupe du bureau AE,
de donner également la permission <code>com.change_article</code>
au groupe <code>Cotisants</code> et enfin de restreindre l'accès
aux vues d'accès aux articles avec <code>LoginRequiredMixin</code>.</p>
</div>
</div>
<div class="tabbed-block">
<div class="language-python highlight"><pre><span></span><code><span id="__span-7-1"><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">django.db</span><span class="w"> </span><span class="kn">import</span> <span class="n">models</span>
</span><span id="__span-7-2"><a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a><span class="kn">from</span><span class="w"> </span><span class="nn">django.conf</span><span class="w"> </span><span class="kn">import</span> <span class="n">settings</span>
</span><span id="__span-7-3"><a id="__codelineno-7-3" name="__codelineno-7-3" href="#__codelineno-7-3"></a><span class="kn">from</span><span class="w"> </span><span class="nn">django.utils.translation</span><span class="w"> </span><span class="kn">import</span> <span class="n">gettext_lazy</span> <span class="k">as</span> <span class="n">_</span>
</span><span id="__span-7-4"><a id="__codelineno-7-4" name="__codelineno-7-4" href="#__codelineno-7-4"></a>
</span><span id="__span-7-5"><a id="__codelineno-7-5" name="__codelineno-7-5" href="#__codelineno-7-5"></a><span class="kn">from</span><span class="w"> </span><span class="nn">core.models</span><span class="w"> </span><span class="kn">import</span> <span class="n">User</span><span class="p">,</span> <span class="n">Group</span>
</span><span id="__span-7-6"><a id="__codelineno-7-6" name="__codelineno-7-6" href="#__codelineno-7-6"></a>
</span><span id="__span-7-7"><a id="__codelineno-7-7" name="__codelineno-7-7" href="#__codelineno-7-7"></a><span class="k">class</span><span class="w"> </span><span class="nc">Article</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
</span><span id="__span-7-8"><a id="__codelineno-7-8" name="__codelineno-7-8" href="#__codelineno-7-8"></a> <span class="n">title</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">_</span><span class="p">(</span><span class="s2">&quot;title&quot;</span><span class="p">),</span> <span class="n">max_length</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span>
</span><span id="__span-7-9"><a id="__codelineno-7-9" name="__codelineno-7-9" href="#__codelineno-7-9"></a> <span class="n">content</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">TextField</span><span class="p">(</span><span class="n">_</span><span class="p">(</span><span class="s2">&quot;content&quot;</span><span class="p">))</span>
</span><span id="__span-7-10"><a id="__codelineno-7-10" name="__codelineno-7-10" href="#__codelineno-7-10"></a>
</span><span id="__span-7-11"><a id="__codelineno-7-11" name="__codelineno-7-11" href="#__codelineno-7-11"></a> <span class="c1"># relation one-to-many</span>
</span><span id="__span-7-12"><a id="__codelineno-7-12" name="__codelineno-7-12" href="#__codelineno-7-12"></a> <span class="n">owner_group</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span> <span class="c1"># (1)!</span>
</span><span id="__span-7-13"><a id="__codelineno-7-13" name="__codelineno-7-13" href="#__codelineno-7-13"></a> <span class="n">Group</span><span class="p">,</span> <span class="n">related_name</span><span class="o">=</span><span class="s2">&quot;owned_articles&quot;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">settings</span><span class="o">.</span><span class="n">SITH_GROUP_ROOT_ID</span>
</span><span id="__span-7-14"><a id="__codelineno-7-14" name="__codelineno-7-14" href="#__codelineno-7-14"></a> <span class="p">)</span>
</span><span id="__span-7-15"><a id="__codelineno-7-15" name="__codelineno-7-15" href="#__codelineno-7-15"></a>
</span><span id="__span-7-16"><a id="__codelineno-7-16" name="__codelineno-7-16" href="#__codelineno-7-16"></a> <span class="c1"># relation many-to-many</span>
</span><span id="__span-7-17"><a id="__codelineno-7-17" name="__codelineno-7-17" href="#__codelineno-7-17"></a> <span class="n">edit_groups</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ManyToManyField</span><span class="p">(</span> <span class="c1"># (2)!</span>
</span><span id="__span-7-18"><a id="__codelineno-7-18" name="__codelineno-7-18" href="#__codelineno-7-18"></a> <span class="n">Group</span><span class="p">,</span>
</span><span id="__span-7-19"><a id="__codelineno-7-19" name="__codelineno-7-19" href="#__codelineno-7-19"></a> <span class="n">related_name</span><span class="o">=</span><span class="s2">&quot;editable_articles&quot;</span><span class="p">,</span>
</span><span id="__span-7-20"><a id="__codelineno-7-20" name="__codelineno-7-20" href="#__codelineno-7-20"></a> <span class="n">verbose_name</span><span class="o">=</span><span class="n">_</span><span class="p">(</span><span class="s2">&quot;edit groups&quot;</span><span class="p">),</span>
</span><span id="__span-7-21"><a id="__codelineno-7-21" name="__codelineno-7-21" href="#__codelineno-7-21"></a> <span class="n">blank</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
</span><span id="__span-7-22"><a id="__codelineno-7-22" name="__codelineno-7-22" href="#__codelineno-7-22"></a> <span class="p">)</span>
</span><span id="__span-7-23"><a id="__codelineno-7-23" name="__codelineno-7-23" href="#__codelineno-7-23"></a>
</span><span id="__span-7-24"><a id="__codelineno-7-24" name="__codelineno-7-24" href="#__codelineno-7-24"></a> <span class="c1"># relation many-to-many</span>
</span><span id="__span-7-25"><a id="__codelineno-7-25" name="__codelineno-7-25" href="#__codelineno-7-25"></a> <span class="n">view_groups</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ManyToManyField</span><span class="p">(</span> <span class="c1"># (3)!</span>
</span><span id="__span-7-26"><a id="__codelineno-7-26" name="__codelineno-7-26" href="#__codelineno-7-26"></a> <span class="n">Group</span><span class="p">,</span>
</span><span id="__span-7-27"><a id="__codelineno-7-27" name="__codelineno-7-27" href="#__codelineno-7-27"></a> <span class="n">related_name</span><span class="o">=</span><span class="s2">&quot;viewable_articles&quot;</span><span class="p">,</span>
</span><span id="__span-7-28"><a id="__codelineno-7-28" name="__codelineno-7-28" href="#__codelineno-7-28"></a> <span class="n">verbose_name</span><span class="o">=</span><span class="n">_</span><span class="p">(</span><span class="s2">&quot;view groups&quot;</span><span class="p">),</span>
</span><span id="__span-7-29"><a id="__codelineno-7-29" name="__codelineno-7-29" href="#__codelineno-7-29"></a> <span class="n">blank</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
</span><span id="__span-7-30"><a id="__codelineno-7-30" name="__codelineno-7-30" href="#__codelineno-7-30"></a> <span class="p">)</span>
</span></code></pre></div>
<ol>
<li>Groupe possédant l'objet
Donne les droits d'édition des propriétés de l'objet.
Il ne peut y avoir qu'un seul groupe <code>owner</code> par objet.</li>
<li>Tous les groupes ayant droit d'édition sur l'objet.
Il peut y avoir autant de groupes d'édition que l'on veut par objet.</li>
<li>Tous les groupes ayant droit de voir l'objet.
Il peut y avoir autant de groupes de vue que l'on veut par objet.</li>
</ol>
</div>
</div>
</div>
<h4 id="application-dans-les-templates">Application dans les templates<a class="headerlink" href="#application-dans-les-templates" title="Permanent link">&para;</a></h4>
<p>Il existe trois fonctions de base sur lesquelles
reposent les vérifications de permission.
Elles sont disponibles dans le contexte par défaut du
moteur de template et peuvent être utilisées à tout moment.</p>
<ul>
<li><a class="autorefs autorefs-internal" href="../../reference/core/auth/#core.auth.mixins.can_edit_prop">can_edit_prop(obj, user)</a> : équivalent de <code>obj.is_owned_by(user)</code></li>
<li><a class="autorefs autorefs-internal" href="../../reference/core/auth/#core.auth.mixins.can_edit">can_edit(obj, user)</a> : équivalent de <code>obj.can_be_edited_by(user)</code></li>
<li><a class="autorefs autorefs-internal" href="../../reference/core/auth/#core.auth.mixins.can_view">can_view(obj, user)</a> : équivalent de <code>obj.can_be_viewed_by(user)</code></li>
</ul>
<p>Voici un exemple d'utilisation dans un template :</p>
<div class="language-jinja highlight"><pre><span></span><code><span id="__span-8-1"><a id="__codelineno-8-1" name="__codelineno-8-1" href="#__codelineno-8-1"></a><span class="c">{# ... #}</span>
</span><span id="__span-8-2"><a id="__codelineno-8-2" name="__codelineno-8-2" href="#__codelineno-8-2"></a><span class="cp">{%</span> <span class="k">if</span> <span class="nv">can_edit</span><span class="o">(</span><span class="nv">club</span><span class="o">,</span> <span class="nv">user</span><span class="o">)</span> <span class="cp">%}</span>
</span><span id="__span-8-3"><a id="__codelineno-8-3" name="__codelineno-8-3" href="#__codelineno-8-3"></a><span class="x"> &lt;a href=&quot;</span><span class="cp">{{</span> <span class="nv">url</span><span class="o">(</span><span class="s1">&#39;club:tools&#39;</span><span class="o">,</span> <span class="nv">club_id</span><span class="o">=</span><span class="nv">club.id</span><span class="o">)</span> <span class="cp">}}</span><span class="x">&quot;&gt;</span><span class="cp">{{</span> <span class="nv">club</span> <span class="cp">}}</span><span class="x">&lt;/a&gt;</span>
</span><span id="__span-8-4"><a id="__codelineno-8-4" name="__codelineno-8-4" href="#__codelineno-8-4"></a><span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
</span></code></pre></div>
<h4 id="application-dans-les-vues">Application dans les vues<a class="headerlink" href="#application-dans-les-vues" title="Permanent link">&para;</a></h4>
<p>Généralement, les vérifications de droits dans les templates
se limitent aux urls à afficher puisqu'il
ne faut normalement pas mettre de logique autre que d'affichage à l'intérieur
(en réalité, c'est un principe qu'on a beaucoup violé, mais promis on le fera plus).
C'est donc habituellement au niveau des vues que cela a lieu.</p>
<p>Pour cela, nous avons rajouté des mixins
à hériter lors de la création d'une vue basée sur une classe.
Ces mixins ne sont compatibles qu'avec les classes récupérant
un objet ou une liste d'objet.
Dans le cas d'un seul objet,
une permission refusée est levée lorsque l'utilisateur
n'a pas le droit de visionner la page.
Dans le cas d'une liste d'objet,
le mixin filtre les objets non autorisés et si aucun ne l'est,
l'utilisateur recevra une liste vide d'objet.</p>
<p>Voici un exemple d'utilisation en reprenant l'objet Article crée précédemment :</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-9-1"><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">django.views.generic</span><span class="w"> </span><span class="kn">import</span> <span class="n">CreateView</span><span class="p">,</span> <span class="n">DetailView</span>
</span><span id="__span-9-2"><a id="__codelineno-9-2" name="__codelineno-9-2" href="#__codelineno-9-2"></a>
</span><span id="__span-9-3"><a id="__codelineno-9-3" name="__codelineno-9-3" href="#__codelineno-9-3"></a><span class="kn">from</span><span class="w"> </span><span class="nn">core.auth.mixins</span><span class="w"> </span><span class="kn">import</span> <span class="n">CanViewMixin</span><span class="p">,</span> <span class="n">CanCreateMixin</span>
</span><span id="__span-9-4"><a id="__codelineno-9-4" name="__codelineno-9-4" href="#__codelineno-9-4"></a>
</span><span id="__span-9-5"><a id="__codelineno-9-5" name="__codelineno-9-5" href="#__codelineno-9-5"></a><span class="kn">from</span><span class="w"> </span><span class="nn">com.models</span><span class="w"> </span><span class="kn">import</span> <span class="n">WeekmailArticle</span>
</span><span id="__span-9-6"><a id="__codelineno-9-6" name="__codelineno-9-6" href="#__codelineno-9-6"></a>
</span><span id="__span-9-7"><a id="__codelineno-9-7" name="__codelineno-9-7" href="#__codelineno-9-7"></a>
</span><span id="__span-9-8"><a id="__codelineno-9-8" name="__codelineno-9-8" href="#__codelineno-9-8"></a><span class="c1"># Il est important de mettre le mixin avant la classe héritée de Django</span>
</span><span id="__span-9-9"><a id="__codelineno-9-9" name="__codelineno-9-9" href="#__codelineno-9-9"></a><span class="c1"># L&#39;héritage multiple se fait de droite à gauche et les mixins ont besoin</span>
</span><span id="__span-9-10"><a id="__codelineno-9-10" name="__codelineno-9-10" href="#__codelineno-9-10"></a><span class="c1"># d&#39;une classe de base pour fonctionner correctement.</span>
</span><span id="__span-9-11"><a id="__codelineno-9-11" name="__codelineno-9-11" href="#__codelineno-9-11"></a><span class="k">class</span><span class="w"> </span><span class="nc">ArticlesDetailView</span><span class="p">(</span><span class="n">CanViewMixin</span><span class="p">,</span> <span class="n">DetailView</span><span class="p">):</span>
</span><span id="__span-9-12"><a id="__codelineno-9-12" name="__codelineno-9-12" href="#__codelineno-9-12"></a> <span class="n">model</span> <span class="o">=</span> <span class="n">WeekmailArticle</span>
</span><span id="__span-9-13"><a id="__codelineno-9-13" name="__codelineno-9-13" href="#__codelineno-9-13"></a>
</span><span id="__span-9-14"><a id="__codelineno-9-14" name="__codelineno-9-14" href="#__codelineno-9-14"></a>
</span><span id="__span-9-15"><a id="__codelineno-9-15" name="__codelineno-9-15" href="#__codelineno-9-15"></a><span class="c1"># Même chose pour une vue de création de l&#39;objet Article</span>
</span><span id="__span-9-16"><a id="__codelineno-9-16" name="__codelineno-9-16" href="#__codelineno-9-16"></a><span class="k">class</span><span class="w"> </span><span class="nc">ArticlesCreateView</span><span class="p">(</span><span class="n">CanCreateMixin</span><span class="p">,</span> <span class="n">CreateView</span><span class="p">):</span>
</span><span id="__span-9-17"><a id="__codelineno-9-17" name="__codelineno-9-17" href="#__codelineno-9-17"></a> <span class="n">model</span> <span class="o">=</span> <span class="n">WeekmailArticle</span>
</span></code></pre></div>
<p>Les mixins suivants sont implémentés :</p>
<ul>
<li><a class="autorefs autorefs-internal" href="../../reference/core/auth/#core.auth.mixins.CanCreateMixin">CanCreateMixin</a> : l'utilisateur peut-il créer l'objet ?
Ce mixin existe, mais est déprécié et ne doit plus être utilisé !</li>
<li><a class="autorefs autorefs-internal" href="../../reference/core/views/#core.views.CanEditPropMixin">CanEditPropMixin</a> : l'utilisateur peut-il éditer les propriétés de l'objet ?</li>
<li><a class="autorefs autorefs-internal" href="../../reference/core/auth/#core.auth.mixins.CanEditMixin">CanEditMixin</a> : L'utilisateur peut-il éditer l'objet ?</li>
<li><a class="autorefs autorefs-internal" href="../../reference/core/auth/#core.auth.mixins.CanViewMixin">CanViewMixin</a> : L'utilisateur peut-il voir l'objet ?</li>
<li><a class="autorefs autorefs-internal" href="../../reference/core/auth/#core.auth.mixins.FormerSubscriberMixin">FormerSubscriberMixin</a> : L'utilisateur a-t-il déjà été cotisant ?</li>
</ul>
<div class="admonition danger">
<p class="admonition-title">CanCreateMixin</p>
<p>L'usage de <code>CanCreateMixin</code> est dangereux et ne doit en aucun cas être
étendu.
La façon dont ce mixin marche est qu'il valide le formulaire
de création et crée l'objet sans le persister en base de données, puis
vérifie les droits sur cet objet non-persisté.
Le danger de ce système vient de multiples raisons :</p>
<ul>
<li>Les vérifications se faisant sur un objet non persisté,
l'utilisation de mécanismes nécessitant une persistance préalable
peut mener à des comportements indésirés, voire à des erreurs.</li>
<li>Les développeurs de django ayant tendance à restreindre progressivement
les actions qui peuvent être faites sur des objets non-persistés,
les mises-à-jour de django deviennent plus compliquées.</li>
<li>La vérification des droits ne se fait que dans les requêtes POST,
à la toute fin de la requête.
Tout ce qui arrive avant n'est absolument pas protégé.
Toute opération (même les suppressions et les créations) qui ont
lieu avant la persistance de l'objet seront appliquées,
même sans permission.</li>
<li>Si un développeur du site fait l'erreur de surcharger
la méthode <code>form_valid</code> (ce qui est plutôt courant,
lorsqu'on veut accomplir certaines actions
quand un formulaire est valide), on peut se retrouver
dans une situation où l'objet est persisté sans aucune protection.</li>
</ul>
</div>
<div class="admonition danger">
<p class="admonition-title">Performance</p>
<p>Ce système maison de permissions fonctionne et répond aux attentes de l'époque de sa conception.<br />
Mais d'un point de vue performance, il est souvent plus que problématique.
En effet, toutes les permissions sont dynamiquement calculées et
nécessitent plusieurs appels en base de données qui ne se résument pas à
une « simple » jointure mais à plusieurs requêtes différentes et
difficiles à optimiser. De plus, à chaque calcul de permission, il est
nécessaire de recommencer tous les calculs depuis le début.<br />
La solution à ça est de mettre du cache de session sur les tests effectués
récemment, mais cela engendre son autre lot de problèmes.</p>
<p>Sur une vue où on manipule un seul objet, passe encore.
Mais sur les <code>ListView</code>, on peut arriver à des temps
de réponse extrêmement élevés.</p>
</div>
<h3 id="filtrage-des-querysets">Filtrage des querysets<a class="headerlink" href="#filtrage-des-querysets" title="Permanent link">&para;</a></h3>
<p>Récupérer tous les objets d'un queryset et vérifier pour chacun que
l'utilisateur a le droit de les voir peut-être excessivement
coûteux en ressources
(cf. l'encart ci-dessus).</p>
<p>Lorsqu'il est nécessaire de récupérer un certain nombre
d'objets depuis la base de données, il est donc préférable
de filtrer directement depuis le queryset.</p>
<p>Pour cela, certains modèles, tels que <a class="autorefs autorefs-internal" href="../../reference/sas/models/#sas.models.Picture">Picture</a>
peuvent être filtrés avec la méthode de queryset <code>viewable_by</code>.
Cette dernière s'utilise comme n'importe quelle autre méthode
de queryset :</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-10-1"><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">sas.models</span><span class="w"> </span><span class="kn">import</span> <span class="n">Picture</span>
</span><span id="__span-10-2"><a id="__codelineno-10-2" name="__codelineno-10-2" href="#__codelineno-10-2"></a><span class="kn">from</span><span class="w"> </span><span class="nn">core.models</span><span class="w"> </span><span class="kn">import</span> <span class="n">User</span>
</span><span id="__span-10-3"><a id="__codelineno-10-3" name="__codelineno-10-3" href="#__codelineno-10-3"></a>
</span><span id="__span-10-4"><a id="__codelineno-10-4" name="__codelineno-10-4" href="#__codelineno-10-4"></a><span class="n">user</span> <span class="o">=</span> <span class="n">User</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">username</span><span class="o">=</span><span class="s2">&quot;bibou&quot;</span><span class="p">)</span>
</span><span id="__span-10-5"><a id="__codelineno-10-5" name="__codelineno-10-5" href="#__codelineno-10-5"></a><span class="n">pictures</span> <span class="o">=</span> <span class="n">Picture</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">viewable_by</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
</span></code></pre></div>
<p>Le résultat de la requête contiendra uniquement des éléments
que l'utilisateur sélectionné a effectivement le droit de voir.</p>
<p>Si vous désirez utiliser cette méthode sur un modèle
qui ne la possède pas, il est relativement facile de l'écrire :</p>
<div class="language-python highlight"><pre><span></span><code><span id="__span-11-1"><a id="__codelineno-11-1" name="__codelineno-11-1" href="#__codelineno-11-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Self</span>
</span><span id="__span-11-2"><a id="__codelineno-11-2" name="__codelineno-11-2" href="#__codelineno-11-2"></a>
</span><span id="__span-11-3"><a id="__codelineno-11-3" name="__codelineno-11-3" href="#__codelineno-11-3"></a><span class="kn">from</span><span class="w"> </span><span class="nn">django.db</span><span class="w"> </span><span class="kn">import</span> <span class="n">models</span>
</span><span id="__span-11-4"><a id="__codelineno-11-4" name="__codelineno-11-4" href="#__codelineno-11-4"></a>
</span><span id="__span-11-5"><a id="__codelineno-11-5" name="__codelineno-11-5" href="#__codelineno-11-5"></a><span class="kn">from</span><span class="w"> </span><span class="nn">core.models</span><span class="w"> </span><span class="kn">import</span> <span class="n">User</span>
</span><span id="__span-11-6"><a id="__codelineno-11-6" name="__codelineno-11-6" href="#__codelineno-11-6"></a>
</span><span id="__span-11-7"><a id="__codelineno-11-7" name="__codelineno-11-7" href="#__codelineno-11-7"></a>
</span><span id="__span-11-8"><a id="__codelineno-11-8" name="__codelineno-11-8" href="#__codelineno-11-8"></a><span class="k">class</span><span class="w"> </span><span class="nc">NewsQuerySet</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">QuerySet</span><span class="p">):</span> <span class="c1"># (1)!</span>
</span><span id="__span-11-9"><a id="__codelineno-11-9" name="__codelineno-11-9" href="#__codelineno-11-9"></a> <span class="k">def</span><span class="w"> </span><span class="nf">viewable_by</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">user</span><span class="p">:</span> <span class="n">User</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Self</span><span class="p">:</span>
</span><span id="__span-11-10"><a id="__codelineno-11-10" name="__codelineno-11-10" href="#__codelineno-11-10"></a> <span class="k">if</span> <span class="n">user</span><span class="o">.</span><span class="n">has_perm</span><span class="p">(</span><span class="s2">&quot;com.view_unmoderated_news&quot;</span><span class="p">):</span>
</span><span id="__span-11-11"><a id="__codelineno-11-11" name="__codelineno-11-11" href="#__codelineno-11-11"></a> <span class="c1"># si l&#39;utilisateur peut tout voir, on retourne tout</span>
</span><span id="__span-11-12"><a id="__codelineno-11-12" name="__codelineno-11-12" href="#__codelineno-11-12"></a> <span class="k">return</span> <span class="bp">self</span>
</span><span id="__span-11-13"><a id="__codelineno-11-13" name="__codelineno-11-13" href="#__codelineno-11-13"></a> <span class="c1"># sinon, on retourne les nouvelles modérées ou dont l&#39;utilisateur</span>
</span><span id="__span-11-14"><a id="__codelineno-11-14" name="__codelineno-11-14" href="#__codelineno-11-14"></a> <span class="c1"># est l&#39;auteur</span>
</span><span id="__span-11-15"><a id="__codelineno-11-15" name="__codelineno-11-15" href="#__codelineno-11-15"></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
</span><span id="__span-11-16"><a id="__codelineno-11-16" name="__codelineno-11-16" href="#__codelineno-11-16"></a> <span class="n">models</span><span class="o">.</span><span class="n">Q</span><span class="p">(</span><span class="n">is_moderated</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span><span id="__span-11-17"><a id="__codelineno-11-17" name="__codelineno-11-17" href="#__codelineno-11-17"></a> <span class="o">|</span> <span class="n">models</span><span class="o">.</span><span class="n">Q</span><span class="p">(</span><span class="n">author</span><span class="o">=</span><span class="n">user</span><span class="p">)</span>
</span><span id="__span-11-18"><a id="__codelineno-11-18" name="__codelineno-11-18" href="#__codelineno-11-18"></a> <span class="p">)</span>
</span><span id="__span-11-19"><a id="__codelineno-11-19" name="__codelineno-11-19" href="#__codelineno-11-19"></a>
</span><span id="__span-11-20"><a id="__codelineno-11-20" name="__codelineno-11-20" href="#__codelineno-11-20"></a>
</span><span id="__span-11-21"><a id="__codelineno-11-21" name="__codelineno-11-21" href="#__codelineno-11-21"></a><span class="k">class</span><span class="w"> </span><span class="nc">News</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
</span><span id="__span-11-22"><a id="__codelineno-11-22" name="__codelineno-11-22" href="#__codelineno-11-22"></a> <span class="n">is_moderated</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">BooleanField</span><span class="p">(</span><span class="n">default</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</span><span id="__span-11-23"><a id="__codelineno-11-23" name="__codelineno-11-23" href="#__codelineno-11-23"></a> <span class="n">author</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span><span class="n">User</span><span class="p">,</span> <span class="n">on_delete</span><span class="o">=</span><span class="n">models</span><span class="o">.</span><span class="n">PROTECT</span><span class="p">)</span>
</span><span id="__span-11-24"><a id="__codelineno-11-24" name="__codelineno-11-24" href="#__codelineno-11-24"></a> <span class="c1"># ...</span>
</span><span id="__span-11-25"><a id="__codelineno-11-25" name="__codelineno-11-25" href="#__codelineno-11-25"></a>
</span><span id="__span-11-26"><a id="__codelineno-11-26" name="__codelineno-11-26" href="#__codelineno-11-26"></a> <span class="n">objects</span> <span class="o">=</span> <span class="n">NewsQuerySet</span><span class="o">.</span><span class="n">as_manager</span><span class="p">()</span> <span class="c1"># (2)!</span>
</span><span id="__span-11-27"><a id="__codelineno-11-27" name="__codelineno-11-27" href="#__codelineno-11-27"></a>
</span><span id="__span-11-28"><a id="__codelineno-11-28" name="__codelineno-11-28" href="#__codelineno-11-28"></a> <span class="k">class</span><span class="w"> </span><span class="nc">Meta</span><span class="p">:</span>
</span><span id="__span-11-29"><a id="__codelineno-11-29" name="__codelineno-11-29" href="#__codelineno-11-29"></a> <span class="n">permissions</span> <span class="o">=</span> <span class="p">[(</span><span class="s2">&quot;view_unmoderated_news&quot;</span><span class="p">,</span> <span class="s2">&quot;Can view non moderated news&quot;</span><span class="p">)]</span>
</span></code></pre></div>
<ol>
<li>On crée un <code>QuerySet</code> maison, dans lequel on définit la méthode <code>viewable_by</code></li>
<li>Puis, on attache ce <code>QuerySet</code> à notre modèle</li>
</ol>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Pour plus d'informations sur la création de <code>QuerySet</code> personnalisés, voir
<a href="https://docs.djangoproject.com/fr/stable/topics/db/managers/">la documentation de django</a></p>
</div>
<h2 id="api">API<a class="headerlink" href="#api" title="Permanent link">&para;</a></h2>
<p>L'API utilise son propre système de permissions.
Ce n'est pas encore un autre système en parallèle, mais un wrapper
autour de notre système de permissions, afin de l'adapter aux besoins
de l'API.</p>
<p>En effet, l'interface attendue pour manipuler le plus aisément
possible les permissions des routes d'API avec la librairie que nous
utilisons est différente de notre système, tout en restant adaptable.
(Pour plus de détail,
<a href="https://eadwincode.github.io/django-ninja-extra/api_controller/api_controller_permission/">voir la doc de la lib</a>).</p>
<p>Si vous avez bien suivi ce qui a été dit plus haut,
vous ne devriez pas être perdu, étant donné
que le système de permissions de l'API utilise
des noms assez similaires : <code>IsInGroup</code>, <code>IsRoot</code>, <code>IsSubscriber</code>...
Vous pouvez trouver des exemples d'utilisation de ce système
dans <a href="../reference/core/api_permissions.md">cette partie</a>.</p>
</article>
</div>
<script>var tabs=__md_get("__tabs");if(Array.isArray(tabs))e:for(var set of document.querySelectorAll(".tabbed-set")){var labels=set.querySelector(".tabbed-labels");for(var tab of tabs)for(var label of labels.getElementsByTagName("label"))if(label.innerText.trim()===tab){var input=document.getElementById(label.htmlFor);input.checked=!0;continue e}}</script>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
</main>
<footer class="md-footer">
<nav class="md-footer__inner md-grid" aria-label="Pied de page" >
<a href="../structure/" class="md-footer__link md-footer__link--prev" aria-label="Précédent: Structure du projet">
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</div>
<div class="md-footer__title">
<span class="md-footer__direction">
Précédent
</span>
<div class="md-ellipsis">
Structure du projet
</div>
</div>
</a>
<a href="../groups/" class="md-footer__link md-footer__link--next" aria-label="Suivant: Gestion des groupes">
<div class="md-footer__title">
<span class="md-footer__direction">
Suivant
</span>
<div class="md-ellipsis">
Gestion des groupes
</div>
</div>
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11z"/></svg>
</div>
</a>
</nav>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"base": "../..", "features": ["navigation.footer", "content.code.annotate", "content.code.copy", "content.tabs.link"], "search": "../../assets/javascripts/workers/search.6ce7567c.min.js", "translations": {"clipboard.copied": "Copi\u00e9 dans le presse-papier", "clipboard.copy": "Copier dans le presse-papier", "search.result.more.one": "1 de plus sur cette page", "search.result.more.other": "# de plus sur cette page", "search.result.none": "Aucun document trouv\u00e9", "search.result.one": "1 document trouv\u00e9", "search.result.other": "# documents trouv\u00e9s", "search.result.placeholder": "Taper pour d\u00e9marrer la recherche", "search.result.term.missing": "Non trouv\u00e9", "select.version": "S\u00e9lectionner la version"}}</script>
<script src="../../assets/javascripts/bundle.88dd0f4e.min.js"></script>
</body>
</html>