diff --git a/ami/base/models.py b/ami/base/models.py index 2f245b745..f08cd334e 100644 --- a/ami/base/models.py +++ b/ami/base/models.py @@ -66,7 +66,11 @@ def visible_for_user(self, user: User | AnonymousUser) -> QuerySet: if not is_anonymous: filter_condition |= Q(owner=user) | Q(members=user) - return self.filter(filter_condition).distinct() + if is_anonymous: + return self.filter(filter_condition) + + visible_project_ids = self.filter(filter_condition).order_by().values_list("pk", flat=True) + return self.filter(pk__in=visible_project_ids) # For models related to Project project_accessor = model.get_project_accessor() @@ -85,7 +89,8 @@ def visible_for_user(self, user: User | AnonymousUser) -> QuerySet: if not is_anonymous: filter_condition |= Q(**{f"{project_field}owner": user}) | Q(**{f"{project_field}members": user}) - return self.filter(filter_condition).distinct() + visible_object_ids = self.filter(filter_condition).order_by().values_list("pk", flat=True) + return self.filter(pk__in=visible_object_ids) class BaseModel(models.Model): diff --git a/ami/main/tests.py b/ami/main/tests.py index c9e3b0d8f..90704db0b 100644 --- a/ami/main/tests.py +++ b/ami/main/tests.py @@ -3232,6 +3232,15 @@ def test_deployment_list_draft_project(self): ids = [d["id"] for d in response.data["results"]] assert self.deployment.pk not in ids + def test_visible_for_user_deduplicates_captures_in_a_primary_key_subquery(self): + self.project.members.add(self.outsider) + queryset = SourceImage.objects.visible_for_user(self.owner) + + self.assertIn(self.deployment.captures.first(), queryset) + capture_ids = list(queryset.values_list("pk", flat=True)) + self.assertEqual(len(capture_ids), len(set(capture_ids))) + self.assertNotIn("SELECT DISTINCT", str(queryset.query)) + def test_visible_for_user_across_all_models(self): all_users = { "superuser": self.superuser,