Ticket #13588: admin_urlresolvers2.diff
File admin_urlresolvers2.diff, 24.2 KB (added by , 14 years ago) |
---|
-
django/contrib/admin/actions.py
diff --git a/django/contrib/admin/actions.py b/django/contrib/admin/actions.py index b75c91b..e98d4eb 100644
a b def delete_selected(modeladmin, request, queryset): 32 32 33 33 # Populate deletable_objects, a data structure of all related objects that 34 34 # will also be deleted. 35 deletable_objects, perms_needed = get_deleted_objects(queryset, opts, request.user, modeladmin.admin_site , levels_to_root=2)35 deletable_objects, perms_needed = get_deleted_objects(queryset, opts, request.user, modeladmin.admin_site) 36 36 37 37 # The user has already confirmed the deletion. 38 38 # Do the deletion and return a None to display the change list view again. -
django/contrib/admin/options.py
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 1f8ff6d..af6a0eb 100644
a b from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_ob 9 9 from django.contrib import messages 10 10 from django.views.decorators.csrf import csrf_protect 11 11 from django.core.exceptions import PermissionDenied, ValidationError 12 from django.core.urlresolvers import reverse 12 13 from django.db import models, transaction 13 14 from django.db.models.fields import BLANK_CHOICE_DASH 14 15 from django.http import Http404, HttpResponse, HttpResponseRedirect … … class BaseModelAdmin(object): 145 146 """ 146 147 db = kwargs.get('using') 147 148 if db_field.name in self.raw_id_fields: 148 kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, using=db) 149 kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, self.admin_site, 150 using=db) 149 151 elif db_field.name in self.radio_fields: 150 152 kwargs['widget'] = widgets.AdminRadioSelect(attrs={ 151 153 'class': get_ul_class(self.radio_fields[db_field.name]), … … class BaseModelAdmin(object): 165 167 db = kwargs.get('using') 166 168 167 169 if db_field.name in self.raw_id_fields: 168 kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, using=db) 170 kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, self.admin_site, 171 using=db) 169 172 kwargs['help_text'] = '' 170 173 elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)): 171 174 kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical)) … … class ModelAdmin(BaseModelAdmin): 663 666 # redirect to the change-list page for this object. Otherwise, 664 667 # redirect to the admin index. 665 668 if self.has_change_permission(request, None): 666 post_url = '../' 669 post_url = reverse('admin:%s_%s_changelist' % 670 (opts.app_label, opts.module_name), 671 current_app=self.admin_site.name) 667 672 else: 668 post_url = '../../../' 673 post_url = reverse('admin:index', 674 current_app=self.admin_site.name) 669 675 return HttpResponseRedirect(post_url) 670 676 671 677 def response_change(self, request, obj): … … class ModelAdmin(BaseModelAdmin): 685 691 elif request.POST.has_key("_saveasnew"): 686 692 msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': force_unicode(opts.verbose_name), 'obj': obj} 687 693 self.message_user(request, msg) 688 return HttpResponseRedirect("../%s/" % pk_value) 694 return HttpResponseRedirect(reverse('admin:%s_%s_change' % 695 (opts.app_label, opts.module_name), 696 args=pk_value, 697 current_app=self.admin_site.name)) 698 689 699 elif request.POST.has_key("_addanother"): 690 700 self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_unicode(opts.verbose_name))) 691 return HttpResponseRedirect("../add/") 701 return HttpResponseRedirect(reverse('admin:%s_%s_add' % 702 (opts.app_label, opts.module_name), 703 current_app=self.admin_site.name)) 692 704 else: 693 705 self.message_user(request, msg) 694 return HttpResponseRedirect("../") 706 return HttpResponseRedirect(reverse('admin:%s_%s_changelist' % 707 (opts.app_label, opts.module_name), 708 current_app=self.admin_site.name)) 695 709 696 710 def response_action(self, request, queryset): 697 711 """ … … class ModelAdmin(BaseModelAdmin): 866 880 raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % {'name': force_unicode(opts.verbose_name), 'key': escape(object_id)}) 867 881 868 882 if request.method == 'POST' and request.POST.has_key("_saveasnew"): 869 return self.add_view(request, form_url='../add/') 883 return self.add_view(request, form_url=reverse('admin:%s_%s_add' % 884 (opts.app_label, opts.module_name), 885 current_app=self.admin_site.name)) 870 886 871 887 ModelForm = self.get_form(request, obj) 872 888 formsets = [] … … class ModelAdmin(BaseModelAdmin): 1118 1134 self.message_user(request, _('The %(name)s "%(obj)s" was deleted successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj_display)}) 1119 1135 1120 1136 if not self.has_change_permission(request, None): 1121 return HttpResponseRedirect("../../../../") 1122 return HttpResponseRedirect("../../") 1137 return HttpResponseRedirect(reverse('admin:index', 1138 current_app=self.admin_site.name)) 1139 return HttpResponseRedirect(reverse('admin:%s_%s_changelist' % 1140 (opts.app_label, opts.module_name), 1141 current_app=self.admin_site.name)) 1123 1142 1124 1143 context = { 1125 1144 "title": _("Are you sure?"), -
django/contrib/admin/sites.py
diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py index 4446490..e451f8f 100644
a b class AdminSite(object): 456 456 context_instance=context_instance 457 457 ) 458 458 459 def root(self, request, url):460 """461 DEPRECATED. This function is the old way of handling URL resolution, and462 is deprecated in favor of real URL resolution -- see ``get_urls()``.463 464 This function still exists for backwards-compatibility; it will be465 removed in Django 1.3.466 """467 import warnings468 warnings.warn(469 "AdminSite.root() is deprecated; use include(admin.site.urls) instead.",470 DeprecationWarning471 )472 473 #474 # Again, remember that the following only exists for475 # backwards-compatibility. Any new URLs, changes to existing URLs, or476 # whatever need to be done up in get_urls(), above!477 #478 479 if request.method == 'GET' and not request.path.endswith('/'):480 return http.HttpResponseRedirect(request.path + '/')481 482 if settings.DEBUG:483 self.check_dependencies()484 485 # Figure out the admin base URL path and stash it for later use486 self.root_path = re.sub(re.escape(url) + '$', '', request.path)487 488 url = url.rstrip('/') # Trim trailing slash, if it exists.489 490 # The 'logout' view doesn't require that the person is logged in.491 if url == 'logout':492 return self.logout(request)493 494 # Check permission to continue or display login form.495 if not self.has_permission(request):496 return self.login(request)497 498 if url == '':499 return self.index(request)500 elif url == 'password_change':501 return self.password_change(request)502 elif url == 'password_change/done':503 return self.password_change_done(request)504 elif url == 'jsi18n':505 return self.i18n_javascript(request)506 # URLs starting with 'r/' are for the "View on site" links.507 elif url.startswith('r/'):508 from django.contrib.contenttypes.views import shortcut509 return shortcut(request, *url.split('/')[1:])510 else:511 if '/' in url:512 return self.model_page(request, *url.split('/', 2))513 else:514 return self.app_index(request, url)515 516 raise http.Http404('The requested admin page does not exist.')517 518 def model_page(self, request, app_label, model_name, rest_of_url=None):519 """520 DEPRECATED. This is the old way of handling a model view on the admin521 site; the new views should use get_urls(), above.522 """523 from django.db import models524 model = models.get_model(app_label, model_name)525 if model is None:526 raise http.Http404("App %r, model %r, not found." % (app_label, model_name))527 try:528 admin_obj = self._registry[model]529 except KeyError:530 raise http.Http404("This model exists but has not been registered with the admin site.")531 return admin_obj(request, rest_of_url)532 model_page = never_cache(model_page)533 459 534 460 # This global object represents the default admin site, for the common case. 535 461 # You can instantiate AdminSite in your own code to create a custom admin site. -
django/contrib/admin/util.py
diff --git a/django/contrib/admin/util.py b/django/contrib/admin/util.py index 776a6f0..fdecf0d 100644
a b from django.utils.safestring import mark_safe 7 7 from django.utils.text import capfirst 8 8 from django.utils.encoding import force_unicode, smart_unicode, smart_str 9 9 from django.utils.translation import ungettext, ugettext as _ 10 from django.core.urlresolvers import reverse , NoReverseMatch10 from django.core.urlresolvers import reverse 11 11 from django.utils.datastructures import SortedDict 12 12 13 13 def quote(s): … … def flatten_fieldsets(fieldsets): 58 58 field_names.append(field) 59 59 return field_names 60 60 61 def _format_callback(obj, user, admin_site, levels_to_root,perms_needed):61 def _format_callback(obj, user, admin_site, perms_needed): 62 62 has_admin = obj.__class__ in admin_site._registry 63 63 opts = obj._meta 64 try:65 admin_url = reverse('%s:%s_%s_change'66 % (admin_site.name,67 opts.app_label,68 opts.object_name.lower()),69 None, (quote(obj._get_pk_val()),))70 except NoReverseMatch:71 admin_url = '%s%s/%s/%s/' % ('../'*levels_to_root,72 opts.app_label,73 opts.object_name.lower(),74 quote(obj._get_pk_val()))75 64 if has_admin: 65 admin_url = reverse('admin:%s_%s_change' 66 % (opts.app_label, 67 opts.object_name.lower()), 68 None, (quote(obj._get_pk_val()),), 69 current_app=admin_site.name) 76 70 p = '%s.%s' % (opts.app_label, 77 71 opts.get_delete_permission()) 78 72 if not user.has_perm(p): … … def _format_callback(obj, user, admin_site, levels_to_root, perms_needed): 88 82 return u'%s: %s' % (capfirst(opts.verbose_name), 89 83 force_unicode(obj)) 90 84 91 def get_deleted_objects(objs, opts, user, admin_site , levels_to_root=4):85 def get_deleted_objects(objs, opts, user, admin_site): 92 86 """ 93 87 Find all objects related to ``objs`` that should also be 94 88 deleted. ``objs`` should be an iterable of objects. 95 89 96 90 Returns a nested list of strings suitable for display in the 97 91 template with the ``unordered_list`` filter. 98 99 `levels_to_root` defines the number of directories (../) to reach100 the admin root path. In a change_view this is 4, in a change_list101 view 2.102 103 This is for backwards compatibility since the options.delete_selected104 method uses this function also from a change_list view.105 This will not be used if we can reverse the URL.106 92 """ 107 93 collector = NestedObjects() 108 94 for obj in objs: … … def get_deleted_objects(objs, opts, user, admin_site, levels_to_root=4): 114 100 to_delete = collector.nested(_format_callback, 115 101 user=user, 116 102 admin_site=admin_site, 117 levels_to_root=levels_to_root,118 103 perms_needed=perms_needed) 119 104 120 105 return to_delete, perms_needed -
django/contrib/admin/widgets.py
diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py index 1d321d0..308f2f2 100644
a b from django.utils.translation import ugettext as _ 13 13 from django.utils.safestring import mark_safe 14 14 from django.utils.encoding import force_unicode 15 15 from django.conf import settings 16 from django.core.urlresolvers import reverse , NoReverseMatch16 from django.core.urlresolvers import reverse 17 17 18 18 class FilteredSelectMultiple(forms.SelectMultiple): 19 19 """ … … class ForeignKeyRawIdWidget(forms.TextInput): 105 105 A Widget for displaying ForeignKeys in the "raw_id" interface rather than 106 106 in a <select> box. 107 107 """ 108 def __init__(self, rel, a ttrs=None, using=None):108 def __init__(self, rel, admin_site, attrs=None, using=None): 109 109 self.rel = rel 110 110 self.db = using 111 self.admin_site = admin_site 111 112 super(ForeignKeyRawIdWidget, self).__init__(attrs) 112 113 113 114 def render(self, name, value, attrs=None): 115 rel_to = self.rel.to 114 116 if attrs is None: 115 117 attrs = {} 116 related_url = '../../../%s/%s/' % (self.rel.to._meta.app_label, self.rel.to._meta.object_name.lower()) 117 params = self.url_parameters() 118 if params: 119 url = '?' + '&'.join(['%s=%s' % (k, v) for k, v in params.items()]) 120 else: 121 url = '' 122 if not attrs.has_key('class'): 123 attrs['class'] = 'vForeignKeyRawIdAdminField' # The JavaScript looks for this hook. 124 output = [super(ForeignKeyRawIdWidget, self).render(name, value, attrs)] 125 # TODO: "id_" is hard-coded here. This should instead use the correct 126 # API to determine the ID dynamically. 127 output.append('<a href="%s%s" class="related-lookup" id="lookup_id_%s" onclick="return showRelatedObjectLookupPopup(this);"> ' % \ 128 (related_url, url, name)) 129 output.append('<img src="%simg/admin/selector-search.gif" width="16" height="16" alt="%s" /></a>' % (settings.ADMIN_MEDIA_PREFIX, _('Lookup'))) 118 119 extra = [] 120 if rel_to in self.admin_site._registry: # If the related object has an admin interface: 121 related_url = reverse('admin:%s_%s_changelist' % 122 (rel_to._meta.app_label, 123 rel_to._meta.module_name), 124 current_app=self.admin_site.name) 125 params = self.url_parameters() 126 if params: 127 url = '?' + '&'.join(['%s=%s' % (k, v) for k, v in params.items()]) 128 else: 129 url = '' 130 if not attrs.has_key('class'): 131 attrs['class'] = 'vForeignKeyRawIdAdminField' # The JavaScript looks for this hook. 132 133 # TODO: "id_" is hard-coded here. This should instead use the correct 134 # API to determine the ID dynamically. 135 extra.append('<a href="%s%s" class="related-lookup" id="lookup_id_%s" onclick="return showRelatedObjectLookupPopup(this);"> ' % \ 136 (related_url, url, name)) 137 extra.append('<img src="%simg/admin/selector-search.gif" width="16" height="16" alt="%s" /></a>' % (settings.ADMIN_MEDIA_PREFIX, _('Lookup'))) 138 139 output = [super(ForeignKeyRawIdWidget, self).render(name, value, attrs)] + extra 130 140 if value: 131 141 output.append(self.label_for_value(value)) 132 142 return mark_safe(u''.join(output)) … … class ManyToManyRawIdWidget(ForeignKeyRawIdWidget): 163 173 A Widget for displaying ManyToMany ids in the "raw_id" interface rather than 164 174 in a <select multiple> box. 165 175 """ 166 def __init__(self, rel, a ttrs=None, using=None):167 super(ManyToManyRawIdWidget, self).__init__(rel, a ttrs, using=None)176 def __init__(self, rel, admin_site, attrs=None, using=None): 177 super(ManyToManyRawIdWidget, self).__init__(rel, admin_site, attrs, using=None) 168 178 169 179 def render(self, name, value, attrs=None): 170 180 attrs['class'] = 'vManyToManyRawIdAdminField' … … class RelatedFieldWidgetWrapper(forms.Widget): 229 239 def render(self, name, value, *args, **kwargs): 230 240 rel_to = self.rel.to 231 241 info = (rel_to._meta.app_label, rel_to._meta.object_name.lower()) 232 try:233 related_url = reverse('admin:%s_%s_add' % info, current_app=self.admin_site.name)234 except NoReverseMatch:235 info = (self.admin_site.root_path, rel_to._meta.app_label, rel_to._meta.object_name.lower())236 related_url = '%s%s/%s/add/' % info237 242 self.widget.choices = self.choices 238 243 output = [self.widget.render(name, value, *args, **kwargs)] 239 244 if rel_to in self.admin_site._registry: # If the related object has an admin interface: 245 related_url = reverse('admin:%s_%s_add' % info, current_app=self.admin_site.name) 240 246 # TODO: "id_" is hard-coded here. This should instead use the correct 241 247 # API to determine the ID dynamically. 242 248 output.append(u'<a href="%s" class="add-another" id="add_id_%s" onclick="return showAddAnotherPopup(this);"> ' % \ -
tests/regressiontests/admin_inlines/models.py
diff --git a/tests/regressiontests/admin_inlines/models.py b/tests/regressiontests/admin_inlines/models.py index 5a12e07..2998373 100644
a b class BookInline(admin.TabularInline): 43 43 class AuthorAdmin(admin.ModelAdmin): 44 44 inlines = [BookInline] 45 45 46 admin.site.register(Book) 46 47 admin.site.register(Author, AuthorAdmin) 47 48 48 49 class Holder(models.Model): -
tests/regressiontests/admin_views/tests.py
diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py index 1385e5e..f60bb04 100644
a b class SaveAsTests(TestCase): 324 324 self.assert_(response.context['save_as']) 325 325 post_data = {'_saveasnew':'', 'name':'John M', 'gender':3, 'alive':'checked'} 326 326 response = self.client.post('/test_admin/admin/admin_views/person/1/', post_data) 327 self.assertEqual(response.context['form_url'], ' ../add/')327 self.assertEqual(response.context['form_url'], '/test_admin/admin/admin_views/person/add/') 328 328 329 329 class CustomModelAdminTest(AdminViewBasicTest): 330 330 urlbit = "admin2" -
tests/regressiontests/admin_widgets/models.py
diff --git a/tests/regressiontests/admin_widgets/models.py b/tests/regressiontests/admin_widgets/models.py index 59d625b..f301f13 100644
a b from django.conf import settings 3 3 from django.db import models 4 4 from django.core.files.storage import default_storage 5 5 from django.contrib.auth.models import User 6 from django.contrib import admin 6 7 7 class MyFileField(models.FileField): 8 class MyFileField(models.FileField): 8 9 pass 9 10 10 11 class Member(models.Model): … … class CarTire(models.Model): 70 71 """ 71 72 car = models.ForeignKey(Car) 72 73 74 admin.site.register(Inventory) 75 admin.site.register(Member) 76 admin.site.register(Band) 77 73 78 __test__ = {'WIDGETS_TESTS': """ 74 79 >>> from datetime import datetime 75 80 >>> from django.utils.html import escape, conditional_escape … … Currently: <a target="_blank" href="%(STORAGE_URL)salbums/hybrid_theory.jpg">alb 121 126 <input type="file" name="test" /> 122 127 123 128 >>> rel = Album._meta.get_field('band').rel 124 >>> w = ForeignKeyRawIdWidget(rel )129 >>> w = ForeignKeyRawIdWidget(rel, admin.site) 125 130 >>> print conditional_escape(w.render('test', band.pk, attrs={})) 126 <input type="text" name="test" value="1" class="vForeignKeyRawIdAdminField" /><a href=" ../../../admin_widgets/band/?t=id" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/admin/selector-search.gif" width="16" height="16" alt="Lookup" /></a> <strong>Linkin Park</strong>131 <input type="text" name="test" value="1" class="vForeignKeyRawIdAdminField" /><a href="/test_admin/admin/admin_widgets/band/?t=id" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/admin/selector-search.gif" width="16" height="16" alt="Lookup" /></a> <strong>Linkin Park</strong> 127 132 128 133 >>> m1 = Member.objects.create(pk=1, name='Chester') 129 134 >>> m2 = Member.objects.create(pk=2, name='Mike') 130 135 >>> band.members.add(m1, m2) 131 136 132 137 >>> rel = Band._meta.get_field('members').rel 133 >>> w = ManyToManyRawIdWidget(rel )138 >>> w = ManyToManyRawIdWidget(rel, admin.site) 134 139 >>> print conditional_escape(w.render('test', [m1.pk, m2.pk], attrs={})) 135 <input type="text" name="test" value="1,2" class="vManyToManyRawIdAdminField" /><a href=" ../../../admin_widgets/member/" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/admin/selector-search.gif" width="16" height="16" alt="Lookup" /></a>140 <input type="text" name="test" value="1,2" class="vManyToManyRawIdAdminField" /><a href="/test_admin/admin/admin_widgets/member/" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/admin/selector-search.gif" width="16" height="16" alt="Lookup" /></a> 136 141 >>> w._has_changed(None, None) 137 142 False 138 143 >>> w._has_changed([], None) … … True 152 157 >>> pear = Inventory.objects.create(barcode=22, name='Pear') 153 158 >>> core = Inventory.objects.create(barcode=87, name='Core', parent=apple) 154 159 >>> rel = Inventory._meta.get_field('parent').rel 155 >>> w = ForeignKeyRawIdWidget(rel )160 >>> w = ForeignKeyRawIdWidget(rel, admin.site) 156 161 >>> print w.render('test', core.parent_id, attrs={}) 157 <input type="text" name="test" value="86" class="vForeignKeyRawIdAdminField" /><a href=" ../../../admin_widgets/inventory/?t=barcode" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/admin/selector-search.gif" width="16" height="16" alt="Lookup" /></a> <strong>Apple</strong>162 <input type="text" name="test" value="86" class="vForeignKeyRawIdAdminField" /><a href="/test_admin/admin/admin_widgets/inventory/?t=barcode" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/admin/selector-search.gif" width="16" height="16" alt="Lookup" /></a> <strong>Apple</strong> 158 163 159 164 # see #9258 160 165 >>> hidden = Inventory.objects.create(barcode=93, name='Hidden', hidden=True) 161 166 >>> child_of_hidden = Inventory.objects.create(barcode=94, name='Child of hidden', parent=hidden) 162 167 >>> print w.render('test', child_of_hidden.parent_id, attrs={}) 163 <input type="text" name="test" value="93" class="vForeignKeyRawIdAdminField" /><a href=" ../../../admin_widgets/inventory/?t=barcode" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/admin/selector-search.gif" width="16" height="16" alt="Lookup" /></a> <strong>Hidden</strong>168 <input type="text" name="test" value="93" class="vForeignKeyRawIdAdminField" /><a href="/test_admin/admin/admin_widgets/inventory/?t=barcode" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/admin/selector-search.gif" width="16" height="16" alt="Lookup" /></a> <strong>Hidden</strong> 164 169 """ % { 165 170 'ADMIN_MEDIA_PREFIX': settings.ADMIN_MEDIA_PREFIX, 166 171 'STORAGE_URL': default_storage.url(''),