From 1e78f2a5344a4d99cc70465378e3cda87426c22d Mon Sep 17 00:00:00 2001 From: Finn Stutzenstein Date: Thu, 6 May 2021 16:06:52 +0200 Subject: [PATCH] Speed up stopping a poll Reduced the amount of queries in BasePoll.stop from 4+ to 3. --- server/openslides/poll/models.py | 32 ++++++++++++------- .../tests/integration/motions/test_polls.py | 25 +++++++++++++++ 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/server/openslides/poll/models.py b/server/openslides/poll/models.py index 7a6169446..427256156 100644 --- a/server/openslides/poll/models.py +++ b/server/openslides/poll/models.py @@ -264,18 +264,25 @@ class BasePoll(models.Model): self.is_pseudoanonymized = False self.save() - def calculate_votes(self): - if self.type != BasePoll.TYPE_ANALOG: - self.votescast = self.voted.count() - if config["users_activate_vote_weight"]: - self.votesvalid = sum(self.voted.values_list("vote_weight", flat=True)) - else: - self.votesvalid = self.votescast - self.votesinvalid = Decimal(0) + def calculate_votes(self, all_voted_users=None): + if self.type == BasePoll.TYPE_ANALOG: + return - def calculate_entitled_users(self): + if all_voted_users is None: + all_voted_users = self.voted.all() + + self.votescast = len(all_voted_users) + if config["users_activate_vote_weight"]: + self.votesvalid = sum(user.vote_weight for user in all_voted_users) + else: + self.votesvalid = self.votescast + self.votesinvalid = Decimal(0) + + def calculate_entitled_users(self, all_voted_users=None): entitled_users = [] entitled_users_ids = set() + if all_voted_users is None: + all_voted_users = self.voted.all() for group in self.groups.all(): for user in group.user_set.all(): if ( @@ -286,7 +293,7 @@ class BasePoll(models.Model): entitled_users.append( { "user_id": user.id, - "voted": user in self.voted.all(), + "voted": user in all_voted_users, "vote_delegated_to_id": user.vote_delegated_to_id, } ) @@ -296,7 +303,8 @@ class BasePoll(models.Model): """ Saves a snapshot of the current voted users into the relevant fields and stops the poll. """ - self.calculate_votes() - self.calculate_entitled_users() + all_voted_users = self.voted.all() # just fetch this once from the database now + self.calculate_votes(all_voted_users) + self.calculate_entitled_users(all_voted_users) self.state = self.STATE_FINISHED self.save() diff --git a/server/tests/integration/motions/test_polls.py b/server/tests/integration/motions/test_polls.py index 6bf633490..da96e1579 100644 --- a/server/tests/integration/motions/test_polls.py +++ b/server/tests/integration/motions/test_polls.py @@ -1211,6 +1211,31 @@ class StopMotionPoll(TestCase): ], ) + def test_stop_poll_multiple_users_database_query_count(self): + """ + The code in BasePoll.stop() should not make too much queries. + """ + self.setup_entitled_users() + expected = [] + for _ in range(10): + user, _ = self.create_user() + user.is_present = True + user.vote_delegated_to = self.admin + user.save() + user.groups.add(self.group) + expected.append( + { + "user_id": user.id, + "voted": False, + "vote_delegated_to_id": self.admin.id, + } + ) + self.admin.is_present = False + self.admin.save() + config["users_activate_vote_weight"] = True + self.assertEqual(count_queries(self.poll.stop)(), 13) + self.assertEqual(MotionPoll.objects.get().entitled_users_at_stop, expected) + def test_stop_poll_assert_no_duplicate_entitled_users(self): self.setup_entitled_users() delegate_group = get_group_model().objects.get(pk=GROUP_DELEGATE_PK)