Ticket #15294: 15294.16.diff
File 15294.16.diff, 131.1 KB (added by , 13 years ago) |
---|
-
django/contrib/admin/options.py
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 5271e02..2825c99 100644
a b from django.contrib import messages 11 11 from django.views.decorators.csrf import csrf_protect 12 12 from django.core.exceptions import PermissionDenied, ValidationError 13 13 from django.core.paginator import Paginator 14 from django.core.urlresolvers import reverse 14 15 from django.db import models, transaction, router 15 16 from django.db.models.related import RelatedObject 16 17 from django.db.models.fields import BLANK_CHOICE_DASH, FieldDoesNotExist … … class ModelAdmin(BaseModelAdmin): 776 777 # redirect to the change-list page for this object. Otherwise, 777 778 # redirect to the admin index. 778 779 if self.has_change_permission(request, None): 779 post_url = '../' 780 post_url = reverse('admin:%s_%s_changelist' % 781 (opts.app_label, opts.module_name), 782 current_app=self.admin_site.name) 780 783 else: 781 post_url = '../../../' 784 post_url = reverse('admin:index', 785 current_app=self.admin_site.name) 782 786 return HttpResponseRedirect(post_url) 783 787 784 788 def response_change(self, request, obj): … … class ModelAdmin(BaseModelAdmin): 787 791 """ 788 792 opts = obj._meta 789 793 790 # Handle proxy models automatically created by .only() or .defer() 794 # Handle proxy models automatically created by .only() or .defer(). 795 # Refs #14529 791 796 verbose_name = opts.verbose_name 797 module_name = opts.module_name 792 798 if obj._deferred: 793 799 opts_ = opts.proxy_for_model._meta 794 800 verbose_name = opts_.verbose_name 801 module_name = opts_.module_name 795 802 796 803 pk_value = obj._get_pk_val() 797 804 … … class ModelAdmin(BaseModelAdmin): 805 812 elif "_saveasnew" in request.POST: 806 813 msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': force_unicode(verbose_name), 'obj': obj} 807 814 self.message_user(request, msg) 808 return HttpResponseRedirect("../%s/" % pk_value) 815 return HttpResponseRedirect(reverse('admin:%s_%s_change' % 816 (opts.app_label, module_name), 817 args=(pk_value,), 818 current_app=self.admin_site.name)) 809 819 elif "_addanother" in request.POST: 810 820 self.message_user(request, msg + ' ' + (_("You may add another %s below.") % force_unicode(verbose_name))) 811 return HttpResponseRedirect("../add/") 821 return HttpResponseRedirect(reverse('admin:%s_%s_add' % 822 (opts.app_label, module_name), 823 current_app=self.admin_site.name)) 812 824 else: 813 825 self.message_user(request, msg) 814 826 # Figure out where to redirect. If the user has change permission, 815 827 # redirect to the change-list page for this object. Otherwise, 816 828 # redirect to the admin index. 817 829 if self.has_change_permission(request, None): 818 return HttpResponseRedirect('../') 830 post_url = reverse('admin:%s_%s_changelist' % 831 (opts.app_label, module_name), 832 current_app=self.admin_site.name) 819 833 else: 820 return HttpResponseRedirect('../../../') 834 post_url = reverse('admin:index', 835 current_app=self.admin_site.name) 836 return HttpResponseRedirect(post_url) 821 837 822 838 def response_action(self, request, queryset): 823 839 """ … … class ModelAdmin(BaseModelAdmin): 990 1006 raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % {'name': force_unicode(opts.verbose_name), 'key': escape(object_id)}) 991 1007 992 1008 if request.method == 'POST' and "_saveasnew" in request.POST: 993 return self.add_view(request, form_url='../add/') 1009 return self.add_view(request, form_url=reverse('admin:%s_%s_add' % 1010 (opts.app_label, opts.module_name), 1011 current_app=self.admin_site.name)) 994 1012 995 1013 ModelForm = self.get_form(request, obj) 996 1014 formsets = [] … … class ModelAdmin(BaseModelAdmin): 1246 1264 self.message_user(request, _('The %(name)s "%(obj)s" was deleted successfully.') % {'name': force_unicode(opts.verbose_name), 'obj': force_unicode(obj_display)}) 1247 1265 1248 1266 if not self.has_change_permission(request, None): 1249 return HttpResponseRedirect("../../../../") 1250 return HttpResponseRedirect("../../") 1267 return HttpResponseRedirect(reverse('admin:index', 1268 current_app=self.admin_site.name)) 1269 return HttpResponseRedirect(reverse('admin:%s_%s_changelist' % 1270 (opts.app_label, opts.module_name), 1271 current_app=self.admin_site.name)) 1251 1272 1252 1273 object_name = force_unicode(opts.verbose_name) 1253 1274 … … class ModelAdmin(BaseModelAdmin): 1292 1313 'module_name': capfirst(force_unicode(opts.verbose_name_plural)), 1293 1314 'object': obj, 1294 1315 'app_label': app_label, 1316 'opts': opts, 1295 1317 } 1296 1318 context.update(extra_context or {}) 1297 1319 return TemplateResponse(request, self.object_history_template or [ -
django/contrib/admin/sites.py
diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py index 9bb9f4a..3a5c12b 100644
a b class AdminSite(object): 339 339 # Check whether user has any perm for this module. 340 340 # If so, add the module to the model_list. 341 341 if True in perms.values(): 342 info = (app_label, model._meta.module_name) 342 343 model_dict = { 343 344 'name': capfirst(model._meta.verbose_name_plural), 344 'admin_url': mark_safe('%s/%s/' % (app_label, model.__name__.lower())), 345 'admin_url': reverse('admin:%s_%s_changelist' % info, current_app=self.name), 346 'add_url': reverse('admin:%s_%s_add' % info, current_app=self.name), 345 347 'perms': perms, 346 348 } 347 349 if app_label in app_dict: … … class AdminSite(object): 349 351 else: 350 352 app_dict[app_label] = { 351 353 'name': app_label.title(), 352 'app_url': app_label + '/',354 'app_url': reverse('admin:app_list', kwargs={'app_label': app_label}, current_app=self.name), 353 355 'has_module_perms': has_module_perms, 354 356 'models': [model_dict], 355 357 } … … class AdminSite(object): 383 385 # Check whether user has any perm for this module. 384 386 # If so, add the module to the model_list. 385 387 if True in perms.values(): 388 info = (app_label, model._meta.module_name) 386 389 model_dict = { 387 390 'name': capfirst(model._meta.verbose_name_plural), 388 'admin_url': '%s/' % model.__name__.lower(), 391 'admin_url': reverse('admin:%s_%s_changelist' % info, current_app=self.name), 392 'add_url': reverse('admin:%s_%s_add' % info, current_app=self.name), 389 393 'perms': perms, 390 394 } 391 395 if app_dict: -
django/contrib/admin/templates/admin/500.html
diff --git a/django/contrib/admin/templates/admin/500.html b/django/contrib/admin/templates/admin/500.html index b30e431..eeb9e8d 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n %} 3 {% load url from future %} 3 4 4 {% block breadcrumbs %}<div class="breadcrumbs"><a href="/">{% trans "Home" %}</a> › {% trans "Server error" %}</div>{% endblock %} 5 {% block breadcrumbs %} 6 <div class="breadcrumbs"> 7 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 8 › {% trans 'Server error' %} 9 </div> 10 {% endblock %} 5 11 6 12 {% block title %}{% trans 'Server error (500)' %}{% endblock %} 7 13 -
django/contrib/admin/templates/admin/app_index.html
diff --git a/django/contrib/admin/templates/admin/app_index.html b/django/contrib/admin/templates/admin/app_index.html index 120433d..4616b16 100644
a b 1 {% extends "admin/index.html" %} 2 {% load i18n %} 1 {% extends "admin/index.html" %} 2 {% load i18n %} 3 {% load url from future %} 3 4 4 5 {% if not is_popup %} 5 6 6 {% block breadcrumbs %} 7 <div class="breadcrumbs"><a href="../"> 8 {% trans "Home" %}</a> › 7 <div class="breadcrumbs"> 8 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 9 › 9 10 {% for app in app_list %} 10 11 {% blocktrans with app.name as name %}{{ name }}{% endblocktrans %} 11 {% endfor %}</div>{% endblock %} 12 13 {% endif %} 12 {% endfor %} 13 </div> 14 {% endblock %} 15 {% endif %} 14 16 15 {% block sidebar %}{% endblock %} 16 No newline at end of file 17 {% block sidebar %}{% endblock %} -
django/contrib/admin/templates/admin/auth/user/change_password.html
diff --git a/django/contrib/admin/templates/admin/auth/user/change_password.html b/django/contrib/admin/templates/admin/auth/user/change_password.html index b18b0aa..f79eacd 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n admin_static admin_modify %} 3 3 {% load url from future %} 4 {% load admin_urls %} 5 4 6 {% block extrahead %}{{ block.super }} 5 7 {% url 'admin:jsi18n' as jsi18nurl %} 6 8 <script type="text/javascript" src="{{ jsi18nurl|default:"../../../../jsi18n/" }}"></script> 7 9 {% endblock %} 8 10 {% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}" />{% endblock %} 9 11 {% block bodyclass %}{{ opts.app_label }}-{{ opts.object_name.lower }} change-form{% endblock %} 10 {% block breadcrumbs %}{%if not is_popup %}11 <div class="breadcrumbs"> 12 <a href="../../../../">{% trans "Home" %}</a> › 13 <a href="../../../">{{ opts.app_label|capfirst|escape }}</a> › 14 <a href="../../">{{ opts.verbose_name_plural|capfirst }}</a> › 15 <a href="../">{{ original|truncatewords:"18" }}</a> › 16 12 {% if not is_popup %} 13 {% block breadcrumbs %} 14 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 15 › <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_label|capfirst|escape }}</a> 16 › <a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a> 17 › <a href="{% url opts|admin_urlname:'changelist' %}{{ original.pk }}">{{ original|truncatewords:"18" }}</a> 18 › {% trans 'Change password' %} 17 19 </div> 18 {% endif %}{% endblock %} 20 {% endblock %} 21 {% endif %} 19 22 {% block content %}<div id="content-main"> 20 23 <form action="{{ form_url }}" method="post" id="{{ opts.module_name }}_form">{% csrf_token %}{% block form_top %}{% endblock %} 21 24 <div> -
django/contrib/admin/templates/admin/base.html
diff --git a/django/contrib/admin/templates/admin/base.html b/django/contrib/admin/templates/admin/base.html index 4b3c429..3b50adc 100644
a b 32 32 {% if docsroot %} 33 33 <a href="{{ docsroot }}">{% trans 'Documentation' %}</a> / 34 34 {% endif %} 35 <a href="{% url 'admin:password_change' %}"> 36 {% trans 'Change password' %}</a> / 37 <a href="{% url 'admin:logout' %}"> 38 {% trans 'Log out' %}</a> 35 <a href="{% url 'admin:password_change' %}">{% trans 'Change password' %}</a> / 36 <a href="{% url 'admin:logout' %}">{% trans 'Log out' %}</a> 39 37 {% endblock %} 40 38 </div> 41 39 {% endif %} 42 40 {% block nav-global %}{% endblock %} 43 41 </div> 44 42 <!-- END Header --> 45 {% block breadcrumbs %}<div class="breadcrumbs"><a href="/">{% trans 'Home' %}</a>{% if title %} › {{ title }}{% endif %}</div>{% endblock %} 43 {% block breadcrumbs %} 44 <div class="breadcrumbs"> 45 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 46 {% if title %} › {{ title }}{% endif %} 47 </div> 48 {% endblock %} 46 49 {% endif %} 47 50 48 51 {% block messages %} -
django/contrib/admin/templates/admin/change_form.html
diff --git a/django/contrib/admin/templates/admin/change_form.html b/django/contrib/admin/templates/admin/change_form.html index 56661e9..0e2803d 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n admin_static admin_modify %} 3 3 {% load url from future %} 4 {% load admin_urls %} 4 5 5 6 {% block extrahead %}{{ block.super }} 6 7 {% url 'admin:jsi18n' as jsi18nurl %} … … 14 15 15 16 {% block bodyclass %}{{ opts.app_label }}-{{ opts.object_name.lower }} change-form{% endblock %} 16 17 17 {% block breadcrumbs %}{%if not is_popup %}18 <div class="breadcrumbs"> 19 <a href="../../../">{% trans "Home" %}</a> › 20 <a href="../../">{{ app_label|capfirst|escape }}</a> › 21 {% if has_change_permission %}<a href="../">{{ opts.verbose_name_plural|capfirst }}</a>{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %} › 22 {% if add %}{% trans "Add"%} {{ opts.verbose_name }}{% else %}{{ original|truncatewords:"18" }}{% endif %}18 {% if not is_popup %} 19 {% block breadcrumbs %} 20 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 21 › <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ app_label|capfirst|escape }}</a> 22 › {% if has_change_permission %}<a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>{% else %}{{ opts.verbose_name_plural|capfirst }}{% endif %} 23 › {% if add %}{% trans 'Add' %} {{ opts.verbose_name }}{% else %}{{ original|truncatewords:"18" }}{% endif %} 23 24 </div> 24 {% endif %}{% endblock %} 25 {% endblock %} 26 {% endif %} 25 27 26 28 {% block content %}<div id="content-main"> 27 29 {% block object-tools %} -
django/contrib/admin/templates/admin/change_list.html
diff --git a/django/contrib/admin/templates/admin/change_list.html b/django/contrib/admin/templates/admin/change_list.html index 24c6d8c..98869cf 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n admin_static admin_list %} 3 3 {% load url from future %} 4 {% load admin_urls %} 5 4 6 {% block extrastyle %} 5 7 {{ block.super }} 6 8 <link rel="stylesheet" type="text/css" href="{% static "admin/css/changelists.css" %}" /> … … 36 38 {% block bodyclass %}change-list{% endblock %} 37 39 38 40 {% if not is_popup %} 39 {% block breadcrumbs %} 40 <div class="breadcrumbs"> 41 <a href="../../"> 42 {% trans "Home" %} 43 </a> 44 › 45 <a href="../"> 46 {{ app_label|capfirst }} 47 </a> 48 › 49 {{ cl.opts.verbose_name_plural|capfirst }} 50 </div> 51 {% endblock %} 41 {% block breadcrumbs %} 42 <div class="breadcrumbs"> 43 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 44 › <a href="{% url 'admin:app_list' app_label=cl.opts.app_label %}">{{ app_label|capfirst|escape }}</a> 45 › {{ cl.opts.verbose_name_plural|capfirst }} 46 </div> 47 {% endblock %} 52 48 {% endif %} 53 49 54 50 {% block coltype %}flex{% endblock %} … … 60 56 <ul class="object-tools"> 61 57 {% block object-tools-items %} 62 58 <li> 63 <a href=" add/{% if is_popup %}?_popup=1{% endif %}" class="addlink">59 <a href="{% url cl.opts|admin_urlname:'add' %}{% if is_popup %}?_popup=1{% endif %}" class="addlink"> 64 60 {% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %} 65 61 </a> 66 62 </li> -
django/contrib/admin/templates/admin/delete_confirmation.html
diff --git a/django/contrib/admin/templates/admin/delete_confirmation.html b/django/contrib/admin/templates/admin/delete_confirmation.html index 0e6d47e..f8b36e9 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n %} 3 {% load url from future %} 4 {% load admin_urls %} 3 5 4 6 {% block breadcrumbs %} 5 7 <div class="breadcrumbs"> 6 <a href="../../../../">{% trans "Home" %}</a> › 7 <a href="../../../">{{ app_label|capfirst }}</a> › 8 <a href="../../">{{ opts.verbose_name_plural|capfirst }}</a> › 9 <a href="../">{{ object|truncatewords:"18" }}</a> › 10 8 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 9 › <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ app_label|capfirst }}</a> 10 › <a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst|escape }}</a> 11 › <a href="{% url opts|admin_urlname:'changelist' %}{{ object.pk }}">{{ object|truncatewords:"18" }}</a> 12 › {% trans 'Delete' %} 11 13 </div> 12 14 {% endblock %} 13 15 -
django/contrib/admin/templates/admin/delete_selected_confirmation.html
diff --git a/django/contrib/admin/templates/admin/delete_selected_confirmation.html b/django/contrib/admin/templates/admin/delete_selected_confirmation.html index 127519b..3120cc5 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n l10n %} 3 {% load url from future %} 4 {% load admin_urls %} 3 5 4 6 {% block breadcrumbs %} 5 7 <div class="breadcrumbs"> 6 <a href="../../">{% trans "Home" %}</a> › 7 <a href="../">{{ app_label|capfirst }}</a> › 8 <a href="./">{{ opts.verbose_name_plural|capfirst }}</a> › 9 8 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 9 › <a href="{% url 'admin:app_list' app_label=app_label %}">{{ app_label|capfirst|escape }}</a> 10 › <a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a> 11 › {% trans 'Delete multiple objects' %} 10 12 </div> 11 13 {% endblock %} 12 14 -
django/contrib/admin/templates/admin/index.html
diff --git a/django/contrib/admin/templates/admin/index.html b/django/contrib/admin/templates/admin/index.html index 7164220..86c795b 100644
a b 26 26 {% endif %} 27 27 28 28 {% if model.perms.add %} 29 <td><a href="{{ model.ad min_url }}add/" class="addlink">{% trans 'Add' %}</a></td>29 <td><a href="{{ model.add_url }}" class="addlink">{% trans 'Add' %}</a></td> 30 30 {% else %} 31 31 <td> </td> 32 32 {% endif %} -
django/contrib/admin/templates/admin/invalid_setup.html
diff --git a/django/contrib/admin/templates/admin/invalid_setup.html b/django/contrib/admin/templates/admin/invalid_setup.html index f09b316..c2df4df 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n %} 3 {% load url from future %} 3 4 4 {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans 'Home' %}</a> › {{ title }}</div>{% endblock %} 5 {% block breadcrumbs %} 6 <div class="breadcrumbs"> 7 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 8 › {{ title }} 9 </div> 10 {% endblock %} 5 11 6 12 {% block content %} 7 13 <p>{% trans "Something's wrong with your database installation. Make sure the appropriate database tables have been created, and make sure the database is readable by the appropriate user." %}</p> -
django/contrib/admin/templates/admin/object_history.html
diff --git a/django/contrib/admin/templates/admin/object_history.html b/django/contrib/admin/templates/admin/object_history.html index 5ae7847..ebd1960 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n %} 3 {% load url from future %} 4 {% load admin_urls %} 3 5 4 6 {% block breadcrumbs %} 5 7 <div class="breadcrumbs"> 6 <a href="../../../../">{% trans 'Home' %}</a> › 7 <a href="../../../">{{ app_label|capfirst }}</a> › 8 <a href="../../">{{ module_name }}</a> › 9 <a href="../">{{ object|truncatewords:"18" }}</a> › 10 8 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 9 › <a href="{% url 'admin:app_list' app_label=app_label %}">{{ app_label|capfirst|escape }}</a> 10 › <a href="{% url opts|admin_urlname:'changelist' %}">{{ module_name }}</a> 11 › <a href="{% url opts|admin_urlname:'changelist' %}{{ object.pk }}">{{ object|truncatewords:"18" }}</a> 12 › {% trans 'History' %} 11 13 </div> 12 14 {% endblock %} 13 15 -
django/contrib/admin/templates/registration/logged_out.html
diff --git a/django/contrib/admin/templates/registration/logged_out.html b/django/contrib/admin/templates/registration/logged_out.html index d339ef0..e95d864 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n %} 3 {% load url from future %} 3 4 4 {% block breadcrumbs %}<div class="breadcrumbs"><a href=" ../">{% trans 'Home' %}</a></div>{% endblock %}5 {% block breadcrumbs %}<div class="breadcrumbs"><a href="{% url 'admin:index' %}">{% trans 'Home' %}</a></div>{% endblock %} 5 6 6 7 {% block content %} 7 8 8 9 <p>{% trans "Thanks for spending some quality time with the Web site today." %}</p> 9 10 10 <p><a href=" ../">{% trans 'Log in again' %}</a></p>11 <p><a href="{% url 'admin:index' %}">{% trans 'Log in again' %}</a></p> 11 12 12 13 {% endblock %} -
django/contrib/admin/templates/registration/password_change_done.html
diff --git a/django/contrib/admin/templates/registration/password_change_done.html b/django/contrib/admin/templates/registration/password_change_done.html index 0c0690d..863fc96 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n %} 3 3 {% load url from future %} 4 {% block userlinks %}{% url 'django-admindocs-docroot' as docsroot %}{% if docsroot %}<a href="{{ docsroot }}">{% trans 'Documentation' %}</a> / {% endif %}{% trans 'Change password' %} / <a href="../../logout/">{% trans 'Log out' %}</a>{% endblock %} 5 {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans 'Home' %}</a> › {% trans 'Password change' %}</div>{% endblock %} 4 {% block userlinks %}{% url 'django-admindocs-docroot' as docsroot %}{% if docsroot %}<a href="{{ docsroot }}">{% trans 'Documentation' %}</a> / {% endif %}{% trans 'Change password' %} / <a href="{% url 'admin:logout' %}">{% trans 'Log out' %}</a>{% endblock %} 5 {% block breadcrumbs %} 6 <div class="breadcrumbs"> 7 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 8 › {% trans 'Password change' %} 9 </div> 10 {% endblock %} 6 11 7 12 {% block title %}{% trans 'Password change successful' %}{% endblock %} 8 13 -
django/contrib/admin/templates/registration/password_change_form.html
diff --git a/django/contrib/admin/templates/registration/password_change_form.html b/django/contrib/admin/templates/registration/password_change_form.html index f76692d..0e4ea53 100644
a b 2 2 {% load i18n static %} 3 3 {% load url from future %} 4 4 {% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}" />{% endblock %} 5 {% block userlinks %}{% url 'django-admindocs-docroot' as docsroot %}{% if docsroot %}<a href="{{ docsroot }}">{% trans 'Documentation' %}</a> / {% endif %} {% trans 'Change password' %} / <a href="../logout/">{% trans 'Log out' %}</a>{% endblock %} 6 {% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{% trans 'Home' %}</a> › {% trans 'Password change' %}</div>{% endblock %} 5 {% block userlinks %}{% url 'django-admindocs-docroot' as docsroot %}{% if docsroot %}<a href="{{ docsroot }}">{% trans 'Documentation' %}</a> / {% endif %} {% trans 'Change password' %} / <a href="{% url 'admin:logout' %}">{% trans 'Log out' %}</a>{% endblock %} 6 {% block breadcrumbs %} 7 <div class="breadcrumbs"> 8 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 9 › {% trans 'Password change' %} 10 </div> 11 {% endblock %} 7 12 8 13 {% block title %}{% trans 'Password change' %}{% endblock %} 9 14 -
django/contrib/admin/templates/registration/password_reset_complete.html
diff --git a/django/contrib/admin/templates/registration/password_reset_complete.html b/django/contrib/admin/templates/registration/password_reset_complete.html index fceb167..7c07707 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n %} 3 {% load url from future %} 3 4 4 {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">{% trans 'Home' %}</a> › {% trans 'Password reset' %}</div>{% endblock %} 5 {% block breadcrumbs %} 6 <div class="breadcrumbs"> 7 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 8 › {% trans 'Password reset' %} 9 </div> 10 {% endblock %} 5 11 6 12 {% block title %}{% trans 'Password reset complete' %}{% endblock %} 7 13 -
django/contrib/admin/templates/registration/password_reset_confirm.html
diff --git a/django/contrib/admin/templates/registration/password_reset_confirm.html b/django/contrib/admin/templates/registration/password_reset_confirm.html index df9cf1b..d5299eb 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n %} 3 {% load url from future %} 3 4 4 {% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{% trans 'Home' %}</a> › {% trans 'Password reset confirmation' %}</div>{% endblock %} 5 {% block breadcrumbs %} 6 <div class="breadcrumbs"> 7 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 8 › {% trans 'Password reset confirmation' %} 9 </div> 10 {% endblock %} 5 11 6 12 {% block title %}{% trans 'Password reset' %}{% endblock %} 7 13 -
django/contrib/admin/templates/registration/password_reset_done.html
diff --git a/django/contrib/admin/templates/registration/password_reset_done.html b/django/contrib/admin/templates/registration/password_reset_done.html index e223bdb..fd73af8 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n %} 3 {% load url from future %} 3 4 4 {% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{% trans 'Home' %}</a> › {% trans 'Password reset' %}</div>{% endblock %} 5 {% block breadcrumbs %} 6 <div class="breadcrumbs"> 7 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 8 › {% trans 'Password reset' %} 9 </div> 10 {% endblock %} 5 11 6 12 {% block title %}{% trans 'Password reset successful' %}{% endblock %} 7 13 -
django/contrib/admin/templates/registration/password_reset_form.html
diff --git a/django/contrib/admin/templates/registration/password_reset_form.html b/django/contrib/admin/templates/registration/password_reset_form.html index d3a1284..2b591fe 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n %} 3 {% load url from future %} 3 4 4 {% block breadcrumbs %}<div class="breadcrumbs"><a href="../">{% trans 'Home' %}</a> › {% trans 'Password reset' %}</div>{% endblock %} 5 {% block breadcrumbs %} 6 <div class="breadcrumbs"> 7 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 8 › {% trans 'Password reset' %} 9 </div> 10 {% endblock %} 5 11 6 12 {% block title %}{% trans "Password reset" %}{% endblock %} 7 13 -
new file django/contrib/admin/templatetags/admin_urls.py
diff --git a/django/contrib/admin/templatetags/admin_urls.py b/django/contrib/admin/templatetags/admin_urls.py new file mode 100644 index 0000000..53dc65b
- + 1 from django.core.urlresolvers import reverse, NoReverseMatch 2 from django import template 3 4 register = template.Library() 5 6 @register.filter 7 def admin_urlname(value, arg): 8 return 'admin:%s_%s_%s' % (value.app_label, value.module_name, arg) -
django/contrib/admindocs/templates/admin_doc/bookmarklets.html
diff --git a/django/contrib/admindocs/templates/admin_doc/bookmarklets.html b/django/contrib/admindocs/templates/admin_doc/bookmarklets.html index 6447529..baa717c 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 3 {% block breadcrumbs %}{% load i18n %}<div class="breadcrumbs"><a href="../../">{% trans "Home" %}</a> › <a href="../">{% trans "Documentation" %}</a> › {% trans "Bookmarklets" %}</div>{% endblock %} 2 {% load i18n %} 3 {% load url from future %} 4 5 {% block breadcrumbs %} 6 <div class="breadcrumbs"> 7 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 8 › <a href="{% url 'django-admindocs-docroot' %}">{% trans 'Documentation' %}</a> 9 › {% trans 'Bookmarklets' %} 10 </div> 11 {% endblock %} 4 12 {% block title %}{% trans "Documentation bookmarklets" %}{% endblock %} 5 13 6 14 {% block content %} -
django/contrib/admindocs/templates/admin_doc/index.html
diff --git a/django/contrib/admindocs/templates/admin_doc/index.html b/django/contrib/admindocs/templates/admin_doc/index.html index a8b21c3..652fbfd 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n %} 3 {% block breadcrumbs %}<div class="breadcrumbs"><a href="{{ root_path }}">Home</a> › Documentation</div>{% endblock %} 3 {% load url from future %} 4 5 {% block breadcrumbs %} 6 <div class="breadcrumbs"> 7 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 8 › {% trans 'Documentation' %}</a> 9 </div> 10 {% endblock %} 4 11 {% block title %}Documentation{% endblock %} 5 12 6 13 {% block content %} -
django/contrib/admindocs/templates/admin_doc/missing_docutils.html
diff --git a/django/contrib/admindocs/templates/admin_doc/missing_docutils.html b/django/contrib/admindocs/templates/admin_doc/missing_docutils.html index 97c9d47..34c18ff 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n %} 3 {% block breadcrumbs %}<div class="breadcrumbs"><a href="../">Home</a> › Documentation</div>{% endblock %} 3 {% load url from future %} 4 5 {% block breadcrumbs %} 6 <div class="breadcrumbs"> 7 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 8 › {% trans 'Documentation' %}</a> 9 </div> 4 10 {% block title %}Please install docutils{% endblock %} 5 11 6 12 {% block content %} -
django/contrib/admindocs/templates/admin_doc/model_detail.html
diff --git a/django/contrib/admindocs/templates/admin_doc/model_detail.html b/django/contrib/admindocs/templates/admin_doc/model_detail.html index 828df18..82cb405 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n %} 3 {% load url from future %} 4 3 5 {% block extrahead %} 4 6 {{ block.super }} 5 7 <style type="text/css"> … … 8 10 </style> 9 11 {% endblock %} 10 12 11 {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> › <a href="../../">Documentation</a> › <a href="../">Models</a> › {{ name }}</div>{% endblock %} 13 {% block breadcrumbs %} 14 <div class="breadcrumbs"> 15 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 16 › <a href="{% url 'django-admindocs-docroot' %}">{% trans 'Documentation' %}</a> 17 › <a href="{% url 'django-admindocs-models-index' %}">{% trans 'Models' %}</a> 18 › {{ name }} 19 </div> 20 {% endblock %} 12 21 13 22 {% block title %}Model: {{ name }}{% endblock %} 14 23 … … 41 50 </table> 42 51 </div> 43 52 44 <p class="small"><a href=" ../">‹ Back to Models Documentation</a></p>53 <p class="small"><a href="{% url 'django-admindocs-models-index' %}">‹ Back to Models Documentation</a></p> 45 54 </div> 46 55 {% endblock %} -
django/contrib/admindocs/templates/admin_doc/model_index.html
diff --git a/django/contrib/admindocs/templates/admin_doc/model_index.html b/django/contrib/admindocs/templates/admin_doc/model_index.html index 47c94c0..4eb3cf6 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n %} 3 {% load url from future %} 4 3 5 {% block coltype %}colSM{% endblock %} 4 {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> › <a href="../">Documentation</a> › Models</div>{% endblock %} 6 7 {% block breadcrumbs %} 8 <div class="breadcrumbs"> 9 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 10 › <a href="{% url 'django-admindocs-docroot' %}">{% trans 'Documentation' %}</a> 11 › {% trans 'Models' %} 12 </div> 13 {% endblock %} 5 14 6 15 {% block title %}Models{% endblock %} 7 16 … … 19 28 <table class="xfull"> 20 29 {% for model in group.list %} 21 30 <tr> 22 <th><a href="{ { model.app_label }}.{{ model.object_name.lower }}/">{{ model.object_name }}</a></th>31 <th><a href="{% url 'django-admindocs-models-detail' app_label=model.app_label model_name=model.object_name.lower %}">{{ model.object_name }}</a></th> 23 32 </tr> 24 33 {% endfor %} 25 34 </table> -
django/contrib/admindocs/templates/admin_doc/template_detail.html
diff --git a/django/contrib/admindocs/templates/admin_doc/template_detail.html b/django/contrib/admindocs/templates/admin_doc/template_detail.html index c04dedc..307dd62 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n %} 3 {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> › <a href="../../">Documentation</a> › Templates › {{ name }}</div>{% endblock %} 3 {% load url from future %} 4 5 {% block breadcrumbs %} 6 <div class="breadcrumbs"> 7 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 8 › <a href="{% url 'django-admindocs-docroot' %}">{% trans 'Documentation' %}</a> 9 › {% trans 'Templates' %} 10 › {{ name }} 11 </div> 12 {% endblock %} 4 13 5 14 {% block title %}Template: {{ name }}{% endblock %} 6 15 … … 17 26 </ol> 18 27 {% endfor %} 19 28 20 <p class="small"><a href=" ../../">‹ Back to Documentation</a></p>29 <p class="small"><a href="{% url 'django-admindocs-docroot' %}">‹ Back to Documentation</a></p> 21 30 {% endblock %} -
django/contrib/admindocs/templates/admin_doc/template_filter_index.html
diff --git a/django/contrib/admindocs/templates/admin_doc/template_filter_index.html b/django/contrib/admindocs/templates/admin_doc/template_filter_index.html index 46ccf0f..1809bc9 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n %} 3 {% load url from future %} 4 3 5 {% block coltype %}colSM{% endblock %} 4 {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> › <a href="../">Documentation</a> › filters</div>{% endblock %} 6 {% block breadcrumbs %} 7 <div class="breadcrumbs"> 8 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 9 › <a href="{% url 'django-admindocs-docroot' %}">{% trans 'Documentation' %}</a> 10 › {% trans 'Filters' %} 11 </div> 12 {% endblock %} 5 13 {% block title %}Template filters{% endblock %} 6 14 7 15 {% block content %} -
django/contrib/admindocs/templates/admin_doc/template_tag_index.html
diff --git a/django/contrib/admindocs/templates/admin_doc/template_tag_index.html b/django/contrib/admindocs/templates/admin_doc/template_tag_index.html index 676c025..18e5d95 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n %} 3 {% load url from future %} 4 3 5 {% block coltype %}colSM{% endblock %} 4 {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> › <a href="../">Documentation</a> › Tags</div>{% endblock %} 6 {% block breadcrumbs %} 7 <div class="breadcrumbs"> 8 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 9 › <a href="{% url 'django-admindocs-docroot' %}">{% trans 'Documentation' %}</a> 10 › {% trans 'Tags' %} 11 </div> 12 {% endblock %} 5 13 {% block title %}Template tags{% endblock %} 6 14 7 15 {% block content %} -
django/contrib/admindocs/templates/admin_doc/view_detail.html
diff --git a/django/contrib/admindocs/templates/admin_doc/view_detail.html b/django/contrib/admindocs/templates/admin_doc/view_detail.html index c6d080c..41c8121 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n %} 3 {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../../">Home</a> › <a href="../../">Documentation</a> › <a href="../">Views</a> › {{ name }}</div>{% endblock %} 3 {% load url from future %} 4 5 {% block breadcrumbs %} 6 <div class="breadcrumbs"> 7 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 8 › <a href="{% url 'django-admindocs-docroot' %}">{% trans 'Documentation' %}</a> 9 › <a href="{% url 'django-admindocs-views-index' %}">{% trans 'Views' %}</a> 10 › {{ name }} 11 </div> 12 {% endblock %} 4 13 {% block title %}View: {{ name }}{% endblock %} 5 14 6 15 {% block content %} … … 21 30 <p>{{ meta.Templates }}</p> 22 31 {% endif %} 23 32 24 <p class="small"><a href=" ../">‹ Back to Views Documentation</a></p>33 <p class="small"><a href="{% url 'django-admindocs-views-index' %}">‹ Back to Views Documentation</a></p> 25 34 {% endblock %} -
django/contrib/admindocs/templates/admin_doc/view_index.html
diff --git a/django/contrib/admindocs/templates/admin_doc/view_index.html b/django/contrib/admindocs/templates/admin_doc/view_index.html index 6b10fa6..e508c84 100644
a b 1 1 {% extends "admin/base_site.html" %} 2 2 {% load i18n %} 3 {% load url from future %} 4 3 5 {% block coltype %}colSM{% endblock %} 4 {% block breadcrumbs %}<div class="breadcrumbs"><a href="../../">Home</a> › <a href="../">Documentation</a> › Views</div>{% endblock %} 6 {% block breadcrumbs %} 7 <div class="breadcrumbs"> 8 <a href="{% url 'admin:index' %}">{% trans 'Home' %}</a> 9 › <a href="{% url 'django-admindocs-docroot' %}">{% trans 'Documentation' %}</a> 10 › {% trans 'Views' %} 11 </div> 12 {% endblock %} 5 13 {% block title %}Views{% endblock %} 6 14 7 15 {% block content %} … … 29 37 30 38 {% for view in site_views.list|dictsort:"url" %} 31 39 {% ifchanged %} 32 <h3><a href="{ { view.module }}.{{ view.name }}/">{{ view.url }}</a></h3>33 <p class="small quiet">View function: {{ view. module }}.{{ view.name }}</p>40 <h3><a href="{% url 'django-admindocs-views-detail' view=view.full_name %}">{{ view.url }}</a></h3> 41 <p class="small quiet">View function: {{ view.full_name }}</p> 34 42 <p>{{ view.title }}</p> 35 43 <hr /> 36 44 {% endifchanged %} -
django/contrib/admindocs/views.py
diff --git a/django/contrib/admindocs/views.py b/django/contrib/admindocs/views.py index 28319be..9725865 100644
a b def view_index(request): 136 136 site_obj = GenericSite() 137 137 for (func, regex) in view_functions: 138 138 views.append({ 139 'name': getattr(func, '__name__', func.__class__.__name__), 140 'module': func.__module__, 139 'full_name': '%s.%s' % (func.__module__, getattr(func, '__name__', func.__class__.__name__)), 141 140 'site_id': settings_mod.SITE_ID, 142 141 'site': site_obj, 143 142 'url': simplify_regex(regex), -
docs/ref/contrib/admin/index.txt
diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt index 2da6774..21145c5 100644
a b if you specifically wanted the admin view from the admin instance named 1960 1960 1961 1961 For more details, see the documentation on :ref:`reversing namespaced URLs 1962 1962 <topics-http-reversing-url-namespaces>`. 1963 1964 To allow easier reversing of the admin urls in templates, Django provides an 1965 ``admin_url`` filter which takes an action as argument: 1966 1967 .. code-block:: html+django 1968 1969 {% load admin_urls %} 1970 {% load url from future %} 1971 <a href="{% url opts|admin_urlname:'add' %}">Add user</a> 1972 <a href="{% url opts|admin_urlname:'delete' user.pk %}">Delete this user</a> 1973 1974 The action in the examples above match the last part of the URL names for 1975 :class:`ModelAdmin` instances described above. The ``opts`` variable can be any 1976 object which has an ``app_label`` and ``module_name`` and is usually supplied 1977 by the admin views for the current model. -
new file tests/regressiontests/admin_changelist/admin.py
diff --git a/tests/regressiontests/admin_changelist/admin.py b/tests/regressiontests/admin_changelist/admin.py new file mode 100644 index 0000000..9490cd5
- + 1 from django.core.paginator import Paginator 2 from django.contrib import admin 3 4 from models import (Child, Parent, Genre, Band, Musician, Group, Quartet, 5 Membership, ChordsMusician, ChordsBand, Invitation) 6 7 site = admin.AdminSite(name="admin") 8 9 class CustomPaginator(Paginator): 10 def __init__(self, queryset, page_size, orphans=0, allow_empty_first_page=True): 11 super(CustomPaginator, self).__init__(queryset, 5, orphans=2, 12 allow_empty_first_page=allow_empty_first_page) 13 14 15 class ParentAdmin(admin.ModelAdmin): 16 list_filter = ['child__name'] 17 search_fields = ['child__name'] 18 19 20 class ChildAdmin(admin.ModelAdmin): 21 list_display = ['name', 'parent'] 22 list_per_page = 10 23 24 def queryset(self, request): 25 return super(ChildAdmin, self).queryset(request).select_related("parent__name") 26 27 28 class CustomPaginationAdmin(ChildAdmin): 29 paginator = CustomPaginator 30 31 32 class FilteredChildAdmin(admin.ModelAdmin): 33 list_display = ['name', 'parent'] 34 list_per_page = 10 35 36 def queryset(self, request): 37 return super(FilteredChildAdmin, self).queryset(request).filter( 38 name__contains='filtered') 39 40 41 class BandAdmin(admin.ModelAdmin): 42 list_filter = ['genres'] 43 44 45 class GroupAdmin(admin.ModelAdmin): 46 list_filter = ['members'] 47 48 49 class QuartetAdmin(admin.ModelAdmin): 50 list_filter = ['members'] 51 52 53 class ChordsBandAdmin(admin.ModelAdmin): 54 list_filter = ['members'] 55 56 57 class DynamicListDisplayChildAdmin(admin.ModelAdmin): 58 list_display = ('name', 'parent') 59 60 def get_list_display(self, request): 61 my_list_display = list(self.list_display) 62 if request.user.username == 'noparents': 63 my_list_display.remove('parent') 64 65 return my_list_display 66 67 site.register(Child, DynamicListDisplayChildAdmin) -
tests/regressiontests/admin_changelist/tests.py
diff --git a/tests/regressiontests/admin_changelist/tests.py b/tests/regressiontests/admin_changelist/tests.py index 09ec190..83ce6e3 100644
a b from __future__ import with_statement 3 3 from django.contrib import admin 4 4 from django.contrib.admin.options import IncorrectLookupParameters 5 5 from django.contrib.admin.views.main import ChangeList, SEARCH_VAR, ALL_VAR 6 from django.core.paginator import Paginator7 6 from django.template import Context, Template 8 7 from django.test import TestCase 9 8 from django.test.client import RequestFactory … … from django.contrib.auth.models import User 12 11 from models import (Child, Parent, Genre, Band, Musician, Group, Quartet, 13 12 Membership, ChordsMusician, ChordsBand, Invitation) 14 13 14 from admin import (ChildAdmin, QuartetAdmin, BandAdmin, ChordsBandAdmin, 15 GroupAdmin, ParentAdmin, DynamicListDisplayChildAdmin, CustomPaginationAdmin, 16 FilteredChildAdmin, CustomPaginator, site as custom_site) 17 15 18 16 19 class ChangeListTests(TestCase): 20 urls = "regressiontests.admin_changelist.urls" 21 17 22 def setUp(self): 18 23 self.factory = RequestFactory() 19 24 … … class ChangeListTests(TestCase): 129 134 new_child = Child.objects.create(name='name %s' % i, parent=new_parent) 130 135 131 136 request = self.factory.get('/child/') 132 m = ChildAdmin(Child, admin.site) 133 m.list_display = ['id', 'name', 'parent'] 134 m.list_display_links = ['id'] 135 m.list_editable = ['name'] 136 m.paginator = CustomPaginator 137 m = CustomPaginationAdmin(Child, admin.site) 137 138 138 139 cl = ChangeList(request, Child, m.list_display, m.list_display_links, 139 140 m.list_filter, m.date_hierarchy, m.search_fields, … … class ChangeListTests(TestCase): 330 331 request.user = user 331 332 return request 332 333 334 m = custom_site._registry[Child] 333 335 # Test with user 'noparents' 334 m = DynamicListDisplayChildAdmin(Child, admin.site)335 336 request = _mocked_authenticated_request(user_noparents) 336 337 response = m.changelist_view(request) 337 338 # XXX - Calling render here to avoid ContentNotRenderedError to be … … class ChangeListTests(TestCase): 340 341 self.assertNotContains(response, 'Parent object') 341 342 342 343 # Test with user 'parents' 343 m = DynamicListDisplayChildAdmin(Child, admin.site)344 344 request = _mocked_authenticated_request(user_parents) 345 345 response = m.changelist_view(request) 346 346 # XXX - #15826 347 347 response.render() 348 348 self.assertContains(response, 'Parent object') 349 349 350 custom_site.unregister(Child) 350 351 # Test default implementation 351 m = ChildAdmin(Child, admin.site) 352 custom_site.register(Child, ChildAdmin) 353 m = custom_site._registry[Child] 352 354 request = _mocked_authenticated_request(user_noparents) 353 355 response = m.changelist_view(request) 354 356 # XXX - #15826 … … class ChangeListTests(TestCase): 383 385 cl.get_results(request) 384 386 self.assertEqual(len(cl.result_list), 10) 385 387 386 387 class ParentAdmin(admin.ModelAdmin):388 list_filter = ['child__name']389 search_fields = ['child__name']390 391 392 class ChildAdmin(admin.ModelAdmin):393 list_display = ['name', 'parent']394 list_per_page = 10395 396 def queryset(self, request):397 return super(ChildAdmin, self).queryset(request).select_related("parent__name")398 399 400 class FilteredChildAdmin(admin.ModelAdmin):401 list_display = ['name', 'parent']402 list_per_page = 10403 404 def queryset(self, request):405 return super(FilteredChildAdmin, self).queryset(request).filter(406 name__contains='filtered')407 408 409 class CustomPaginator(Paginator):410 def __init__(self, queryset, page_size, orphans=0, allow_empty_first_page=True):411 super(CustomPaginator, self).__init__(queryset, 5, orphans=2,412 allow_empty_first_page=allow_empty_first_page)413 414 415 class BandAdmin(admin.ModelAdmin):416 list_filter = ['genres']417 418 419 class GroupAdmin(admin.ModelAdmin):420 list_filter = ['members']421 422 423 class QuartetAdmin(admin.ModelAdmin):424 list_filter = ['members']425 426 427 class ChordsBandAdmin(admin.ModelAdmin):428 list_filter = ['members']429 430 431 class DynamicListDisplayChildAdmin(admin.ModelAdmin):432 list_display = ('name', 'parent')433 434 def get_list_display(self, request):435 my_list_display = list(self.list_display)436 if request.user.username == 'noparents':437 my_list_display.remove('parent')438 439 return my_list_display -
new file tests/regressiontests/admin_changelist/urls.py
diff --git a/tests/regressiontests/admin_changelist/urls.py b/tests/regressiontests/admin_changelist/urls.py new file mode 100644 index 0000000..1cbb496
- + 1 from django.conf.urls.defaults import * 2 3 import admin 4 5 urlpatterns = patterns('', 6 (r'^admin/', include(admin.site.urls)), 7 ) -
new file tests/regressiontests/admin_custom_urls/__init__.py
diff --git a/tests/regressiontests/admin_custom_urls/__init__.py b/tests/regressiontests/admin_custom_urls/__init__.py new file mode 100644 index 0000000..792d600
- + 1 # -
new file tests/regressiontests/admin_custom_urls/fixtures/actions.json
diff --git a/tests/regressiontests/admin_custom_urls/fixtures/actions.json b/tests/regressiontests/admin_custom_urls/fixtures/actions.json new file mode 100644 index 0000000..d803393
- + 1 [ 2 { 3 "pk": "delete", 4 "model": "admin_custom_urls.action", 5 "fields": { 6 "description": "Remove things." 7 } 8 }, 9 { 10 "pk": "rename", 11 "model": "admin_custom_urls.action", 12 "fields": { 13 "description": "Gives things other names." 14 } 15 }, 16 { 17 "pk": "add", 18 "model": "admin_custom_urls.action", 19 "fields": { 20 "description": "Add things." 21 } 22 }, 23 { 24 "pk": "path/to/file/", 25 "model": "admin_custom_urls.action", 26 "fields": { 27 "description": "An action with '/' in its name." 28 } 29 }, 30 { 31 "pk": "path/to/html/document.html", 32 "model": "admin_custom_urls.action", 33 "fields": { 34 "description": "An action with a name similar to a HTML doc path." 35 } 36 }, 37 { 38 "pk": "javascript:alert('Hello world');\">Click here</a>", 39 "model": "admin_custom_urls.action", 40 "fields": { 41 "description": "An action with a name suspected of being a XSS attempt" 42 } 43 } 44 ] 45 No newline at end of file -
new file tests/regressiontests/admin_custom_urls/fixtures/users.json
diff --git a/tests/regressiontests/admin_custom_urls/fixtures/users.json b/tests/regressiontests/admin_custom_urls/fixtures/users.json new file mode 100644 index 0000000..72d86d7
- + 1 [ 2 { 3 "pk": 100, 4 "model": "auth.user", 5 "fields": { 6 "username": "super", 7 "first_name": "Super", 8 "last_name": "User", 9 "is_active": true, 10 "is_superuser": true, 11 "is_staff": true, 12 "last_login": "2007-05-30 13:20:10", 13 "groups": [], 14 "user_permissions": [], 15 "password": "sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158", 16 "email": "super@example.com", 17 "date_joined": "2007-05-30 13:20:10" 18 } 19 } 20 ] -
new file tests/regressiontests/admin_custom_urls/models.py
diff --git a/tests/regressiontests/admin_custom_urls/models.py b/tests/regressiontests/admin_custom_urls/models.py new file mode 100644 index 0000000..f8c83a9
- + 1 from functools import update_wrapper 2 3 from django.contrib import admin 4 from django.db import models 5 6 7 class Action(models.Model): 8 name = models.CharField(max_length=50, primary_key=True) 9 description = models.CharField(max_length=70) 10 11 def __unicode__(self): 12 return self.name 13 14 15 class ActionAdmin(admin.ModelAdmin): 16 """ 17 A ModelAdmin for the Action model that changes the URL of the add_view 18 to '<app name>/<model name>/!add/' 19 The Action model has a CharField PK. 20 """ 21 22 list_display = ('name', 'description') 23 24 def remove_url(self, name): 25 """ 26 Remove all entries named 'name' from the ModelAdmin instance URL 27 patterns list 28 """ 29 return filter(lambda e: e.name != name, super(ActionAdmin, self).get_urls()) 30 31 def get_urls(self): 32 # Add the URL of our custom 'add_view' view to the front of the URLs 33 # list. Remove the existing one(s) first 34 from django.conf.urls.defaults import patterns, url 35 36 def wrap(view): 37 def wrapper(*args, **kwargs): 38 return self.admin_site.admin_view(view)(*args, **kwargs) 39 return update_wrapper(wrapper, view) 40 41 info = self.model._meta.app_label, self.model._meta.module_name 42 43 view_name = '%s_%s_add' % info 44 45 return patterns('', 46 url(r'^!add/$', wrap(self.add_view), name=view_name), 47 ) + self.remove_url(view_name) 48 49 50 admin.site.register(Action, ActionAdmin) -
new file tests/regressiontests/admin_custom_urls/tests.py
diff --git a/tests/regressiontests/admin_custom_urls/tests.py b/tests/regressiontests/admin_custom_urls/tests.py new file mode 100644 index 0000000..cfc6b85
- + 1 from django.core.urlresolvers import reverse 2 from django.template.response import TemplateResponse 3 from django.test import TestCase 4 5 from models import Action 6 7 8 class AdminCustomUrlsTest(TestCase): 9 fixtures = ['users.json', 'actions.json'] 10 11 def setUp(self): 12 self.client.login(username='super', password='secret') 13 14 def tearDown(self): 15 self.client.logout() 16 17 def testBasicAddGet(self): 18 """ 19 A smoke test to ensure GET on the add_view works. 20 """ 21 response = self.client.get('/custom_urls/admin/admin_custom_urls/action/!add/') 22 self.assertIsInstance(response, TemplateResponse) 23 self.assertEqual(response.status_code, 200) 24 25 def testAddWithGETArgs(self): 26 response = self.client.get('/custom_urls/admin/admin_custom_urls/action/!add/', {'name': 'My Action'}) 27 self.assertEqual(response.status_code, 200) 28 self.assertTrue( 29 'value="My Action"' in response.content, 30 "Couldn't find an input with the right value in the response." 31 ) 32 33 def testBasicAddPost(self): 34 """ 35 A smoke test to ensure POST on add_view works. 36 """ 37 post_data = { 38 '_popup': u'1', 39 "name": u'Action added through a popup', 40 "description": u"Description of added action", 41 } 42 response = self.client.post('/custom_urls/admin/admin_custom_urls/action/!add/', post_data) 43 self.assertEqual(response.status_code, 200) 44 self.assertContains(response, 'dismissAddAnotherPopup') 45 self.assertContains(response, 'Action added through a popup') 46 47 def testAdminUrlsNoClash(self): 48 """ 49 Test that some admin URLs work correctly. The model has a CharField 50 PK and the add_view URL has been customized. 51 """ 52 # Should get the change_view for model instance with PK 'add', not show 53 # the add_view 54 response = self.client.get('/custom_urls/admin/admin_custom_urls/action/add/') 55 self.assertEqual(response.status_code, 200) 56 self.assertContains(response, 'Change action') 57 58 # Ditto, but use reverse() to build the URL 59 path = reverse('admin:%s_action_change' % Action._meta.app_label, 60 args=('add',)) 61 response = self.client.get(path) 62 self.assertEqual(response.status_code, 200) 63 self.assertContains(response, 'Change action') 64 65 # Should correctly get the change_view for the model instance with the 66 # funny-looking PK 67 path = reverse('admin:%s_action_change' % Action._meta.app_label, 68 args=("path/to/html/document.html",)) 69 response = self.client.get(path) 70 self.assertEqual(response.status_code, 200) 71 self.assertContains(response, 'Change action') 72 self.assertContains(response, 'value="path/to/html/document.html"') -
new file tests/regressiontests/admin_custom_urls/urls.py
diff --git a/tests/regressiontests/admin_custom_urls/urls.py b/tests/regressiontests/admin_custom_urls/urls.py new file mode 100644 index 0000000..6c2761a
- + 1 from django.conf.urls.defaults import * 2 from django.contrib import admin 3 4 urlpatterns = patterns('', 5 (r'^admin/', include(admin.site.urls)), 6 ) 7 -
new file tests/regressiontests/admin_inlines/admin.py
diff --git a/tests/regressiontests/admin_inlines/admin.py b/tests/regressiontests/admin_inlines/admin.py new file mode 100644 index 0000000..098d7b5
- + 1 from django.contrib import admin 2 from django import forms 3 4 from models import * 5 6 site = admin.AdminSite(name="admin") 7 8 9 class BookInline(admin.TabularInline): 10 model = Author.books.through 11 12 13 class AuthorAdmin(admin.ModelAdmin): 14 inlines = [BookInline] 15 16 17 class InnerInline(admin.StackedInline): 18 model = Inner 19 can_delete = False 20 readonly_fields = ('readonly',) # For bug #13174 tests. 21 22 23 class HolderAdmin(admin.ModelAdmin): 24 25 class Media: 26 js = ('my_awesome_admin_scripts.js',) 27 28 29 class InnerInline2(admin.StackedInline): 30 model = Inner2 31 32 class Media: 33 js = ('my_awesome_inline_scripts.js',) 34 35 36 class InnerInline3(admin.StackedInline): 37 model = Inner3 38 39 class Media: 40 js = ('my_awesome_inline_scripts.js',) 41 42 43 class TitleForm(forms.ModelForm): 44 45 def clean(self): 46 cleaned_data = self.cleaned_data 47 title1 = cleaned_data.get("title1") 48 title2 = cleaned_data.get("title2") 49 if title1 != title2: 50 raise forms.ValidationError("The two titles must be the same") 51 return cleaned_data 52 53 54 class TitleInline(admin.TabularInline): 55 model = Title 56 form = TitleForm 57 extra = 1 58 59 60 class Inner4StackedInline(admin.StackedInline): 61 model = Inner4Stacked 62 63 64 class Inner4TabularInline(admin.TabularInline): 65 model = Inner4Tabular 66 67 68 class Holder4Admin(admin.ModelAdmin): 69 inlines = [Inner4StackedInline, Inner4TabularInline] 70 71 72 class InlineWeakness(admin.TabularInline): 73 model = ShoppingWeakness 74 extra = 1 75 76 77 class QuestionInline(admin.TabularInline): 78 model = Question 79 readonly_fields=['call_me'] 80 81 def call_me(self, obj): 82 return 'Callable in QuestionInline' 83 84 85 class PollAdmin(admin.ModelAdmin): 86 inlines = [QuestionInline] 87 88 def call_me(self, obj): 89 return 'Callable in PollAdmin' 90 91 92 class ChapterInline(admin.TabularInline): 93 model = Chapter 94 readonly_fields=['call_me'] 95 96 def call_me(self, obj): 97 return 'Callable in ChapterInline' 98 99 100 class NovelAdmin(admin.ModelAdmin): 101 inlines = [ChapterInline] 102 103 104 site.register(TitleCollection, inlines=[TitleInline]) 105 # Test bug #12561 and #12778 106 # only ModelAdmin media 107 site.register(Holder, HolderAdmin, inlines=[InnerInline]) 108 # ModelAdmin and Inline media 109 site.register(Holder2, HolderAdmin, inlines=[InnerInline2]) 110 # only Inline media 111 site.register(Holder3, inlines=[InnerInline3]) 112 113 site.register(Poll, PollAdmin) 114 site.register(Novel, NovelAdmin) 115 site.register(Fashionista, inlines=[InlineWeakness]) 116 site.register(Holder4, Holder4Admin) 117 site.register(Author, AuthorAdmin) 118 -
tests/regressiontests/admin_inlines/models.py
diff --git a/tests/regressiontests/admin_inlines/models.py b/tests/regressiontests/admin_inlines/models.py index 8d9ca7c..f4e58f2 100644
a b Testing of admin inline formsets. 3 3 4 4 """ 5 5 from django.db import models 6 from django.contrib import admin7 6 from django.contrib.contenttypes.models import ContentType 8 7 from django.contrib.contenttypes import generic 9 from django import forms 8 10 9 11 10 class Parent(models.Model): 12 11 name = models.CharField(max_length=50) … … class Parent(models.Model): 14 13 def __unicode__(self): 15 14 return self.name 16 15 16 17 17 class Teacher(models.Model): 18 18 name = models.CharField(max_length=50) 19 19 20 20 def __unicode__(self): 21 21 return self.name 22 22 23 23 24 class Child(models.Model): 24 25 name = models.CharField(max_length=50) 25 26 teacher = models.ForeignKey(Teacher) … … class Child(models.Model): 31 32 def __unicode__(self): 32 33 return u'I am %s, a child of %s' % (self.name, self.parent) 33 34 35 34 36 class Book(models.Model): 35 37 name = models.CharField(max_length=50) 36 38 39 37 40 class Author(models.Model): 38 41 name = models.CharField(max_length=50) 39 42 books = models.ManyToManyField(Book) 40 43 41 class BookInline(admin.TabularInline):42 model = Author.books.through43 44 class AuthorAdmin(admin.ModelAdmin):45 inlines = [BookInline]46 47 admin.site.register(Author, AuthorAdmin)48 44 49 45 class Holder(models.Model): 50 46 dummy = models.IntegerField() … … class Inner(models.Model): 56 52 readonly = models.CharField("Inner readonly label", max_length=1) 57 53 58 54 59 class InnerInline(admin.StackedInline):60 model = Inner61 can_delete = False62 readonly_fields = ('readonly',) # For bug #13174 tests.63 64 65 55 class Holder2(models.Model): 66 56 dummy = models.IntegerField() 67 57 … … class Inner2(models.Model): 70 60 dummy = models.IntegerField() 71 61 holder = models.ForeignKey(Holder2) 72 62 73 class HolderAdmin(admin.ModelAdmin):74 75 class Media:76 js = ('my_awesome_admin_scripts.js',)77 78 class InnerInline2(admin.StackedInline):79 model = Inner280 81 class Media:82 js = ('my_awesome_inline_scripts.js',)83 84 63 class Holder3(models.Model): 85 64 dummy = models.IntegerField() 86 65 … … class Inner3(models.Model): 89 68 dummy = models.IntegerField() 90 69 holder = models.ForeignKey(Holder3) 91 70 92 class InnerInline3(admin.StackedInline):93 model = Inner394 95 class Media:96 js = ('my_awesome_inline_scripts.js',)97 98 # Test bug #12561 and #1277899 # only ModelAdmin media100 admin.site.register(Holder, HolderAdmin, inlines=[InnerInline])101 # ModelAdmin and Inline media102 admin.site.register(Holder2, HolderAdmin, inlines=[InnerInline2])103 # only Inline media104 admin.site.register(Holder3, inlines=[InnerInline3])105 106 107 71 # Models for ticket #8190 108 72 109 73 class Holder4(models.Model): … … class Inner4Tabular(models.Model): 117 81 dummy = models.IntegerField(help_text="Awesome tabular help text is awesome.") 118 82 holder = models.ForeignKey(Holder4) 119 83 120 class Inner4StackedInline(admin.StackedInline):121 model = Inner4Stacked122 123 class Inner4TabularInline(admin.TabularInline):124 model = Inner4Tabular125 126 class Holder4Admin(admin.ModelAdmin):127 inlines = [Inner4StackedInline, Inner4TabularInline]128 129 admin.site.register(Holder4, Holder4Admin)130 131 84 132 85 # Models for #12749 133 86 … … class ShoppingWeakness(models.Model): 145 98 fashionista = models.ForeignKey(Fashionista) 146 99 item = models.ForeignKey(OutfitItem) 147 100 148 class InlineWeakness(admin.TabularInline):149 model = ShoppingWeakness150 extra = 1151 152 admin.site.register(Fashionista, inlines=[InlineWeakness])153 154 101 # Models for #13510 155 102 156 103 class TitleCollection(models.Model): … … class Title(models.Model): 161 108 title1 = models.CharField(max_length=100) 162 109 title2 = models.CharField(max_length=100) 163 110 164 class TitleForm(forms.ModelForm):165 166 def clean(self):167 cleaned_data = self.cleaned_data168 title1 = cleaned_data.get("title1")169 title2 = cleaned_data.get("title2")170 if title1 != title2:171 raise forms.ValidationError("The two titles must be the same")172 return cleaned_data173 174 class TitleInline(admin.TabularInline):175 model = Title176 form = TitleForm177 extra = 1178 179 admin.site.register(TitleCollection, inlines=[TitleInline])180 181 111 # Models for #15424 182 112 183 113 class Poll(models.Model): … … class Poll(models.Model): 186 116 class Question(models.Model): 187 117 poll = models.ForeignKey(Poll) 188 118 189 class QuestionInline(admin.TabularInline):190 model = Question191 readonly_fields=['call_me']192 193 def call_me(self, obj):194 return 'Callable in QuestionInline'195 196 class PollAdmin(admin.ModelAdmin):197 inlines = [QuestionInline]198 199 def call_me(self, obj):200 return 'Callable in PollAdmin'201 202 119 class Novel(models.Model): 203 120 name = models.CharField(max_length=40) 204 121 205 122 class Chapter(models.Model): 206 123 novel = models.ForeignKey(Novel) 207 124 208 class ChapterInline(admin.TabularInline):209 model = Chapter210 readonly_fields=['call_me']211 212 def call_me(self, obj):213 return 'Callable in ChapterInline'214 215 class NovelAdmin(admin.ModelAdmin):216 inlines = [ChapterInline]217 218 admin.site.register(Poll, PollAdmin)219 admin.site.register(Novel, NovelAdmin) -
tests/regressiontests/admin_inlines/tests.py
diff --git a/tests/regressiontests/admin_inlines/tests.py b/tests/regressiontests/admin_inlines/tests.py index 45ecb70..efa6cf6 100644
a b from django.contrib.contenttypes.models import ContentType 3 3 from django.test import TestCase 4 4 5 5 # local test models 6 from models import (Holder, Inner, InnerInline,Holder2, Inner2, Holder3,6 from models import (Holder, Inner, Holder2, Inner2, Holder3, 7 7 Inner3, Person, OutfitItem, Fashionista, Teacher, Parent, Child) 8 from admin import InnerInline 8 9 9 10 10 11 class TestInline(TestCase): 12 urls = "regressiontests.admin_inlines.urls" 11 13 fixtures = ['admin-views-users.xml'] 12 14 13 15 def setUp(self): 14 16 holder = Holder(dummy=13) 15 17 holder.save() 16 18 Inner(dummy=42, holder=holder).save() 17 self.change_url = '/ test_admin/admin/admin_inlines/holder/%i/' % holder.id19 self.change_url = '/admin/admin_inlines/holder/%i/' % holder.id 18 20 19 21 result = self.client.login(username='super', password='secret') 20 22 self.assertEqual(result, True) … … class TestInline(TestCase): 36 38 """Bug #13174.""" 37 39 holder = Holder.objects.create(dummy=42) 38 40 inner = Inner.objects.create(holder=holder, dummy=42, readonly='') 39 response = self.client.get('/ test_admin/admin/admin_inlines/holder/%i/'41 response = self.client.get('/admin/admin_inlines/holder/%i/' 40 42 % holder.id) 41 43 self.assertContains(response, '<label>Inner readonly label:</label>') 42 44 43 45 def test_many_to_many_inlines(self): 44 46 "Autogenerated many-to-many inlines are displayed correctly (#13407)" 45 response = self.client.get('/ test_admin/admin/admin_inlines/author/add/')47 response = self.client.get('/admin/admin_inlines/author/add/') 46 48 # The heading for the m2m inline block uses the right text 47 49 self.assertContains(response, '<h2>Author-book relationships</h2>') 48 50 # The "add another" label is correct … … class TestInline(TestCase): 63 65 'max_weight': 0, 64 66 'shoppingweakness_set-0-item': item.id, 65 67 } 66 response = self.client.post('/ test_admin/admin/admin_inlines/fashionista/add/', data)68 response = self.client.post('/admin/admin_inlines/fashionista/add/', data) 67 69 self.assertEqual(response.status_code, 302) 68 70 self.assertEqual(len(Fashionista.objects.filter(person__firstname='Imelda')), 1) 69 71 … … class TestInline(TestCase): 80 82 'title_set-0-title1': 'a title', 81 83 'title_set-0-title2': 'a different title', 82 84 } 83 response = self.client.post('/ test_admin/admin/admin_inlines/titlecollection/add/', data)85 response = self.client.post('/admin/admin_inlines/titlecollection/add/', data) 84 86 # Here colspan is "4": two fields (title1 and title2), one hidden field and the delete checkbock. 85 87 self.assertContains(response, '<tr><td colspan="4"><ul class="errorlist"><li>The two titles must be the same</li></ul></td></tr>') 86 88 … … class TestInline(TestCase): 88 90 """Admin inline `readonly_field` shouldn't invoke parent ModelAdmin callable""" 89 91 # Identically named callable isn't present in the parent ModelAdmin, 90 92 # rendering of the add view shouldn't explode 91 response = self.client.get('/ test_admin/admin/admin_inlines/novel/add/')93 response = self.client.get('/admin/admin_inlines/novel/add/') 92 94 self.assertEqual(response.status_code, 200) 93 95 # View should have the child inlines section 94 96 self.assertContains(response, '<div class="inline-group" id="chapter_set-group">') 95 97 96 98 def test_callable_lookup(self): 97 99 """Admin inline should invoke local callable when its name is listed in readonly_fields""" 98 response = self.client.get('/ test_admin/admin/admin_inlines/poll/add/')100 response = self.client.get('/admin/admin_inlines/poll/add/') 99 101 self.assertEqual(response.status_code, 200) 100 102 # Add parent object view should have the child inlines section 101 103 self.assertContains(response, '<div class="inline-group" id="question_set-group">') … … class TestInline(TestCase): 109 111 using both the stacked and tabular layouts. 110 112 Ref #8190. 111 113 """ 112 response = self.client.get('/ test_admin/admin/admin_inlines/holder4/add/')114 response = self.client.get('/admin/admin_inlines/holder4/add/') 113 115 self.assertContains(response, '<p class="help">Awesome stacked help text is awesome.</p>', 4) 114 116 self.assertContains(response, '<img src="/static/admin/img/icon-unknown.gif" class="help help-tooltip" width="10" height="10" alt="(Awesome tabular help text is awesome.)" title="Awesome tabular help text is awesome." />', 1) 115 117 116 118 class TestInlineMedia(TestCase): 119 urls = "regressiontests.admin_inlines.urls" 117 120 fixtures = ['admin-views-users.xml'] 118 121 119 122 def setUp(self): … … class TestInlineMedia(TestCase): 128 131 holder = Holder(dummy=13) 129 132 holder.save() 130 133 Inner(dummy=42, holder=holder).save() 131 change_url = '/ test_admin/admin/admin_inlines/holder/%i/' % holder.id134 change_url = '/admin/admin_inlines/holder/%i/' % holder.id 132 135 response = self.client.get(change_url) 133 136 self.assertContains(response, 'my_awesome_admin_scripts.js') 134 137 … … class TestInlineMedia(TestCase): 136 139 holder = Holder3(dummy=13) 137 140 holder.save() 138 141 Inner3(dummy=42, holder=holder).save() 139 change_url = '/ test_admin/admin/admin_inlines/holder3/%i/' % holder.id142 change_url = '/admin/admin_inlines/holder3/%i/' % holder.id 140 143 response = self.client.get(change_url) 141 144 self.assertContains(response, 'my_awesome_inline_scripts.js') 142 145 … … class TestInlineMedia(TestCase): 144 147 holder = Holder2(dummy=13) 145 148 holder.save() 146 149 Inner2(dummy=42, holder=holder).save() 147 change_url = '/ test_admin/admin/admin_inlines/holder2/%i/' % holder.id150 change_url = '/admin/admin_inlines/holder2/%i/' % holder.id 148 151 response = self.client.get(change_url) 149 152 self.assertContains(response, 'my_awesome_admin_scripts.js') 150 153 self.assertContains(response, 'my_awesome_inline_scripts.js') 151 154 152 155 class TestInlineAdminForm(TestCase): 156 urls = "regressiontests.admin_inlines.urls" 153 157 154 158 def test_immutable_content_type(self): 155 159 """Regression for #9362 -
new file tests/regressiontests/admin_inlines/urls.py
diff --git a/tests/regressiontests/admin_inlines/urls.py b/tests/regressiontests/admin_inlines/urls.py new file mode 100644 index 0000000..1cbb496
- + 1 from django.conf.urls.defaults import * 2 3 import admin 4 5 urlpatterns = patterns('', 6 (r'^admin/', include(admin.site.urls)), 7 ) -
new file tests/regressiontests/admin_views/admin.py
diff --git a/tests/regressiontests/admin_views/admin.py b/tests/regressiontests/admin_views/admin.py new file mode 100644 index 0000000..11b0b9e
- + 1 # -*- coding: utf-8 -*- 2 import datetime 3 import tempfile 4 import os 5 6 from django.contrib import admin 7 from django.contrib.admin.views.main import ChangeList 8 from django.forms.models import BaseModelFormSet 9 from django.core.mail import EmailMessage 10 11 from models import * 12 13 14 def callable_year(dt_value): 15 return dt_value.year 16 callable_year.admin_order_field = 'date' 17 18 19 class ArticleInline(admin.TabularInline): 20 model = Article 21 22 23 class ChapterInline(admin.TabularInline): 24 model = Chapter 25 26 27 class ChapterXtra1Admin(admin.ModelAdmin): 28 list_filter = ('chap', 29 'chap__title', 30 'chap__book', 31 'chap__book__name', 32 'chap__book__promo', 33 'chap__book__promo__name',) 34 35 36 class ArticleAdmin(admin.ModelAdmin): 37 list_display = ('content', 'date', callable_year, 'model_year', 'modeladmin_year') 38 list_filter = ('date', 'section') 39 40 def changelist_view(self, request): 41 "Test that extra_context works" 42 return super(ArticleAdmin, self).changelist_view( 43 request, extra_context={ 44 'extra_var': 'Hello!' 45 } 46 ) 47 48 def modeladmin_year(self, obj): 49 return obj.date.year 50 modeladmin_year.admin_order_field = 'date' 51 modeladmin_year.short_description = None 52 53 def delete_model(self, request, obj): 54 EmailMessage( 55 'Greetings from a deleted object', 56 'I hereby inform you that some user deleted me', 57 'from@example.com', 58 ['to@example.com'] 59 ).send() 60 return super(ArticleAdmin, self).delete_model(request, obj) 61 62 def save_model(self, request, obj, form, change=True): 63 EmailMessage( 64 'Greetings from a created object', 65 'I hereby inform you that some user created me', 66 'from@example.com', 67 ['to@example.com'] 68 ).send() 69 return super(ArticleAdmin, self).save_model(request, obj, form, change) 70 71 72 class RowLevelChangePermissionModelAdmin(admin.ModelAdmin): 73 def has_change_permission(self, request, obj=None): 74 """ Only allow changing objects with even id number """ 75 return request.user.is_staff and (obj is not None) and (obj.id % 2 == 0) 76 77 78 class CustomArticleAdmin(admin.ModelAdmin): 79 """ 80 Tests various hooks for using custom templates and contexts. 81 """ 82 change_list_template = 'custom_admin/change_list.html' 83 change_form_template = 'custom_admin/change_form.html' 84 add_form_template = 'custom_admin/add_form.html' 85 object_history_template = 'custom_admin/object_history.html' 86 delete_confirmation_template = 'custom_admin/delete_confirmation.html' 87 delete_selected_confirmation_template = 'custom_admin/delete_selected_confirmation.html' 88 89 def changelist_view(self, request): 90 "Test that extra_context works" 91 return super(CustomArticleAdmin, self).changelist_view( 92 request, extra_context={ 93 'extra_var': 'Hello!' 94 } 95 ) 96 97 98 class ThingAdmin(admin.ModelAdmin): 99 list_filter = ('color__warm', 'color__value') 100 101 102 class InquisitionAdmin(admin.ModelAdmin): 103 list_display = ('leader', 'country', 'expected') 104 105 106 class SketchAdmin(admin.ModelAdmin): 107 raw_id_fields = ('inquisition',) 108 109 110 class FabricAdmin(admin.ModelAdmin): 111 list_display = ('surface',) 112 list_filter = ('surface',) 113 114 115 class BasePersonModelFormSet(BaseModelFormSet): 116 def clean(self): 117 for person_dict in self.cleaned_data: 118 person = person_dict.get('id') 119 alive = person_dict.get('alive') 120 if person and alive and person.name == "Grace Hopper": 121 raise forms.ValidationError("Grace is not a Zombie") 122 123 124 class PersonAdmin(admin.ModelAdmin): 125 list_display = ('name', 'gender', 'alive') 126 list_editable = ('gender', 'alive') 127 list_filter = ('gender',) 128 search_fields = ('^name',) 129 save_as = True 130 131 def get_changelist_formset(self, request, **kwargs): 132 return super(PersonAdmin, self).get_changelist_formset(request, 133 formset=BasePersonModelFormSet, **kwargs) 134 135 def queryset(self, request): 136 # Order by a field that isn't in list display, to be able to test 137 # whether ordering is preserved. 138 return super(PersonAdmin, self).queryset(request).order_by('age') 139 140 141 class FooAccount(Account): 142 """A service-specific account of type Foo.""" 143 servicename = u'foo' 144 145 146 class BarAccount(Account): 147 """A service-specific account of type Bar.""" 148 servicename = u'bar' 149 150 151 class FooAccountAdmin(admin.StackedInline): 152 model = FooAccount 153 extra = 1 154 155 156 class BarAccountAdmin(admin.StackedInline): 157 model = BarAccount 158 extra = 1 159 160 161 class PersonaAdmin(admin.ModelAdmin): 162 inlines = ( 163 FooAccountAdmin, 164 BarAccountAdmin 165 ) 166 167 168 class SubscriberAdmin(admin.ModelAdmin): 169 actions = ['mail_admin'] 170 171 def mail_admin(self, request, selected): 172 EmailMessage( 173 'Greetings from a ModelAdmin action', 174 'This is the test email from a admin action', 175 'from@example.com', 176 ['to@example.com'] 177 ).send() 178 179 180 def external_mail(modeladmin, request, selected): 181 EmailMessage( 182 'Greetings from a function action', 183 'This is the test email from a function action', 184 'from@example.com', 185 ['to@example.com'] 186 ).send() 187 external_mail.short_description = 'External mail (Another awesome action)' 188 189 190 def redirect_to(modeladmin, request, selected): 191 from django.http import HttpResponseRedirect 192 return HttpResponseRedirect('/some-where-else/') 193 redirect_to.short_description = 'Redirect to (Awesome action)' 194 195 196 class ExternalSubscriberAdmin(admin.ModelAdmin): 197 actions = [redirect_to, external_mail] 198 199 200 class Podcast(Media): 201 release_date = models.DateField() 202 203 class Meta: 204 ordering = ('release_date',) # overridden in PodcastAdmin 205 206 207 class PodcastAdmin(admin.ModelAdmin): 208 list_display = ('name', 'release_date') 209 list_editable = ('release_date',) 210 date_hierarchy = 'release_date' 211 ordering = ('name',) 212 213 214 class VodcastAdmin(admin.ModelAdmin): 215 list_display = ('name', 'released') 216 list_editable = ('released',) 217 218 ordering = ('name',) 219 220 221 class ChildInline(admin.StackedInline): 222 model = Child 223 224 225 class ParentAdmin(admin.ModelAdmin): 226 model = Parent 227 inlines = [ChildInline] 228 229 list_editable = ('name',) 230 231 def save_related(self, request, form, formsets, change): 232 super(ParentAdmin, self).save_related(request, form, formsets, change) 233 first_name, last_name = form.instance.name.split() 234 for child in form.instance.child_set.all(): 235 if len(child.name.split()) < 2: 236 child.name = child.name + ' ' + last_name 237 child.save() 238 239 240 class EmptyModelAdmin(admin.ModelAdmin): 241 def queryset(self, request): 242 return super(EmptyModelAdmin, self).queryset(request).filter(pk__gt=1) 243 244 245 class OldSubscriberAdmin(admin.ModelAdmin): 246 actions = None 247 248 249 temp_storage = FileSystemStorage(tempfile.mkdtemp()) 250 UPLOAD_TO = os.path.join(temp_storage.location, 'test_upload') 251 252 253 class PictureInline(admin.TabularInline): 254 model = Picture 255 extra = 1 256 257 258 class GalleryAdmin(admin.ModelAdmin): 259 inlines = [PictureInline] 260 261 262 class PictureAdmin(admin.ModelAdmin): 263 pass 264 265 266 class LanguageAdmin(admin.ModelAdmin): 267 list_display = ['iso', 'shortlist', 'english_name', 'name'] 268 list_editable = ['shortlist'] 269 270 271 class RecommendationAdmin(admin.ModelAdmin): 272 search_fields = ('=titletranslation__text', '=recommender__titletranslation__text',) 273 274 275 class WidgetInline(admin.StackedInline): 276 model = Widget 277 278 279 class DooHickeyInline(admin.StackedInline): 280 model = DooHickey 281 282 283 class GrommetInline(admin.StackedInline): 284 model = Grommet 285 286 287 class WhatsitInline(admin.StackedInline): 288 model = Whatsit 289 290 291 class FancyDoodadInline(admin.StackedInline): 292 model = FancyDoodad 293 294 295 class CategoryAdmin(admin.ModelAdmin): 296 list_display = ('id', 'collector', 'order') 297 list_editable = ('order',) 298 299 300 class CategoryInline(admin.StackedInline): 301 model = Category 302 303 304 class CollectorAdmin(admin.ModelAdmin): 305 inlines = [ 306 WidgetInline, DooHickeyInline, GrommetInline, WhatsitInline, 307 FancyDoodadInline, CategoryInline 308 ] 309 310 311 class LinkInline(admin.TabularInline): 312 model = Link 313 extra = 1 314 315 readonly_fields = ("posted",) 316 317 318 class SubPostInline(admin.TabularInline): 319 model = PrePopulatedSubPost 320 321 prepopulated_fields = { 322 'subslug' : ('subtitle',) 323 } 324 325 def get_readonly_fields(self, request, obj=None): 326 if obj and obj.published: 327 return ('subslug',) 328 return self.readonly_fields 329 330 def get_prepopulated_fields(self, request, obj=None): 331 if obj and obj.published: 332 return {} 333 return self.prepopulated_fields 334 335 336 class PrePopulatedPostAdmin(admin.ModelAdmin): 337 list_display = ['title', 'slug'] 338 prepopulated_fields = { 339 'slug' : ('title',) 340 } 341 342 inlines = [SubPostInline] 343 344 def get_readonly_fields(self, request, obj=None): 345 if obj and obj.published: 346 return ('slug',) 347 return self.readonly_fields 348 349 def get_prepopulated_fields(self, request, obj=None): 350 if obj and obj.published: 351 return {} 352 return self.prepopulated_fields 353 354 355 class PostAdmin(admin.ModelAdmin): 356 list_display = ['title', 'public'] 357 readonly_fields = ('posted', 'awesomeness_level', 'coolness', 'value', lambda obj: "foo") 358 359 inlines = [ 360 LinkInline 361 ] 362 363 def coolness(self, instance): 364 if instance.pk: 365 return "%d amount of cool." % instance.pk 366 else: 367 return "Unkown coolness." 368 369 def value(self, instance): 370 return 1000 371 value.short_description = 'Value in $US' 372 373 374 class CustomChangeList(ChangeList): 375 def get_query_set(self, request): 376 return self.root_query_set.filter(pk=9999) # Does not exist 377 378 379 class GadgetAdmin(admin.ModelAdmin): 380 def get_changelist(self, request, **kwargs): 381 return CustomChangeList 382 383 384 class PizzaAdmin(admin.ModelAdmin): 385 readonly_fields = ('toppings',) 386 387 388 class WorkHourAdmin(admin.ModelAdmin): 389 list_display = ('datum', 'employee') 390 list_filter = ('employee',) 391 392 393 class FoodDeliveryAdmin(admin.ModelAdmin): 394 list_display=('reference', 'driver', 'restaurant') 395 list_editable = ('driver', 'restaurant') 396 397 398 class PaperAdmin(admin.ModelAdmin): 399 """ 400 A ModelAdin with a custom queryset() method that uses only(), to test 401 verbose_name display in messages shown after adding Paper instances. 402 """ 403 404 def queryset(self, request): 405 return super(PaperAdmin, self).queryset(request).only('title') 406 407 408 class CoverLetterAdmin(admin.ModelAdmin): 409 """ 410 A ModelAdin with a custom queryset() method that uses only(), to test 411 verbose_name display in messages shown after adding CoverLetter instances. 412 Note that the CoverLetter model defines a __unicode__ method. 413 """ 414 415 def queryset(self, request): 416 return super(CoverLetterAdmin, self).queryset(request).defer('date_written') 417 418 419 class StoryForm(forms.ModelForm): 420 class Meta: 421 widgets = {'title': forms.HiddenInput} 422 423 424 class StoryAdmin(admin.ModelAdmin): 425 list_display = ('id', 'title', 'content') 426 list_display_links = ('title',) # 'id' not in list_display_links 427 list_editable = ('content', ) 428 form = StoryForm 429 ordering = ["-pk"] 430 431 432 class OtherStoryAdmin(admin.ModelAdmin): 433 list_display = ('id', 'title', 'content') 434 list_display_links = ('title', 'id') # 'id' in list_display_links 435 list_editable = ('content', ) 436 ordering = ["-pk"] 437 438 439 class ComplexSortedPersonAdmin(admin.ModelAdmin): 440 list_display = ('name', 'age', 'is_employee', 'colored_name') 441 ordering = ('name',) 442 443 def colored_name(self, obj): 444 return '<span style="color: #%s;">%s</span>' % ('ff00ff', obj.name) 445 colored_name.allow_tags = True 446 colored_name.admin_order_field = 'name' 447 448 449 class AlbumAdmin(admin.ModelAdmin): 450 list_filter = ['title'] 451 452 453 class WorkHourAdmin(admin.ModelAdmin): 454 list_display = ('datum', 'employee') 455 list_filter = ('employee',) 456 457 458 site = admin.AdminSite(name="admin") 459 site.register(Article, ArticleAdmin) 460 site.register(CustomArticle, CustomArticleAdmin) 461 site.register(Section, save_as=True, inlines=[ArticleInline]) 462 site.register(ModelWithStringPrimaryKey) 463 site.register(Color) 464 site.register(Thing, ThingAdmin) 465 site.register(Actor) 466 site.register(Inquisition, InquisitionAdmin) 467 site.register(Sketch, SketchAdmin) 468 site.register(Person, PersonAdmin) 469 site.register(Persona, PersonaAdmin) 470 site.register(Subscriber, SubscriberAdmin) 471 site.register(ExternalSubscriber, ExternalSubscriberAdmin) 472 site.register(OldSubscriber, OldSubscriberAdmin) 473 site.register(Podcast, PodcastAdmin) 474 site.register(Vodcast, VodcastAdmin) 475 site.register(Parent, ParentAdmin) 476 site.register(EmptyModel, EmptyModelAdmin) 477 site.register(Fabric, FabricAdmin) 478 site.register(Gallery, GalleryAdmin) 479 site.register(Picture, PictureAdmin) 480 site.register(Language, LanguageAdmin) 481 site.register(Recommendation, RecommendationAdmin) 482 site.register(Recommender) 483 site.register(Collector, CollectorAdmin) 484 site.register(Category, CategoryAdmin) 485 site.register(Post, PostAdmin) 486 site.register(Gadget, GadgetAdmin) 487 site.register(Villain) 488 site.register(SuperVillain) 489 site.register(Plot) 490 site.register(PlotDetails) 491 site.register(CyclicOne) 492 site.register(CyclicTwo) 493 site.register(WorkHour, WorkHourAdmin) 494 site.register(Reservation) 495 site.register(FoodDelivery, FoodDeliveryAdmin) 496 site.register(RowLevelChangePermissionModel, RowLevelChangePermissionModelAdmin) 497 site.register(Paper, PaperAdmin) 498 site.register(CoverLetter, CoverLetterAdmin) 499 site.register(Story, StoryAdmin) 500 site.register(OtherStory, OtherStoryAdmin) 501 502 # We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2. 503 # That way we cover all four cases: 504 # related ForeignKey object registered in admin 505 # related ForeignKey object not registered in admin 506 # related OneToOne object registered in admin 507 # related OneToOne object not registered in admin 508 # when deleting Book so as exercise all four troublesome (w.r.t escaping 509 # and calling force_unicode to avoid problems on Python 2.3) paths through 510 # contrib.admin.util's get_deleted_objects function. 511 site.register(Book, inlines=[ChapterInline]) 512 site.register(Promo) 513 site.register(ChapterXtra1, ChapterXtra1Admin) 514 site.register(Pizza, PizzaAdmin) 515 site.register(Topping) 516 site.register(Album, AlbumAdmin) 517 site.register(Question) 518 site.register(Answer) 519 site.register(PrePopulatedPost, PrePopulatedPostAdmin) 520 site.register(ComplexSortedPerson, ComplexSortedPersonAdmin) 521 522 # Register core models we need in our tests 523 from django.contrib.auth.models import User, Group 524 from django.contrib.auth.admin import UserAdmin, GroupAdmin 525 site.register(User, UserAdmin) 526 site.register(Group, GroupAdmin) -
tests/regressiontests/admin_views/customadmin.py
diff --git a/tests/regressiontests/admin_views/customadmin.py b/tests/regressiontests/admin_views/customadmin.py index 760e93f..a696e9f 100644
a b from django.conf.urls import patterns 5 5 from django.contrib import admin 6 6 from django.http import HttpResponse 7 7 8 import models, forms 8 import models, forms, admin as base_admin 9 9 10 10 class Admin2(admin.AdminSite): 11 11 login_form = forms.CustomAdminAuthenticationForm … … class Admin2(admin.AdminSite): 29 29 30 30 site = Admin2(name="admin2") 31 31 32 site.register(models.Article, models.ArticleAdmin)33 site.register(models.Section, inlines=[ models.ArticleInline])34 site.register(models.Thing, models.ThingAdmin)35 site.register(models.Fabric, models.FabricAdmin)36 site.register(models.ChapterXtra1, models.ChapterXtra1Admin)32 site.register(models.Article, base_admin.ArticleAdmin) 33 site.register(models.Section, inlines=[base_admin.ArticleInline]) 34 site.register(models.Thing, base_admin.ThingAdmin) 35 site.register(models.Fabric, base_admin.FabricAdmin) 36 site.register(models.ChapterXtra1, base_admin.ChapterXtra1Admin) -
tests/regressiontests/admin_views/models.py
diff --git a/tests/regressiontests/admin_views/models.py b/tests/regressiontests/admin_views/models.py index 8dc61e3..bb8d026 100644
a b import datetime 3 3 import tempfile 4 4 import os 5 5 6 from django.contrib import admin7 6 from django.core.files.storage import FileSystemStorage 8 from django.contrib.admin.views.main import ChangeList9 from django.core.mail import EmailMessage10 7 from django.db import models 11 8 from django import forms 12 from django.forms.models import BaseModelFormSet13 9 from django.contrib.auth.models import User 14 10 from django.contrib.contenttypes import generic 15 11 from django.contrib.contenttypes.models import ContentType 16 12 13 17 14 class Section(models.Model): 18 15 """ 19 16 A simple section that links to articles, to test linking to related items … … class Section(models.Model): 21 18 """ 22 19 name = models.CharField(max_length=100) 23 20 21 24 22 class Article(models.Model): 25 23 """ 26 24 A simple article to test admin views. Test backwards compatibility. … … class Article(models.Model): 38 36 model_year.admin_order_field = 'date' 39 37 model_year.short_description = '' 40 38 39 41 40 class Book(models.Model): 42 41 """ 43 42 A simple book that has chapters. … … class Book(models.Model): 47 46 def __unicode__(self): 48 47 return self.name 49 48 49 50 50 class Promo(models.Model): 51 51 name = models.CharField(max_length=100, verbose_name=u'¿Name?') 52 52 book = models.ForeignKey(Book) … … class Promo(models.Model): 54 54 def __unicode__(self): 55 55 return self.name 56 56 57 57 58 class Chapter(models.Model): 58 59 title = models.CharField(max_length=100, verbose_name=u'¿Title?') 59 60 content = models.TextField() … … class Chapter(models.Model): 66 67 # Use a utf-8 bytestring to ensure it works (see #11710) 67 68 verbose_name = '¿Chapter?' 68 69 70 69 71 class ChapterXtra1(models.Model): 70 72 chap = models.OneToOneField(Chapter, verbose_name=u'¿Chap?') 71 73 xtra = models.CharField(max_length=100, verbose_name=u'¿Xtra?') … … class ChapterXtra1(models.Model): 73 75 def __unicode__(self): 74 76 return u'¿Xtra1: %s' % self.xtra 75 77 78 76 79 class ChapterXtra2(models.Model): 77 80 chap = models.OneToOneField(Chapter, verbose_name=u'¿Chap?') 78 81 xtra = models.CharField(max_length=100, verbose_name=u'¿Xtra?') … … class ChapterXtra2(models.Model): 80 83 def __unicode__(self): 81 84 return u'¿Xtra2: %s' % self.xtra 82 85 83 def callable_year(dt_value):84 return dt_value.year85 callable_year.admin_order_field = 'date'86 87 class ArticleInline(admin.TabularInline):88 model = Article89 90 class ChapterInline(admin.TabularInline):91 model = Chapter92 93 class ChapterXtra1Admin(admin.ModelAdmin):94 list_filter = ('chap',95 'chap__title',96 'chap__book',97 'chap__book__name',98 'chap__book__promo',99 'chap__book__promo__name',)100 101 class ArticleAdmin(admin.ModelAdmin):102 list_display = ('content', 'date', callable_year, 'model_year', 'modeladmin_year')103 list_filter = ('date', 'section')104 105 def changelist_view(self, request):106 "Test that extra_context works"107 return super(ArticleAdmin, self).changelist_view(108 request, extra_context={109 'extra_var': 'Hello!'110 }111 )112 113 def modeladmin_year(self, obj):114 return obj.date.year115 modeladmin_year.admin_order_field = 'date'116 modeladmin_year.short_description = None117 118 def delete_model(self, request, obj):119 EmailMessage(120 'Greetings from a deleted object',121 'I hereby inform you that some user deleted me',122 'from@example.com',123 ['to@example.com']124 ).send()125 return super(ArticleAdmin, self).delete_model(request, obj)126 127 def save_model(self, request, obj, form, change=True):128 EmailMessage(129 'Greetings from a created object',130 'I hereby inform you that some user created me',131 'from@example.com',132 ['to@example.com']133 ).send()134 return super(ArticleAdmin, self).save_model(request, obj, form, change)135 86 136 87 class RowLevelChangePermissionModel(models.Model): 137 88 name = models.CharField(max_length=100, blank=True) 138 89 139 class RowLevelChangePermissionModelAdmin(admin.ModelAdmin):140 def has_change_permission(self, request, obj=None):141 """ Only allow changing objects with even id number """142 return request.user.is_staff and (obj is not None) and (obj.id % 2 == 0)143 90 144 91 class CustomArticle(models.Model): 145 92 content = models.TextField() 146 93 date = models.DateTimeField() 147 94 148 class CustomArticleAdmin(admin.ModelAdmin):149 """150 Tests various hooks for using custom templates and contexts.151 """152 change_list_template = 'custom_admin/change_list.html'153 change_form_template = 'custom_admin/change_form.html'154 add_form_template = 'custom_admin/add_form.html'155 object_history_template = 'custom_admin/object_history.html'156 delete_confirmation_template = 'custom_admin/delete_confirmation.html'157 delete_selected_confirmation_template = 'custom_admin/delete_selected_confirmation.html'158 159 def changelist_view(self, request):160 "Test that extra_context works"161 return super(CustomArticleAdmin, self).changelist_view(162 request, extra_context={163 'extra_var': 'Hello!'164 }165 )166 95 167 96 class ModelWithStringPrimaryKey(models.Model): 168 97 id = models.CharField(max_length=255, primary_key=True) … … class ModelWithStringPrimaryKey(models.Model): 170 99 def __unicode__(self): 171 100 return self.id 172 101 102 173 103 class Color(models.Model): 174 104 value = models.CharField(max_length=10) 175 105 warm = models.BooleanField() 176 106 def __unicode__(self): 177 107 return self.value 178 108 109 179 110 class Thing(models.Model): 180 111 title = models.CharField(max_length=20) 181 112 color = models.ForeignKey(Color, limit_choices_to={'warm': True}) 182 113 def __unicode__(self): 183 114 return self.title 184 115 185 class ThingAdmin(admin.ModelAdmin):186 list_filter = ('color__warm', 'color__value')187 116 188 117 class Actor(models.Model): 189 118 name = models.CharField(max_length=50) … … class Actor(models.Model): 191 120 def __unicode__(self): 192 121 return self.name 193 122 123 194 124 class Inquisition(models.Model): 195 125 expected = models.BooleanField() 196 126 leader = models.ForeignKey(Actor) … … class Inquisition(models.Model): 199 129 def __unicode__(self): 200 130 return u"by %s from %s" % (self.leader, self.country) 201 131 202 class InquisitionAdmin(admin.ModelAdmin):203 list_display = ('leader', 'country', 'expected')204 132 205 133 class Sketch(models.Model): 206 134 title = models.CharField(max_length=100) … … class Sketch(models.Model): 212 140 def __unicode__(self): 213 141 return self.title 214 142 215 class SketchAdmin(admin.ModelAdmin):216 raw_id_fields = ('inquisition',)217 143 218 144 class Fabric(models.Model): 219 145 NG_CHOICES = ( … … class Fabric(models.Model): 226 152 ) 227 153 surface = models.CharField(max_length=20, choices=NG_CHOICES) 228 154 229 class FabricAdmin(admin.ModelAdmin):230 list_display = ('surface',)231 list_filter = ('surface',)232 155 233 156 class Person(models.Model): 234 157 GENDER_CHOICES = ( … … class Person(models.Model): 243 166 def __unicode__(self): 244 167 return self.name 245 168 246 class BasePersonModelFormSet(BaseModelFormSet):247 def clean(self):248 for person_dict in self.cleaned_data:249 person = person_dict.get('id')250 alive = person_dict.get('alive')251 if person and alive and person.name == "Grace Hopper":252 raise forms.ValidationError("Grace is not a Zombie")253 254 class PersonAdmin(admin.ModelAdmin):255 list_display = ('name', 'gender', 'alive')256 list_editable = ('gender', 'alive')257 list_filter = ('gender',)258 search_fields = ('^name',)259 save_as = True260 261 def get_changelist_formset(self, request, **kwargs):262 return super(PersonAdmin, self).get_changelist_formset(request,263 formset=BasePersonModelFormSet, **kwargs)264 265 def queryset(self, request):266 # Order by a field that isn't in list display, to be able to test267 # whether ordering is preserved.268 return super(PersonAdmin, self).queryset(request).order_by('age')269 270 169 271 170 class Persona(models.Model): 272 171 """ … … class Persona(models.Model): 277 176 def __unicode__(self): 278 177 return self.name 279 178 179 280 180 class Account(models.Model): 281 181 """ 282 182 A simple, generic account encapsulating the information shared by all … … class Account(models.Model): 289 189 def __unicode__(self): 290 190 return "%s: %s" % (self.servicename, self.username) 291 191 192 292 193 class FooAccount(Account): 293 194 """A service-specific account of type Foo.""" 294 195 servicename = u'foo' 295 196 197 296 198 class BarAccount(Account): 297 199 """A service-specific account of type Bar.""" 298 200 servicename = u'bar' 299 201 300 class FooAccountAdmin(admin.StackedInline):301 model = FooAccount302 extra = 1303 304 class BarAccountAdmin(admin.StackedInline):305 model = BarAccount306 extra = 1307 308 class PersonaAdmin(admin.ModelAdmin):309 inlines = (310 FooAccountAdmin,311 BarAccountAdmin312 )313 202 314 203 class Subscriber(models.Model): 315 204 name = models.CharField(blank=False, max_length=80) … … class Subscriber(models.Model): 318 207 def __unicode__(self): 319 208 return "%s (%s)" % (self.name, self.email) 320 209 321 class SubscriberAdmin(admin.ModelAdmin):322 actions = ['mail_admin']323 324 def mail_admin(self, request, selected):325 EmailMessage(326 'Greetings from a ModelAdmin action',327 'This is the test email from a admin action',328 'from@example.com',329 ['to@example.com']330 ).send()331 210 332 211 class ExternalSubscriber(Subscriber): 333 212 pass 334 213 214 335 215 class OldSubscriber(Subscriber): 336 216 pass 337 217 338 def external_mail(modeladmin, request, selected):339 EmailMessage(340 'Greetings from a function action',341 'This is the test email from a function action',342 'from@example.com',343 ['to@example.com']344 ).send()345 external_mail.short_description = 'External mail (Another awesome action)'346 347 def redirect_to(modeladmin, request, selected):348 from django.http import HttpResponseRedirect349 return HttpResponseRedirect('/some-where-else/')350 redirect_to.short_description = 'Redirect to (Awesome action)'351 352 class ExternalSubscriberAdmin(admin.ModelAdmin):353 actions = [redirect_to, external_mail]354 218 355 219 class Media(models.Model): 356 220 name = models.CharField(max_length=60) 357 221 222 358 223 class Podcast(Media): 359 224 release_date = models.DateField() 360 225 361 226 class Meta: 362 227 ordering = ('release_date',) # overridden in PodcastAdmin 363 228 364 class PodcastAdmin(admin.ModelAdmin):365 list_display = ('name', 'release_date')366 list_editable = ('release_date',)367 date_hierarchy = 'release_date'368 ordering = ('name',)369 229 370 230 class Vodcast(Media): 371 231 media = models.OneToOneField(Media, primary_key=True, parent_link=True) 372 232 released = models.BooleanField(default=False) 373 233 374 class VodcastAdmin(admin.ModelAdmin):375 list_display = ('name', 'released')376 list_editable = ('released',)377 378 ordering = ('name',)379 234 380 235 class Parent(models.Model): 381 236 name = models.CharField(max_length=128) 382 237 238 383 239 class Child(models.Model): 384 240 parent = models.ForeignKey(Parent, editable=False) 385 241 name = models.CharField(max_length=30, blank=True) 386 242 387 class ChildInline(admin.StackedInline):388 model = Child389 390 class ParentAdmin(admin.ModelAdmin):391 model = Parent392 inlines = [ChildInline]393 394 list_editable = ('name',)395 396 def save_related(self, request, form, formsets, change):397 super(ParentAdmin, self).save_related(request, form, formsets, change)398 first_name, last_name = form.instance.name.split()399 for child in form.instance.child_set.all():400 if len(child.name.split()) < 2:401 child.name = child.name + ' ' + last_name402 child.save()403 243 404 244 class EmptyModel(models.Model): 405 245 def __unicode__(self): 406 246 return "Primary key = %s" % self.id 407 247 408 class EmptyModelAdmin(admin.ModelAdmin):409 def queryset(self, request):410 return super(EmptyModelAdmin, self).queryset(request).filter(pk__gt=1)411 412 class OldSubscriberAdmin(admin.ModelAdmin):413 actions = None414 248 415 249 temp_storage = FileSystemStorage(tempfile.mkdtemp()) 416 250 UPLOAD_TO = os.path.join(temp_storage.location, 'test_upload') 417 251 252 418 253 class Gallery(models.Model): 419 254 name = models.CharField(max_length=100) 420 255 256 421 257 class Picture(models.Model): 422 258 name = models.CharField(max_length=100) 423 259 image = models.FileField(storage=temp_storage, upload_to='test_upload') 424 260 gallery = models.ForeignKey(Gallery, related_name="pictures") 425 261 426 class PictureInline(admin.TabularInline):427 model = Picture428 extra = 1429 430 class GalleryAdmin(admin.ModelAdmin):431 inlines = [PictureInline]432 433 class PictureAdmin(admin.ModelAdmin):434 pass435 262 436 263 class Language(models.Model): 437 264 iso = models.CharField(max_length=5, primary_key=True) … … class Language(models.Model): 442 269 class Meta: 443 270 ordering = ('iso',) 444 271 445 class LanguageAdmin(admin.ModelAdmin):446 list_display = ['iso', 'shortlist', 'english_name', 'name']447 list_editable = ['shortlist']448 272 449 273 # a base class for Recommender and Recommendation 450 274 class Title(models.Model): 451 275 pass 452 276 277 453 278 class TitleTranslation(models.Model): 454 279 title = models.ForeignKey(Title) 455 280 text = models.CharField(max_length=100) 456 281 282 457 283 class Recommender(Title): 458 284 pass 459 285 286 460 287 class Recommendation(Title): 461 288 recommender = models.ForeignKey(Recommender) 462 289 463 class RecommendationAdmin(admin.ModelAdmin):464 search_fields = ('=titletranslation__text', '=recommender__titletranslation__text',)465 290 466 291 class Collector(models.Model): 467 292 name = models.CharField(max_length=100) 468 293 294 469 295 class Widget(models.Model): 470 296 owner = models.ForeignKey(Collector) 471 297 name = models.CharField(max_length=100) 472 298 299 473 300 class DooHickey(models.Model): 474 301 code = models.CharField(max_length=10, primary_key=True) 475 302 owner = models.ForeignKey(Collector) 476 303 name = models.CharField(max_length=100) 477 304 305 478 306 class Grommet(models.Model): 479 307 code = models.AutoField(primary_key=True) 480 308 owner = models.ForeignKey(Collector) 481 309 name = models.CharField(max_length=100) 482 310 311 483 312 class Whatsit(models.Model): 484 313 index = models.IntegerField(primary_key=True) 485 314 owner = models.ForeignKey(Collector) 486 315 name = models.CharField(max_length=100) 487 316 317 488 318 class Doodad(models.Model): 489 319 name = models.CharField(max_length=100) 490 320 321 491 322 class FancyDoodad(Doodad): 492 323 owner = models.ForeignKey(Collector) 493 324 expensive = models.BooleanField(default=True) 494 325 495 class WidgetInline(admin.StackedInline):496 model = Widget497 498 class DooHickeyInline(admin.StackedInline):499 model = DooHickey500 501 class GrommetInline(admin.StackedInline):502 model = Grommet503 504 class WhatsitInline(admin.StackedInline):505 model = Whatsit506 507 class FancyDoodadInline(admin.StackedInline):508 model = FancyDoodad509 326 510 327 class Category(models.Model): 511 328 collector = models.ForeignKey(Collector) … … class Category(models.Model): 517 334 def __unicode__(self): 518 335 return u'%s:o%s' % (self.id, self.order) 519 336 520 class CategoryAdmin(admin.ModelAdmin):521 list_display = ('id', 'collector', 'order')522 list_editable = ('order',)523 524 class CategoryInline(admin.StackedInline):525 model = Category526 527 class CollectorAdmin(admin.ModelAdmin):528 inlines = [529 WidgetInline, DooHickeyInline, GrommetInline, WhatsitInline,530 FancyDoodadInline, CategoryInline531 ]532 337 533 338 class Link(models.Model): 534 339 posted = models.DateField( … … class Link(models.Model): 538 343 post = models.ForeignKey("Post") 539 344 540 345 541 class LinkInline(admin.TabularInline):542 model = Link543 extra = 1544 545 readonly_fields = ("posted",)546 547 548 346 class PrePopulatedPost(models.Model): 549 347 title = models.CharField(max_length=100) 550 348 published = models.BooleanField() 551 349 slug = models.SlugField() 552 350 351 553 352 class PrePopulatedSubPost(models.Model): 554 353 post = models.ForeignKey(PrePopulatedPost) 555 354 subtitle = models.CharField(max_length=100) 556 355 subslug = models.SlugField() 557 356 558 class SubPostInline(admin.TabularInline):559 model = PrePopulatedSubPost560 561 prepopulated_fields = {562 'subslug' : ('subtitle',)563 }564 565 def get_readonly_fields(self, request, obj=None):566 if obj and obj.published:567 return ('subslug',)568 return self.readonly_fields569 570 def get_prepopulated_fields(self, request, obj=None):571 if obj and obj.published:572 return {}573 return self.prepopulated_fields574 575 class PrePopulatedPostAdmin(admin.ModelAdmin):576 list_display = ['title', 'slug']577 prepopulated_fields = {578 'slug' : ('title',)579 }580 581 inlines = [SubPostInline]582 583 def get_readonly_fields(self, request, obj=None):584 if obj and obj.published:585 return ('slug',)586 return self.readonly_fields587 588 def get_prepopulated_fields(self, request, obj=None):589 if obj and obj.published:590 return {}591 return self.prepopulated_fields592 357 593 358 class Post(models.Model): 594 359 title = models.CharField(max_length=100, help_text="Some help text for the title (with unicode ŠĐĆŽćžšđ)") … … class Post(models.Model): 602 367 def awesomeness_level(self): 603 368 return "Very awesome." 604 369 605 class PostAdmin(admin.ModelAdmin):606 list_display = ['title', 'public']607 readonly_fields = ('posted', 'awesomeness_level', 'coolness', 'value', lambda obj: "foo")608 609 inlines = [610 LinkInline611 ]612 613 def coolness(self, instance):614 if instance.pk:615 return "%d amount of cool." % instance.pk616 else:617 return "Unkown coolness."618 619 def value(self, instance):620 return 1000621 value.short_description = 'Value in $US'622 370 623 371 class Gadget(models.Model): 624 372 name = models.CharField(max_length=100) … … class Gadget(models.Model): 626 374 def __unicode__(self): 627 375 return self.name 628 376 629 class CustomChangeList(ChangeList):630 def get_query_set(self, request):631 return self.root_query_set.filter(pk=9999) # Does not exist632 633 class GadgetAdmin(admin.ModelAdmin):634 def get_changelist(self, request, **kwargs):635 return CustomChangeList636 377 637 378 class Villain(models.Model): 638 379 name = models.CharField(max_length=100) … … class Villain(models.Model): 640 381 def __unicode__(self): 641 382 return self.name 642 383 384 643 385 class SuperVillain(Villain): 644 386 pass 645 387 388 646 389 class FunkyTag(models.Model): 647 390 "Because we all know there's only one real use case for GFKs." 648 391 name = models.CharField(max_length=25) … … class FunkyTag(models.Model): 653 396 def __unicode__(self): 654 397 return self.name 655 398 399 656 400 class Plot(models.Model): 657 401 name = models.CharField(max_length=100) 658 402 team_leader = models.ForeignKey(Villain, related_name='lead_plots') … … class Plot(models.Model): 662 406 def __unicode__(self): 663 407 return self.name 664 408 409 665 410 class PlotDetails(models.Model): 666 411 details = models.CharField(max_length=100) 667 412 plot = models.OneToOneField(Plot) … … class PlotDetails(models.Model): 669 414 def __unicode__(self): 670 415 return self.details 671 416 417 672 418 class SecretHideout(models.Model): 673 419 """ Secret! Not registered with the admin! """ 674 420 location = models.CharField(max_length=100) … … class SecretHideout(models.Model): 677 423 def __unicode__(self): 678 424 return self.location 679 425 426 680 427 class SuperSecretHideout(models.Model): 681 428 """ Secret! Not registered with the admin! """ 682 429 location = models.CharField(max_length=100) … … class SuperSecretHideout(models.Model): 685 432 def __unicode__(self): 686 433 return self.location 687 434 435 688 436 class CyclicOne(models.Model): 689 437 name = models.CharField(max_length=25) 690 438 two = models.ForeignKey('CyclicTwo') … … class CyclicOne(models.Model): 692 440 def __unicode__(self): 693 441 return self.name 694 442 443 695 444 class CyclicTwo(models.Model): 696 445 name = models.CharField(max_length=25) 697 446 one = models.ForeignKey(CyclicOne) … … class CyclicTwo(models.Model): 699 448 def __unicode__(self): 700 449 return self.name 701 450 451 702 452 class Topping(models.Model): 703 453 name = models.CharField(max_length=20) 704 454 455 705 456 class Pizza(models.Model): 706 457 name = models.CharField(max_length=20) 707 458 toppings = models.ManyToManyField('Topping') 708 459 709 class PizzaAdmin(admin.ModelAdmin):710 readonly_fields = ('toppings',)711 460 712 461 class Album(models.Model): 713 462 owner = models.ForeignKey(User) 714 463 title = models.CharField(max_length=30) 715 464 716 class AlbumAdmin(admin.ModelAdmin):717 list_filter = ['title']718 465 719 466 class Employee(Person): 720 467 code = models.CharField(max_length=20) 721 468 469 722 470 class WorkHour(models.Model): 723 471 datum = models.DateField() 724 472 employee = models.ForeignKey(Employee) 725 473 726 class WorkHourAdmin(admin.ModelAdmin):727 list_display = ('datum', 'employee')728 list_filter = ('employee',)729 474 730 475 class Question(models.Model): 731 476 question = models.CharField(max_length=20) 732 477 478 733 479 class Answer(models.Model): 734 480 question = models.ForeignKey(Question, on_delete=models.PROTECT) 735 481 answer = models.CharField(max_length=20) … … class Answer(models.Model): 737 483 def __unicode__(self): 738 484 return self.answer 739 485 486 740 487 class Reservation(models.Model): 741 488 start_date = models.DateTimeField() 742 489 price = models.IntegerField() … … RESTAURANT_CHOICES = ( 753 500 (u'pizza', u'Pizza Mama'), 754 501 ) 755 502 503 756 504 class FoodDelivery(models.Model): 757 505 reference = models.CharField(max_length=100) 758 506 driver = models.CharField(max_length=100, choices=DRIVER_CHOICES, blank=True) … … class FoodDelivery(models.Model): 761 509 class Meta: 762 510 unique_together = (("driver", "restaurant"),) 763 511 764 class FoodDeliveryAdmin(admin.ModelAdmin):765 list_display=('reference', 'driver', 'restaurant')766 list_editable = ('driver', 'restaurant')767 512 768 513 class Paper(models.Model): 769 514 title = models.CharField(max_length=30) 770 515 author = models.CharField(max_length=30, blank=True, null=True) 771 516 517 772 518 class CoverLetter(models.Model): 773 519 author = models.CharField(max_length=30) 774 520 date_written = models.DateField(null=True, blank=True) … … class CoverLetter(models.Model): 776 522 def __unicode__(self): 777 523 return self.author 778 524 779 class PaperAdmin(admin.ModelAdmin):780 """781 A ModelAdin with a custom queryset() method that uses only(), to test782 verbose_name display in messages shown after adding Paper instances.783 """784 785 def queryset(self, request):786 return super(PaperAdmin, self).queryset(request).only('title')787 788 class CoverLetterAdmin(admin.ModelAdmin):789 """790 A ModelAdin with a custom queryset() method that uses only(), to test791 verbose_name display in messages shown after adding CoverLetter instances.792 Note that the CoverLetter model defines a __unicode__ method.793 """794 795 def queryset(self, request):796 return super(CoverLetterAdmin, self).queryset(request).defer('date_written')797 525 798 526 class Story(models.Model): 799 527 title = models.CharField(max_length=100) 800 528 content = models.TextField() 801 529 802 class StoryForm(forms.ModelForm):803 class Meta:804 widgets = {'title': forms.HiddenInput}805 806 class StoryAdmin(admin.ModelAdmin):807 list_display = ('id', 'title', 'content')808 list_display_links = ('title',) # 'id' not in list_display_links809 list_editable = ('content', )810 form = StoryForm811 ordering = ["-pk"]812 530 813 531 class OtherStory(models.Model): 814 532 title = models.CharField(max_length=100) 815 533 content = models.TextField() 816 534 817 class OtherStoryAdmin(admin.ModelAdmin):818 list_display = ('id', 'title', 'content')819 list_display_links = ('title', 'id') # 'id' in list_display_links820 list_editable = ('content', )821 ordering = ["-pk"]822 535 823 536 class ComplexSortedPerson(models.Model): 824 537 name = models.CharField(max_length=100) 825 538 age = models.PositiveIntegerField() 826 539 is_employee = models.NullBooleanField() 827 540 828 class ComplexSortedPersonAdmin(admin.ModelAdmin):829 list_display = ('name', 'age', 'is_employee', 'colored_name')830 ordering = ('name',)831 832 def colored_name(self, obj):833 return '<span style="color: #%s;">%s</span>' % ('ff00ff', obj.name)834 colored_name.allow_tags = True835 colored_name.admin_order_field = 'name'836 837 admin.site.register(Article, ArticleAdmin)838 admin.site.register(CustomArticle, CustomArticleAdmin)839 admin.site.register(Section, save_as=True, inlines=[ArticleInline])840 admin.site.register(ModelWithStringPrimaryKey)841 admin.site.register(Color)842 admin.site.register(Thing, ThingAdmin)843 admin.site.register(Actor)844 admin.site.register(Inquisition, InquisitionAdmin)845 admin.site.register(Sketch, SketchAdmin)846 admin.site.register(Person, PersonAdmin)847 admin.site.register(Persona, PersonaAdmin)848 admin.site.register(Subscriber, SubscriberAdmin)849 admin.site.register(ExternalSubscriber, ExternalSubscriberAdmin)850 admin.site.register(OldSubscriber, OldSubscriberAdmin)851 admin.site.register(Podcast, PodcastAdmin)852 admin.site.register(Vodcast, VodcastAdmin)853 admin.site.register(Parent, ParentAdmin)854 admin.site.register(EmptyModel, EmptyModelAdmin)855 admin.site.register(Fabric, FabricAdmin)856 admin.site.register(Gallery, GalleryAdmin)857 admin.site.register(Picture, PictureAdmin)858 admin.site.register(Language, LanguageAdmin)859 admin.site.register(Recommendation, RecommendationAdmin)860 admin.site.register(Recommender)861 admin.site.register(Collector, CollectorAdmin)862 admin.site.register(Category, CategoryAdmin)863 admin.site.register(Post, PostAdmin)864 admin.site.register(Gadget, GadgetAdmin)865 admin.site.register(Villain)866 admin.site.register(SuperVillain)867 admin.site.register(Plot)868 admin.site.register(PlotDetails)869 admin.site.register(CyclicOne)870 admin.site.register(CyclicTwo)871 admin.site.register(WorkHour, WorkHourAdmin)872 admin.site.register(Reservation)873 admin.site.register(FoodDelivery, FoodDeliveryAdmin)874 admin.site.register(RowLevelChangePermissionModel, RowLevelChangePermissionModelAdmin)875 admin.site.register(Paper, PaperAdmin)876 admin.site.register(CoverLetter, CoverLetterAdmin)877 admin.site.register(Story, StoryAdmin)878 admin.site.register(OtherStory, OtherStoryAdmin)879 880 # We intentionally register Promo and ChapterXtra1 but not Chapter nor ChapterXtra2.881 # That way we cover all four cases:882 # related ForeignKey object registered in admin883 # related ForeignKey object not registered in admin884 # related OneToOne object registered in admin885 # related OneToOne object not registered in admin886 # when deleting Book so as exercise all four troublesome (w.r.t escaping887 # and calling force_unicode to avoid problems on Python 2.3) paths through888 # contrib.admin.util's get_deleted_objects function.889 admin.site.register(Book, inlines=[ChapterInline])890 admin.site.register(Promo)891 admin.site.register(ChapterXtra1, ChapterXtra1Admin)892 admin.site.register(Pizza, PizzaAdmin)893 admin.site.register(Topping)894 admin.site.register(Album, AlbumAdmin)895 admin.site.register(Question)896 admin.site.register(Answer)897 admin.site.register(PrePopulatedPost, PrePopulatedPostAdmin)898 admin.site.register(ComplexSortedPerson, ComplexSortedPersonAdmin) -
tests/regressiontests/admin_views/tests.py
diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py index 22b65a6..d4b2715 100644
a b from django.utils import unittest 32 32 33 33 # local test models 34 34 from models import (Article, BarAccount, CustomArticle, EmptyModel, 35 FooAccount, Gallery, PersonAdmin,ModelWithStringPrimaryKey,35 FooAccount, Gallery, ModelWithStringPrimaryKey, 36 36 Person, Persona, Picture, Podcast, Section, Subscriber, Vodcast, 37 37 Language, Collector, Widget, Grommet, DooHickey, FancyDoodad, Whatsit, 38 38 Category, Post, Plot, FunkyTag, Chapter, Book, Promo, WorkHour, Employee, … … from models import (Article, BarAccount, CustomArticle, EmptyModel, 40 40 RowLevelChangePermissionModel, Paper, CoverLetter, Story, OtherStory, 41 41 ComplexSortedPerson, Parent, Child) 42 42 43 from admin import PersonAdmin 44 43 45 44 46 class AdminViewBasicTest(TestCase): 45 47 fixtures = ['admin-views-users.xml', 'admin-views-colors.xml', … … class AdminViewBasicTest(TestCase): 50 52 # this test case and changing urlbit. 51 53 urlbit = 'admin' 52 54 55 urls = "regressiontests.admin_views.urls" 56 53 57 def setUp(self): 54 58 self.old_USE_I18N = settings.USE_I18N 55 59 self.old_USE_L10N = settings.USE_L10N … … class AdminViewBasicTest(TestCase): 542 546 self.fail("Filters should be allowed if they are defined on a ForeignKey pointing to this model") 543 547 544 548 class AdminJavaScriptTest(AdminViewBasicTest): 549 urls = "regressiontests.admin_views.urls" 550 545 551 def testSingleWidgetFirsFieldFocus(self): 546 552 """ 547 553 JavaScript-assisted auto-focus on first field. … … class AdminJavaScriptTest(AdminViewBasicTest): 565 571 566 572 567 573 class SaveAsTests(TestCase): 574 urls = "regressiontests.admin_views.urls" 568 575 fixtures = ['admin-views-users.xml','admin-views-person.xml'] 569 576 570 577 def setUp(self): … … class SaveAsTests(TestCase): 590 597 self.assertTrue(response.context['save_as']) 591 598 post_data = {'_saveasnew':'', 'name':'John M', 'gender':3, 'alive':'checked'} 592 599 response = self.client.post('/test_admin/admin/admin_views/person/1/', post_data) 593 self.assertEqual(response.context['form_url'], ' ../add/')600 self.assertEqual(response.context['form_url'], '/test_admin/admin/admin_views/person/add/') 594 601 595 602 class CustomModelAdminTest(AdminViewBasicTest): 603 urls = "regressiontests.admin_views.urls" 596 604 urlbit = "admin2" 597 605 598 606 def testCustomAdminSiteLoginForm(self): … … def get_perm(Model, perm): 654 662 class AdminViewPermissionsTest(TestCase): 655 663 """Tests for Admin Views Permissions.""" 656 664 665 urls = "regressiontests.admin_views.urls" 657 666 fixtures = ['admin-views-users.xml'] 658 667 659 668 def setUp(self): … … class AdminViewPermissionsTest(TestCase): 835 844 self.client.post('/test_admin/admin/', self.adduser_login) 836 845 addpage = self.client.get('/test_admin/admin/admin_views/article/add/') 837 846 self.assertEqual(addpage.status_code, 200) 838 change_list_link = ' <a href="../">Articles</a> ›'847 change_list_link = '› <a href="/test_admin/admin/admin_views/article/">Articles</a>' 839 848 self.assertFalse(change_list_link in addpage.content, 840 849 'User restricted to add permission is given link to change list view in breadcrumbs.') 841 850 post = self.client.post('/test_admin/admin/admin_views/article/add/', add_dict) … … class AdminViewPermissionsTest(TestCase): 1055 1064 1056 1065 1057 1066 class AdminViewDeletedObjectsTest(TestCase): 1067 urls = "regressiontests.admin_views.urls" 1058 1068 fixtures = ['admin-views-users.xml', 'deleted-objects.xml'] 1059 1069 1060 1070 def setUp(self): … … class AdminViewDeletedObjectsTest(TestCase): 1170 1180 self.assertContains(response, should_contain) 1171 1181 1172 1182 class AdminViewStringPrimaryKeyTest(TestCase): 1183 urls = "regressiontests.admin_views.urls" 1173 1184 fixtures = ['admin-views-users.xml', 'string-primary-key.xml'] 1174 1185 1175 1186 def __init__(self, *args): … … class AdminViewStringPrimaryKeyTest(TestCase): 1261 1272 1262 1273 1263 1274 class SecureViewTests(TestCase): 1275 urls = "regressiontests.admin_views.urls" 1264 1276 fixtures = ['admin-views-users.xml'] 1265 1277 1266 1278 def setUp(self): … … class SecureViewTests(TestCase): 1418 1430 self.assertEqual(response['Location'], 'http://example.com/users/super/') 1419 1431 1420 1432 class AdminViewUnicodeTest(TestCase): 1433 urls = "regressiontests.admin_views.urls" 1421 1434 fixtures = ['admin-views-unicode.xml'] 1422 1435 1423 1436 def setUp(self): … … class AdminViewUnicodeTest(TestCase): 1471 1484 1472 1485 1473 1486 class AdminViewListEditable(TestCase): 1487 urls = "regressiontests.admin_views.urls" 1474 1488 fixtures = ['admin-views-users.xml', 'admin-views-person.xml'] 1475 1489 1476 1490 def setUp(self): … … class AdminViewListEditable(TestCase): 1827 1841 1828 1842 1829 1843 class AdminSearchTest(TestCase): 1844 urls = "regressiontests.admin_views.urls" 1830 1845 fixtures = ['admin-views-users', 'multiple-child-classes', 1831 1846 'admin-views-person'] 1832 1847 … … class AdminSearchTest(TestCase): 1873 1888 1874 1889 1875 1890 class AdminInheritedInlinesTest(TestCase): 1891 urls = "regressiontests.admin_views.urls" 1876 1892 fixtures = ['admin-views-users.xml',] 1877 1893 1878 1894 def setUp(self): … … class AdminInheritedInlinesTest(TestCase): 1958 1974 self.assertEqual(Persona.objects.all()[0].accounts.count(), 2) 1959 1975 1960 1976 class AdminActionsTest(TestCase): 1977 urls = "regressiontests.admin_views.urls" 1961 1978 fixtures = ['admin-views-users.xml', 'admin-views-actions.xml'] 1962 1979 1963 1980 def setUp(self): … … class AdminActionsTest(TestCase): 2179 2196 2180 2197 2181 2198 class TestCustomChangeList(TestCase): 2199 urls = "regressiontests.admin_views.urls" 2182 2200 fixtures = ['admin-views-users.xml'] 2183 2201 urlbit = 'admin' 2184 2202 … … class TestCustomChangeList(TestCase): 2206 2224 2207 2225 2208 2226 class TestInlineNotEditable(TestCase): 2227 urls = "regressiontests.admin_views.urls" 2209 2228 fixtures = ['admin-views-users.xml'] 2210 2229 2211 2230 def setUp(self): … … class TestInlineNotEditable(TestCase): 2223 2242 self.assertEqual(response.status_code, 200) 2224 2243 2225 2244 class AdminCustomQuerysetTest(TestCase): 2245 urls = "regressiontests.admin_views.urls" 2226 2246 fixtures = ['admin-views-users.xml'] 2227 2247 2228 2248 def setUp(self): … … class AdminCustomQuerysetTest(TestCase): 2277 2297 self.assertContains(response, '<li class="info">The cover letter "John Doe II" was changed successfully.</li>') 2278 2298 2279 2299 class AdminInlineFileUploadTest(TestCase): 2300 urls = "regressiontests.admin_views.urls" 2280 2301 fixtures = ['admin-views-users.xml', 'admin-views-actions.xml'] 2281 2302 urlbit = 'admin' 2282 2303 … … class AdminInlineFileUploadTest(TestCase): 2322 2343 2323 2344 2324 2345 class AdminInlineTests(TestCase): 2346 urls = "regressiontests.admin_views.urls" 2325 2347 fixtures = ['admin-views-users.xml'] 2326 2348 2327 2349 def setUp(self): … … class AdminInlineTests(TestCase): 2639 2661 2640 2662 2641 2663 class NeverCacheTests(TestCase): 2664 urls = "regressiontests.admin_views.urls" 2642 2665 fixtures = ['admin-views-users.xml', 'admin-views-colors.xml', 'admin-views-fabrics.xml'] 2643 2666 2644 2667 def setUp(self): … … class NeverCacheTests(TestCase): 2711 2734 2712 2735 2713 2736 class PrePopulatedTest(TestCase): 2737 urls = "regressiontests.admin_views.urls" 2714 2738 fixtures = ['admin-views-users.xml'] 2715 2739 2716 2740 def setUp(self): … … class PrePopulatedTest(TestCase): 2735 2759 self.assertNotContains(response, "id: '#id_prepopulatedsubpost_set-0-subslug',") 2736 2760 2737 2761 class ReadonlyTest(TestCase): 2762 urls = "regressiontests.admin_views.urls" 2738 2763 fixtures = ['admin-views-users.xml'] 2739 2764 2740 2765 def setUp(self): … … class ReadonlyTest(TestCase): 2802 2827 2803 2828 2804 2829 class RawIdFieldsTest(TestCase): 2830 urls = "regressiontests.admin_views.urls" 2805 2831 fixtures = ['admin-views-users.xml'] 2806 2832 2807 2833 def setUp(self): … … class UserAdminTest(TestCase): 2837 2863 """ 2838 2864 Tests user CRUD functionality. 2839 2865 """ 2866 urls = "regressiontests.admin_views.urls" 2840 2867 fixtures = ['admin-views-users.xml'] 2841 2868 2842 2869 def setUp(self): … … class GroupAdminTest(TestCase): 2928 2955 """ 2929 2956 Tests group CRUD functionality. 2930 2957 """ 2958 urls = "regressiontests.admin_views.urls" 2931 2959 fixtures = ['admin-views-users.xml'] 2932 2960 2933 2961 def setUp(self): … … except ImportError: 2961 2989 2962 2990 #@unittest.skipUnless(docutils, "no docutils installed.") 2963 2991 class AdminDocsTest(TestCase): 2992 urls = "regressiontests.admin_views.urls" 2964 2993 fixtures = ['admin-views-users.xml'] 2965 2994 2966 2995 def setUp(self): … … class AdminDocsTest(TestCase): 3003 3032 AdminDocsTest = unittest.skipUnless(docutils, "no docutils installed.")(AdminDocsTest) 3004 3033 3005 3034 class ValidXHTMLTests(TestCase): 3035 urls = "regressiontests.admin_views.urls" 3006 3036 fixtures = ['admin-views-users.xml'] 3007 3037 urlbit = 'admin' 3008 3038 … … class ValidXHTMLTests(TestCase): 3033 3063 3034 3064 3035 3065 class DateHierarchyTests(TestCase): 3066 urls = "regressiontests.admin_views.urls" 3036 3067 fixtures = ['admin-views-users.xml'] 3037 3068 3038 3069 def setUp(self): … … class AdminCustomSaveRelatedTests(TestCase): 3162 3193 Ensure that one can easily customize the way related objects are saved. 3163 3194 Refs #16115. 3164 3195 """ 3196 urls = "regressiontests.admin_views.urls" 3165 3197 fixtures = ['admin-views-users.xml'] 3166 3198 3167 3199 def setUp(self): -
tests/regressiontests/admin_views/urls.py
diff --git a/tests/regressiontests/admin_views/urls.py b/tests/regressiontests/admin_views/urls.py index 7320a3c..9f41c95 100644
a b from django.conf.urls import patterns, include 2 2 from django.contrib import admin 3 3 import views 4 4 import customadmin 5 import admin 5 6 6 7 urlpatterns = patterns('', 7 (r'^ admin/doc/', include('django.contrib.admindocs.urls')),8 (r'^ admin/secure-view/$', views.secure_view),9 (r'^ admin/', include(admin.site.urls)),10 (r'^ admin2/', include(customadmin.site.urls)),8 (r'^test_admin/admin/doc/', include('django.contrib.admindocs.urls')), 9 (r'^test_admin/admin/secure-view/$', views.secure_view), 10 (r'^test_admin/admin/', include(admin.site.urls)), 11 (r'^test_admin/admin2/', include(customadmin.site.urls)), 11 12 ) -
tests/regressiontests/cache/tests.py
diff --git a/tests/regressiontests/cache/tests.py b/tests/regressiontests/cache/tests.py index d307030..07bcab7 100644
a b TestWithTemplateResponse = override_settings( 1591 1591 1592 1592 class TestEtagWithAdmin(TestCase): 1593 1593 # See https://code.djangoproject.com/ticket/16003 1594 urls = "regressiontests.admin_views.urls" 1595 1594 1596 def test_admin(self): 1595 1597 with self.settings(USE_ETAGS=False): 1596 1598 response = self.client.get('/test_admin/admin/') -
new file tests/regressiontests/generic_inline_admin/admin.py
diff --git a/tests/regressiontests/generic_inline_admin/admin.py b/tests/regressiontests/generic_inline_admin/admin.py new file mode 100644 index 0000000..87224ed
- + 1 from django.contrib import admin 2 from django.contrib.contenttypes import generic 3 4 from models import (Media, PhoneNumber, Episode, EpisodeExtra, Contact, 5 Category, EpisodePermanent, EpisodeMaxNum) 6 7 site = admin.AdminSite(name="admin") 8 9 class MediaInline(generic.GenericTabularInline): 10 model = Media 11 12 13 class EpisodeAdmin(admin.ModelAdmin): 14 inlines = [ 15 MediaInline, 16 ] 17 18 19 class MediaExtraInline(generic.GenericTabularInline): 20 model = Media 21 extra = 0 22 23 24 class MediaMaxNumInline(generic.GenericTabularInline): 25 model = Media 26 extra = 5 27 max_num = 2 28 29 30 class PhoneNumberInline(generic.GenericTabularInline): 31 model = PhoneNumber 32 33 34 class MediaPermanentInline(generic.GenericTabularInline): 35 model = Media 36 can_delete = False 37 38 39 site.register(Episode, EpisodeAdmin) 40 site.register(EpisodeExtra, inlines=[MediaExtraInline]) 41 site.register(EpisodeMaxNum, inlines=[MediaMaxNumInline]) 42 site.register(Contact, inlines=[PhoneNumberInline]) 43 site.register(Category) 44 site.register(EpisodePermanent, inlines=[MediaPermanentInline]) -
tests/regressiontests/generic_inline_admin/models.py
diff --git a/tests/regressiontests/generic_inline_admin/models.py b/tests/regressiontests/generic_inline_admin/models.py index 32ecd3b..e78f110 100644
a b 1 1 from django.db import models 2 from django.contrib import admin3 2 from django.contrib.contenttypes import generic 4 3 from django.contrib.contenttypes.models import ContentType 5 4 5 6 6 class Episode(models.Model): 7 7 name = models.CharField(max_length=100) 8 8 length = models.CharField(max_length=100, blank=True) 9 9 author = models.CharField(max_length=100, blank=True) 10 10 11 11 12 class Media(models.Model): 12 13 """ 13 14 Media that can associated to any object. … … class Media(models.Model): 22 23 def __unicode__(self): 23 24 return self.url 24 25 25 class MediaInline(generic.GenericTabularInline):26 model = Media27 28 class EpisodeAdmin(admin.ModelAdmin):29 inlines = [30 MediaInline,31 ]32 admin.site.register(Episode, EpisodeAdmin)33 34 26 # 35 27 # These models let us test the different GenericInline settings at 36 28 # different urls in the admin site. … … admin.site.register(Episode, EpisodeAdmin) 43 35 class EpisodeExtra(Episode): 44 36 pass 45 37 46 class MediaExtraInline(generic.GenericTabularInline):47 model = Media48 extra = 049 50 admin.site.register(EpisodeExtra, inlines=[MediaExtraInline])51 38 52 39 # 53 40 # Generic inline with extra and max_num 54 41 # 55 56 42 class EpisodeMaxNum(Episode): 57 43 pass 58 44 59 class MediaMaxNumInline(generic.GenericTabularInline):60 model = Media61 extra = 562 max_num = 263 64 admin.site.register(EpisodeMaxNum, inlines=[MediaMaxNumInline])65 66 45 67 46 # 68 47 # Generic inline with unique_together 69 48 # 70 71 49 class Category(models.Model): 72 50 name = models.CharField(max_length=50) 73 51 52 74 53 class PhoneNumber(models.Model): 75 54 content_type = models.ForeignKey(ContentType) 76 55 object_id = models.PositiveIntegerField() … … class PhoneNumber(models.Model): 81 60 class Meta: 82 61 unique_together = (('content_type', 'object_id', 'phone_number',),) 83 62 63 84 64 class Contact(models.Model): 85 65 name = models.CharField(max_length=50) 86 66 phone_numbers = generic.GenericRelation(PhoneNumber) 87 67 88 class PhoneNumberInline(generic.GenericTabularInline):89 model = PhoneNumber90 91 admin.site.register(Contact, inlines=[PhoneNumberInline])92 admin.site.register(Category)93 94 68 # 95 69 # Generic inline with can_delete=False 96 70 # 97 98 71 class EpisodePermanent(Episode): 99 72 pass 100 73 101 class MediaPermanentInline(generic.GenericTabularInline):102 model = Media103 can_delete = False104 74 105 admin.site.register(EpisodePermanent, inlines=[MediaPermanentInline]) -
tests/regressiontests/generic_inline_admin/tests.py
diff --git a/tests/regressiontests/generic_inline_admin/tests.py b/tests/regressiontests/generic_inline_admin/tests.py index da59922..858d6a5 100644
a b from django.test import TestCase 10 10 11 11 # local test models 12 12 from models import (Episode, EpisodeExtra, EpisodeMaxNum, Media, 13 MediaInline, EpisodePermanent, MediaPermanentInline, Category) 13 EpisodePermanent, Category) 14 from admin import MediaInline, MediaPermanentInline 14 15 15 16 16 17 class GenericAdminViewTest(TestCase): 18 urls = "regressiontests.generic_inline_admin.urls" 17 19 fixtures = ['users.xml'] 18 20 19 21 def setUp(self): … … class GenericAdminViewTest(TestCase): 125 127 self.assertTrue(formset.get_queryset().ordered) 126 128 127 129 class GenericInlineAdminParametersTest(TestCase): 130 urls = "regressiontests.generic_inline_admin.urls" 128 131 fixtures = ['users.xml'] 129 132 130 133 def setUp(self): … … class GenericInlineAdminParametersTest(TestCase): 177 180 178 181 179 182 class GenericInlineAdminWithUniqueTogetherTest(TestCase): 183 urls = "regressiontests.generic_inline_admin.urls" 180 184 fixtures = ['users.xml'] 181 185 182 186 def setUp(self): … … class GenericInlineAdminWithUniqueTogetherTest(TestCase): 203 207 self.assertEqual(response.status_code, 302) # redirect somewhere 204 208 205 209 class NoInlineDeletionTest(TestCase): 210 urls = "regressiontests.generic_inline_admin.urls" 211 206 212 def test_no_deletion(self): 207 213 fake_site = object() 208 214 inline = MediaPermanentInline(EpisodePermanent, fake_site) … … class NoInlineDeletionTest(TestCase): 211 217 self.assertFalse(formset.can_delete) 212 218 213 219 class GenericInlineModelAdminTest(TestCase): 220 urls = "regressiontests.generic_inline_admin.urls" 214 221 215 222 def setUp(self): 216 223 self.site = AdminSite() -
tests/regressiontests/generic_inline_admin/urls.py
diff --git a/tests/regressiontests/generic_inline_admin/urls.py b/tests/regressiontests/generic_inline_admin/urls.py index f415872..03431d3 100644
a b 1 1 from django.conf.urls import patterns, include 2 from django.contrib import admin 2 3 import admin 3 4 4 5 urlpatterns = patterns('', 5 (r'^ admin/', include(admin.site.urls)),6 (r'^generic_inline_admin/admin/', include(admin.site.urls)), 6 7 ) -
tests/urls.py
diff --git a/tests/urls.py b/tests/urls.py index 654111d..e7c23e5 100644
a b 1 1 from django.conf.urls import patterns, include 2 2 3 4 3 urlpatterns = patterns('', 5 4 # test_client modeltest urls 6 5 (r'^test_client/', include('modeltests.test_client.urls')), … … urlpatterns = patterns('', 22 21 # test urlconf for middleware tests 23 22 (r'^middleware/', include('regressiontests.middleware.urls')), 24 23 25 # admin view tests26 (r'^test_admin/', include('regressiontests.admin_views.urls')),27 (r'^generic_inline_admin/', include('regressiontests.generic_inline_admin.urls')),28 29 24 # admin widget tests 30 25 (r'widget_admin/', include('regressiontests.admin_widgets.urls')), 31 26 27 # admin custom URL tests 28 (r'^custom_urls/', include('regressiontests.admin_custom_urls.urls')), 29 32 30 )