Example #1
0
def delete_objects(seen_objs):
    """
    Iterate through a list of seen classes, and remove any instances that are
    referred to.
    """
    try:
        ordered_classes = seen_objs.keys()
    except CyclicDependency:
        # If there is a cyclic dependency, we cannot in general delete the
        # objects.  However, if an appropriate transaction is set up, or if the
        # database is lax enough, it will succeed. So for now, we go ahead and
        # try anyway.
        ordered_classes = seen_objs.unordered_keys()

    obj_pairs = {}
    for cls in ordered_classes:
        items = seen_objs[cls].items()
        items.sort()
        obj_pairs[cls] = items

        # Pre-notify all instances to be deleted.
        for pk_val, instance in items:
            signals.pre_delete.send(sender=cls, instance=instance)

        pk_list = [pk for pk, instance in items]
        del_query = sql.DeleteQuery(cls, connection)
        del_query.delete_batch_related(pk_list)

        update_query = sql.UpdateQuery(cls, connection)
        for field, model in cls._meta.get_fields_with_model():
            if (field.rel and field.null and field.rel.to in seen_objs
                    and filter(lambda f: f.column == field.column,
                               field.rel.to._meta.fields)):
                if model:
                    sql.UpdateQuery(model,
                                    connection).clear_related(field, pk_list)
                else:
                    update_query.clear_related(field, pk_list)

    # Now delete the actual data.
    for cls in ordered_classes:
        items = obj_pairs[cls]
        items.reverse()

        pk_list = [pk for pk, instance in items]
        del_query = sql.DeleteQuery(cls, connection)
        del_query.delete_batch(pk_list)

        # Last cleanup; set NULLs where there once was a reference to the
        # object, NULL the primary key of the found objects, and perform
        # post-notification.
        for pk_val, instance in items:
            for field in cls._meta.fields:
                if field.rel and field.null and field.rel.to in seen_objs:
                    setattr(instance, field.attname, None)

            signals.post_delete.send(sender=cls, instance=instance)
            setattr(instance, cls._meta.pk.attname, None)

    transaction.commit_unless_managed()
    def delete(self):
        # sort instance collections
        for model, instances in self.data.items():
            self.data[model] = sorted(instances, key=attrgetter("pk"))

        # if possible, bring the models in an order suitable for databases that
        # don't support transactions or cannot defer constraint checks until the
        # end of a transaction.
        self.sort()
        # number of objects deleted for each model label
        deleted_counter = Counter()

        with transaction.atomic(using=self.using, savepoint=False):
            # send pre_delete signals
            for model, obj in self.instances_with_model():
                if not model._meta.auto_created:
                    signals.pre_delete.send(sender=model,
                                            instance=obj,
                                            using=self.using)

            # fast deletes
            for qs in self.fast_deletes:
                pk_list = [obj.pk for obj in qs]
                if pk_list:
                    query = sql.UpdateQuery(qs.model)
                    query.update_batch([obj.pk for obj in qs],
                                       {'is_deleted': True}, self.using)
                # deleted_counter[qs.model._meta.label] += count

            # reverse instance collections
            for instances in self.data.values():
                instances.reverse()

            # delete instances
            for model, instances in self.data.items():
                pk_list = [obj.pk for obj in instances]
                if pk_list:
                    query = sql.UpdateQuery(model)
                    query.update_batch(pk_list, {'is_deleted': True},
                                       self.using)
                # deleted_counter[model._meta.label] += count

                if not model._meta.auto_created:
                    for obj in instances:
                        signals.post_delete.send(sender=model,
                                                 instance=obj,
                                                 using=self.using)

        # update collected instances
        for model, instances_for_fieldvalues in self.field_updates.items():
            for (field, value), instances in instances_for_fieldvalues.items():
                for obj in instances:
                    setattr(obj, field.attname, value)
        for model, instances in self.data.items():
            for instance in instances:
                setattr(instance, model._meta.pk.attname, None)
        return sum(deleted_counter.values()), dict(deleted_counter)
Example #3
0
    def delete(self):
        self.sort()

        # collect pk_list before deletion (once things start to delete
        # queries might not be able to retreive pk list)
        del_dict = OrderedDict()
        for model, instances in self.data.items():
            del_dict.setdefault(model, [])
            for inst in instances:
                del_dict[model] += list(inst.values_list('pk', flat=True))

        deleted_counter = Counter()

        with transaction.atomic(using=self.using, savepoint=False):

            # update fields
            for model, instances_for_fieldvalues in self.field_updates.items():
                for (field, value), instances in instances_for_fieldvalues.items():
                    for inst in instances:
                        query = sql.UpdateQuery(model)
                        query.update_batch(inst.values_list('pk', flat=True), {field.name: value}, self.using)
            # fast deletes
            for qs in self.fast_deletes:
                count = qs._raw_delete(using=self.using)
                deleted_counter[qs.model._meta.label] += count

            # delete instances
            for model, pk_list in del_dict.items():
                query = sql.DeleteQuery(model)
                count = query.delete_batch(pk_list, self.using)
                deleted_counter[model._meta.label] += count

            return sum(deleted_counter.values()), dict(deleted_counter)
Example #4
0
    def delete(self):
        self.sort()
        # number of objects deleted for each model label
        deleted_counter = Counter()

        with transaction.atomic(using=self.using, savepoint=False):

            # fast deletes
            for qs in self.fast_deletes:
                count = qs._raw_delete(using=self.using)
                deleted_counter[qs.model._meta.label] += count

            # update fields
            for model, instances_for_fieldvalues in self.field_updates.items():
                for (field,
                     value), instances in instances_for_fieldvalues.items():
                    query = sql.UpdateQuery(model)
                    query.update_batch(instances.values_list('pk', flat=True),
                                       {field.name: value}, self.using)

            # delete instances
            for model, instances in self.data.items():
                query = sql.DeleteQuery(model)
                pk_list = instances.values_list('pk', flat=True)
                print('Deleting', instances)
                count = query.delete_batch(pk_list, self.using)
                deleted_counter[model._meta.label] += count
Example #5
0
    def delete(self):
        # sort instance collections
        for model, instances in self.data.items():
            self.data[model] = sorted(instances, key=attrgetter("pk"))

        # if possible, bring the models in an order suitable for databases that
        # don't support transactions or cannot defer constraint checks until the
        # end of a transaction.
        self.sort()

        # send pre_delete signals
        for model, obj in self.instances_with_model():
            if not model._meta.auto_created:
                signals.pre_delete.send(sender=model,
                                        instance=obj,
                                        using=self.using)

        # update fields
        for model, instances_for_fieldvalues in six.iteritems(
                self.field_updates):
            query = sql.UpdateQuery(model)
            for (field,
                 value), instances in six.iteritems(instances_for_fieldvalues):
                query.update_batch([obj.pk for obj in instances],
                                   {field.name: value}, self.using)

        # reverse instance collections
        for instances in six.itervalues(self.data):
            instances.reverse()

        # delete batches
        for model, batches in six.iteritems(self.batches):
            query = sql.DeleteQuery(model)
            for field, instances in six.iteritems(batches):
                query.delete_batch([obj.pk for obj in instances], self.using,
                                   field)

        # delete instances
        for model, instances in six.iteritems(self.data):
            query = sql.DeleteQuery(model)
            pk_list = [obj.pk for obj in instances]
            query.delete_batch(pk_list, self.using)

        # send post_delete signals
        for model, obj in self.instances_with_model():
            if not model._meta.auto_created:
                signals.post_delete.send(sender=model,
                                         instance=obj,
                                         using=self.using)

        # update collected instances
        for model, instances_for_fieldvalues in six.iteritems(
                self.field_updates):
            for (field,
                 value), instances in six.iteritems(instances_for_fieldvalues):
                for obj in instances:
                    setattr(obj, field.attname, value)
        for model, instances in six.iteritems(self.data):
            for instance in instances:
                setattr(instance, model._meta.pk.attname, None)
Example #6
0
        def close_records(ids_to_close):
            query = sql.UpdateQuery(self.model)

            pk_field = query.get_meta().pk
            query.add_update_values({'ends_at': now})
            query.where = query.where_class()
            constr = sql.where.Constraint(None, pk_field.column, pk_field)
            query.where.add((constr, 'in', ids_to_close), sql.where.AND)
            query.add_q(Q(ends_at__isnull=True))
            query.get_compiler(self.db).execute_sql(None)
Example #7
0
    def as_sql(self):
        """ Generate SQL queries that perform related deletion """
        # List of (sql, params) tuples to perform deletion
        query_list = []

        for model, instances in self.data.items():
            self.data[model] = sorted(instances, key=attrgetter("pk"))
        self.sort()
        # Do not send pre_delete signals as in .delete()

        # Fast deletes
        for qs in self.fast_deletes:
            # TODO Check for any potential caveats from complex queries - assume none are generated by Collector

            # Clone queryset into DeleteQuery to use .as_sql()
            query_list.append(
                qs.query.clone(klass=sql.DeleteQuery).get_compiler(
                    self.using).as_sql())

        # update fields
        for model, instances_for_fieldvalues in six.iteritems(
                self.field_updates):
            query = sql.UpdateQuery(model)
            for (field,
                 value), instances in six.iteritems(instances_for_fieldvalues):
                query.add_update_values({field.name: value})
                query.add_q(models.Q(pk__in=[obj.pk for obj in instances]))
                query_list.append(
                    query.get_compiler(using=self.using).as_sql())

        # reverse instance collections
        for instances in six.itervalues(self.data):
            instances.reverse()

        # delete instances
        for model, instances in six.iteritems(self.data):
            query = sql.DeleteQuery(model)
            pk_list = [obj.pk for obj in instances]
            query.where = query.where_class()
            query.add_q(models.Q(pk__in=pk_list))
            query_list.append(query.get_compiler(using=self.using).as_sql())

        # Do not update instances as in .delete()
        return query_list
Example #8
0
 def sql_model_wise_batch_update(self, model, instances, deleted=None):
     query = sql.UpdateQuery(model)
     query.update_batch([obj.pk for obj in instances], {'deleted': deleted},
                        self.using)
Example #9
0
    def delete(self):
        # sort instance collections
        for model, instances in self.data.items():
            self.data[model] = sorted(instances, key=attrgetter("pk"))

        # if possible, bring the models in an order suitable for databases that
        # don't support transactions or cannot defer constraint checks until the
        # end of a transaction.
        self.sort()
        # number of objects deleted for each model label
        deleted_counter = Counter()

        # Optimize for the case with a single obj and no dependencies
        if len(self.data) == 1 and len(instances) == 1:
            instance = list(instances)[0]
            if self.can_fast_delete(instance):
                with transaction.mark_for_rollback_on_error(self.using):
                    count = sql.DeleteQuery(model).delete_batch([instance.pk],
                                                                self.using)
                setattr(instance, model._meta.pk.attname, None)
                return count, {model._meta.label: count}

        with transaction.atomic(using=self.using, savepoint=False):
            # send pre_delete signals
            for model, obj in self.instances_with_model():
                if not model._meta.auto_created:
                    signals.pre_delete.send(
                        sender=model,
                        instance=obj,
                        using=self.using,
                        origin=self.origin,
                    )

            # fast deletes
            for qs in self.fast_deletes:
                count = qs._raw_delete(using=self.using)
                if count:
                    deleted_counter[qs.model._meta.label] += count

            # update fields
            for model, instances_for_fieldvalues in self.field_updates.items():
                for (field,
                     value), instances in instances_for_fieldvalues.items():
                    query = sql.UpdateQuery(model)
                    query.update_batch([obj.pk for obj in instances],
                                       {field.name: value}, self.using)

            # reverse instance collections
            for instances in self.data.values():
                instances.reverse()

            # delete instances
            for model, instances in self.data.items():
                query = sql.DeleteQuery(model)
                pk_list = [obj.pk for obj in instances]
                count = query.delete_batch(pk_list, self.using)
                if count:
                    deleted_counter[model._meta.label] += count

                if not model._meta.auto_created:
                    for obj in instances:
                        signals.post_delete.send(
                            sender=model,
                            instance=obj,
                            using=self.using,
                            origin=self.origin,
                        )

        # update collected instances
        for instances_for_fieldvalues in self.field_updates.values():
            for (field, value), instances in instances_for_fieldvalues.items():
                for obj in instances:
                    setattr(obj, field.attname, value)
        for model, instances in self.data.items():
            for instance in instances:
                setattr(instance, model._meta.pk.attname, None)
        return sum(deleted_counter.values()), dict(deleted_counter)
Example #10
0
    def delete(self):
        """
        Patched the BaseCollector.delete with soft delete support for PermanentModel
        """
        from .models import PermanentModel
        time = now()

        # sort instance collections
        for model, instances in self.data.items():
            self.data[model] = sorted(instances, key=attrgetter("pk"))

        # if possible, bring the models in an order suitable for databases that
        # don't support transactions or cannot defer constraint checks until the
        # end of a transaction.
        self.sort()

        with transaction.atomic(using=self.using, savepoint=False):
            # send pre_delete signals
            for model, obj in self.instances_with_model():
                if not model._meta.auto_created:
                    signals.pre_delete.send(sender=model,
                                            instance=obj,
                                            using=self.using)

            # fast deletes
            for qs in self.fast_deletes:
                if issubclass(
                        qs.model,
                        PermanentModel):  # Update PermanentModel instance
                    pk_list = [obj.pk for obj in qs]
                    qs = sql.UpdateQuery(qs.model)
                    qs.update_batch(pk_list, {settings.FIELD: time},
                                    self.using)
                else:
                    qs._raw_delete(using=self.using)

            # update fields
            for model, instances_for_fieldvalues in six.iteritems(
                    self.field_updates):
                query = sql.UpdateQuery(model)
                for (field, value
                     ), instances in six.iteritems(instances_for_fieldvalues):
                    query.update_batch([obj.pk for obj in instances],
                                       {field.name: value}, self.using)

            # reverse instance collections
            for instances in six.itervalues(self.data):
                instances.reverse()

            # delete instances
            for model, instances in six.iteritems(self.data):
                pk_list = [obj.pk for obj in instances]
                if issubclass(model, PermanentModel):
                    query = sql.UpdateQuery(model)
                    query.update_batch(pk_list, {settings.FIELD: time},
                                       self.using)
                else:
                    query = sql.DeleteQuery(model)
                    query.delete_batch(pk_list, self.using)

                if not model._meta.auto_created:
                    for obj in instances:
                        signals.post_delete.send(sender=model,
                                                 instance=obj,
                                                 using=self.using)

        # update collected instances
        for model, instances_for_fieldvalues in six.iteritems(
                self.field_updates):
            for (field,
                 value), instances in six.iteritems(instances_for_fieldvalues):
                for obj in instances:
                    setattr(obj, field.attname, value)
        for model, instances in six.iteritems(self.data):
            for instance in instances:
                if issubclass(model, PermanentModel):
                    continue
                setattr(instance, model._meta.pk.attname, None)
Example #11
0
    def delete(self, using=None, keep_parents=False, **kwargs):
        """
        Mark this instance as deleted and call `delete()` on all related objects.

        Don’t call `super`!
        """
        logger.info('DELETE %s' % self)
        self.deleted = True
        self.save(**kwargs)

        # the following is copied from django.db.models.base.Model

        using = using or router.db_for_write(self.__class__, instance=self)
        assert self._get_pk_val() is not None, (
            "%s object can't be deleted because its %s attribute is set to None."
            % (self._meta.object_name, self._meta.pk.attname))

        # Find all the related objects that need to be deleted.
        collector = Collector(using=using)
        collector.collect([self], keep_parents=keep_parents)
        #return collector.delete()

        # remove self from deletion collection
        myself_and_friends = collector.data[type(self)].remove(self)
        if myself_and_friends:
            collector.data[type(self)] = myself_and_friends
        else:
            del collector.data[type(self)]

        # Problem: collector.delete() doesn’t call object’s delete method, but deletes!

        # The following is copied from collector.delete() (db.models.deletion)

        # sort instance collections
        for model, instances in collector.data.items():
            collector.data[model] = sorted(instances, key=attrgetter("pk"))

        # if possible, bring the models in an order suitable for databases that
        # don't support transactions or cannot defer constraint checks until the
        # end of a transaction.
        collector.sort()
        # number of objects deleted for each model label
        deleted_counter = Counter()

        with transaction.atomic(using=collector.using, savepoint=False):
            # send pre_delete signals
            for model, obj in collector.instances_with_model():
                if not model._meta.auto_created:
                    signals.pre_delete.send(sender=model,
                                            instance=obj,
                                            using=collector.using)

            ## fast deletes
            #for qs in collector.fast_deletes:
            #    count = qs._raw_delete(using=collector.using)
            #    deleted_counter[qs.model._meta.label] += count

            # update fields
            for model, instances_for_fieldvalues in six.iteritems(
                    collector.field_updates):
                query = sql.UpdateQuery(model)
                for (field, value
                     ), instances in six.iteritems(instances_for_fieldvalues):
                    query.update_batch([obj.pk for obj in instances],
                                       {field.name: value}, collector.using)

            # reverse instance collections
            for instances in six.itervalues(collector.data):
                instances.reverse()

            # delete instances
            for model, instances in six.iteritems(collector.data):
                if not issubclass(model, DorsaleBaseModel):
                    # handle non-cerebrale models as usual
                    query = sql.DeleteQuery(model)
                    pk_list = [obj.pk for obj in instances]
                    count = query.delete_batch(pk_list, collector.using)
                    deleted_counter[model._meta.label] += count
                else:
                    for inst in instances:
                        inst.delete()  # expensive operation!

                if not model._meta.auto_created:
                    for obj in instances:
                        signals.post_delete.send(sender=model,
                                                 instance=obj,
                                                 using=collector.using)

        # update collected instances
        for model, instances_for_fieldvalues in six.iteritems(
                collector.field_updates):
            for (field,
                 value), instances in six.iteritems(instances_for_fieldvalues):
                for obj in instances:
                    setattr(obj, field.attname, value)
        for model, instances in six.iteritems(collector.data):
            for instance in instances:
                setattr(instance, model._meta.pk.attname, None)
        return sum(deleted_counter.values()), dict(deleted_counter)
def delete(self, force=False):
    """
    Patched the BaseCollector.delete with soft delete support for PermanentModel
    """
    from .models import PermanentModel

    time = now()
    deleted_counter = Counter()

    # sort instance collections
    for model, instances in self.data.items():
        self.data[model] = sorted(instances, key=attrgetter("pk"))

    # if possible, bring the models in an order suitable for databases that
    # don't support transactions or cannot defer constraint checks until the
    # end of a transaction.
    self.sort()
    # number of objects deleted for each model label
    deleted_counter = Counter()

    if DJANGO_VERSION < (1, 8, 0):
        transaction_handling = partial(
            transaction.commit_on_success_unless_managed, using=self.using)
    else:
        transaction_handling = partial(transaction.atomic,
                                       using=self.using,
                                       savepoint=False)

    with transaction_handling():
        # send pre_delete signals
        for model, obj in self.instances_with_model():
            if not model._meta.auto_created:
                signals.pre_delete.send(sender=model,
                                        instance=obj,
                                        using=self.using)

        # fast deletes
        for qs in self.fast_deletes:
            if (issubclass(qs.model, PermanentModel)
                    and not force):  # Update PermanentModel instance
                pk_list = [obj.pk for obj in qs]
                qs = sql.UpdateQuery(qs.model)
                qs.update_batch(pk_list, {FIELD: time}, self.using)
                count = len(pk_list)
            else:
                count = qs._raw_delete(using=self.using)

            if DJANGO_VERSION >= (1, 9, 0):
                deleted_counter[qs.model._meta.label] += count

        # update fields
        for model, instances_for_fieldvalues in six.iteritems(
                self.field_updates):
            query = sql.UpdateQuery(model)
            for (field,
                 value), instances in six.iteritems(instances_for_fieldvalues):
                query.update_batch([obj.pk for obj in instances],
                                   {field.name: value}, self.using)

        # reverse instance collections
        for instances in six.itervalues(self.data):
            instances.reverse()

        # delete instances
        for model, instances in six.iteritems(self.data):
            pk_list = [obj.pk for obj in instances]
            if issubclass(model, PermanentModel) and not force:
                query = sql.UpdateQuery(model)
                query.update_batch(pk_list, {FIELD: time}, self.using)
                for instance in instances:
                    setattr(instance, FIELD, time)
                count = len(pk_list)
            else:
                query = sql.DeleteQuery(model)
                count = query.delete_batch(pk_list, self.using)

            if DJANGO_VERSION >= (1, 9, 0):
                deleted_counter[model._meta.label] += count

            if not model._meta.auto_created:
                for obj in instances:
                    signals.post_delete.send(sender=model,
                                             instance=obj,
                                             using=self.using)

    # update collected instances
    for model, instances_for_fieldvalues in six.iteritems(self.field_updates):
        for (field,
             value), instances in six.iteritems(instances_for_fieldvalues):
            for obj in instances:
                setattr(obj, field.attname, value)
    for model, instances in six.iteritems(self.data):
        for instance in instances:
            if issubclass(model, PermanentModel) and not force:
                continue
            setattr(instance, model._meta.pk.attname, None)

    if DJANGO_VERSION >= (1, 9, 0):
        return sum(deleted_counter.values()), dict(deleted_counter)
Example #13
0
    def delete(self, using=None, *args, **kwargs):
        """
        Mark this instance as deleted and call `delete()` on all related objects.
        
        Don’t call `super`!
        """
        logger.info('DELETE %s' % self)
        self.deleted = True
        self.save(*args, **kwargs)

        # the following is copied from django.db.models.base.Model

        using = using or router.db_for_write(self.__class__, instance=self)
        assert self._get_pk_val(
        ) is not None, "%s object can't be deleted because its %s attribute is set to None." % (
            self._meta.object_name, self._meta.pk.attname)

        # Find all the related objects than need to be deleted.
        collector = Collector(using=using)
        collector.collect([self])
        # remove self from deletion collection
        myself_and_friends = collector.data[type(self)].remove(self)
        if myself_and_friends:
            collector.data[type(self)] = myself_and_friends
        else:
            del collector.data[type(self)]

        # Problem: collector.delete() doesn’t call object’s delete method, but deletes!

        # The following is copied from collector.delete()

        # sort instance collections
        for model, instances in collector.data.items():
            collector.data[model] = sorted(instances, key=attrgetter("pk"))

        # if possible, bring the models in an order suitable for databases that
        # don't support transactions or cannot defer contraint checks until the
        # end of a transaction.
        collector.sort()

        # send pre_delete signals
        for model, obj in collector.instances_with_model():
            if not model._meta.auto_created:
                signals.pre_delete.send(sender=model,
                                        instance=obj,
                                        using=collector.using)

        # update fields
        for model, instances_for_fieldvalues in collector.field_updates.iteritems(
        ):
            query = sql.UpdateQuery(model)
            for (field,
                 value), instances in instances_for_fieldvalues.iteritems():
                query.update_batch([obj.pk for obj in instances],
                                   {field.name: value}, collector.using)

        # reverse instance collections
        for instances in collector.data.itervalues():
            instances.reverse()

        # delete batches
        for model, batches in collector.batches.iteritems():
            if not issubclass(model, CerebraleBaseModel):
                # handle non-cerebrale models as usual
                query = sql.DeleteQuery(model)
                for field, instances in batches.iteritems():
                    query.delete_batch([obj.pk for obj in instances],
                                       collector.using, field)
            else:
                # don’t know what to do
                pass

        # delete instances
        for model, instances in collector.data.iteritems():
            if not issubclass(model, CerebraleBaseModel):
                # handle non-cerebrale models as usual
                query = sql.DeleteQuery(model)
                pk_list = [obj.pk for obj in instances]
                query.delete_batch(pk_list, collector.using)
            else:
                for inst in instances:
                    inst.delete()  # expensive operation!

        # send post_delete signals
        for model, obj in collector.instances_with_model():
            if not model._meta.auto_created:
                signals.post_delete.send(sender=model,
                                         instance=obj,
                                         using=collector.using)

        # update collected instances
        for model, instances_for_fieldvalues in collector.field_updates.iteritems(
        ):
            for (field,
                 value), instances in instances_for_fieldvalues.iteritems():
                for obj in instances:
                    setattr(obj, field.attname, value)
        for model, instances in collector.data.iteritems():
            for instance in instances:
                setattr(instance, model._meta.pk.attname, None)
def Collector__delete(self):
    # NOTE: Original Django code. Only changes are marked as ADDED.

    # sort instance collections
    for model, instances in self.data.items():
        self.data[model] = sorted(instances, key=attrgetter("pk"))

    # if possible, bring the models in an order suitable for databases that
    # don't support transactions or cannot defer constraint checks until the
    # end of a transaction.
    self.sort()
    # number of objects deleted for each model label
    deleted_counter = Counter()

    with transaction.atomic(using=self.using, savepoint=False):
        # ADDED: Chunk deletion of larger amounts of related objects (+6 lines)
        for obj_queryset in self.chunk_deletes:
            exists = True
            while exists:
                values_list = obj_queryset.values_list('pk', flat=True)[:DELETION_MAX_CHUNK]
                obj_queryset.model.objects.filter(pk__in=values_list).delete()
                exists = obj_queryset.exists()

        # send pre_delete signals
        for model, obj in self.instances_with_model():
            if not model._meta.auto_created:
                signals.pre_delete.send(
                    sender=model, instance=obj, using=self.using
                )

        # fast deletes
        for qs in self.fast_deletes:
            count = qs._raw_delete(using=self.using)
            deleted_counter[qs.model._meta.label] += count

        # update fields
        for model, instances_for_fieldvalues in self.field_updates.items():
            for (field, value), instances in instances_for_fieldvalues.items():
                query = sql.UpdateQuery(model)
                query.update_batch([obj.pk for obj in instances],
                                   {field.name: value}, self.using)

        # reverse instance collections
        for instances in self.data.values():
            instances.reverse()

        # delete instances
        for model, instances in self.data.items():
            query = sql.DeleteQuery(model)
            pk_list = [obj.pk for obj in instances]
            count = query.delete_batch(pk_list, self.using)
            deleted_counter[model._meta.label] += count

            if not model._meta.auto_created:
                for obj in instances:
                    signals.post_delete.send(
                        sender=model, instance=obj, using=self.using
                    )

    # update collected instances
    for model, instances_for_fieldvalues in self.field_updates.items():
        for (field, value), instances in instances_for_fieldvalues.items():
            for obj in instances:
                setattr(obj, field.attname, value)
    for model, instances in self.data.items():
        for instance in instances:
            setattr(instance, model._meta.pk.attname, None)
    return sum(deleted_counter.values()), dict(deleted_counter)
Example #15
0
    def delete(self, schema):
        if schema == None:  # add schema
            import inspect
            fx = inspect.stack()
            error_detail = ""
            for x in fx:
                error_detail += "\n\t {0}, line {1}".format(fx[1], fx[2])
            raise (Exception(
                "can not call ''{1}'' without schema in '{0}'.\nDetail:\n{2}".
                format(__file__, "Collector.delete", error_detail)))

        # sort instance collections
        for model, instances in self.data.items():
            self.data[model] = sorted(instances, key=attrgetter("pk"))

        # if possible, bring the models in an order suitable for databases that
        # don't support transactions or cannot defer constraint checks until the
        # end of a transaction.
        self.sort()

        with transaction.commit_on_success_unless_managed(using=self.using):
            # send pre_delete signals
            for model, obj in self.instances_with_model():
                if not model._meta.auto_created:
                    signals.pre_delete.send(sender=model,
                                            instance=obj,
                                            using=self.using,
                                            schema=schema)

            # fast deletes
            for qs in self.fast_deletes:
                qs._raw_delete(using=self.using)

            # update fields
            for model, instances_for_fieldvalues in six.iteritems(
                    self.field_updates):
                query = sql.UpdateQuery(model)
                for (field, value
                     ), instances in six.iteritems(instances_for_fieldvalues):
                    query.update_batch([obj.pk for obj in instances],
                                       {field.name: value}, self.using)

            # reverse instance collections
            for instances in six.itervalues(self.data):
                instances.reverse()

            # delete instances
            for model, instances in six.iteritems(self.data):
                query = sql.DeleteQuery(model)
                pk_list = [obj.pk for obj in instances]
                query.delete_batch(pk_list, self.using, schema=schema)

                if not model._meta.auto_created:
                    for obj in instances:
                        signals.post_delete.send(sender=model,
                                                 instance=obj,
                                                 using=self.using,
                                                 schema=schema)

        # update collected instances
        for model, instances_for_fieldvalues in six.iteritems(
                self.field_updates):
            for (field,
                 value), instances in six.iteritems(instances_for_fieldvalues):
                for obj in instances:
                    setattr(obj, field.attname, value)
        for model, instances in six.iteritems(self.data):
            for instance in instances:
                setattr(instance, model._meta.pk.attname, None)
Example #16
0
    def delete(self):
        """ deletion for versioned objects means setting the 'ends_at' field
        to the current datetime. Applied only for active versions, having
        ends_at=NULL """
        now = timezone.now()

        # sort instance collections
        for model, instances in self.data.items():
            self.data[model] = sorted(instances, key=attrgetter("pk"))

        # if possible, bring the models in an order suitable for databases that
        # don't support transactions or cannot defer constraint checks until the
        # end of a transaction.
        self.sort()

        with transaction.commit_on_success_unless_managed(using=self.using):
            # send pre_delete signals
            for model, obj in self.instances_with_model():
                if not model._meta.auto_created:
                    signals.pre_delete.send(sender=model,
                                            instance=obj,
                                            using=self.using)

            # fast deletes - TODO check works correctly with versioned rels
            for qs in self.fast_deletes:
                query = sql.UpdateQuery(qs.model)
                pk_list = [obj.pk for obj in qs.all()]
                query.update_batch(pk_list, {'ends_at': now}, self.using)

            # update fields - TODO check works correctly with versioned rels
            for model, instances_for_fieldvalues in six.iteritems(
                    self.field_updates):
                for (field, value
                     ), instances in six.iteritems(instances_for_fieldvalues):
                    for o in instances:  # update FK fields
                        setattr(o, field.name, value)
                    model.objects.bulk_create(instances)

            # reverse instance collections
            for instances in six.itervalues(self.data):
                instances.reverse()

            # delete instances by setting 'ends_at' to 'now'
            for model, instances in six.iteritems(self.data):
                query = sql.UpdateQuery(model)
                pk_list = [obj.pk for obj in instances]
                query.update_batch(pk_list, {'ends_at': now}, self.using)

                if not model._meta.auto_created:
                    for obj in instances:
                        signals.post_delete.send(sender=model,
                                                 instance=obj,
                                                 using=self.using)

        # update collected instances
        for model, instances_for_fieldvalues in six.iteritems(
                self.field_updates):
            for (field,
                 value), instances in six.iteritems(instances_for_fieldvalues):
                for obj in instances:
                    setattr(obj, field.attname, value)
        for model, instances in six.iteritems(self.data):
            for instance in instances:
                setattr(instance, model._meta.pk.attname, None)