Ticket #1007: restrict_delete.diff

File restrict_delete.diff, 6.2 KB (added by Jeff Forcier, 18 years ago)
  • core/meta/__init__.py

     
    287287        fields=None, ordering=None, unique_together=None, admin=None, has_related_links=False,
    288288        where_constraints=None, object_name=None, app_label=None,
    289289        exceptions=None, permissions=None, get_latest_by=None,
    290         order_with_respect_to=None, module_constants=None):
     290        order_with_respect_to=None, module_constants=None,restrict_delete=False):
    291291
    292292        # Save the original function args, for use by copy(). Note that we're
    293293        # NOT using copy.deepcopy(), because that would create a new copy of
     
    332332            self.order_with_respect_to = None
    333333        self.module_constants = module_constants or {}
    334334        self.admin = admin
     335        self.restrict_delete = restrict_delete
    335336
    336337        # Calculate one_to_one_field.
    337338        self.one_to_one_field = None
     
    600601                get_latest_by = meta_attrs.pop('get_latest_by', None),
    601602                order_with_respect_to = meta_attrs.pop('order_with_respect_to', None),
    602603                module_constants = meta_attrs.pop('module_constants', None),
     604                restrict_delete = meta_attrs.pop('restrict_delete', False),
    603605            )
    604606
    605607        if meta_attrs != {}:
     
    954956
    955957def method_delete(opts, self):
    956958    assert getattr(self, opts.pk.attname) is not None, "%r can't be deleted because it doesn't have an ID."
    957     # Run any pre-delete hooks.
    958     if hasattr(self, '_pre_delete'):
    959         self._pre_delete()
    960     cursor = db.db.cursor()
    961     for related in opts.get_all_related_objects():
     959    rels = set(opts.get_all_related_objects()).union(set(opts.get_all_related_many_to_many_objects())).difference(set(opts.get_followed_related_objects()))
     960    has_nonfollows = False
     961    for related in rels:
    962962        rel_opts_name = related.get_method_name_part()
    963963        if isinstance(related.field.rel, OneToOne):
    964964            try:
     
    966966            except ObjectDoesNotExist:
    967967                pass
    968968            else:
    969                 sub_obj.delete()
     969                has_nonfollows= True
     970                break
    970971        else:
    971             for sub_obj in getattr(self, 'get_%s_list' % rel_opts_name)():
    972                 sub_obj.delete()
    973     for related in opts.get_all_related_many_to_many_objects():
     972            if getattr(self, 'get_%s_count' % related.get_method_name_part())():
     973                has_nonfollows= True
     974                break
     975
     976    if has_nonfollows and self._meta.restrict_delete:
     977        raise AssertionError, "Delete restricted - other objects depend upon this object and are not set to 'follow' (or don't have 'edit_inline' specified)."
     978    else:
     979        # Run any pre-delete hooks.
     980        if hasattr(self, '_pre_delete'):
     981            self._pre_delete()
     982        cursor = db.db.cursor()
     983        for related in opts.get_all_related_objects():
     984            rel_opts_name = related.get_method_name_part()
     985            if isinstance(related.field.rel, OneToOne):
     986                try:
     987                    sub_obj = getattr(self, 'get_%s' % rel_opts_name)()
     988                except ObjectDoesNotExist:
     989                    pass
     990                else:
     991                    sub_obj.delete()
     992            else:
     993                for sub_obj in getattr(self, 'get_%s_list' % rel_opts_name)():
     994                    sub_obj.delete()
     995        for related in opts.get_all_related_many_to_many_objects():
     996            cursor.execute("DELETE FROM %s WHERE %s=%%s" % \
     997                (db.db.quote_name(related.field.get_m2m_db_table(related.opts)),
     998                db.db.quote_name(self._meta.object_name.lower() + '_id')), [getattr(self, opts.pk.attname)])
     999        for f in opts.many_to_many:
     1000            cursor.execute("DELETE FROM %s WHERE %s=%%s" % \
     1001                (db.db.quote_name(f.get_m2m_db_table(opts)),
     1002                db.db.quote_name(self._meta.object_name.lower() + '_id')),
     1003                [getattr(self, opts.pk.attname)])
    9741004        cursor.execute("DELETE FROM %s WHERE %s=%%s" % \
    975             (db.db.quote_name(related.field.get_m2m_db_table(related.opts)),
    976             db.db.quote_name(self._meta.object_name.lower() + '_id')), [getattr(self, opts.pk.attname)])
    977     for f in opts.many_to_many:
    978         cursor.execute("DELETE FROM %s WHERE %s=%%s" % \
    979             (db.db.quote_name(f.get_m2m_db_table(opts)),
    980             db.db.quote_name(self._meta.object_name.lower() + '_id')),
     1005            (db.db.quote_name(opts.db_table), db.db.quote_name(opts.pk.column)),
    9811006            [getattr(self, opts.pk.attname)])
    982     cursor.execute("DELETE FROM %s WHERE %s=%%s" % \
    983         (db.db.quote_name(opts.db_table), db.db.quote_name(opts.pk.column)),
    984         [getattr(self, opts.pk.attname)])
    985     db.db.commit()
    986     setattr(self, opts.pk.attname, None)
    987     for f in opts.fields:
    988         if isinstance(f, FileField) and getattr(self, f.attname):
    989             file_name = getattr(self, 'get_%s_filename' % f.name)()
    990             # If the file exists and no other object of this type references it,
    991             # delete it from the filesystem.
    992             if os.path.exists(file_name) and not opts.get_model_module().get_list(**{'%s__exact' % f.name: getattr(self, f.name)}):
    993                 os.remove(file_name)
    994     # Run any post-delete hooks.
    995     if hasattr(self, '_post_delete'):
    996         self._post_delete()
     1007        db.db.commit()
     1008        setattr(self, opts.pk.attname, None)
     1009        for f in opts.fields:
     1010            if isinstance(f, FileField) and getattr(self, f.attname):
     1011                file_name = getattr(self, 'get_%s_filename' % f.name)()
     1012                # If the file exists and no other object of this type references it,
     1013                # delete it from the filesystem.
     1014                if os.path.exists(file_name) and not opts.get_model_module().get_list(**{'%s__exact' % f.name: getattr(self, f.name)}):
     1015                    os.remove(file_name)
     1016        # Run any post-delete hooks.
     1017        if hasattr(self, '_post_delete'):
     1018            self._post_delete()
    9971019
    9981020def method_get_next_in_order(opts, order_field, self):
    9991021    if not hasattr(self, '_next_in_order_cache'):
Back to Top