diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 290bcf48c..95f798ea6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -17,7 +17,7 @@ Core: - Enabled docs for using OpenSlides with Gunicorn and Uvicorn in big mode [#3799, #3817]. - Changed format for elements send via autoupdate [#3926]. - - Fixed autoupdate system for related objects [#4140]. + - Fixed autoupdate system for related objects [#4140, #4201]. - Add a change-id system to get only new elements [#3938]. - Switch from Yarn back to npm [#3964]. - Added password reset link (password reset via email) [#3914, #4199]. diff --git a/openslides/core/apps.py b/openslides/core/apps.py index 909aa0338..d30715058 100644 --- a/openslides/core/apps.py +++ b/openslides/core/apps.py @@ -6,7 +6,7 @@ from typing import Any, Dict, List, Set from django.apps import AppConfig from django.conf import settings -from django.db.models.signals import post_migrate +from django.db.models.signals import post_migrate, pre_delete class CoreAppConfig(AppConfig): @@ -20,6 +20,7 @@ class CoreAppConfig(AppConfig): from .projector import register_projector_slides from . import serializers # noqa from .signals import ( + autoupdate_for_many_to_many_relations, delete_django_app_permissions, get_permission_change_data, permission_change, @@ -64,6 +65,10 @@ class CoreAppConfig(AppConfig): sender=self, dispatch_uid="core_save_config_default_values", ) + pre_delete.connect( + autoupdate_for_many_to_many_relations, + dispatch_uid="core_autoupdate_for_many_to_many_relations", + ) # Register viewsets. router.register( diff --git a/openslides/core/signals.py b/openslides/core/signals.py index d3884b05e..84d2fa718 100644 --- a/openslides/core/signals.py +++ b/openslides/core/signals.py @@ -4,6 +4,8 @@ from django.contrib.contenttypes.models import ContentType from django.db.models import Q from django.dispatch import Signal +from ..utils.autoupdate import Element, inform_changed_elements + # This signal is send when the migrate command is done. That means it is sent # after post_migrate sending and creating all Permission objects. Don't use it @@ -40,3 +42,32 @@ def get_permission_change_data(sender, permissions, **kwargs): yield core_app.get_model("Countdown") elif permission.codename == "can_use_chat": yield core_app.get_model("ChatMessage") + + +def autoupdate_for_many_to_many_relations(sender, instance, **kwargs): + """ + Send autoupdate for many-to-many related objects if the other side + is deleted. + """ + m2m_fields = ( + field + for field in instance._meta.get_fields(include_hidden=True) + if field.many_to_many and field.auto_created + ) + for field in m2m_fields: + queryset = getattr(instance, field.get_accessor_name()).all() + for related_instance in queryset: + if hasattr(related_instance, "get_root_rest_element"): + # The related instance is or has a root rest element. + # So lets send it via autoupdate. + root_rest_element = related_instance.get_root_rest_element() + inform_changed_elements( + [ + Element( + collection_string=root_rest_element.get_collection_string(), + id=root_rest_element.pk, + full_data=None, + reload=True, + ) + ] + )