Skip to content

Commit

Permalink
Merge pull request #1281 from loic/ticket6903
Browse files Browse the repository at this point in the history
Fixed #6903 - Preserved admin changelist filters.
  • Loading branch information
aaugustin committed Jun 18, 2013
2 parents a01b1ee + c86a9b6 commit 9da9b3e
Show file tree
Hide file tree
Showing 14 changed files with 317 additions and 42 deletions.
107 changes: 79 additions & 28 deletions django/contrib/admin/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
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
Expand All @@ -33,6 +34,7 @@
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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -755,6 +758,27 @@ def get_list_filter(self, request):
"""
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.
Expand Down Expand Up @@ -846,6 +870,8 @@ def save_related(self, request, form, formsets, change):
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,
Expand Down Expand Up @@ -877,32 +903,36 @@ def response_add(self, request, obj, post_url_continue=None):
"""
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:
post_url_continue = reverse('admin:%s_%s_change' %
(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)
Expand All @@ -913,30 +943,36 @@ def response_change(self, request, obj):
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)
Expand All @@ -952,6 +988,8 @@ def response_post_save_add(self, request, obj):
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)
Expand All @@ -963,10 +1001,13 @@ def response_post_save_change(self, request, obj):
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)
Expand Down Expand Up @@ -1122,6 +1163,7 @@ def add_view(self, request, form_url='', extra_context=None):
'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)
Expand Down Expand Up @@ -1214,6 +1256,7 @@ def change_view(self, request, object_id, form_url='', extra_context=None):
'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)
Expand Down Expand Up @@ -1357,11 +1400,13 @@ def changelist_view(self, request, extra_context=None):
'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 {})

Expand Down Expand Up @@ -1406,12 +1451,16 @@ def delete_view(self, request, object_id, extra_context=None):
'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)

Expand All @@ -1429,6 +1478,7 @@ def delete_view(self, request, object_id, extra_context=None):
"protected": protected,
"opts": opts,
"app_label": app_label,
'preserved_filters': self.get_preserved_filters(request),
}
context.update(extra_context or {})

Expand Down Expand Up @@ -1463,6 +1513,7 @@ def history_view(self, request, object_id, extra_context=None):
'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 [
Expand Down
8 changes: 5 additions & 3 deletions django/contrib/admin/templates/admin/change_form.html
Original file line number Diff line number Diff line change
@@ -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>
Expand Down Expand Up @@ -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>
Expand Down
6 changes: 3 additions & 3 deletions django/contrib/admin/templates/admin/change_list.html
Original file line number Diff line number Diff line change
@@ -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 }}
Expand Down Expand Up @@ -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>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{% extends "admin/base_site.html" %}
{% load i18n %}
{% load admin_urls %}
{% load i18n admin_urls %}

{% block breadcrumbs %}
<div class="breadcrumbs">
Expand Down
Original file line number Diff line number Diff line change
@@ -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">
Expand Down
3 changes: 1 addition & 2 deletions django/contrib/admin/templates/admin/object_history.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{% extends "admin/base_site.html" %}
{% load i18n %}
{% load admin_urls %}
{% load i18n admin_urls %}

{% block breadcrumbs %}
<div class="breadcrumbs">
Expand Down
5 changes: 4 additions & 1 deletion django/contrib/admin/templates/admin/submit_line.html
Original file line number Diff line number Diff line change
@@ -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 %}
Expand Down
2 changes: 2 additions & 0 deletions django/contrib/admin/templatetags/admin_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

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,
Expand Down Expand Up @@ -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:
Expand Down
3 changes: 2 additions & 1 deletion django/contrib/admin/templatetags/admin_modify.py
Original file line number Diff line number Diff line change
Expand Up @@ -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']
Expand Down
Loading

0 comments on commit 9da9b3e

Please sign in to comment.