diff --git a/README.md b/README.md index 6a378c7..634f6f0 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/adminsortable/__init__.py b/adminsortable/__init__.py index d824970..b0cb5fc 100755 --- a/adminsortable/__init__.py +++ b/adminsortable/__init__.py @@ -1,4 +1,4 @@ -VERSION = (1, 6, 5) # following PEP 386 +VERSION = (1, 6, 6) # following PEP 386 DEV_N = None diff --git a/adminsortable/admin.py b/adminsortable/admin.py index 7a49d71..fd0fb37 100644 --- a/adminsortable/admin.py +++ b/adminsortable/admin.py @@ -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 \ diff --git a/adminsortable/models.py b/adminsortable/models.py index d3dfef4..a076e94 100644 --- a/adminsortable/models.py +++ b/adminsortable/models.py @@ -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 diff --git a/adminsortable/templates/adminsortable/change_list_with_sort_link.html b/adminsortable/templates/adminsortable/change_list_with_sort_link.html index b51c631..c78550a 100644 --- a/adminsortable/templates/adminsortable/change_list_with_sort_link.html +++ b/adminsortable/templates/adminsortable/change_list_with_sort_link.html @@ -2,8 +2,14 @@ {% load i18n %} {% block object-tools-items %} -