Ticket #12025: t12025_r11366.4.patch

File t12025_r11366.4.patch, 9.7 KB (added by anonymous, 5 years ago)

add delete confirmation for top (deleted) obj

  • django/db/models/options.py

     
    412412                    cache[obj] = parent
    413413                else:
    414414                    cache[obj] = model
     415        from django.contrib.contenttypes import generic
    415416        for klass in get_models():
    416417            for f in klass._meta.local_many_to_many:
    417                 if f.rel and not isinstance(f.rel.to, str) and self == f.rel.to._meta:
     418                if f.rel and isinstance(f, generic.GenericRelation) and self == klass._meta:
     419                    cache[RelatedObject(klass, f.rel.to, f)] = None
     420                elif f.rel and not isinstance(f.rel.to, str) and self == f.rel.to._meta:
    418421                    cache[RelatedObject(f.rel.to, klass, f)] = None
    419422        if app_cache_ready():
    420423            self._related_many_to_many_cache = cache
  • django/contrib/admin/util.py

     
    7171    except NoReverseMatch:
    7272        return '%s%s/%s/%s/' % ('../'*levels_to_root, app_label, module_name, pk)
    7373
    74 def get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current_depth, admin_site, levels_to_root=4):
     74def get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current_depth, admin_site, levels_to_root=4, objs_seen=[]):
    7575    """
    7676    Helper function that recursively populates deleted_objects.
    7777
     
    8686    if current_depth > 16:
    8787        return # Avoid recursing too deep.
    8888    opts_seen = []
     89    if current_depth == 1:
     90        objs_seen = [] # avoid to have the older objs_seen
     91        if obj.__class__ in admin_site._registry and \
     92            hasattr(admin_site._registry[obj.__class__], 'get_delete_confirmation_message'):
     93            # Display a link to the admin page but use an admin function in order to change the message, obj and link
     94            result_msg = admin_site._registry[obj.__class__].get_delete_confirmation_message(
     95                obj, deleted_objects[0], obj, admin_site, levels_to_root)
     96        if result_msg:
     97            deleted_objects[0] = mark_safe(result_msg)
    8998    for related in opts.get_all_related_objects():
    9099        has_admin = related.model in admin_site._registry
    91         if related.opts in opts_seen:
     100        rel_opts_name = related.get_accessor_name()
     101        if rel_opts_name in opts_seen:
    92102            continue
    93         opts_seen.append(related.opts)
    94         rel_opts_name = related.get_accessor_name()
     103        opts_seen.append(rel_opts_name)
    95104        if isinstance(related.field.rel, models.OneToOneRel):
    96105            try:
    97106                sub_obj = getattr(obj, rel_opts_name)
    98107            except ObjectDoesNotExist:
    99108                pass
    100109            else:
     110                if sub_obj in objs_seen:
     111                    continue # avoid to have the same object
     112                objs_seen.append(sub_obj)
    101113                if has_admin:
    102114                    p = '%s.%s' % (related.opts.app_label, related.opts.get_delete_permission())
    103115                    if not user.has_perm(p):
     
    109121                    # admin or is edited inline.
    110122                    nh(deleted_objects, current_depth,
    111123                        [u'%s: %s' % (capfirst(related.opts.verbose_name), force_unicode(sub_obj)), []])
     124                elif has_admin and hasattr(admin_site._registry[related.model], 'get_delete_confirmation_message'):
     125                    # Display a link to the admin page but use an admin function in order to change the message, obj and link
     126                    result_msg = admin_site._registry[related.model].get_delete_confirmation_message(
     127                        obj, u'%s:' % capfirst(related.opts.verbose_name), sub_obj, admin_site, levels_to_root)
     128                    if not result_msg:
     129                        objs_seen.remove(sub_obj) # in order to repeat this obj in other relation
     130                        continue
     131                    nh(deleted_objects, current_depth, [mark_safe(result_msg), []])
    112132                else:
    113133                    # Display a link to the admin page.
    114134                    nh(deleted_objects, current_depth, [mark_safe(u'%s: <a href="%s">%s</a>' %
     
    119139                                            admin_site,
    120140                                            levels_to_root),
    121141                        escape(sub_obj))), []])
    122                 get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2, admin_site)
     142                get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2, admin_site, objs_seen=objs_seen)
    123143        else:
    124144            has_related_objs = False
    125145            for sub_obj in getattr(obj, rel_opts_name).all():
     146                if sub_obj in objs_seen:
     147                    continue # avoid to have the same object
     148                objs_seen.append(sub_obj)
    126149                has_related_objs = True
    127150                if not has_admin:
    128151                    # Don't display link to edit, because it either has no
    129152                    # admin or is edited inline.
    130153                    nh(deleted_objects, current_depth,
    131154                        [u'%s: %s' % (capfirst(related.opts.verbose_name), force_unicode(sub_obj)), []])
     155                elif has_admin and hasattr(admin_site._registry[related.model], 'get_delete_confirmation_message'):
     156                    # Display a link to the admin page but use an admin function in order to change the message, obj and link
     157                    result_msg = admin_site._registry[related.model].get_delete_confirmation_message(
     158                        obj, u'%s:' % capfirst(related.opts.verbose_name), sub_obj, admin_site, levels_to_root)
     159                    if not result_msg:
     160                        objs_seen.remove(sub_obj) # in order to repeat this obj in other relation
     161                        continue
     162                    nh(deleted_objects, current_depth, [mark_safe(result_msg), []])
    132163                else:
    133164                    # Display a link to the admin page.
    134165                    nh(deleted_objects, current_depth, [mark_safe(u'%s: <a href="%s">%s</a>' %
     
    139170                                            admin_site,
    140171                                            levels_to_root),
    141172                        escape(sub_obj))), []])
    142                 get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2, admin_site)
     173                get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2, admin_site, objs_seen=objs_seen)
    143174            # If there were related objects, and the user doesn't have
    144175            # permission to delete them, add the missing perm to perms_needed.
    145176            if has_admin and has_related_objs:
    146177                p = '%s.%s' % (related.opts.app_label, related.opts.get_delete_permission())
    147178                if not user.has_perm(p):
    148179                    perms_needed.add(related.opts.verbose_name)
     180    from django.contrib.contenttypes import generic
    149181    for related in opts.get_all_related_many_to_many_objects():
    150182        has_admin = related.model in admin_site._registry
    151         if related.opts in opts_seen:
     183        rel_opts_name = related.get_accessor_name()
     184        if rel_opts_name in opts_seen:
    152185            continue
    153         opts_seen.append(related.opts)
    154         rel_opts_name = related.get_accessor_name()
     186        opts_seen.append(rel_opts_name)
    155187        has_related_objs = False
    156188
    157189        # related.get_accessor_name() could return None for symmetrical relationships
    158190        if rel_opts_name:
    159             rel_objs = getattr(obj, rel_opts_name, None)
     191            rel_objs = getattr(obj, rel_opts_name, None) or \
     192                (isinstance(related.field, generic.GenericRelation) and getattr(obj, related.field.verbose_name, None))               
    160193            if rel_objs:
    161194                has_related_objs = True
    162195
    163196        if has_related_objs:
    164197            for sub_obj in rel_objs.all():
     198                if sub_obj in objs_seen:
     199                    continue # avoid to have the same object
     200                objs_seen.append(sub_obj)
    165201                if not has_admin:
    166202                    # Don't display link to edit, because it either has no
    167203                    # admin or is edited inline.
    168204                    nh(deleted_objects, current_depth, [_('One or more %(fieldname)s in %(name)s: %(obj)s') % \
    169205                        {'fieldname': force_unicode(related.field.verbose_name), 'name': force_unicode(related.opts.verbose_name), 'obj': escape(sub_obj)}, []])
     206                elif has_admin and hasattr(admin_site._registry[related.model], 'get_delete_confirmation_message'):
     207                    # Display a link to the admin page but use an admin function in order to change the message, obj and link
     208                    result_msg = admin_site._registry[related.model].get_delete_confirmation_message(
     209                        obj, (_('One or more %(fieldname)s in %(name)s:') % \
     210                            {'fieldname': escape(force_unicode(related.field.verbose_name)), 'name': escape(force_unicode(related.opts.verbose_name))}),
     211                        sub_obj, admin_site, levels_to_root)
     212                    if not result_msg:
     213                        objs_seen.remove(sub_obj) # in order to repeat this obj in other relation
     214                        continue
     215                    nh(deleted_objects, current_depth, [mark_safe(result_msg), []])
    170216                else:
    171217                    # Display a link to the admin page.
    172218                    nh(deleted_objects, current_depth, [
Back to Top