Ticket #12025: t12025_r11366.4.patch
File t12025_r11366.4.patch, 9.7 KB (added by , 15 years ago) |
---|
-
django/db/models/options.py
412 412 cache[obj] = parent 413 413 else: 414 414 cache[obj] = model 415 from django.contrib.contenttypes import generic 415 416 for klass in get_models(): 416 417 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: 418 421 cache[RelatedObject(f.rel.to, klass, f)] = None 419 422 if app_cache_ready(): 420 423 self._related_many_to_many_cache = cache -
django/contrib/admin/util.py
71 71 except NoReverseMatch: 72 72 return '%s%s/%s/%s/' % ('../'*levels_to_root, app_label, module_name, pk) 73 73 74 def get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current_depth, admin_site, levels_to_root=4 ):74 def get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current_depth, admin_site, levels_to_root=4, objs_seen=[]): 75 75 """ 76 76 Helper function that recursively populates deleted_objects. 77 77 … … 86 86 if current_depth > 16: 87 87 return # Avoid recursing too deep. 88 88 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) 89 98 for related in opts.get_all_related_objects(): 90 99 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: 92 102 continue 93 opts_seen.append(related.opts) 94 rel_opts_name = related.get_accessor_name() 103 opts_seen.append(rel_opts_name) 95 104 if isinstance(related.field.rel, models.OneToOneRel): 96 105 try: 97 106 sub_obj = getattr(obj, rel_opts_name) 98 107 except ObjectDoesNotExist: 99 108 pass 100 109 else: 110 if sub_obj in objs_seen: 111 continue # avoid to have the same object 112 objs_seen.append(sub_obj) 101 113 if has_admin: 102 114 p = '%s.%s' % (related.opts.app_label, related.opts.get_delete_permission()) 103 115 if not user.has_perm(p): … … 109 121 # admin or is edited inline. 110 122 nh(deleted_objects, current_depth, 111 123 [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), []]) 112 132 else: 113 133 # Display a link to the admin page. 114 134 nh(deleted_objects, current_depth, [mark_safe(u'%s: <a href="%s">%s</a>' % … … 119 139 admin_site, 120 140 levels_to_root), 121 141 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) 123 143 else: 124 144 has_related_objs = False 125 145 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) 126 149 has_related_objs = True 127 150 if not has_admin: 128 151 # Don't display link to edit, because it either has no 129 152 # admin or is edited inline. 130 153 nh(deleted_objects, current_depth, 131 154 [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), []]) 132 163 else: 133 164 # Display a link to the admin page. 134 165 nh(deleted_objects, current_depth, [mark_safe(u'%s: <a href="%s">%s</a>' % … … 139 170 admin_site, 140 171 levels_to_root), 141 172 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) 143 174 # If there were related objects, and the user doesn't have 144 175 # permission to delete them, add the missing perm to perms_needed. 145 176 if has_admin and has_related_objs: 146 177 p = '%s.%s' % (related.opts.app_label, related.opts.get_delete_permission()) 147 178 if not user.has_perm(p): 148 179 perms_needed.add(related.opts.verbose_name) 180 from django.contrib.contenttypes import generic 149 181 for related in opts.get_all_related_many_to_many_objects(): 150 182 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: 152 185 continue 153 opts_seen.append(related.opts) 154 rel_opts_name = related.get_accessor_name() 186 opts_seen.append(rel_opts_name) 155 187 has_related_objs = False 156 188 157 189 # related.get_accessor_name() could return None for symmetrical relationships 158 190 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)) 160 193 if rel_objs: 161 194 has_related_objs = True 162 195 163 196 if has_related_objs: 164 197 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) 165 201 if not has_admin: 166 202 # Don't display link to edit, because it either has no 167 203 # admin or is edited inline. 168 204 nh(deleted_objects, current_depth, [_('One or more %(fieldname)s in %(name)s: %(obj)s') % \ 169 205 {'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), []]) 170 216 else: 171 217 # Display a link to the admin page. 172 218 nh(deleted_objects, current_depth, [