diff --git a/apps/api/viewsets.py b/apps/api/viewsets.py
index 6c5a207a114e0ab1f41323d6f4c6ff777e776a98..c700339faf977f039734a032dc5689955c0a50a0 100644
--- a/apps/api/viewsets.py
+++ b/apps/api/viewsets.py
@@ -5,15 +5,19 @@ from django.contrib.contenttypes.models import ContentType
 from member.backends import PermissionBackend
 from rest_framework import viewsets
 
+from note_kfet.middlewares import get_current_authenticated_user
+
 
 class ReadProtectedModelViewSet(viewsets.ModelViewSet):
     """
     Protect a ModelViewSet by filtering the objects that the user cannot see.
     """
 
-    def get_queryset(self):
-        model = ContentType.objects.get_for_model(self.serializer_class.Meta.model)
-        return super().get_queryset().filter(PermissionBackend.filter_queryset(self.request.user, model, "view"))
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        model = ContentType.objects.get_for_model(self.serializer_class.Meta.model).model_class()
+        user = get_current_authenticated_user()
+        self.queryset = model.objects.filter(PermissionBackend.filter_queryset(user, model, "view"))
 
 
 class ReadOnlyProtectedModelViewSet(viewsets.ReadOnlyModelViewSet):
@@ -21,6 +25,8 @@ class ReadOnlyProtectedModelViewSet(viewsets.ReadOnlyModelViewSet):
     Protect a ReadOnlyModelViewSet by filtering the objects that the user cannot see.
     """
 
-    def get_queryset(self):
-        model = ContentType.objects.get_for_model(self.serializer_class.Meta.model)
-        return super().get_queryset().filter(PermissionBackend.filter_queryset(self.request.user, model, "view"))
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        model = ContentType.objects.get_for_model(self.serializer_class.Meta.model).model_class()
+        user = get_current_authenticated_user()
+        self.queryset = model.objects.filter(PermissionBackend.filter_queryset(user, model, "view"))
diff --git a/apps/member/backends.py b/apps/member/backends.py
index 099ef8a853f0d1dd231fa7f7f1d964108bd8cb58..90dc70f8e11daac7964cbf3a7eef67e64ffaa585 100644
--- a/apps/member/backends.py
+++ b/apps/member/backends.py
@@ -19,30 +19,28 @@ class PermissionBackend(ModelBackend):
 
     @staticmethod
     def permissions(user, model, type):
-        for membership in Membership.objects.filter(user=user).all():
-            if not membership.valid() or membership.roles is None:
-                continue
-
-            for permission in Permission.objects.filter(
-                    rolepermissions__role=membership.roles,
-                    model__app_label=model.app_label,  # For polymorphic models, we don't filter on model type
-                    type=type
-            ).all():
-                permission = permission.about(
-                    user=user,
-                    club=membership.club,
-                    User=User,
-                    Club=Club,
-                    Membership=Membership,
-                    Note=Note,
-                    NoteUser=NoteUser,
-                    NoteClub=NoteClub,
-                    NoteSpecial=NoteSpecial,
-                    F=F,
-                    Q=Q
-                )
-                if permission.mask.rank <= get_current_session().get("permission_mask", 0):
-                    yield permission
+        for permission in Permission.objects.annotate(club=F("rolepermissions__role__membership__club")) \
+                .filter(
+            rolepermissions__role__membership__user=user,
+            model__app_label=model.app_label,  # For polymorphic models, we don't filter on model type
+            type=type,
+        ).all():
+            club = Club.objects.get(pk=permission.club)
+            permission = permission.about(
+                user=user,
+                club=club,
+                User=User,
+                Club=Club,
+                Membership=Membership,
+                Note=Note,
+                NoteUser=NoteUser,
+                NoteClub=NoteClub,
+                NoteSpecial=NoteSpecial,
+                F=F,
+                Q=Q
+            )
+            if permission.mask.rank <= get_current_session().get("permission_mask", 0):
+                yield permission
 
     @staticmethod
     def filter_queryset(user, model, t, field=None):
@@ -55,6 +53,9 @@ class PermissionBackend(ModelBackend):
         :return: A query that corresponds to the filter to give to a queryset
         """
 
+        from time import time
+        ti = time()
+
         if user.is_superuser and get_current_session().get("permission_mask", 0) >= 42:
             # Superusers have all rights
             return Q()
@@ -64,11 +65,13 @@ class PermissionBackend(ModelBackend):
 
         # Never satisfied
         query = Q(pk=-1)
-        for perm in PermissionBackend.permissions(user, model, t):
+        perms = PermissionBackend.permissions(user, model, t)
+        for perm in perms:
             if perm.field and field != perm.field:
                 continue
             if perm.type != t or perm.model != model:
                 continue
+            perm.update_query()
             query = query | perm.query
         return query
 
diff --git a/apps/note/api/views.py b/apps/note/api/views.py
index e09557f456eca73fae3beb00da3c888b43a93752..f4bf5668847514673834b662ec206e1d7a316ba0 100644
--- a/apps/note/api/views.py
+++ b/apps/note/api/views.py
@@ -6,7 +6,6 @@ from django_filters.rest_framework import DjangoFilterBackend
 from rest_framework.filters import OrderingFilter, SearchFilter
 
 from api.viewsets import ReadProtectedModelViewSet, ReadOnlyProtectedModelViewSet
-from member.backends import PermissionBackend
 from .serializers import NotePolymorphicSerializer, AliasSerializer, TemplateCategorySerializer, \
     TransactionTemplateSerializer, TransactionPolymorphicSerializer
 from ..models.notes import Note, Alias
@@ -30,7 +29,7 @@ class NotePolymorphicViewSet(ReadOnlyProtectedModelViewSet):
         Parse query and apply filters.
         :return: The filtered set of requested notes
         """
-        queryset = super().get_queryset().filter(PermissionBackend.filter_queryset(self.request.user, Note, "view"))
+        queryset = super().get_queryset()
 
         alias = self.request.query_params.get("alias", ".*")
         queryset = queryset.filter(
@@ -57,7 +56,7 @@ class AliasViewSet(ReadProtectedModelViewSet):
         :return: The filtered set of requested aliases
         """
 
-        queryset = super().get_queryset().filter(PermissionBackend.filter_queryset(self.request.user, Alias, "view"))
+        queryset = super().get_queryset()
 
         alias = self.request.query_params.get("alias", ".*")
         queryset = queryset.filter(
diff --git a/apps/permission/models.py b/apps/permission/models.py
index f7752517c7458087d590cd7c92f2e10b84d3a568..fca4b36b40b66183a5fd9ec5f3cbf5957eee0367 100644
--- a/apps/permission/models.py
+++ b/apps/permission/models.py
@@ -14,12 +14,14 @@ from django.utils.translation import gettext_lazy as _
 
 class InstancedPermission:
 
-    def __init__(self, model, query, type, field, mask):
+    def __init__(self, model, query, type, field, mask, **kwargs):
         self.model = model
-        self.query = query
+        self.raw_query = query
+        self.query = None
         self.type = type
         self.field = field
         self.mask = mask
+        self.kwargs = kwargs
 
     def applies(self, obj, permission_type, field_name=None):
         """
@@ -33,6 +35,8 @@ class InstancedPermission:
 
         if self.type == 'add':
             if permission_type == self.type:
+                self.update_query()
+
                 # Don't increase indexes
                 obj.pk = 0
                 # Force insertion, no data verification, no trigger
@@ -45,10 +49,16 @@ class InstancedPermission:
         if permission_type == self.type:
             if self.field and field_name != self.field:
                 return False
+            self.update_query()
             return obj in self.model.model_class().objects.filter(self.query).all()
         else:
             return False
 
+    def update_query(self):
+        if not self.query:
+            # noinspection PyProtectedMember
+            self.query = Permission._about(self.raw_query, **self.kwargs)
+
     def __repr__(self):
         if self.field:
             return _("Can {type} {model}.{field} in {query}").format(type=self.type, model=self.model, field=self.field, query=self.query)
@@ -178,7 +188,8 @@ class Permission(models.Model):
                 field = getattr(field, value[i])
         return field
 
-    def _about(self, query, **kwargs):
+    @staticmethod
+    def _about(query, **kwargs):
         if len(query) == 0:
             # The query is either [] or {} and
             # applies to all objects of the model
@@ -186,11 +197,11 @@ class Permission(models.Model):
             return Q(pk=F("pk"))
         if isinstance(query, list):
             if query[0] == 'AND':
-                return functools.reduce(operator.and_, [self._about(query, **kwargs) for query in query[1:]])
+                return functools.reduce(operator.and_, [Permission._about(query, **kwargs) for query in query[1:]])
             elif query[0] == 'OR':
-                return functools.reduce(operator.or_, [self._about(query, **kwargs) for query in query[1:]])
+                return functools.reduce(operator.or_, [Permission._about(query, **kwargs) for query in query[1:]])
             elif query[0] == 'NOT':
-                return ~self._about(query[1], **kwargs)
+                return ~Permission._about(query[1], **kwargs)
         elif isinstance(query, dict):
             q_kwargs = {}
             for key in query:
@@ -206,7 +217,7 @@ class Permission(models.Model):
             return Q(**q_kwargs)
         else:
             # TODO: find a better way to crash here
-            raise Exception("query {} is wrong".format(self.query))
+            raise Exception("query {} is wrong".format(query))
 
     def about(self, **kwargs):
         """
@@ -214,8 +225,8 @@ class Permission(models.Model):
         replaced by their values and the query interpreted
         """
         query = json.loads(self.query)
-        query = self._about(query, **kwargs)
-        return InstancedPermission(self.model, query, self.type, self.field, self.mask)
+        # query = self._about(query, **kwargs)
+        return InstancedPermission(self.model, query, self.type, self.field, self.mask, **kwargs)
 
     def __str__(self):
         if self.field:
diff --git a/apps/permission/templatetags/perms.py b/apps/permission/templatetags/perms.py
index 859f1ef2732a7578b6859b8e6e03f5e1ae22a0ec..79a9640f3f83deac3e651e284eeb2fae779a9ef4 100644
--- a/apps/permission/templatetags/perms.py
+++ b/apps/permission/templatetags/perms.py
@@ -13,27 +13,35 @@ from member.backends import PermissionBackend
 @stringfilter
 def not_empty_model_list(model_name):
     user = get_current_authenticated_user()
+    session = get_current_session()
     if user is None:
         return False
-    elif user.is_superuser and get_current_session().get("permission_mask", 0) >= 42:
+    elif user.is_superuser and session.get("permission_mask", 0) >= 42:
         return True
+    if session.get("not_empty_model_list_" + model_name, None):
+        return session.get("not_empty_model_list_" + model_name, None) == 1
     spl = model_name.split(".")
     ct = ContentType.objects.get(app_label=spl[0], model=spl[1])
     qs = ct.model_class().objects.filter(PermissionBackend.filter_queryset(user, ct, "view"))
-    return qs.exists()
+    session["not_empty_model_list_" + model_name] = 1 if qs.exists() else 2
+    return session.get("not_empty_model_list_" + model_name) == 1
 
 
 @stringfilter
 def not_empty_model_change_list(model_name):
     user = get_current_authenticated_user()
+    session = get_current_session()
     if user is None:
         return False
-    elif user.is_superuser and get_current_session().get("permission_mask", 0) >= 42:
+    elif user.is_superuser and session.get("permission_mask", 0) >= 42:
         return True
+    if session.get("not_empty_model_change_list_" + model_name, None):
+        return session.get("not_empty_model_change_list_" + model_name, None) == 1
     spl = model_name.split(".")
     ct = ContentType.objects.get(app_label=spl[0], model=spl[1])
     qs = ct.model_class().objects.filter(PermissionBackend.filter_queryset(user, ct, "change"))
-    return qs.exists()
+    session["not_empty_model_change_list_" + model_name] = 1 if qs.exists() else 2
+    return session.get("not_empty_model_change_list_" + model_name) == 1
 
 
 register = template.Library()
diff --git a/static/js/base.js b/static/js/base.js
index 1cc242e8ab6f38511ef932ae0b547315bf5c3c94..4f94893ee024849a99f8968f01ed56fd23ed6d14 100644
--- a/static/js/base.js
+++ b/static/js/base.js
@@ -199,6 +199,7 @@ function autoCompleteNote(field_id, alias_matched_id, note_list_id, notes, notes
                 // When the user click on an alias, the associated note is added to the emitters
                 alias_obj.click(function () {
                     field.val("");
+                    old_pattern = "";
                     // If the note is already an emitter, we increase the quantity
                     var disp = null;
                     notes_display.forEach(function (d) {