* Use `{% include "..." with ... %}` instead of template tags that do
nothing but pass through or rename context variables and render a
template. This appears to yield a 2x increase in performance.
As a side effect, this change also appears to fix some glitches with
the rendering of `fa-sort`, `fa-sort-asc` and `fa-sort-desc` icons.
* Move queryset filtering from `sort_view()` to new `get_sort_view_queryset()`
method, so subclasses can override to apply different or additional
filtering (based on `request` and `sortable_by_expression`) to reduce
the number of objects being reordered.
`django-admin-sortable` already provides a mechanism to reorder a
subset of objects via `sorting_filters`, but this is restricted to a
small number of hard coded filters, and we found it not very useful.
We have tens of thousands of nested objects grouped under hundreds or
thousands of parent objects, and we needed a way to reorder child
objects just within their own group.
We also needed a way to reorder a subset of flat (not grouped by
parent) sortable objects with much more flexibility.
Here's an example of additional filtering that allows us to reorder a
contiguous sequence of objects (nested or flat) that bounded by the min
and max (by ordering) selected objects:
```python
class MyBaseSortableAdmin(SortableAdmin):
def get_sort_view_queryset(self, request, sortable_by_expression):
"""
Filter the sort view queryset to include only a contiguous sequence of
objects between the first and last of given parent objects, according
to the current ordering.
This should avoid inconsistent or ambiguous behaviour that might occur
when re-ordering a non-contiguous sequence.
"""
sortable_by_expression = sortable_by_expression or 'pk'
queryset = super(MyBaseSortableAdmin, self) \
.get_sort_view_queryset(request, sortable_by_expression)
pks = [
int(pk) for pk in request.GET.get('pks', '').split(',') if pk
]
if pks:
queryset = queryset.filter(**{
'%s__in' % sortable_by_expression: pks,
})
return queryset
def reorder_children(self, qs, child):
# Get the min and max order field value for the selected objects, then
# get contiguous PKs for objects between the min and max and pass to
# the sort view, to avoid inconsistent or ambiguous behaviour.
field = self.opts.ordering[0].replace('-', '')
qs = qs.model.objects.filter(**qs.aggregate(**{
'%s__gte' % field: Min(field),
'%s__lte' % field: Max(field),
}))
ct = ContentType.objects.get_for_model(child)
url = '%ssort/?pks=%s' % (
reverse('admin:%s_%s_changelist' % (ct.app_label, ct.model)),
','.join([str(pk) for pk in qs.values_list('pk', flat=True)]),
)
return http.HttpResponseRedirect(url)
class MyModelAdmin(MyBaseSortableAdmin):
actions = (
"reorder_mymodel",
"reorder_childmodel",
)
def reorder_mymodel(self, request, qs):
return self.reorder_children(qs, MyModel)
reorder_chapters.short_description = 'Reorder selected MyModels'
def reorder_childmodel(self, request, qs):
return self.reorder_children(qs, ChildModel)
reorder_elements.short_description = 'Reorder ChildModels for the selected MyModels'
```
This could be made generic enough for inclusion by default with a few
tweaks, so that `Reorder selected {{ parent.verbose_name_plural }}` and
`Reorder {{ child.verbose_name_plural }} for selected {{ parent.verbose_name_plural }}`
admin actions could be included in sortable change lists.
Refactored database and changed "app" to "samples" so name didn't conflict with "AppConfig".
Replaced deprecated assignment_tag with simple_tag.
Updated unit tests.
Removed do_inline_sorting_url and get_object_or_404 check in admin. The model_type_id should *always* be passed in.
Removed test that asserted that Categories weren't sortable as part of the Project admin. Categories *should* be sortable as part of Project admin as they are a Sortable ForeignKey.
Fixed object_rep template to pass in model_type_id again.
Updated README.
Version bump to 2.0.21
- Move icons to the header of the row. By this way they will play nicely with custom
admin themes (like djangocms-admin-style).
- Also fix icons for Django 1.5 (now the admin looks the same as with Django >= 1.6)
Added support for custom CSRF_COOKIE_NAME by refactoring the jquery.django-csrf.js file into a separate .html file that can be used as an include, passing in the CSRF_COOKIE_NAME from settings.
Refactored sample_project imports to be compatible with Django 1.9
Updated unit tests for get_next/previous.
Version bump to 2.0.8.
Fixed typo in docs.
the first `if` call did execute the whole `select` query with (perhaps)
millions of records in them, even though the only result needed here
is one record.
The acually used queryset later will be filtered by the parent-model.