Fix Sorting by ForeignKey

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
master
Brandon Taylor 2016-10-30 11:33:20 -04:00
parent 8df41a9533
commit 863ff69719
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,
@ -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')