Merge branch 'develop'

master
Brandon Taylor 2016-10-30 11:39:17 -04:00
commit b96896d890
6 changed files with 21 additions and 59 deletions

View File

@ -2,7 +2,7 @@
[![Build Status](https://travis-ci.org/iambrandontaylor/django-admin-sortable.svg?branch=master)](https://travis-ci.org/iambrandontaylor/django-admin-sortable) [![Build Status](https://travis-ci.org/iambrandontaylor/django-admin-sortable.svg?branch=master)](https://travis-ci.org/iambrandontaylor/django-admin-sortable)
Current version: 2.0.20 Current version: 2.0.21
This project makes it easy to add drag-and-drop ordering to any model in 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, Django admin. Inlines for a sortable model may also be made sortable,
@ -19,7 +19,7 @@ Sorting inlines:
## Supported Django Versions ## Supported Django Versions
For Django 1.5.x to 1.9.x, use version 2.0.18. For Django 1.5.x to 1.9.x, use version 2.0.18.
For Django 1.10.x, use 2.0.19 or higher. For Django 1.10.x, use 2.0.19 or higher.
### Other notes of interest regarding versions ### Other notes of interest regarding versions
django-admin-sortable 1.5.2 introduced backward-incompatible changes for Django 1.4.x django-admin-sortable 1.5.2 introduced backward-incompatible changes for Django 1.4.x
@ -500,8 +500,8 @@ ordering on top of that just seemed a little much in my opinion.
### Status ### Status
django-admin-sortable is currently used in production. django-admin-sortable is currently used in production.
### What's new in 2.0.20? ### What's new in 2.0.21?
- Support for models that use another type of field besides `AutoField` for their primary key. Thanks [@rubendura](https://github.com/rubendura). - Fixed a regression introduced by [ Pull Request 143](https://github.com/iambrandontaylor/django-admin-sortable/pull/143) which caused models sortable by a foriegn key to not persist the sort order correctly.
### Future ### Future
- Better template support for foreign keys that are self referential. If someone would like to take on rendering recursive sortables, that would be super. - Better template support for foreign keys that are self referential. If someone would like to take on rendering recursive sortables, that would be super.

View File

@ -3,7 +3,7 @@ Django Admin Sortable
|Build Status| |Build Status|
Current version: 2.0.20 Current version: 2.0.21
This project makes it easy to add drag-and-drop ordering to any model in 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, Django admin. Inlines for a sortable model may also be made sortable,
@ -617,12 +617,13 @@ Status
django-admin-sortable is currently used in production. django-admin-sortable is currently used in production.
What's new in 2.0.20? What's new in 2.0.21?
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~
- Support for models that use another type of field besides - Fixed a regression introduced by `Pull Request
``AutoField`` for their primary key. Thanks 143 <https://github.com/iambrandontaylor/django-admin-sortable/pull/143>`__
[@rubendura](https://github.com/rubendura). which caused models sortable by a foriegn key to not persist the sort
order correctly.
Future Future
~~~~~~ ~~~~~~

View File

@ -1,4 +1,4 @@
VERSION = (2, 0, 20) VERSION = (2, 0, 21)
DEV_N = None DEV_N = None

View File

@ -106,16 +106,10 @@ class SortableAdmin(SortableAdminBase, ModelAdmin):
info = opts.app_label, opts.model_name info = opts.app_label, opts.model_name
except AttributeError: except AttributeError:
# Django < 1.7 # Django < 1.7
info = opts.app_label, opts.modul_name info = opts.app_label, opts.model_name
# this ajax view changes the order of instances of self.model # this ajax view changes the order of instances of the model type
admin_do_sorting_url = url( admin_do_sorting_url = url(
r'^sort/do-sorting/$',
self.admin_site.admin_view(self.do_sorting_view),
name='%s_%s_do_sorting' % info)
# this ajax view changes the order of instances of inline models
admin_do_inline_sorting_url = url(
r'^sort/do-sorting/(?P<model_type_id>\d+)/$', r'^sort/do-sorting/(?P<model_type_id>\d+)/$',
self.admin_site.admin_view(self.do_sorting_view), self.admin_site.admin_view(self.do_sorting_view),
name='%s_%s_do_sorting' % info) name='%s_%s_do_sorting' % info)
@ -127,7 +121,6 @@ class SortableAdmin(SortableAdminBase, ModelAdmin):
name='%s_%s_sort' % info) name='%s_%s_sort' % info)
urls = [ urls = [
admin_do_inline_sorting_url,
admin_do_sorting_url, admin_do_sorting_url,
admin_sort_url admin_sort_url
] + urls ] + urls
@ -280,15 +273,7 @@ class SortableAdmin(SortableAdminBase, ModelAdmin):
if request.is_ajax(): if request.is_ajax():
try: try:
if model_type_id is None: klass = ContentType.objects.get(id=model_type_id).model_class()
klass = self.model
else:
klass = get_object_or_404(ContentType,
id=model_type_id).model_class()
if klass not in (inline.model for inline in self.inlines):
raise Http404(
'There is no inline model with type id: {0}'.format(
model_type_id))
indexes = list(map(str, indexes = list(map(str,
request.POST.get('indexes', []).split(','))) request.POST.get('indexes', []).split(',')))

View File

@ -2,5 +2,5 @@
<form> <form>
<input name="pk" type="hidden" value="{{ object.pk }}" /> <input name="pk" type="hidden" value="{{ object.pk }}" />
<a href="{% url opts|admin_urlname:'do_sorting' %}" class="admin_sorting_url"><i class="fa fa-{% if forloop.first %}sort-desc{% elif forloop.last %}sort-asc{% else %}sort{% endif %}"></i> {{ object }}</a> <a href="{% url opts|admin_urlname:'do_sorting' object.model_type_id %}" class="admin_sorting_url"><i class="fa fa-{% if forloop.first %}sort-desc{% elif forloop.last %}sort-asc{% else %}sort{% endif %}"></i> {{ object }}</a>
</form> </form>

View File

@ -123,10 +123,7 @@ class SortableTestCase(TestCase):
category3 = self.create_category(title='Category 3') category3 = self.create_category(title='Category 3')
return category1, category2, category3 return category1, category2, category3
def get_sorting_url(self): def get_sorting_url(self, model):
return '/admin/app/category/sort/do-sorting/'
def get_inline_sorting_url(self, model):
return '/admin/app/project/sort/do-sorting/{0}/'.format( return '/admin/app/project/sort/do-sorting/{0}/'.format(
model.model_type_id()) model.model_type_id())
@ -155,7 +152,7 @@ class SortableTestCase(TestCase):
category1, category2, category3 = self.make_test_categories() category1, category2, category3 = self.make_test_categories()
# make a normal GET # make a normal GET
response = self.client.get( response = self.client.get(
self.get_sorting_url(), self.get_sorting_url(Category),
data=self.get_category_indexes(category1, category2, category3)) data=self.get_category_indexes(category1, category2, category3))
self.assertEqual( self.assertEqual(
@ -171,7 +168,7 @@ class SortableTestCase(TestCase):
category1, category2, category3 = self.make_test_categories() category1, category2, category3 = self.make_test_categories()
# make a normal POST # make a normal POST
response = self.client.post( response = self.client.post(
self.get_sorting_url(), self.get_sorting_url(Category),
data=self.get_category_indexes(category1, category2, category3)) data=self.get_category_indexes(category1, category2, category3))
self.assertEqual( self.assertEqual(
@ -186,7 +183,7 @@ class SortableTestCase(TestCase):
category1, category2, category3 = self.make_test_categories() category1, category2, category3 = self.make_test_categories()
# make a normal POST # make a normal POST
response = self.client.post(self.get_sorting_url(), response = self.client.post(self.get_sorting_url(Category),
data=self.get_category_indexes(category1, category2, category3)) data=self.get_category_indexes(category1, category2, category3))
content = json.loads(response.content.decode(encoding='UTF-8'), content = json.loads(response.content.decode(encoding='UTF-8'),
'latin-1') 'latin-1')
@ -202,7 +199,7 @@ class SortableTestCase(TestCase):
category1, category2, category3 = self.make_test_categories() category1, category2, category3 = self.make_test_categories()
# make an Ajax POST # make an Ajax POST
response = self.client.post(self.get_sorting_url(), response = self.client.post(self.get_sorting_url(Category),
data=self.get_category_indexes(category3, category2, category1), data=self.get_category_indexes(category3, category2, category1),
HTTP_X_REQUESTED_WITH='XMLHttpRequest') HTTP_X_REQUESTED_WITH='XMLHttpRequest')
content = json.loads(response.content.decode(encoding='UTF-8'), content = json.loads(response.content.decode(encoding='UTF-8'),
@ -273,27 +270,6 @@ class SortableTestCase(TestCase):
self.assertEquals(response.status_code, httplib.FORBIDDEN, self.assertEquals(response.status_code, httplib.FORBIDDEN,
'Sort view must be forbidden.') 'Sort view must be forbidden.')
def test_adminsortable_inline_changelist_not_found(self):
self.client.login(username=self.user.username,
password=self.user_raw_password)
project = Project.objects.create(
category=self.create_category(),
description='Test project'
)
note1 = project.note_set.create(text='note 1')
note2 = project.note_set.create(text='note 2')
response = self.client.post(
self.get_inline_sorting_url(Category),
data=self.get_category_indexes(note2, note1),
HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(
response.status_code,
httplib.NOT_FOUND,
'Categories must not be sortable trough ProjectAdmin')
def test_adminsortable_inline_changelist_success(self): def test_adminsortable_inline_changelist_success(self):
self.client.login(username=self.user.username, self.client.login(username=self.user.username,
password=self.user_raw_password) password=self.user_raw_password)
@ -307,7 +283,7 @@ class SortableTestCase(TestCase):
note3 = project.note_set.create(text='note 3') note3 = project.note_set.create(text='note 3')
response = self.client.post( response = self.client.post(
self.get_inline_sorting_url(project.note_set.model), self.get_sorting_url(project.note_set.model),
data=self.get_category_indexes(note3, note2, note1), data=self.get_category_indexes(note3, note2, note1),
HTTP_X_REQUESTED_WITH='XMLHttpRequest') HTTP_X_REQUESTED_WITH='XMLHttpRequest')