Skip to content

[vote] Model changes - #3734

Merged
m-schieder merged 16 commits into
OpenSlides:feature/votefrom
vkrasnovyd:model-changes
Sep 1, 2026
Merged

[vote] Model changes#3734
m-schieder merged 16 commits into
OpenSlides:feature/votefrom
vkrasnovyd:model-changes

Conversation

@vkrasnovyd

@vkrasnovyd vkrasnovyd commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Changes for OpenSlides/openslides-meta#575

History information

The new field history_entry/structured_information was needed to let the vote service calculate entitled users on stop. The approach has changed and the field is not needed anymore. Field for machine-readble history information will be added eventually after proper prototyping. Therefore:

  • Removed all the code that was writing structured_information
  • Kept the new types, helper methods and changes in actions that allow and/or simplify backend to process multiple history_entry fields

poll_option

Relation poll_option/meeting_user_id was transformed into generic relation poll_option/content_object_id to either meeting_user or user.

  1. Vote service will take care of writing the initial value. It was discussed, that when user gets removed from the meeting, the generic relation for the related options should switch from meeting_user to user. No switching back logic is needed on adding user back to the meeting. On user delete poll_option/content_object_id should be set to None.

  2. I've moved the check for the conflicts from the meeting_user merge mixin back to the user action to check these relations together.

poll_entitled_user

It is important to preserve the correct number of entitled users on stop. That's why dublicates don't get deleted on user merge.

Comment on lines +398 to +406
meeting_users = self.datastore.get_many(
[
GetManyRequest(
"meeting_user",
model.get("meeting_user_ids", []),
["poll_option_ids"],
),
]
)["meeting_user"]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For performance reasons pull this out of the for loop.
No need to do as many get_manys as we have users here, when we can do just one for the meeting_users of all users at once.

If you need to iterate over the meeting_users for one of the users later on, just iterate over the meeting_user_ids instead and use the ids to get the meeting_user from the get_many result.

Perhaps you could look into whether this is also possible for the poll_option get_many request in the if condition in 412.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Was also able to retrieve all the options at once.

Comment thread openslides_backend/action/actions/user/merge_together.py Outdated
Comment thread openslides_backend/shared/history_events.py Outdated
Comment thread openslides_backend/shared/typing.py Outdated
Comment thread openslides_backend/action/actions/user/merge_mixins.py
vkrasnovyd and others added 3 commits September 1, 2026 09:27
Co-authored-by: luisa-beerboom <101706784+luisa-beerboom@users.noreply.github.com>
Comment on lines +418 to +425
poll_options = self.datastore.filter(
"poll_option",
Or(
FilterOperator("content_object_id", "=", fqid)
for fqid in content_object_ids
),
["poll_id", "content_object_id"],
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Massive generated Or or And filter lists are not ideal.
As a rule of thumb they should be avoided, since in the past there have been cases where such requests failed because they exceeded postgres' request character limit.

The models in all_users would have all fields loaded, AFAIK.
In that case

        poll_options = self.datastore.get_many(
            [GetManyRequest(
                "poll_option",
                list({
                    o_id
                    for u_or_mu in [*meeting_users, *all_users]
                    for o_id in u_or_mu.get("poll_option_ids", [])
                }),
                ["poll_id", "content_object_id"]
            )]
        )["poll_option"]

would probably be preferable.

Using Or and And filters is fine if you have a set amount of inner operators (e.g. when checking if the content is one of two values or smth)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. This approach was my first implementation of these changes, actually, so simply returned those changes.

meeting_users = self.datastore.filter(
"meeting_user",
And(
Or(FilterOperator("user_id", "=", user_id) for user_id in all_users),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See below.

Honestly it's not as bad here, since we can expect that cases where massive amounts of users, of a degree that would crash the filter, are merged are unlikely.
However that also means that filtering the meeting_users afterwards would not be that costly either, so I'd still prefer to see a get_many request.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@vkrasnovyd

Copy link
Copy Markdown
Contributor Author

Also updated meta hash and regenerated models to match the current state of feature/vote in meta.

@vkrasnovyd vkrasnovyd removed their assignment Sep 1, 2026
@m-schieder
m-schieder merged commit adad6ef into OpenSlides:feature/vote Sep 1, 2026
5 of 6 checks passed
@vkrasnovyd
vkrasnovyd deleted the model-changes branch September 1, 2026 16:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants