Ticket #10262: delete_cascade_option_with_tests_r9834.diff
File delete_cascade_option_with_tests_r9834.diff, 7.1 KB (added by , 16 years ago) |
---|
-
tests/modeltests/delete/models.py
40 40 class F(DefaultRepr, models.Model): 41 41 e = models.ForeignKey(E, related_name='f_rel') 42 42 43 # Standard many to one and one to one relation, with no delete cascade behaviour 44 class G(DefaultRepr, models.Model): 45 pass 43 46 47 class H(DefaultRepr, models.Model): 48 g = models.ForeignKey(G, null=True, delete_cascade=False) 49 50 class I(DefaultRepr, models.Model): 51 h = models.OneToOneField(H, null=True, delete_cascade=False) 52 44 53 __test__ = {'API_TESTS': """ 45 54 ### Tests for models A,B,C,D ### 46 55 … … 186 195 187 196 >>> f2.delete() 188 197 198 # Testing non delete cascade behaviour. 199 200 >>> g1 = G() 201 >>> g1.save() 202 >>> h1 = H(g=g1) 203 >>> h1.save() 204 >>> g1.delete() 205 >>> H.objects.count() 206 1 207 208 >>> i = I(h=h1) 209 >>> i.save() 210 >>> h1.delete() 211 >>> I.objects.count() 212 1 213 189 214 """ 190 215 } -
django/db/models/base.py
11 11 import django.db.models.manager # Imported to register signal handler. 12 12 from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, FieldError 13 13 from django.db.models.fields import AutoField, FieldDoesNotExist 14 from django.db.models.fields.related import OneToOneRel, ManyToOneRel, OneToOneField 14 from django.db.models.fields.related import OneToOneRel, ManyToOneRel, OneToOneField, RelatedObject 15 15 from django.db.models.query import delete_objects, Q, CollectedObjects 16 16 from django.db.models.options import Options 17 17 from django.db import connection, transaction, DatabaseError … … 456 456 def delete(self): 457 457 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) 458 458 459 # Clear all related objects with no delete cascade relation behaviour 460 related_objects_updated = False 461 for field in self._meta.get_all_fields(): 462 if isinstance(field, RelatedObject) and \ 463 isinstance(field.field.rel, ManyToOneRel) and \ 464 not field.field.rel.delete_cascade: 465 if isinstance(field.field.rel, OneToOneRel): 466 try: 467 rel_obj = getattr(self, field.get_accessor_name()) 468 setattr(rel_obj, field.field.name, None) 469 rel_obj.save() 470 except ObjectDoesNotExist: 471 pass # nothing to do 472 else: # ManyToOneRel 473 related_manager = getattr(self, field.get_accessor_name()) 474 related_manager.clear() 475 related_objects_updated = True 476 if related_objects_updated: 477 # we ensure that refill related object cache 478 del self._meta._related_objects_cache 479 459 480 # Find all the objects than need to be deleted. 460 481 seen_objs = CollectedObjects() 461 482 self._collect_sub_objects(seen_objs) -
django/db/models/options.py
283 283 raise FieldDoesNotExist('%s has no field named %r' 284 284 % (self.object_name, name)) 285 285 286 def get_all_fields(self): 287 """ 288 Returns a list of all fields that are possible for this model 289 (including reverse relation names). 290 """ 291 try: 292 cache = self._name_map 293 except AttributeError: 294 cache = self.init_name_map() 295 fields = [ r[0] for r in cache.values() ] 296 return fields 297 286 298 def get_all_field_names(self): 287 299 """ 288 300 Returns a list of all field names that are possible for this model -
django/db/models/fields/related.py
583 583 manager.add(*value) 584 584 585 585 class ManyToOneRel(object): 586 def __init__(self, to, field_name, related_name=None, 587 l imit_choices_to=None, lookup_overrides=None, parent_link=False):586 def __init__(self, to, field_name, related_name=None, limit_choices_to=None, 587 lookup_overrides=None, parent_link=False, delete_cascade=True): 588 588 try: 589 589 to._meta 590 590 except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT … … 597 597 self.lookup_overrides = lookup_overrides or {} 598 598 self.multiple = True 599 599 self.parent_link = parent_link 600 self.delete_cascade = delete_cascade 600 601 601 602 def get_related_field(self): 602 603 """ … … 610 611 return data[0] 611 612 612 613 class OneToOneRel(ManyToOneRel): 613 def __init__(self, to, field_name, related_name=None, 614 l imit_choices_to=None, lookup_overrides=None, parent_link=False):614 def __init__(self, to, field_name, related_name=None, limit_choices_to=None, 615 lookup_overrides=None, parent_link=False, delete_cascade=True): 615 616 super(OneToOneRel, self).__init__(to, field_name, 616 617 related_name=related_name, limit_choices_to=limit_choices_to, 617 lookup_overrides=lookup_overrides, parent_link=parent_link) 618 lookup_overrides=lookup_overrides, parent_link=parent_link, 619 delete_cascade=delete_cascade) 618 620 self.multiple = False 619 621 620 622 class ManyToManyRel(object): … … 645 647 related_name=kwargs.pop('related_name', None), 646 648 limit_choices_to=kwargs.pop('limit_choices_to', None), 647 649 lookup_overrides=kwargs.pop('lookup_overrides', None), 648 parent_link=kwargs.pop('parent_link', False)) 650 parent_link=kwargs.pop('parent_link', False), 651 delete_cascade=kwargs.pop('delete_cascade', True)) 652 649 653 Field.__init__(self, **kwargs) 650 654 651 655 self.db_index = True 656 assert self.null or self.rel.delete_cascade, "%s cannot define a not null relation (null=False) without deleting cascade (delete_cascade=False)" % self.__class__.__name__ 652 657 653 658 def get_attname(self): 654 659 return '%s_id' % self.name -
django/contrib/admin/util.py
71 71 if related.opts in opts_seen: 72 72 continue 73 73 opts_seen.append(related.opts) 74 if not related.field.rel.delete_cascade: 75 # Avoid deleting objects without a delete cascade relation 76 continue 74 77 rel_opts_name = related.get_accessor_name() 78 75 79 if isinstance(related.field.rel, models.OneToOneRel): 76 80 try: 77 81 sub_obj = getattr(obj, rel_opts_name)