Fixed #6903 - Preserve admin changelist filters after saving or deleting an object
This commit is contained in:
parent
2c4fe761a0
commit
c86a9b6398
|
@ -13,6 +13,7 @@ from django.contrib.admin.util import (unquote, flatten_fieldsets, get_deleted_o
|
|||
model_format_dict, NestedObjects, lookup_needs_distinct)
|
||||
from django.contrib.admin import validation
|
||||
from django.contrib.admin.templatetags.admin_static import static
|
||||
from django.contrib.admin.templatetags.admin_urls import add_preserved_filters
|
||||
from django.contrib import messages
|
||||
from django.views.decorators.csrf import csrf_protect
|
||||
from django.core.exceptions import PermissionDenied, ValidationError, FieldError
|
||||
|
@ -33,6 +34,7 @@ from django.utils.html import escape, escapejs
|
|||
from django.utils.safestring import mark_safe
|
||||
from django.utils import six
|
||||
from django.utils.deprecation import RenameMethodsBase
|
||||
from django.utils.http import urlencode
|
||||
from django.utils.text import capfirst, get_text_list
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.translation import ungettext
|
||||
|
@ -393,6 +395,7 @@ class ModelAdmin(BaseModelAdmin):
|
|||
save_as = False
|
||||
save_on_top = False
|
||||
paginator = Paginator
|
||||
preserve_filters = True
|
||||
inlines = []
|
||||
|
||||
# Custom templates (designed to be over-ridden in subclasses)
|
||||
|
@ -755,6 +758,27 @@ class ModelAdmin(BaseModelAdmin):
|
|||
"""
|
||||
return self.list_filter
|
||||
|
||||
def get_preserved_filters(self, request):
|
||||
"""
|
||||
Returns the preserved filters querystring.
|
||||
"""
|
||||
|
||||
# FIXME: We can remove that getattr as soon as #20619 is fixed.
|
||||
match = getattr(request, 'resolver_match', None)
|
||||
|
||||
if self.preserve_filters and match:
|
||||
opts = self.model._meta
|
||||
current_url = '%s:%s' % (match.namespace, match.url_name)
|
||||
changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name)
|
||||
if current_url == changelist_url:
|
||||
preserved_filters = request.GET.urlencode()
|
||||
else:
|
||||
preserved_filters = request.GET.get('_changelist_filters')
|
||||
|
||||
if preserved_filters:
|
||||
return urlencode({'_changelist_filters': preserved_filters})
|
||||
return ''
|
||||
|
||||
def construct_change_message(self, request, form, formsets):
|
||||
"""
|
||||
Construct a change message from a changed object.
|
||||
|
@ -846,6 +870,8 @@ class ModelAdmin(BaseModelAdmin):
|
|||
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
|
||||
opts = self.model._meta
|
||||
app_label = opts.app_label
|
||||
preserved_filters = self.get_preserved_filters(request)
|
||||
form_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, form_url)
|
||||
context.update({
|
||||
'add': add,
|
||||
'change': change,
|
||||
|
@ -877,11 +903,19 @@ class ModelAdmin(BaseModelAdmin):
|
|||
"""
|
||||
opts = obj._meta
|
||||
pk_value = obj._get_pk_val()
|
||||
preserved_filters = self.get_preserved_filters(request)
|
||||
|
||||
msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)}
|
||||
# Here, we distinguish between different save types by checking for
|
||||
# the presence of keys in request.POST.
|
||||
if "_continue" in request.POST:
|
||||
if "_popup" in request.POST:
|
||||
return HttpResponse(
|
||||
'<!DOCTYPE html><html><head><title></title></head><body>'
|
||||
'<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script></body></html>' % \
|
||||
# escape() calls force_text.
|
||||
(escape(pk_value), escapejs(obj)))
|
||||
|
||||
elif "_continue" in request.POST:
|
||||
msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict
|
||||
self.message_user(request, msg, messages.SUCCESS)
|
||||
if post_url_continue is None:
|
||||
|
@ -889,20 +923,16 @@ class ModelAdmin(BaseModelAdmin):
|
|||
(opts.app_label, opts.model_name),
|
||||
args=(pk_value,),
|
||||
current_app=self.admin_site.name)
|
||||
if "_popup" in request.POST:
|
||||
post_url_continue += "?_popup=1"
|
||||
post_url_continue = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url_continue)
|
||||
return HttpResponseRedirect(post_url_continue)
|
||||
|
||||
if "_popup" in request.POST:
|
||||
return HttpResponse(
|
||||
'<!DOCTYPE html><html><head><title></title></head><body>'
|
||||
'<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script></body></html>' % \
|
||||
# escape() calls force_text.
|
||||
(escape(pk_value), escapejs(obj)))
|
||||
elif "_addanother" in request.POST:
|
||||
msg = _('The %(name)s "%(obj)s" was added successfully. You may add another %(name)s below.') % msg_dict
|
||||
self.message_user(request, msg, messages.SUCCESS)
|
||||
return HttpResponseRedirect(request.path)
|
||||
redirect_url = request.path
|
||||
redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url)
|
||||
return HttpResponseRedirect(redirect_url)
|
||||
|
||||
else:
|
||||
msg = _('The %(name)s "%(obj)s" was added successfully.') % msg_dict
|
||||
self.message_user(request, msg, messages.SUCCESS)
|
||||
|
@ -913,30 +943,36 @@ class ModelAdmin(BaseModelAdmin):
|
|||
Determines the HttpResponse for the change_view stage.
|
||||
"""
|
||||
opts = self.model._meta
|
||||
|
||||
pk_value = obj._get_pk_val()
|
||||
preserved_filters = self.get_preserved_filters(request)
|
||||
|
||||
msg_dict = {'name': force_text(opts.verbose_name), 'obj': force_text(obj)}
|
||||
if "_continue" in request.POST:
|
||||
msg = _('The %(name)s "%(obj)s" was changed successfully. You may edit it again below.') % msg_dict
|
||||
self.message_user(request, msg, messages.SUCCESS)
|
||||
if "_popup" in request.REQUEST:
|
||||
return HttpResponseRedirect(request.path + "?_popup=1")
|
||||
else:
|
||||
return HttpResponseRedirect(request.path)
|
||||
redirect_url = request.path
|
||||
redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url)
|
||||
return HttpResponseRedirect(redirect_url)
|
||||
|
||||
elif "_saveasnew" in request.POST:
|
||||
msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % msg_dict
|
||||
self.message_user(request, msg, messages.SUCCESS)
|
||||
return HttpResponseRedirect(reverse('admin:%s_%s_change' %
|
||||
(opts.app_label, opts.model_name),
|
||||
args=(pk_value,),
|
||||
current_app=self.admin_site.name))
|
||||
redirect_url = reverse('admin:%s_%s_change' %
|
||||
(opts.app_label, opts.model_name),
|
||||
args=(pk_value,),
|
||||
current_app=self.admin_site.name)
|
||||
redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url)
|
||||
return HttpResponseRedirect(redirect_url)
|
||||
|
||||
elif "_addanother" in request.POST:
|
||||
msg = _('The %(name)s "%(obj)s" was changed successfully. You may add another %(name)s below.') % msg_dict
|
||||
self.message_user(request, msg, messages.SUCCESS)
|
||||
return HttpResponseRedirect(reverse('admin:%s_%s_add' %
|
||||
(opts.app_label, opts.model_name),
|
||||
current_app=self.admin_site.name))
|
||||
redirect_url = reverse('admin:%s_%s_add' %
|
||||
(opts.app_label, opts.model_name),
|
||||
current_app=self.admin_site.name)
|
||||
redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url)
|
||||
return HttpResponseRedirect(redirect_url)
|
||||
|
||||
else:
|
||||
msg = _('The %(name)s "%(obj)s" was changed successfully.') % msg_dict
|
||||
self.message_user(request, msg, messages.SUCCESS)
|
||||
|
@ -952,6 +988,8 @@ class ModelAdmin(BaseModelAdmin):
|
|||
post_url = reverse('admin:%s_%s_changelist' %
|
||||
(opts.app_label, opts.model_name),
|
||||
current_app=self.admin_site.name)
|
||||
preserved_filters = self.get_preserved_filters(request)
|
||||
post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url)
|
||||
else:
|
||||
post_url = reverse('admin:index',
|
||||
current_app=self.admin_site.name)
|
||||
|
@ -963,10 +1001,13 @@ class ModelAdmin(BaseModelAdmin):
|
|||
when editing an existing object.
|
||||
"""
|
||||
opts = self.model._meta
|
||||
|
||||
if self.has_change_permission(request, None):
|
||||
post_url = reverse('admin:%s_%s_changelist' %
|
||||
(opts.app_label, opts.model_name),
|
||||
current_app=self.admin_site.name)
|
||||
preserved_filters = self.get_preserved_filters(request)
|
||||
post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url)
|
||||
else:
|
||||
post_url = reverse('admin:index',
|
||||
current_app=self.admin_site.name)
|
||||
|
@ -1122,6 +1163,7 @@ class ModelAdmin(BaseModelAdmin):
|
|||
'inline_admin_formsets': inline_admin_formsets,
|
||||
'errors': helpers.AdminErrorList(form, formsets),
|
||||
'app_label': opts.app_label,
|
||||
'preserved_filters': self.get_preserved_filters(request),
|
||||
}
|
||||
context.update(extra_context or {})
|
||||
return self.render_change_form(request, context, form_url=form_url, add=True)
|
||||
|
@ -1214,6 +1256,7 @@ class ModelAdmin(BaseModelAdmin):
|
|||
'inline_admin_formsets': inline_admin_formsets,
|
||||
'errors': helpers.AdminErrorList(form, formsets),
|
||||
'app_label': opts.app_label,
|
||||
'preserved_filters': self.get_preserved_filters(request),
|
||||
}
|
||||
context.update(extra_context or {})
|
||||
return self.render_change_form(request, context, change=True, obj=obj, form_url=form_url)
|
||||
|
@ -1357,11 +1400,13 @@ class ModelAdmin(BaseModelAdmin):
|
|||
'cl': cl,
|
||||
'media': media,
|
||||
'has_add_permission': self.has_add_permission(request),
|
||||
'opts': cl.opts,
|
||||
'app_label': app_label,
|
||||
'action_form': action_form,
|
||||
'actions_on_top': self.actions_on_top,
|
||||
'actions_on_bottom': self.actions_on_bottom,
|
||||
'actions_selection_counter': self.actions_selection_counter,
|
||||
'preserved_filters': self.get_preserved_filters(request),
|
||||
}
|
||||
context.update(extra_context or {})
|
||||
|
||||
|
@ -1406,12 +1451,16 @@ class ModelAdmin(BaseModelAdmin):
|
|||
'obj': force_text(obj_display)},
|
||||
messages.SUCCESS)
|
||||
|
||||
if not self.has_change_permission(request, None):
|
||||
return HttpResponseRedirect(reverse('admin:index',
|
||||
current_app=self.admin_site.name))
|
||||
return HttpResponseRedirect(reverse('admin:%s_%s_changelist' %
|
||||
(opts.app_label, opts.model_name),
|
||||
current_app=self.admin_site.name))
|
||||
if self.has_change_permission(request, None):
|
||||
post_url = reverse('admin:%s_%s_changelist' %
|
||||
(opts.app_label, opts.model_name),
|
||||
current_app=self.admin_site.name)
|
||||
preserved_filters = self.get_preserved_filters(request)
|
||||
post_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, post_url)
|
||||
else:
|
||||
post_url = reverse('admin:index',
|
||||
current_app=self.admin_site.name)
|
||||
return HttpResponseRedirect(post_url)
|
||||
|
||||
object_name = force_text(opts.verbose_name)
|
||||
|
||||
|
@ -1429,6 +1478,7 @@ class ModelAdmin(BaseModelAdmin):
|
|||
"protected": protected,
|
||||
"opts": opts,
|
||||
"app_label": app_label,
|
||||
'preserved_filters': self.get_preserved_filters(request),
|
||||
}
|
||||
context.update(extra_context or {})
|
||||
|
||||
|
@ -1463,6 +1513,7 @@ class ModelAdmin(BaseModelAdmin):
|
|||
'object': obj,
|
||||
'app_label': app_label,
|
||||
'opts': opts,
|
||||
'preserved_filters': self.get_preserved_filters(request),
|
||||
}
|
||||
context.update(extra_context or {})
|
||||
return TemplateResponse(request, self.object_history_template or [
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
{% extends "admin/base_site.html" %}
|
||||
{% load i18n admin_static admin_modify %}
|
||||
{% load admin_urls %}
|
||||
{% load i18n admin_urls admin_static admin_modify %}
|
||||
|
||||
{% block extrahead %}{{ block.super }}
|
||||
<script type="text/javascript" src="{% url 'admin:jsi18n' %}"></script>
|
||||
|
@ -29,7 +28,10 @@
|
|||
{% if change %}{% if not is_popup %}
|
||||
<ul class="object-tools">
|
||||
{% block object-tools-items %}
|
||||
<li><a href="{% url opts|admin_urlname:'history' original.pk|admin_urlquote %}" class="historylink">{% trans "History" %}</a></li>
|
||||
<li>
|
||||
{% url opts|admin_urlname:'history' original.pk|admin_urlquote as history_url %}
|
||||
<a href="{% add_preserved_filters history_url %}" class="historylink">{% trans "History" %}</a>
|
||||
</li>
|
||||
{% if has_absolute_url %}<li><a href="{% url 'admin:view_on_site' content_type_id original.pk %}" class="viewsitelink">{% trans "View on site" %}</a></li>{% endif%}
|
||||
{% endblock %}
|
||||
</ul>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
{% extends "admin/base_site.html" %}
|
||||
{% load i18n admin_static admin_list %}
|
||||
{% load admin_urls %}
|
||||
{% load i18n admin_urls admin_static admin_list %}
|
||||
|
||||
{% block extrastyle %}
|
||||
{{ block.super }}
|
||||
|
@ -54,7 +53,8 @@
|
|||
<ul class="object-tools">
|
||||
{% block object-tools-items %}
|
||||
<li>
|
||||
<a href="{% url cl.opts|admin_urlname:'add' %}{% if is_popup %}?_popup=1{% endif %}" class="addlink">
|
||||
{% url cl.opts|admin_urlname:'add' as add_url %}
|
||||
<a href="{% add_preserved_filters add_url is_popup %}" class="addlink">
|
||||
{% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %}
|
||||
</a>
|
||||
</li>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
{% extends "admin/base_site.html" %}
|
||||
{% load i18n %}
|
||||
{% load admin_urls %}
|
||||
{% load i18n admin_urls %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<div class="breadcrumbs">
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
{% extends "admin/base_site.html" %}
|
||||
{% load i18n l10n %}
|
||||
{% load admin_urls %}
|
||||
{% load i18n l10n admin_urls %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<div class="breadcrumbs">
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
{% extends "admin/base_site.html" %}
|
||||
{% load i18n %}
|
||||
{% load admin_urls %}
|
||||
{% load i18n admin_urls %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<div class="breadcrumbs">
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
{% load i18n admin_urls %}
|
||||
<div class="submit-row">
|
||||
{% if show_save %}<input type="submit" value="{% trans 'Save' %}" class="default" name="_save" />{% endif %}
|
||||
{% if show_delete_link %}<p class="deletelink-box"><a href="{% url opts|admin_urlname:'delete' original.pk|admin_urlquote %}" class="deletelink">{% trans "Delete" %}</a></p>{% endif %}
|
||||
{% if show_delete_link %}
|
||||
{% url opts|admin_urlname:'delete' original.pk|admin_urlquote as delete_url %}
|
||||
<p class="deletelink-box"><a href="{% add_preserved_filters delete_url %}" class="deletelink">{% trans "Delete" %}</a></p>
|
||||
{% endif %}
|
||||
{% if show_save_as_new %}<input type="submit" value="{% trans 'Save as new' %}" name="_saveasnew" />{%endif%}
|
||||
{% if show_save_and_add_another %}<input type="submit" value="{% trans 'Save and add another' %}" name="_addanother" />{% endif %}
|
||||
{% if show_save_and_continue %}<input type="submit" value="{% trans 'Save and continue editing' %}" name="_continue" />{% endif %}
|
||||
|
|
|
@ -2,6 +2,7 @@ from __future__ import unicode_literals
|
|||
|
||||
import datetime
|
||||
|
||||
from django.contrib.admin.templatetags.admin_urls import add_preserved_filters
|
||||
from django.contrib.admin.util import (lookup_field, display_for_field,
|
||||
display_for_value, label_for_field)
|
||||
from django.contrib.admin.views.main import (ALL_VAR, EMPTY_CHANGELIST_VALUE,
|
||||
|
@ -217,6 +218,7 @@ def items_for_result(cl, result, form):
|
|||
table_tag = {True:'th', False:'td'}[first]
|
||||
first = False
|
||||
url = cl.url_for_result(result)
|
||||
url = add_preserved_filters({'preserved_filters': cl.preserved_filters, 'opts': cl.opts}, url)
|
||||
# Convert the pk to something that can be used in Javascript.
|
||||
# Problem cases are long ints (23L) and non-ASCII strings.
|
||||
if cl.to_field:
|
||||
|
|
|
@ -37,7 +37,8 @@ def submit_row(context):
|
|||
not is_popup and (not save_as or context['add']),
|
||||
'show_save_and_continue': not is_popup and context['has_change_permission'],
|
||||
'is_popup': is_popup,
|
||||
'show_save': True
|
||||
'show_save': True,
|
||||
'preserved_filters': context.get('preserved_filters'),
|
||||
}
|
||||
if context.get('original') is not None:
|
||||
ctx['original'] = context['original']
|
||||
|
|
|
@ -1,8 +1,17 @@
|
|||
from django.utils.http import urlencode
|
||||
|
||||
try:
|
||||
from urllib.parse import parse_qsl, urlparse, urlunparse
|
||||
except ImportError:
|
||||
from urlparse import parse_qsl, urlparse, urlunparse
|
||||
|
||||
from django import template
|
||||
from django.contrib.admin.util import quote
|
||||
from django.core.urlresolvers import resolve, Resolver404
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.filter
|
||||
def admin_urlname(value, arg):
|
||||
return 'admin:%s_%s_%s' % (value.app_label, value.model_name, arg)
|
||||
|
@ -11,3 +20,36 @@ def admin_urlname(value, arg):
|
|||
@register.filter
|
||||
def admin_urlquote(value):
|
||||
return quote(value)
|
||||
|
||||
|
||||
@register.simple_tag(takes_context=True)
|
||||
def add_preserved_filters(context, url, popup=False):
|
||||
opts = context.get('opts')
|
||||
preserved_filters = context.get('preserved_filters')
|
||||
|
||||
parsed_url = list(urlparse(url))
|
||||
parsed_qs = dict(parse_qsl(parsed_url[4]))
|
||||
merged_qs = dict()
|
||||
|
||||
if opts and preserved_filters:
|
||||
preserved_filters = dict(parse_qsl(preserved_filters))
|
||||
|
||||
try:
|
||||
match = resolve(url)
|
||||
except Resolver404:
|
||||
pass
|
||||
else:
|
||||
current_url = '%s:%s' % (match.namespace, match.url_name)
|
||||
changelist_url = 'admin:%s_%s_changelist' % (opts.app_label, opts.model_name)
|
||||
if changelist_url == current_url and '_changelist_filters' in preserved_filters:
|
||||
preserved_filters = dict(parse_qsl(preserved_filters['_changelist_filters']))
|
||||
|
||||
merged_qs.update(preserved_filters)
|
||||
|
||||
if popup:
|
||||
merged_qs['_popup'] = 1
|
||||
|
||||
merged_qs.update(parsed_qs)
|
||||
|
||||
parsed_url[4] = urlencode(merged_qs)
|
||||
return urlunparse(parsed_url)
|
||||
|
|
|
@ -59,6 +59,7 @@ class ChangeList(six.with_metaclass(RenameChangeListMethods)):
|
|||
self.list_per_page = list_per_page
|
||||
self.list_max_show_all = list_max_show_all
|
||||
self.model_admin = model_admin
|
||||
self.preserved_filters = model_admin.get_preserved_filters(request)
|
||||
|
||||
# Get search parameters from the query string.
|
||||
try:
|
||||
|
|
|
@ -870,6 +870,14 @@ subclass::
|
|||
``prepopulated_fields`` doesn't accept ``DateTimeField``, ``ForeignKey``,
|
||||
nor ``ManyToManyField`` fields.
|
||||
|
||||
.. attribute:: ModelAdmin.preserve_filters
|
||||
|
||||
.. versionadded:: 1.6
|
||||
|
||||
The admin now preserves filters on the list view after creating, editing
|
||||
or deleting an object. You can restore the previous behavior of clearing
|
||||
filters by setting this attribute to ``False``.
|
||||
|
||||
.. attribute:: ModelAdmin.radio_fields
|
||||
|
||||
By default, Django's admin uses a select-box interface (<select>) for
|
||||
|
|
|
@ -325,6 +325,11 @@ Minor features
|
|||
:ref:`see the updated recommendation <raising-validation-error>` for raising
|
||||
a ``ValidationError``.
|
||||
|
||||
* :class:`~django.contrib.admin.ModelAdmin` now preserves filters on the list view
|
||||
after creating, editing or deleting an object. It's possible to restore the previous
|
||||
behavior of clearing filters by setting the
|
||||
:attr:`~django.contrib.admin.ModelAdmin.preserve_filters` attribute to ``False``.
|
||||
|
||||
Backwards incompatible changes in 1.6
|
||||
=====================================
|
||||
|
||||
|
@ -634,6 +639,16 @@ will render something like:
|
|||
If you want to keep the current behavior of rendering ``label_tag`` without
|
||||
the ``label_suffix``, instantiate the form ``label_suffix=''``.
|
||||
|
||||
Admin views ``_changelist_filters`` GET parameter
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
To achieve preserving and restoring list view filters, admin views now
|
||||
pass around the `_changelist_filters` GET parameter. It's important that you
|
||||
account for that change if you have custom admin templates or if your tests
|
||||
rely on the previous URLs. If you want to revert to the original behavior you
|
||||
can set the
|
||||
:attr:`~django.contrib.admin.ModelAdmin.preserve_filters` attribute to ``False``.
|
||||
|
||||
Miscellaneous
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -4157,3 +4157,156 @@ class AdminUserMessageTest(TestCase):
|
|||
self.assertContains(response,
|
||||
'<li class="extra_tag info">Test tags</li>',
|
||||
html=True)
|
||||
|
||||
|
||||
@override_settings(PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
|
||||
class AdminKeepChangeListFiltersTests(TestCase):
|
||||
urls = "admin_views.urls"
|
||||
fixtures = ['admin-views-users.xml']
|
||||
|
||||
def setUp(self):
|
||||
self.client.login(username='super', password='secret')
|
||||
|
||||
def tearDown(self):
|
||||
self.client.logout()
|
||||
|
||||
def get_changelist_filters_querystring(self):
|
||||
return urlencode({
|
||||
'is_superuser__exact': 0,
|
||||
'is_staff__exact': 0,
|
||||
})
|
||||
|
||||
def get_preserved_filters_querystring(self):
|
||||
return urlencode({
|
||||
'_changelist_filters': self.get_changelist_filters_querystring()
|
||||
})
|
||||
|
||||
def get_sample_user_id(self):
|
||||
return 104
|
||||
|
||||
def get_changelist_url(self):
|
||||
return '%s?%s' % (
|
||||
reverse('admin:auth_user_changelist'),
|
||||
self.get_changelist_filters_querystring(),
|
||||
)
|
||||
|
||||
def get_add_url(self):
|
||||
return '%s?%s' % (
|
||||
reverse('admin:auth_user_add'),
|
||||
self.get_preserved_filters_querystring(),
|
||||
)
|
||||
|
||||
def get_change_url(self, user_id=None):
|
||||
if user_id is None:
|
||||
user_id = self.get_sample_user_id()
|
||||
return "%s?%s" % (
|
||||
reverse('admin:auth_user_change', args=(user_id,)),
|
||||
self.get_preserved_filters_querystring(),
|
||||
)
|
||||
|
||||
def get_history_url(self, user_id=None):
|
||||
if user_id is None:
|
||||
user_id = self.get_sample_user_id()
|
||||
return "%s?%s" % (
|
||||
reverse('admin:auth_user_history', args=(user_id,)),
|
||||
self.get_preserved_filters_querystring(),
|
||||
)
|
||||
|
||||
def get_delete_url(self, user_id=None):
|
||||
if user_id is None:
|
||||
user_id = self.get_sample_user_id()
|
||||
return "%s?%s" % (
|
||||
reverse('admin:auth_user_delete', args=(user_id,)),
|
||||
self.get_preserved_filters_querystring(),
|
||||
)
|
||||
|
||||
def test_changelist_view(self):
|
||||
response = self.client.get(self.get_changelist_url())
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
# Check the `change_view` link has the correct querystring.
|
||||
detail_link = """<a href="%s">joepublic</a>""" % self.get_change_url()
|
||||
self.assertContains(response, detail_link, count=1)
|
||||
|
||||
def test_change_view(self):
|
||||
# Get the `change_view`.
|
||||
response = self.client.get(self.get_change_url())
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
# Check the form action.
|
||||
form_action = """<form enctype="multipart/form-data" action="?%s" method="post" id="user_form">""" % self.get_preserved_filters_querystring()
|
||||
self.assertContains(response, form_action, count=1)
|
||||
|
||||
# Check the history link.
|
||||
history_link = """<a href="%s" class="historylink">History</a>""" % self.get_history_url()
|
||||
self.assertContains(response, history_link, count=1)
|
||||
|
||||
# Check the delete link.
|
||||
delete_link = """<a href="%s" class="deletelink">Delete</a>""" % (self.get_delete_url())
|
||||
self.assertContains(response, delete_link, count=1)
|
||||
|
||||
# Test redirect on "Save".
|
||||
post_data = {
|
||||
'username': 'joepublic',
|
||||
'last_login_0': '2007-05-30',
|
||||
'last_login_1': '13:20:10',
|
||||
'date_joined_0': '2007-05-30',
|
||||
'date_joined_1': '13:20:10',
|
||||
}
|
||||
|
||||
post_data['_save'] = 1
|
||||
response = self.client.post(self.get_change_url(), data=post_data)
|
||||
self.assertRedirects(response, self.get_changelist_url())
|
||||
post_data.pop('_save')
|
||||
|
||||
# Test redirect on "Save and continue".
|
||||
post_data['_continue'] = 1
|
||||
response = self.client.post(self.get_change_url(), data=post_data)
|
||||
self.assertRedirects(response, self.get_change_url())
|
||||
post_data.pop('_continue')
|
||||
|
||||
# Test redirect on "Save and add new".
|
||||
post_data['_addanother'] = 1
|
||||
response = self.client.post(self.get_change_url(), data=post_data)
|
||||
self.assertRedirects(response, self.get_add_url())
|
||||
post_data.pop('_addanother')
|
||||
|
||||
def test_add_view(self):
|
||||
# Get the `add_view`.
|
||||
response = self.client.get(self.get_add_url())
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
# Check the form action.
|
||||
form_action = """<form enctype="multipart/form-data" action="?%s" method="post" id="user_form">""" % self.get_preserved_filters_querystring()
|
||||
self.assertContains(response, form_action, count=1)
|
||||
|
||||
# Test redirect on "Save".
|
||||
post_data = {
|
||||
'username': 'dummy',
|
||||
'password1': 'test',
|
||||
'password2': 'test',
|
||||
}
|
||||
|
||||
post_data['_save'] = 1
|
||||
response = self.client.post(self.get_add_url(), data=post_data)
|
||||
self.assertRedirects(response, self.get_change_url(self.get_sample_user_id() + 1))
|
||||
post_data.pop('_save')
|
||||
|
||||
# Test redirect on "Save and continue".
|
||||
post_data['username'] = 'dummy2'
|
||||
post_data['_continue'] = 1
|
||||
response = self.client.post(self.get_add_url(), data=post_data)
|
||||
self.assertRedirects(response, self.get_change_url(self.get_sample_user_id() + 2))
|
||||
post_data.pop('_continue')
|
||||
|
||||
# Test redirect on "Save and add new".
|
||||
post_data['username'] = 'dummy3'
|
||||
post_data['_addanother'] = 1
|
||||
response = self.client.post(self.get_add_url(), data=post_data)
|
||||
self.assertRedirects(response, self.get_add_url())
|
||||
post_data.pop('_addanother')
|
||||
|
||||
def test_delete_view(self):
|
||||
# Test redirect on "Delete".
|
||||
response = self.client.post(self.get_delete_url(), {'post': 'yes'})
|
||||
self.assertRedirects(response, self.get_changelist_url())
|
||||
|
|
Loading…
Reference in New Issue