Added properties to allow sortable change list and change form view to extend a custom template or extend the default admin change form and change list templates.
Fixed a problem with the detection of sortability of inline models at the template level that was preventing the drag-and-drop messaging in the template to be displayed. Updated unit tests.master
parent
32c6f7c034
commit
847b471872
|
|
@ -40,6 +40,13 @@ class SortableAdminBase(object):
|
|||
self.change_list_template = \
|
||||
self.sortable_change_list_with_sort_link_template
|
||||
self.is_sortable = True
|
||||
|
||||
if extra_context is None:
|
||||
extra_context = {}
|
||||
|
||||
extra_context.update({
|
||||
'change_list_template_extends': self.change_list_template_extends
|
||||
})
|
||||
return super(SortableAdminBase, self).changelist_view(request,
|
||||
extra_context=extra_context)
|
||||
|
||||
|
|
@ -58,6 +65,9 @@ class SortableAdmin(SortableAdminBase, ModelAdmin):
|
|||
sortable_javascript_includes_template = \
|
||||
'adminsortable/shared/javascript_includes.html'
|
||||
|
||||
change_form_template_extends = 'admin/change_form.html'
|
||||
change_list_template_extends = 'admin/change_list.html'
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
|
@ -162,6 +172,13 @@ class SortableAdmin(SortableAdminBase, ModelAdmin):
|
|||
self.has_sortable_tabular_inlines = False
|
||||
self.has_sortable_stacked_inlines = False
|
||||
|
||||
if extra_context is None:
|
||||
extra_context = {}
|
||||
|
||||
extra_context.update({
|
||||
'change_form_template_extends': self.change_form_template_extends
|
||||
})
|
||||
|
||||
for klass in self.inlines:
|
||||
is_sortable = klass.model.is_sortable
|
||||
if issubclass(klass, SortableTabularInline) and is_sortable:
|
||||
|
|
@ -171,15 +188,18 @@ class SortableAdmin(SortableAdminBase, ModelAdmin):
|
|||
|
||||
if self.has_sortable_tabular_inlines or \
|
||||
self.has_sortable_stacked_inlines:
|
||||
|
||||
self.change_form_template = self.sortable_change_form_template
|
||||
extra_context = {
|
||||
|
||||
extra_context.update({
|
||||
'sortable_javascript_includes_template':
|
||||
self.sortable_javascript_includes_template,
|
||||
'has_sortable_tabular_inlines':
|
||||
self.has_sortable_tabular_inlines,
|
||||
'has_sortable_stacked_inlines':
|
||||
self.has_sortable_stacked_inlines
|
||||
}
|
||||
})
|
||||
|
||||
return super(SortableAdmin, self).change_view(request, object_id,
|
||||
extra_context=extra_context)
|
||||
|
||||
|
|
@ -238,21 +258,21 @@ class SortableInlineBase(SortableAdminBase, InlineModelAdmin):
|
|||
return qs
|
||||
|
||||
|
||||
class SortableTabularInline(SortableInlineBase, TabularInline):
|
||||
class SortableTabularInline(TabularInline, SortableInlineBase):
|
||||
"""Custom template that enables sorting for tabular inlines"""
|
||||
template = 'adminsortable/edit_inline/tabular.html'
|
||||
|
||||
|
||||
class SortableStackedInline(SortableInlineBase, StackedInline):
|
||||
class SortableStackedInline(StackedInline, SortableInlineBase):
|
||||
"""Custom template that enables sorting for stacked inlines"""
|
||||
template = 'adminsortable/edit_inline/stacked.html'
|
||||
|
||||
|
||||
class SortableGenericTabularInline(SortableInlineBase, GenericTabularInline):
|
||||
class SortableGenericTabularInline(GenericTabularInline, SortableInlineBase):
|
||||
"""Custom template that enables sorting for tabular inlines"""
|
||||
template = 'adminsortable/edit_inline/tabular.html'
|
||||
|
||||
|
||||
class SortableGenericStackedInline(SortableInlineBase, GenericStackedInline):
|
||||
class SortableGenericStackedInline(GenericStackedInline, SortableInlineBase):
|
||||
"""Custom template that enables sorting for stacked inlines"""
|
||||
template = 'adminsortable/edit_inline/stacked.html'
|
||||
|
|
|
|||
|
|
@ -39,19 +39,6 @@ class Sortable(models.Model):
|
|||
abstract = True
|
||||
ordering = ['order']
|
||||
|
||||
# @classmethod
|
||||
# def determine_if_sortable(cls):
|
||||
# try:
|
||||
# max_order = cls.objects.aggregate(
|
||||
# models.Max('order'))['order__max']
|
||||
# except (TypeError, IndexError):
|
||||
# max_order = 0
|
||||
|
||||
# if max_order > 1:
|
||||
# cls.is_sortable = True
|
||||
# else:
|
||||
# cls.is_sortable = False
|
||||
|
||||
@classmethod
|
||||
def model_type_id(cls):
|
||||
return ContentType.objects.get_for_model(cls).id
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "admin/change_form.html" %}
|
||||
{% extends change_form_template_extends %}
|
||||
{% load i18n admin_modify %}
|
||||
{% load url from future %}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{% extends 'admin/change_list.html' %}
|
||||
{% extends change_list_template_extends %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block object-tools-items %}
|
||||
|
|
@ -6,4 +6,4 @@
|
|||
<a href="./sort/">{% trans 'Change Order' %}</a>
|
||||
</li>
|
||||
{{ block.super }}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{% load i18n admin_modify adminsortable_tags %}
|
||||
<div class="inline-group" id="{{ inline_admin_formset.formset.prefix }}-group">
|
||||
<h2>{{ inline_admin_formset.opts.verbose_name_plural|title }} {% if inline_admin_formset.opts.is_sortable %} - drag and drop to change order{% endif %}</h2>
|
||||
<h2>{{ inline_admin_formset.opts.verbose_name_plural|title }} {% if inline_admin_formset.formset.initial_form_count > 1 %} - drag and drop to change order{% endif %}</h2>
|
||||
{{ inline_admin_formset.formset.management_form }}
|
||||
{{ inline_admin_formset.formset.non_form_errors }}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<div class="tabular inline-related {% if forloop.last %}last-related{% endif %}">
|
||||
{{ inline_admin_formset.formset.management_form }}
|
||||
<fieldset class="module">
|
||||
<h2>{{ inline_admin_formset.opts.verbose_name_plural|capfirst }} {% if inline_admin_formset.opts.is_sortable %} - drag and drop to change order{% endif %}</h2>
|
||||
<h2>{{ inline_admin_formset.opts.verbose_name_plural|capfirst }} {% if inline_admin_formset.formset.initial_form_count > 1 %} - drag and drop to change order{% endif %}</h2>
|
||||
{{ inline_admin_formset.formset.non_form_errors }}
|
||||
<table>
|
||||
<thead><tr>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@ class ComponentInline(SortableStackedInline):
|
|||
model = Component
|
||||
|
||||
def queryset(self, request):
|
||||
qs = super(ComponentInline, self).queryset(request).exclude(title__icontains='2')
|
||||
qs = super(ComponentInline, self).queryset(
|
||||
request).exclude(title__icontains='2')
|
||||
if get_is_sortable(qs):
|
||||
self.model.is_sortable = True
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ from django.test.client import Client, RequestFactory
|
|||
|
||||
from adminsortable.fields import SortableForeignKey
|
||||
from adminsortable.models import Sortable
|
||||
from adminsortable.utils import get_is_sortable
|
||||
from app.models import Category, Credit, Note
|
||||
|
||||
|
||||
|
|
@ -52,13 +53,13 @@ class SortableTestCase(TestCase):
|
|||
record to sort.
|
||||
"""
|
||||
self.create_category()
|
||||
self.assertFalse(Category.is_sortable(),
|
||||
self.assertFalse(get_is_sortable(Category.objects.all()),
|
||||
'Category only has one record. It should not be sortable.')
|
||||
|
||||
def test_is_sortable(self):
|
||||
self.create_category()
|
||||
self.create_category(title='Category 2')
|
||||
self.assertTrue(Category.is_sortable(),
|
||||
self.assertTrue(get_is_sortable(Category.objects.all()),
|
||||
'Category has more than one record. It should be sortable.')
|
||||
|
||||
def test_save_order_incremented(self):
|
||||
|
|
@ -82,8 +83,8 @@ class SortableTestCase(TestCase):
|
|||
return category1, category2, category3
|
||||
|
||||
def get_sorting_url(self):
|
||||
return reverse('admin:app_do_sorting', args=(),
|
||||
kwargs={'model_type_id': Category.model_type_id()})
|
||||
return '/admin/app/category/sorting/do-sorting/{0}/'.format(
|
||||
Category.model_type_id())
|
||||
|
||||
def get_category_indexes(self, *categories):
|
||||
return {'indexes': ','.join([str(c.id) for c in categories])}
|
||||
|
|
@ -93,7 +94,7 @@ class SortableTestCase(TestCase):
|
|||
password=self.user_raw_password)
|
||||
self.assertTrue(logged_in, 'User is not logged in')
|
||||
|
||||
response = self.client.get(reverse('admin:app_sort'))
|
||||
response = self.client.get('/admin/app/category/sort/')
|
||||
self.assertEqual(response.status_code, httplib.OK,
|
||||
'Admin sort request failed.')
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in New Issue