4
4
from django.utils.safestring import mark_safe
5
5
from django.utils.text import capfirst
6
6
from django.utils.encoding import force_unicode
7
from django.utils.translation import ugettext as _
7
from django.utils.translation import ungettext, ugettext as _
8
from django.core.urlresolvers import reverse, NoReverseMatch
61
61
current = current[-1]
62
62
current.append(val)
64
def get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current_depth, admin_site):
65
"Helper function that recursively populates deleted_objects."
64
def get_change_view_url(app_label, module_name, pk, admin_site, levels_to_root):
66
Returns the url to the admin change view for the given app_label,
67
module_name and primary key.
70
return reverse('%sadmin_%s_%s_change' % (admin_site.name, app_label, module_name), None, (pk,))
71
except NoReverseMatch:
72
return '%s%s/%s/%s/' % ('../'*levels_to_root, app_label, module_name, pk)
74
def get_deleted_objects(deleted_objects, perms_needed, user, obj, opts, current_depth, admin_site, levels_to_root=4):
76
Helper function that recursively populates deleted_objects.
78
`levels_to_root` defines the number of directories (../) to reach the
79
admin root path. In a change_view this is 4, in a change_list view 2.
81
This is for backwards compatibility since the options.delete_selected
82
method uses this function also from a change_list view.
83
This will not be used if we can reverse the URL.
66
85
nh = _nest_help # Bind to local variable for performance
67
86
if current_depth > 16:
68
87
return # Avoid recursing too deep.
89
108
# Don't display link to edit, because it either has no
90
109
# admin or is edited inline.
91
nh(deleted_objects, current_depth, [u'%s: %s' % (force_unicode(capfirst(related.opts.verbose_name)), sub_obj), []])
110
nh(deleted_objects, current_depth,
111
[u'%s: %s' % (capfirst(related.opts.verbose_name), force_unicode(sub_obj)), []])
93
113
# Display a link to the admin page.
94
nh(deleted_objects, current_depth, [mark_safe(u'%s: <a href="../../../../%s/%s/%s/">%s</a>' %
95
(escape(force_unicode(capfirst(related.opts.verbose_name))),
96
related.opts.app_label,
97
related.opts.object_name.lower(),
98
sub_obj._get_pk_val(), sub_obj)), []])
114
nh(deleted_objects, current_depth, [mark_safe(u'%s: <a href="%s">%s</a>' %
115
(escape(capfirst(related.opts.verbose_name)),
116
get_change_view_url(related.opts.app_label,
117
related.opts.object_name.lower(),
118
sub_obj._get_pk_val(),
121
escape(sub_obj))), []])
99
122
get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2, admin_site)
101
124
has_related_objs = False
104
127
if not has_admin:
105
128
# Don't display link to edit, because it either has no
106
129
# admin or is edited inline.
107
nh(deleted_objects, current_depth, [u'%s: %s' % (force_unicode(capfirst(related.opts.verbose_name)), sub_obj), []])
130
nh(deleted_objects, current_depth,
131
[u'%s: %s' % (capfirst(related.opts.verbose_name), force_unicode(sub_obj)), []])
109
133
# Display a link to the admin page.
110
nh(deleted_objects, current_depth, [mark_safe(u'%s: <a href="../../../../%s/%s/%s/">%s</a>' % \
111
(escape(force_unicode(capfirst(related.opts.verbose_name))), related.opts.app_label, related.opts.object_name.lower(), sub_obj._get_pk_val(), escape(sub_obj))), []])
134
nh(deleted_objects, current_depth, [mark_safe(u'%s: <a href="%s">%s</a>' %
135
(escape(capfirst(related.opts.verbose_name)),
136
get_change_view_url(related.opts.app_label,
137
related.opts.object_name.lower(),
138
sub_obj._get_pk_val(),
141
escape(sub_obj))), []])
112
142
get_deleted_objects(deleted_objects, perms_needed, user, sub_obj, related.opts, current_depth+2, admin_site)
113
143
# If there were related objects, and the user doesn't have
114
144
# permission to delete them, add the missing perm to perms_needed.
141
171
# Display a link to the admin page.
142
172
nh(deleted_objects, current_depth, [
143
173
mark_safe((_('One or more %(fieldname)s in %(name)s:') % {'fieldname': escape(force_unicode(related.field.verbose_name)), 'name': escape(force_unicode(related.opts.verbose_name))}) + \
144
(u' <a href="../../../../%s/%s/%s/">%s</a>' % \
145
(related.opts.app_label, related.opts.module_name, sub_obj._get_pk_val(), escape(sub_obj)))), []])
174
(u' <a href="%s">%s</a>' % \
175
(get_change_view_url(related.opts.app_label,
176
related.opts.object_name.lower(),
177
sub_obj._get_pk_val(),
180
escape(sub_obj)))), []])
146
181
# If there were related objects, and the user doesn't have
147
182
# permission to change them, add the missing perm to perms_needed.
148
183
if has_admin and has_related_objs:
149
184
p = u'%s.%s' % (related.opts.app_label, related.opts.get_change_permission())
150
185
if not user.has_perm(p):
151
186
perms_needed.add(related.opts.verbose_name)
188
def model_format_dict(obj):
190
Return a `dict` with keys 'verbose_name' and 'verbose_name_plural',
191
typically for use with string formatting.
193
`obj` may be a `Model` instance, `Model` subclass, or `QuerySet` instance.
196
if isinstance(obj, (models.Model, models.base.ModelBase)):
198
elif isinstance(obj, models.query.QuerySet):
199
opts = obj.model._meta
203
'verbose_name': force_unicode(opts.verbose_name),
204
'verbose_name_plural': force_unicode(opts.verbose_name_plural)
207
def model_ngettext(obj, n=None):
209
Return the appropriate `verbose_name` or `verbose_name_plural` value for
210
`obj` depending on the count `n`.
212
`obj` may be a `Model` instance, `Model` subclass, or `QuerySet` instance.
213
If `obj` is a `QuerySet` instance, `n` is optional and the length of the
217
if isinstance(obj, models.query.QuerySet):
221
d = model_format_dict(obj)
222
singular, plural = d["verbose_name"], d["verbose_name_plural"]
223
return ungettext(singular, plural, n or 0)