def __set__(self, instance, value):
        """
        Completely overridden to avoid bulk deletion that happens when the
        parent method calls clear().

        The parent method's logic is basically: clear all in bulk, then add
        the given objects in bulk.
        Instead, we figure out which ones are being added and removed, and
        call add and remove for these values.
        This lets us retain the versioning information.

        Since this is a many-to-many relationship, it is assumed here that
        the django.db.models.deletion.Collector logic, that is used in
        clear(), is not necessary here. Collector collects related models,
        e.g. ones that should also be deleted because they have
        a ON CASCADE DELETE relationship to the object, or, in the case of
        "Multi-table inheritance", are parent objects.

        :param instance: The instance on which the getter was called
        :param value: iterable of items to set
        """

        if not instance.is_current:
            raise SuspiciousOperation(
                "Related values can only be directly set on the current "
                "version of an object")

        if not self.field.remote_field.through._meta.auto_created:
            opts = self.field.rel.through._meta
            raise AttributeError((
                                     "Cannot set values on a ManyToManyField "
                                     "which specifies an intermediary model. "
                                     "Use %s.%s's Manager instead.") % (
                                     opts.app_label, opts.object_name))

        manager = self.__get__(instance)
        # Below comment is from parent __set__ method.  We'll force
        # evaluation, too:
        # clear() can change expected output of 'value' queryset, we force
        # evaluation of queryset before clear; ticket #19816
        value = tuple(value)

        being_removed, being_added = self.get_current_m2m_diff(instance, value)
        timestamp = get_utc_now()
        manager.remove_at(timestamp, *being_removed)
        manager.add_at(timestamp, *being_added)
def __set__ ( self , instance , value ) : if not instance . is_current : raise SuspiciousOperation ( "Related values can only be directly set on the current " "version of an object" ) if not self . field . remote_field . through . _meta . auto_created : opts = self . field . rel . through . _meta raise AttributeError ( ( "Cannot set values on a ManyToManyField " "which specifies an intermediary model. " "Use %s.%s's Manager instead." ) % ( opts . app_label , opts . object_name ) ) manager = self . __get__ ( instance ) value = tuple ( value ) being_removed , being_added = self . get_current_m2m_diff ( instance , value ) timestamp = get_utc_now ( ) manager . remove_at ( timestamp , * being_removed ) manager . add_at ( timestamp , * being_added )
Completely overridden to avoid bulk deletion that happens when the
        parent method calls clear().

        The parent method's logic is basically: clear all in bulk, then add
        the given objects in bulk.
        Instead, we figure out which ones are being added and removed, and
        call add and remove for these values.
        This lets us retain the versioning information.

        Since this is a many-to-many relationship, it is assumed here that
        the django.db.models.deletion.Collector logic, that is used in
        clear(), is not necessary here. Collector collects related models,
        e.g. ones that should also be deleted because they have
        a ON CASCADE DELETE relationship to the object, or, in the case of
        "Multi-table inheritance", are parent objects.

        :param instance: The instance on which the getter was called
        :param value: iterable of items to set