| 146 | | def _nest_help(obj, depth, val): |
|---|
| 147 | | current = obj |
|---|
| 148 | | for i in range(depth): |
|---|
| 149 | | current = current[-1] |
|---|
| 150 | | current.append(val) |
|---|
| 151 | | |
|---|
| 152 | | def _get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current_depth): |
|---|
| 153 | | "Helper function that recursively populates deleted_objects." |
|---|
| 154 | | nh = _nest_help # Bind to local variable for performance |
|---|
| 155 | | if current_depth > 16: |
|---|
| 156 | | return # Avoid recursing too deep. |
|---|
| 157 | | opts_seen = [] |
|---|
| 158 | | for related in opts.get_all_related_objects(): |
|---|
| 159 | | if related.opts in opts_seen: |
|---|
| 160 | | continue |
|---|
| 161 | | opts_seen.append(related.opts) |
|---|
| 162 | | rel_opts_name = related.get_accessor_name() |
|---|
| 163 | | if isinstance(related.field.rel, models.OneToOneRel): |
|---|
| 164 | | try: |
|---|
| 165 | | sub_obj = getattr(obj, rel_opts_name) |
|---|
| 166 | | except ObjectDoesNotExist: |
|---|
| 167 | | pass |
|---|
| 168 | | else: |
|---|
| 169 | | if related.opts.admin: |
|---|
| 170 | | p = '%s.%s' % (related.opts.app_label, related.opts.get_delete_permission()) |
|---|
| 171 | | if not user.has_perm(p): |
|---|
| 172 | | perms_needed.add(related.opts.verbose_name) |
|---|
| 173 | | # We don't care about populating deleted_objects now. |
|---|
| 174 | | continue |
|---|
| 175 | | if related.field.rel.edit_inline or not related.opts.admin: |
|---|
| 176 | | # Don't display link to edit, because it either has no |
|---|
| 177 | | # admin or is edited inline. |
|---|
| 178 | | nh(deleted_objects, current_depth, [u'%s: %s' % (force_unicode(capfirst(related.opts.verbose_name)), sub_obj), []]) |
|---|
| 179 | | else: |
|---|
| 180 | | # Display a link to the admin page. |
|---|
| 181 | | nh(deleted_objects, current_depth, [u'%s: <a href="../../../../%s/%s/%s/">%s</a>' % \ |
|---|
| 182 | | (force_unicode(capfirst(related.opts.verbose_name)), related.opts.app_label, related.opts.object_name.lower(), |
|---|
| 183 | | sub_obj._get_pk_val(), sub_obj), []]) |
|---|
| 184 | | _get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2) |
|---|
| 185 | | else: |
|---|
| 186 | | has_related_objs = False |
|---|
| 187 | | for sub_obj in getattr(obj, rel_opts_name).all(): |
|---|
| 188 | | has_related_objs = True |
|---|
| 189 | | if related.field.rel.edit_inline or not related.opts.admin: |
|---|
| 190 | | # Don't display link to edit, because it either has no |
|---|
| 191 | | # admin or is edited inline. |
|---|
| 192 | | nh(deleted_objects, current_depth, [u'%s: %s' % (force_unicode(capfirst(related.opts.verbose_name)), escape(sub_obj)), []]) |
|---|
| 193 | | else: |
|---|
| 194 | | # Display a link to the admin page. |
|---|
| 195 | | nh(deleted_objects, current_depth, [u'%s: <a href="../../../../%s/%s/%s/">%s</a>' % \ |
|---|
| 196 | | (force_unicode(capfirst(related.opts.verbose_name)), related.opts.app_label, related.opts.object_name.lower(), sub_obj._get_pk_val(), escape(sub_obj)), []]) |
|---|
| 197 | | _get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2) |
|---|
| 198 | | # If there were related objects, and the user doesn't have |
|---|
| 199 | | # permission to delete them, add the missing perm to perms_needed. |
|---|
| 200 | | if related.opts.admin and has_related_objs: |
|---|
| 201 | | p = '%s.%s' % (related.opts.app_label, related.opts.get_delete_permission()) |
|---|
| 202 | | if not user.has_perm(p): |
|---|
| 203 | | perms_needed.add(related.opts.verbose_name) |
|---|
| 204 | | for related in opts.get_all_related_many_to_many_objects(): |
|---|
| 205 | | if related.opts in opts_seen: |
|---|
| 206 | | continue |
|---|
| 207 | | opts_seen.append(related.opts) |
|---|
| 208 | | rel_opts_name = related.get_accessor_name() |
|---|
| 209 | | has_related_objs = False |
|---|
| 210 | | |
|---|
| 211 | | # related.get_accessor_name() could return None for symmetrical relationships |
|---|
| 212 | | if rel_opts_name: |
|---|
| 213 | | rel_objs = getattr(obj, rel_opts_name, None) |
|---|
| 214 | | if rel_objs: |
|---|
| 215 | | has_related_objs = True |
|---|
| 216 | | |
|---|
| 217 | | if has_related_objs: |
|---|
| 218 | | for sub_obj in rel_objs.all(): |
|---|
| 219 | | if related.field.rel.edit_inline or not related.opts.admin: |
|---|
| 220 | | # Don't display link to edit, because it either has no |
|---|
| 221 | | # admin or is edited inline. |
|---|
| 222 | | nh(deleted_objects, current_depth, [_('One or more %(fieldname)s in %(name)s: %(obj)s') % \ |
|---|
| 223 | | {'fieldname': force_unicode(related.field.verbose_name), 'name': force_unicode(related.opts.verbose_name), 'obj': escape(sub_obj)}, []]) |
|---|
| 224 | | else: |
|---|
| 225 | | # Display a link to the admin page. |
|---|
| 226 | | nh(deleted_objects, current_depth, [ |
|---|
| 227 | | (_('One or more %(fieldname)s in %(name)s:') % {'fieldname': force_unicode(related.field.verbose_name), 'name': force_unicode(related.opts.verbose_name)}) + \ |
|---|
| 228 | | (u' <a href="../../../../%s/%s/%s/">%s</a>' % \ |
|---|
| 229 | | (related.opts.app_label, related.opts.module_name, sub_obj._get_pk_val(), escape(sub_obj))), []]) |
|---|
| 230 | | # If there were related objects, and the user doesn't have |
|---|
| 231 | | # permission to change them, add the missing perm to perms_needed. |
|---|
| 232 | | if related.opts.admin and has_related_objs: |
|---|
| 233 | | p = u'%s.%s' % (related.opts.app_label, related.opts.get_change_permission()) |
|---|
| 234 | | if not user.has_perm(p): |
|---|
| 235 | | perms_needed.add(related.opts.verbose_name) |
|---|