Skip to content

Commit 45821d7

Browse files
committed
Merge branch 'master' of github.com:jrief/django-admin-sortable2
2 parents 7194b76 + 1b3041e commit 45821d7

File tree

23 files changed

+128
-138
lines changed

23 files changed

+128
-138
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
.DS_Store
99
.tmp*
1010
.tox
11+
.venv
12+
env
1113
local_settings.py
1214
build
1315
docs/_build

.travis.yml

Lines changed: 5 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
11
dist: xenial
22
language: python
33
python:
4-
- 2.7
5-
- 3.4
6-
- 3.5
74
- 3.6
85
- 3.7
96
- 3.8
7+
- 3.9
108

119
env:
12-
- DJANGO="django<1.11"
13-
- DJANGO="django<2.0"
14-
- DJANGO="django<2.1"
15-
- DJANGO="django<2.2"
1610
- DJANGO="django<2.3"
1711
- DJANGO="django<3.1"
1812
- DJANGO="django<3.2"
13+
- DJANGO="django<3.3"
1914
- DJANGO='https://github.com/django/django/archive/master.tar.gz'
2015

2116
install:
@@ -26,38 +21,8 @@ script:
2621
- cd example/ && ./manage.py test testapp --settings=testapp.settings
2722

2823
matrix:
29-
exclude:
30-
- python: 2.7
31-
env: DJANGO="django<2.1"
32-
- python: 2.7
33-
env: DJANGO="django<2.2"
34-
- python: 2.7
35-
env: DJANGO="django<2.3"
36-
- python: 2.7
37-
env: DJANGO="django<3.1"
38-
- python: 2.7
39-
env: DJANGO="django<3.2"
40-
- python: 2.7
41-
env: DJANGO='https://github.com/django/django/archive/master.tar.gz'
42-
- python: 3.4
43-
env: DJANGO="django<2.3"
44-
- python: 3.4
45-
env: DJANGO="django<3.1"
46-
- python: 3.4
47-
env: DJANGO="django<3.2"
48-
- python: 3.4
49-
env: DJANGO='https://github.com/django/django/archive/master.tar.gz'
50-
- python: 3.5
51-
env: DJANGO="django<3.1"
52-
- python: 3.5
53-
env: DJANGO="django<3.2"
54-
- python: 3.5
55-
env: DJANGO='https://github.com/django/django/archive/master.tar.gz'
56-
- python: 3.8
57-
env: DJANGO="django<1.11"
58-
- python: 3.8
59-
env: DJANGO="django<2.0"
60-
- python: 3.8
61-
env: DJANGO="django<2.1"
6224
allow_failures:
6325
- env: DJANGO='https://github.com/django/django/archive/master.tar.gz'
26+
exclude:
27+
- python: 3.9
28+
env: DJANGO="django<2.3"

adminsortable2/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '0.7.7'
1+
__version__ = '0.7.8'

adminsortable2/admin.py

Lines changed: 65 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
# -*- coding: utf-8 -*-
2-
from __future__ import unicode_literals
3-
41
import os
52
import json
63
from itertools import chain
@@ -15,7 +12,7 @@
1512
else:
1613
from django.utils.translation import ugettext_lazy as _
1714
from django.utils.safestring import mark_safe
18-
from django.conf.urls import url
15+
from django.urls import path
1916
from django.contrib import admin, messages
2017
from django.core.exceptions import ImproperlyConfigured
2118
from django.core.paginator import EmptyPage
@@ -34,6 +31,13 @@
3431
from django.http import (
3532
HttpResponse, HttpResponseBadRequest,
3633
HttpResponseNotAllowed, HttpResponseForbidden)
34+
from django.contrib.contenttypes.models import ContentType
35+
from django.contrib.contenttypes.forms import (
36+
BaseGenericInlineFormSet,
37+
)
38+
from django.contrib.contenttypes.admin import (
39+
GenericStackedInline, GenericTabularInline
40+
)
3741

3842
__all__ = ['SortableAdminMixin', 'SortableInlineAdminMixin']
3943

@@ -82,7 +86,7 @@ def media(self):
8286
'adminsortable2/js/libs/jquery.ui.touch-punch-0.2.3.js',
8387
'adminsortable2/js/libs/jquery.ui.sortable-1.11.4.js',
8488
]
85-
return super(SortableAdminBase, self).media + widgets.Media(css=css, js=js)
89+
return super().media + widgets.Media(css=css, js=js)
8690

8791

8892
class SortableAdminMixin(SortableAdminBase):
@@ -101,7 +105,7 @@ def change_list_template(self):
101105

102106
def __init__(self, model, admin_site):
103107
self.default_order_direction, self.default_order_field = _get_default_ordering(model, self)
104-
super(SortableAdminMixin, self).__init__(model, admin_site)
108+
super().__init__(model, admin_site)
105109
self.enable_sorting = False
106110
self.order_by = None
107111
if not isinstance(self.exclude, (list, tuple)):
@@ -141,14 +145,16 @@ def _get_update_url_name(self):
141145

142146
def get_urls(self):
143147
my_urls = [
144-
url(r'^adminsortable2_update/$',
148+
path(
149+
'adminsortable2_update/',
145150
self.admin_site.admin_view(self.update_order),
146-
name=self._get_update_url_name()),
151+
name=self._get_update_url_name()
152+
),
147153
]
148-
return my_urls + super(SortableAdminMixin, self).get_urls()
154+
return my_urls + super().get_urls()
149155

150156
def get_actions(self, request):
151-
actions = super(SortableAdminMixin, self).get_actions(request)
157+
actions = super().get_actions(request)
152158
paginator = self.get_paginator(request, self.get_queryset(request), self.list_per_page)
153159
if len(paginator.page_range) > 1 and 'all' not in request.GET and self.enable_sorting:
154160
# add actions for moving items to other pages
@@ -173,7 +179,7 @@ def get_changelist(self, request, **kwargs):
173179
self.order_by = "{}{}".format(first_order_direction, self.default_order_field)
174180
else:
175181
self.enable_sorting = False
176-
return super(SortableAdminMixin, self).get_changelist(request, **kwargs)
182+
return super().get_changelist(request, **kwargs)
177183

178184
def _get_first_ordering(self, request):
179185
"""
@@ -200,7 +206,7 @@ def _get_first_ordering(self, request):
200206

201207
@property
202208
def media(self):
203-
m = super(SortableAdminMixin, self).media
209+
m = super().media
204210
if self.enable_sorting:
205211
m = m + widgets.Media(js=[
206212
'adminsortable2/js/libs/jquery.ui.sortable-1.11.4.js',
@@ -249,7 +255,7 @@ def update_order(self, request):
249255
def save_model(self, request, obj, form, change):
250256
if not change:
251257
setattr(obj, self.default_order_field, self.get_max_order(request, obj) + 1)
252-
super(SortableAdminMixin, self).save_model(request, obj, form, change)
258+
super().save_model(request, obj, form, change)
253259

254260
def move_to_exact_page(self, request, queryset):
255261
self._bulk_move(request, queryset, self.EXACT)
@@ -406,7 +412,7 @@ def changelist_view(self, request, extra_context=None):
406412

407413
extra_context['sortable_update_url'] = self.get_update_url(request)
408414
extra_context['default_order_direction'] = self.default_order_direction
409-
return super(SortableAdminMixin, self).changelist_view(request, extra_context)
415+
return super().changelist_view(request, extra_context)
410416

411417
def get_update_url(self, request):
412418
"""
@@ -426,7 +432,7 @@ def get_max_order(self, request, obj=None):
426432
return self.base_model.objects.aggregate(max_order=Coalesce(Max(self.default_order_field), 0))['max_order']
427433

428434

429-
class CustomInlineFormSet(BaseInlineFormSet):
435+
class CustomInlineFormSetMixin():
430436
def __init__(self, *args, **kwargs):
431437
self.default_order_direction, self.default_order_field = _get_default_ordering(self.model, self)
432438

@@ -437,7 +443,11 @@ def __init__(self, *args, **kwargs):
437443
self.form.base_fields[self.default_order_field].required = False
438444
self.form.base_fields[self.default_order_field].widget = widgets.HiddenInput()
439445

440-
super(CustomInlineFormSet, self).__init__(*args, **kwargs)
446+
super().__init__(*args, **kwargs)
447+
448+
def get_max_order(self):
449+
query_set = self.model.objects.filter(**{self.fk.get_attname(): self.instance.pk})
450+
return query_set.aggregate(max_order=Coalesce(Max(self.default_order_field), 0))['max_order']
441451

442452
def save_new(self, form, commit=True):
443453
"""
@@ -446,11 +456,11 @@ def save_new(self, form, commit=True):
446456
Strange behaviour when field has a default, this might be evaluated on new object and the value
447457
will be not None, but the default value.
448458
"""
449-
obj = super(CustomInlineFormSet, self).save_new(form, commit=False)
459+
obj = super().save_new(form, commit=False)
460+
450461
default_order_field = getattr(obj, self.default_order_field, None)
451462
if default_order_field is None or default_order_field >= 0:
452-
query_set = self.model.objects.filter(**{self.fk.get_attname(): self.instance.pk})
453-
max_order = query_set.aggregate(max_order=Coalesce(Max(self.default_order_field), 0))['max_order']
463+
max_order = self.get_max_order()
454464
setattr(obj, self.default_order_field, max_order + 1)
455465
if commit:
456466
obj.save()
@@ -459,12 +469,14 @@ def save_new(self, form, commit=True):
459469
form.save_m2m()
460470
return obj
461471

472+
class CustomInlineFormSet(CustomInlineFormSetMixin, BaseInlineFormSet):
473+
pass
462474

463475
class SortableInlineAdminMixin(SortableAdminBase):
464476
formset = CustomInlineFormSet
465477

466478
def get_fields(self, request, obj=None):
467-
fields = super(SortableInlineAdminMixin, self).get_fields(request, obj)
479+
fields = super().get_fields(request, obj)
468480
_, default_order_field = _get_default_ordering(self.model, self)
469481
fields = list(fields)
470482

@@ -488,25 +500,52 @@ def get_fields(self, request, obj=None):
488500

489501
return fields
490502

503+
@property
504+
def is_stacked(self):
505+
return isinstance(self, admin.StackedInline)
506+
507+
@property
508+
def is_tabular(self):
509+
return isinstance(self, admin.TabularInline)
510+
491511
@property
492512
def media(self):
493513
shared = (
494-
super(SortableInlineAdminMixin, self).media
495-
+ widgets.Media(js=('adminsortable2/js/libs/jquery.ui.sortable-1.11.4.js',
496-
'adminsortable2/js/inline-sortable.js')))
514+
super().media + widgets.Media(
515+
js=('adminsortable2/js/libs/jquery.ui.sortable-1.11.4.js',
516+
'adminsortable2/js/inline-sortable.js')))
497517
if isinstance(self, admin.StackedInline):
498518
return shared + widgets.Media(
499519
js=('adminsortable2/js/inline-sortable.js',
500520
'adminsortable2/js/inline-stacked.js'))
501-
if isinstance(self, admin.TabularInline):
521+
else:
522+
# assume TabularInline (don't return None in any case)
502523
return shared + widgets.Media(
503524
js=('adminsortable2/js/inline-sortable.js',
504525
'adminsortable2/js/inline-tabular.js'))
505526

506527
@property
507528
def template(self):
508-
if isinstance(self, admin.StackedInline):
529+
if self.is_stacked:
509530
return 'adminsortable2/stacked.html'
510-
if isinstance(self, admin.TabularInline):
531+
elif self.is_tabular:
511532
return 'adminsortable2/tabular.html'
512533
raise ImproperlyConfigured('Class {0}.{1} must also derive from admin.TabularInline or admin.StackedInline'.format(self.__module__, self.__class__))
534+
535+
536+
class CustomGenericInlineFormSet(CustomInlineFormSetMixin, BaseGenericInlineFormSet):
537+
def get_max_order(self):
538+
query_set = self.model.objects.filter(**{self.ct_fk_field.name: self.instance.pk,
539+
self.ct_field.name: ContentType.objects.get_for_model(self.instance, for_concrete_model=self.for_concrete_model)})
540+
return query_set.aggregate(max_order=Coalesce(Max(self.default_order_field), 0))['max_order']
541+
542+
class SortableGenericInlineAdminMixin(SortableInlineAdminMixin):
543+
formset = CustomGenericInlineFormSet
544+
545+
@property
546+
def is_stacked(self):
547+
return isinstance(self, GenericStackedInline)
548+
549+
@property
550+
def is_tabular(self):
551+
return isinstance(self, GenericTabularInline)
256 Bytes
Binary file not shown.

adminsortable2/locale/it/LC_MESSAGES/django.po

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,60 +7,61 @@ msgid ""
77
msgstr ""
88
"Project-Id-Version: \n"
99
"Report-Msgid-Bugs-To: \n"
10-
"POT-Creation-Date: 2014-06-06 17:55+0200\n"
11-
"PO-Revision-Date: 2015-05-19 15:43+0100\n"
10+
"POT-Creation-Date: 2020-12-09 21:24+0100\n"
11+
"PO-Revision-Date: 2020-12-09 21:49+0100\n"
12+
"Last-Translator: \n"
13+
"Language-Team: \n"
1214
"Language: it\n"
1315
"MIME-Version: 1.0\n"
1416
"Content-Type: text/plain; charset=UTF-8\n"
1517
"Content-Transfer-Encoding: 8bit\n"
16-
"Last-Translator: \n"
17-
"Language-Team: \n"
18-
"X-Generator: Poedit 1.7.6\n"
18+
"X-Generator: Poedit 2.3\n"
1919

20-
#: admin.py:127 templates/adminsortable/tabular-1.5.html:9
21-
#: templates/adminsortable/tabular-1.6.html:9
20+
#: admin.py templates/adminsortable2/tabular.html
2221
msgid "Sort"
2322
msgstr "Ordinamento"
2423

25-
#: admin.py:151
26-
msgid "Move selected to previous page"
24+
#: admin.py
25+
msgid "Move selected to specific page"
26+
msgstr "Spostare selezione alla pagina specifica"
27+
28+
#: admin.py
29+
msgid "Move selected ... pages back"
2730
msgstr "Spostare selezione alla pagina precedente"
2831

29-
#: admin.py:155
30-
msgid "Move selected to next page"
32+
#: admin.py
33+
msgid "Move selected ... pages forward"
3134
msgstr "Spostare selezione alla pagina successiva"
3235

33-
#: admin.py:159
36+
#: admin.py
3437
msgid "Move selected to first page"
3538
msgstr "Spostare selezione alla prima pagina"
3639

37-
#: admin.py:163
40+
#: admin.py
3841
msgid "Move selected to last page"
3942
msgstr "Spostare selezione all'ultima pagina"
4043

41-
#: templates/adminsortable/stacked-1.5.html:10
42-
#: templates/adminsortable/stacked-1.6.html:10
43-
#: templates/adminsortable/tabular-1.5.html:31
44-
#: templates/adminsortable/tabular-1.6.html:31
44+
#: admin.py
45+
msgid "The target page size is {}. It is too small for {} items."
46+
msgstr "La dimensione della pagina di destinazione è {}. È troppo piccolo per {} articoli."
47+
48+
#: templates/adminsortable2/stacked.html templates/adminsortable2/tabular.html
49+
msgid "Change"
50+
msgstr "Modifica"
51+
52+
#: templates/adminsortable2/stacked.html templates/adminsortable2/tabular.html
4553
msgid "View on site"
4654
msgstr "Vedi sul sito"
4755

48-
#: templates/adminsortable/stacked-1.5.html:28
49-
#: templates/adminsortable/stacked-1.6.html:28
50-
#: templates/adminsortable/tabular-1.5.html:78
51-
#: templates/adminsortable/tabular-1.6.html:77
56+
#: templates/adminsortable2/stacked.html templates/adminsortable2/tabular.html
5257
msgid "Remove"
5358
msgstr "Rimuovi"
5459

55-
#: templates/adminsortable/stacked-1.5.html:29
56-
#: templates/adminsortable/stacked-1.6.html:29
57-
#: templates/adminsortable/tabular-1.5.html:77
58-
#: templates/adminsortable/tabular-1.6.html:76
60+
#: templates/adminsortable2/stacked.html templates/adminsortable2/tabular.html
5961
#, python-format
6062
msgid "Add another %(verbose_name)s"
6163
msgstr "Aggiungi un altro %(verbose_name)s"
6264

63-
#: templates/adminsortable/tabular-1.5.html:17
64-
#: templates/adminsortable/tabular-1.6.html:17
65+
#: templates/adminsortable2/tabular.html
6566
msgid "Delete?"
6667
msgstr "Eliminare?"
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-
# -*- coding: utf-8 -*-
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-
# -*- coding: utf-8 -*-

adminsortable2/management/commands/reorder.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
# -*- coding: utf-8 -*-
2-
from __future__ import unicode_literals
3-
41
from django.apps import apps
52
from django.core.management.base import BaseCommand, CommandError
63

0 commit comments

Comments
 (0)