Refactored sorting_filters into a tuple and moved logic for retrieving sorting filters into the sort_view versus changelist_view.

Updated readme.
Updated sample project to leverage new sorting_filters on Person model and admin.
Removed custom change list template for Person admin.
master
Brandon Taylor 2014-03-05 09:10:47 -05:00
parent af6c8f2e15
commit 80bdaafdc3
9 changed files with 70 additions and 51 deletions

View File

@ -1,6 +1,6 @@
# Django Admin Sortable
Current version: 1.6.5
Current version: 1.6.6
This project makes it easy to add drag-and-drop ordering to any model in
Django admin. Inlines for a sortable model may also be made sortable,
@ -12,6 +12,8 @@ For Django 1.5.x or higher, use the latest version of django-admin-sortable.
django-admin-sortable 1.5.2 introduced backward-incompatible changes for Django 1.4.x
django-admin-sortable 1.6.6 introduced a backward-incompatible change for the `sorting_filters` attribute. Please convert your attributes to the new tuple-based format.
## Installation
1. pip install django-admin-sortable
@ -31,7 +33,7 @@ Download django-admin-sortable from [source](https://github.com/iambrandontaylor
### Static Media
Preferred:
Use the [staticfiles app](https://docs.djangoproject.com/en/1.4/ref/contrib/staticfiles/)
Use the [staticfiles app](https://docs.djangoproject.com/en/1.6/ref/contrib/staticfiles/)
Alternate:
Copy the `adminsortable` folder from the `static` folder to the
@ -184,23 +186,29 @@ may change, and adminsortable won't be able to automatically determine
if the inline model is sortable from here, which is why we have to set the
`is_sortable` property of the model in this method.
#### Sorting a subset of objects
It is also possible to sort a subset of objects in your model by adding a `sorting_filters` dictionary. This dictionary works exactly the same as `.filter()` on a QuerySet, and is applied *after* `get_queryset()` on the admin class, allowing you to override the queryset as you would normally in admin but apply additional filters for sorting.
#### Sorting subsets of objects
It is also possible to sort a subset of objects in your model by adding a `sorting_filters` tuple. This works exactly the same as `.filter()` on a QuerySet, and is applied *after* `get_queryset()` on the admin class, allowing you to override the queryset as you would normally in admin but apply additional filters for sorting. The text "Change Order of" will appear before each filter in the Change List template, and the filter groups are displayed from left to right in the order listed. If no `sorting_filters` are specified, the text "Change Order" will be displayed for the link.
This is useful when you need to have some objects orderable via drag-and-drop, and others not. An example would be a "Board of Directors". In this use case, you have a list of "People". Some of these people are on the Board of Directors, and you need to sort them at will. Other people need to be sorted alphabetically.
#####Important!
django-admin-sortable 1.6.6 introduces a backwards-incompatible change for `sorting_filters`. Previously this attribute was defined as a dictionary, so you'll need to change your values over to the new tuple-based format.
An example of sorting subsets would be a "Board of Directors". In this use case, you have a list of "People" objects. Some of these people are on the Board of Directors and some not, and you need to sort them independently.
class Person(Sortable):
class Meta(Sortable.Meta):
verbose_name_plural = 'People'
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
is_board_member = models.BooleanField(default=False)
sorting_filters = {'is_board_member': True}
def __unicode__(self):
return '{} {}'.format(self.first_name, self.last_name)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
is_board_member = models.BooleanField('Board Member', default=False)
sorting_filters = (
('Board Members', {'is_board_member': True}),
('Non-Board Members', {'is_board_member': False}),
)
def __unicode__(self):
return '{} {}'.format(self.first_name, self.last_name)
#### Extending custom templates
By default, adminsortable's change form and change list views inherit from
@ -208,12 +216,12 @@ Django admin's standard templates. Sometimes you need to have a custom change
form or change list, but also need adminsortable's CSS and JavaScript for
inline models that are sortable for example.
SortableAdmin has two properties you can override for this use case:
SortableAdmin has two attributes you can override for this use case:
change_form_template_extends
change_list_template_extends
These properties have default values of:
These attributes have default values of:
change_form_template_extends = 'admin/change_form.html'
change_list_template_extends = 'admin/change_list.html'
@ -308,8 +316,8 @@ ordering on top of that just seemed a little much in my opinion.
django-admin-sortable is currently used in production.
### What's new in 1.6.5?
- Namespace fixes for jQuery in Django admin
### What's new in 1.6.6?
- Multiple sorting_filters
### Future

View File

@ -1,4 +1,4 @@
VERSION = (1, 6, 5) # following PEP 386
VERSION = (1, 6, 6) # following PEP 386
DEV_N = None

View File

@ -28,8 +28,6 @@ STATIC_URL = settings.STATIC_URL
class SortableAdminBase(object):
filtered_objects = []
def changelist_view(self, request, extra_context=None):
"""
If the model that inherits Sortable has more than one object,
@ -37,11 +35,10 @@ class SortableAdminBase(object):
object_tools block to take people to the view to change the sorting.
"""
# Apply any additional filters to create a subset of sortable objects
self.filtered_objects = self.queryset(request).filter(
**self.model.sorting_filters)
# get sort group index from querystring
sort_filter_index = request.GET.get('sort_filter')
if get_is_sortable(self.filtered_objects):
if get_is_sortable(self.queryset(request)):
self.change_list_template = \
self.sortable_change_list_with_sort_link_template
self.is_sortable = True
@ -50,7 +47,8 @@ class SortableAdminBase(object):
extra_context = {}
extra_context.update({
'change_list_template_extends': self.change_list_template_extends
'change_list_template_extends': self.change_list_template_extends,
'sorting_filters': [sort_filter[0] for sort_filter in self.model.sorting_filters]
})
return super(SortableAdminBase, self).changelist_view(request,
extra_context=extra_context)
@ -106,7 +104,18 @@ class SortableAdmin(SortableAdminBase, ModelAdmin):
has_perm = request.user.has_perm('{0}.{1}'.format(opts.app_label,
opts.get_change_permission()))
objects = self.filtered_objects
# get sort group index from querystring if present
sort_filter_index = request.GET.get('sort_filter')
filters = {}
if sort_filter_index:
try:
filters = self.model.sorting_filters[int(sort_filter_index)][1]
except IndexError, ValueError:
pass
# Apply any sort filters to create a subset of sortable objects
objects = self.queryset(request).filter(**filters)
# Determine if we need to regroup objects relative to a
# foreign key specified on the model class that is extending Sortable.
@ -191,9 +200,11 @@ class SortableAdmin(SortableAdminBase, ModelAdmin):
})
for klass in self.inlines:
if issubclass(klass, SortableTabularInline) or issubclass(klass, SortableGenericTabularInline):
if issubclass(klass, SortableTabularInline) or issubclass(klass,
SortableGenericTabularInline):
self.has_sortable_tabular_inlines = True
if issubclass(klass, SortableStackedInline) or issubclass(klass, SortableGenericStackedInline):
if issubclass(klass, SortableStackedInline) or issubclass(klass,
SortableGenericStackedInline):
self.has_sortable_stacked_inlines = True
if self.has_sortable_tabular_inlines or \

View File

@ -14,9 +14,6 @@ class MultipleSortableForeignKeyException(Exception):
class Sortable(models.Model):
"""
Unfortunately, Django doesn't support using more than one AutoField
in a model or this class could be simplified.
`is_sortable` determines whether or not the Model is sortable by
determining if the last value of `order` is greater than the default
of 1, which should be present if there is only one object.
@ -31,7 +28,7 @@ class Sortable(models.Model):
order = models.PositiveIntegerField(editable=False, default=1,
db_index=True)
is_sortable = False
sorting_filters = {}
sorting_filters = ()
# legacy support
sortable_by = None

View File

@ -2,8 +2,14 @@
{% load i18n %}
{% block object-tools-items %}
<li>
<a href="./sort/">{% trans 'Change Order' %}</a>
</li>
{{ block.super }}
{% for sorting_filter in sorting_filters %}
<li>
<a href="./sort/?sort_filter={{ forloop.counter0 }}">{% trans 'Change Order of' %} {{ sorting_filter }}</a>
</li>
{% empty %}
<li>
<a href="./sort/">{% trans 'Change Order' %}</a>
</li>
{% endfor %}
{{ block.super }}
{% endblock %}

View File

@ -61,7 +61,6 @@ admin.site.register(Project, ProjectAdmin)
class PersonAdmin(SortableAdmin):
sortable_change_list_with_sort_link_template = 'app/person/admin/change_list_with_sort_link.html'
list_display = ['__unicode__', 'is_board_member']
admin.site.register(Person, PersonAdmin)

View File

@ -83,7 +83,7 @@ class GenericNote(SimpleModel, Sortable):
pass
def __unicode__(self):
return u'{0} : {1}'.format(self.title, self.content_object)
return u'{}: {}'.format(self.title, self.content_object)
# An model registered as an inline that has a custom queryset
@ -103,9 +103,16 @@ class Person(Sortable):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
is_board_member = models.BooleanField(default=False)
is_board_member = models.BooleanField('Board Member', default=False)
sorting_filters = {'is_board_member': True}
# Sorting Filters allow you to set up sub-sets of objects that need
# to have independent sorting. They are listed in order, from left
# to right in the sorting change list. You can use any standard
# Django ORM filter method.
sorting_filters = (
('Board Members', {'is_board_member': True}),
('Non-Board Members', {'is_board_member': False}),
)
def __unicode__(self):
return '{} {}'.format(self.first_name, self.last_name)

View File

@ -1,9 +0,0 @@
{% extends change_list_template_extends %}
{% load i18n %}
{% block object-tools-items %}
<li>
<a href="./sort/">{% trans 'Change Order of Board Members' %}</a>
</li>
{{ block.super }}
{% endblock %}