python / expert
Snippet
Django Generic Views with Dynamic Queryset Filtering and Permission Matrix
Generic views combined with permission matrices enable fine-grained access control without repetitive decorator logic. The permission_matrix cached_property caches permission checks per request avoiding repeated database queries. Dynamic queryset filtering via GET parameters allows non-JavaScript filtered views while maintaining query efficiency through select_related.
snippet.py
python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
from django.views.generic import ListView, DetailViewfrom django.core.exceptions import PermissionDeniedfrom django.contrib.auth.mixins import LoginRequiredMixinfrom functools import cached_propertyclass ArticleDetailView(LoginRequiredMixin, DetailView):model = Articlecontext_object_name = 'article'template_name = 'articles/detail.html'def get_queryset(self):user = self.request.userif user.is_superuser:return Article.objects.all()if user.has_perm('articles.view_article'):return Article.objects.filter(status='published')return Article.objects.none()def get_object(self):obj = super().get_object()if not self.request.user.has_perm('articles.view_detail', obj):raise PermissionDenied('Access denied to unpublished details')return objclass ArticleListView(ListView):model = Articlecontext_object_name = 'articles'paginate_by = 20@cached_propertydef permission_matrix(self):return {'can_publish': self.request.user.has_perm('articles.publish'),'can_archive': self.request.user.has_perm('articles.archive'),'can_edit': self.request.user.has_perm('articles.change'),}def get_queryset(self):queryset = Article.objects.select_related('author')status = self.request.GET.get('status')if status in ['published', 'draft', 'archived']:queryset = queryset.filter(status=status)author = self.request.GET.get('author')if author:queryset = queryset.filter(author__username=author)return querysetdef get_context_data(self, **kwargs):context = super().get_context_data(**kwargs)context['permissions'] = self.permission_matrixreturn context
django
Breakdown
1
@cached_property
def permission_matrix(self):
Caches permission checks for entire request lifecycle
2
if user.is_superuser: return Article.objects.all()
Superusers bypass filtering to see all articles
3
if not self.request.user.has_perm('articles.view_detail', obj):
Object-level permission check with dynamic obj parameter
4
status = self.request.GET.get('status')
if status in [...]:
Dynamic queryset filtering from URL query parameters
5
context_object_name = 'articles'
Context variable naming convention for template clarity