diff --git a/arkindex/project/mixins.py b/arkindex/project/mixins.py
index 94a41281c1dd218024ce481c87339cad6103524c..84c3562bc2cedcf9ae8c4958b6877fd5bc184724 100644
--- a/arkindex/project/mixins.py
+++ b/arkindex/project/mixins.py
@@ -1,6 +1,6 @@
 from django.conf import settings
 from django.core.exceptions import PermissionDenied
-from django.db.models import Q, functions
+from django.db.models import IntegerField, Q, Value, functions
 from django.shortcuts import get_object_or_404
 from django.views.decorators.cache import cache_page
 from rest_framework.exceptions import APIException, ValidationError
@@ -28,43 +28,48 @@ class ACLMixin(object):
     def user(self):
         return self._user or self.request.user
 
+    def get_public_instances(self, model, default_level):
+        return model.objects \
+            .filter(public=True) \
+            .annotate(max_level=Value(default_level, IntegerField()))
+
     def rights_filter(self, model, level, public=False):
         """
-        Return a model queryset matching a given access level for this user
+        Return a model queryset matching a given access level for this user.
         """
         # Handle specific cases (i.e. admin or anonymous user)
         if self.user.is_admin or self.user.is_internal:
-            return model.objects.all()
-        elif user.is_anonymous:
-            if level > Role.Guest.value or not public:
+            return model.objects.all().annotate(max_level=Value(Role.Admin.value))
+        elif self.user.is_anonymous:
+            if not public:
                 return model.objects.none()
             else:
-                return model.objects.filter(public=True)
+                return self.get_public_instances(model, Role.Guest.value)
 
+        # Filter users rights and annotate the resulting level for those rights
         queryset = model.objects \
             .filter(
-                # Filter instances with direct and groups rights for this user (They may be duplicated)
+                # Filter instances with rights concerning this user. This may create duplicates
                 Q(memberships__user=self.user)
                 | Q(memberships__group__memberships__user=self.user)
             ) \
             .annotate(
                 # Keep only the lowest level for each right via group
                 max_level=functions.Least(
-                    # In case of direct right, group level will be skipped (Null value)
                     'memberships__level',
+                    # In case of direct right, the group level will be skipped (Null value)
                     'memberships__group__memberships__level'
                 )
-            ) \
-            .filter(
-                # Ensure one of the right has an adequate level
-                max_level__gte=level
             )
+        # Ensure one of the right has an adequate level
+        queryset = queryset.filter(max_level__gte=level)
 
-        if (public):
-            # Allow access to public instances if the public parameter is set
-            queryset = queryset | model.objects.filter(public=True)
+        # Use a join to add public instances as this is the more elegant solution
+        if public and level <= Role.Guest.value:
+            queryset = queryset.union(self.get_public_instances(model, Role.Guest.value))
 
-        return queryset.distinct()
+        # Return distinct corpus with the max right level among matching rights
+        return queryset.order_by('id', '-max_level').distinct('id')
 
     def has_access(self, instance, level):
         if self.user.is_admin or self.user.is_internal:
@@ -86,11 +91,13 @@ class ACLMixin(object):
 
 class RepositoryACLMixin(ACLMixin):
 
+    @property
     def readable_repositories(self):
-        return self.rights_filter(Repository, Role.Guest.value, public=False)
+        return self.rights_filter(Repository, Role.Guest.value)
 
+    @property
     def executable_repositories(self):
-        return self.rights_filter(Repository, Role.Contributor.value, public=False)
+        return self.rights_filter(Repository, Role.Contributor.value)
 
     def has_read_access(self, repo):
         return self.has_access(repo, Role.Guest.value)
@@ -103,12 +110,16 @@ class RepositoryACLMixin(ACLMixin):
 
 
 class NewCorpusACLMixin(ACLMixin):
+
+    @property
     def readable_corpora(self):
         return self.rights_filter(Corpus, Role.Guest.value, public=True)
 
+    @property
     def writable_corpora(self):
         return self.rights_filter(Corpus, Role.Contributor.value)
 
+    @property
     def administrable_corpora(self):
         return self.rights_filter(Corpus, Role.Admin.value)