Ticket #1007: restrict_delete-0.95.1.diff

File restrict_delete-0.95.1.diff, 3.7 KB (added by Jeff Forcier <reg@…>, 17 years ago)

Patch updated (redone, really) for 0.95.1

  • db/models/options.py

     
    1313
    1414DEFAULT_NAMES = ('verbose_name', 'db_table', 'ordering',
    1515                 'unique_together', 'permissions', 'get_latest_by',
    16                  'order_with_respect_to', 'app_label')
     16                 'order_with_respect_to', 'app_label', 'restrict_delete')
    1717
    1818class Options(object):
    1919    def __init__(self, meta):
     
    3333        self.has_auto_field = False
    3434        self.one_to_one_field = None
    3535        self.parents = []
     36        self.restrict_delete = False
    3637
    3738    def contribute_to_class(self, cls, name):
    3839        cls._meta = self
  • db/models/base.py

     
    11import django.db.models.manipulators
    22import django.db.models.manager
    33from django.core import validators
    4 from django.core.exceptions import ObjectDoesNotExist
     4from django.core.exceptions import ObjectDoesNotExist, IntegrityError
    55from django.db.models.fields import AutoField, ImageField, FieldDoesNotExist
    66from django.db.models.fields.related import OneToOneRel, ManyToOneRel
    77from django.db.models.query import delete_objects
     
    238238                error_dict[f.name] = errors
    239239        return error_dict
    240240
    241     def _collect_sub_objects(self, seen_objs):
     241    def _collect_sub_objects(self, seen_objs, restrict_delete=False):
    242242        """
    243243        Recursively populates seen_objs with all objects related to this object.
    244244        When done, seen_objs will be in the format:
     
    250250            return
    251251        seen_objs.setdefault(self.__class__, {})[pk_val] = self
    252252
    253         for related in self._meta.get_all_related_objects():
     253        has_nonfollows = False
     254        for related in self._meta.get_all_related_objects():
    254255            rel_opts_name = related.get_accessor_name()
    255256            if isinstance(related.field.rel, OneToOneRel):
    256257                try:
     
    258259                except ObjectDoesNotExist:
    259260                    pass
    260261                else:
     262                    # If the item in question isn't from a 'followed' field, don't continue - this should trigger RESTRICT.
     263                    if restrict_delete and not related.get_follow():
     264                        has_nonfollows = True
     265                        break
    261266                    sub_obj._collect_sub_objects(seen_objs)
    262267            else:
     268                # If we find a count for this relation and the field is not a 'followed' one, trigger RESTRICT.
     269                if restrict_delete and not related.get_follow() and getattr(self,rel_opts_name).count():
     270                    has_nonfollows=True
     271                    break
    263272                for sub_obj in getattr(self, rel_opts_name).all():
    264273                    sub_obj._collect_sub_objects(seen_objs)
    265274
     275        # This will only be true if restrict_delete is True and we found related non-followed objects
     276        if has_nonfollows:
     277            raise IntegrityError, "The requested object could not be deleted because it is referenced by other objects."
     278
     279
    266280    def delete(self):
    267281        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)
    268282
    269283        # Find all the objects than need to be deleted
    270284        seen_objs = SortedDict()
    271         self._collect_sub_objects(seen_objs)
     285        self._collect_sub_objects(seen_objs,self._meta.restrict_delete)
    272286
    273287        # Actually delete the objects
    274288        delete_objects(seen_objs)
Back to Top