Skip to content

Commit 782ce00

Browse files
beryczboxed
authored andcommitted
reorderable EditTable, models.Orderable, model_fields.SortOrderField
1 parent f5000d1 commit 782ce00

6 files changed

Lines changed: 170 additions & 0 deletions

File tree

conftest.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
Album,
99
Artist,
1010
Track,
11+
FavoriteArtist,
1112
)
1213

1314

@@ -253,3 +254,20 @@ def really_big_discography():
253254
@pytest.fixture
254255
def staff_user():
255256
return User.objects.create(username='staff_user', is_staff=True)
257+
258+
259+
@pytest.fixture
260+
def john_doe_user(transactional_db):
261+
return User.objects.create(username='john.doe', email='john.doe@example.com')
262+
263+
264+
@pytest.fixture
265+
def damnation(transactional_db):
266+
return Artist.objects.create(name='Damnation')
267+
268+
269+
@pytest.fixture
270+
def fav_artists(john_doe_user, black_sabbath, damnation, ozzy):
271+
FavoriteArtist.objects.create(user=john_doe_user, artist=black_sabbath, comment='Love it!', sort_order=0)
272+
FavoriteArtist.objects.create(user=john_doe_user, artist=ozzy, comment='I love this too!', sort_order=1)
273+
FavoriteArtist.objects.create(user=john_doe_user, artist=damnation, comment='And this as well', sort_order=2)

docs/models.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
OneToOneField,
99
TextField,
1010
)
11+
from django.conf import settings
12+
13+
from iommi.models import Orderable
1114

1215

1316
class Genre(Model):
@@ -91,3 +94,15 @@ def __str__(self):
9194
class Meta:
9295
ordering = ('artist__name',)
9396
app_label = 'docs'
97+
98+
99+
class FavoriteArtist(Orderable):
100+
user = ForeignKey(settings.AUTH_USER_MODEL, on_delete=CASCADE, related_name='favorite_artists')
101+
artist = ForeignKey(Artist, on_delete=CASCADE, related_name='+')
102+
comment = CharField(max_length=255)
103+
104+
def __str__(self):
105+
return self.artist.name
106+
107+
class Meta(Orderable.Meta):
108+
app_label = 'docs'

docs/test_doc_edit_tables.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
from django.contrib.auth import get_user_model
2+
13
import pytest
24
from docs.models import *
35
from iommi import *
6+
from iommi.form import save_nested_forms
47
from tests.helpers import (
58
req,
69
show_output,
@@ -46,3 +49,104 @@ def test_edit_tables(really_big_discography):
4649

4750
show_output(t.bind(request=request))
4851
# @end
52+
53+
54+
def test_orderable_edit_tables(fav_artists):
55+
# language=rst
56+
"""
57+
.. _orderable-edit-tables:
58+
59+
Orderable edit tables
60+
=====================
61+
62+
iommi edit tables also support ordering. That can be especially useful for editing reverse FK's in nested forms.
63+
"""
64+
65+
# language=rst
66+
"""
67+
The easiest way to make an EditTable orderable is to inherit your model from `iommi.models.Orderable`:
68+
69+
.. code-block:: python
70+
71+
class FavoriteArtist(Orderable):
72+
user = ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='favorite_artists')
73+
artist = ForeignKey(Artist, on_delete=CASCADE, related_name='+')
74+
comment = CharField(max_length=255)
75+
76+
def __str__(self):
77+
return self.artist.name
78+
"""
79+
80+
class UserForm(Form):
81+
class Meta:
82+
auto__model = get_user_model()
83+
auto__include = ['username', 'email']
84+
fields__username__editable = False
85+
86+
class FavoriteArtists(EditTable):
87+
class Meta:
88+
auto__model = FavoriteArtist
89+
auto__include = ['artist__name', 'comment', 'sort_order']
90+
columns__comment__field__include = True
91+
92+
user = get_user_model().objects.get(username='john.doe')
93+
94+
class ParentForm(Form):
95+
user_form = UserForm.edit(auto__instance=user)
96+
favorite_artists = FavoriteArtists(rows=user.favorite_artists.all())
97+
98+
class Meta:
99+
actions__submit__post_handler = save_nested_forms
100+
101+
# @test
102+
t = (
103+
# @end
104+
105+
ParentForm()
106+
107+
# @test
108+
)
109+
110+
show_output(t.bind(request=request))
111+
# @end
112+
113+
# language=rst
114+
"""
115+
If you already have a custom model field for ordering, you can register it as a reorderderin column:
116+
117+
.. code-block:: python
118+
119+
from iommi import register_edit_column_factory
120+
121+
register_edit_column_factory(YourOrderField, shortcut_name='reorder_handle')
122+
"""
123+
124+
# language=rst
125+
"""
126+
If you just use any django integer field, you can still make your EditTable orderable with:
127+
128+
.. code-block:: python
129+
130+
class MyEditTable(EditTable):
131+
class Meta:
132+
auto__model = Foo
133+
columns__bar = EditColumn.reorder_handle()
134+
"""
135+
136+
# language=rst
137+
"""
138+
We use SortableJS and if you want, you can also pass other `options <https://github.com/SortableJS/Sortable?tab=readme-ov-file#options>`__.
139+
For example this allows multi-drag:
140+
141+
.. code-block:: python
142+
143+
class MyEditTable(EditTable):
144+
class Meta:
145+
auto__model = Foo
146+
columns__bar = EditColumn.reorder_handle()
147+
reorderable = {
148+
"multiDrag": True, # Enable multi-drag
149+
"selectedClass": 'selected', # The class applied to the selected items
150+
"fallbackTolerance": 3, # So that we can select items on mobile
151+
}
152+
"""

iommi/_db_compat.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
def setup_db_compat():
66
setup_db_compat_django()
7+
setup_db_compat_iommi()
78

89

910
def register_factory(django_field_class, *, shortcut_name=MISSING, factory=MISSING, **kwargs):
@@ -168,6 +169,13 @@ def fn(model_field, **_):
168169
register_field_factory(FileField, shortcut_name='file')
169170

170171

172+
def setup_db_compat_iommi():
173+
from iommi.model_fields import SortOrderField
174+
from iommi.edit_table import register_edit_column_factory
175+
176+
register_edit_column_factory(SortOrderField, shortcut_name='reorder_handle')
177+
178+
171179
def base_defaults_factory(model_field):
172180
from iommi.base import capitalize
173181

iommi/model_fields.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from django.db.models import PositiveIntegerField
2+
from django import VERSION as DJANGO_VERSION
3+
4+
5+
class SortOrderField(PositiveIntegerField):
6+
def __init__(self, to=None, **kwargs):
7+
kwargs.setdefault("null", False)
8+
kwargs.setdefault("blank", False)
9+
if DJANGO_VERSION[0] >= 5:
10+
kwargs.setdefault("db_default", 0)
11+
kwargs.setdefault("db_index", True)
12+
kwargs.setdefault("default", 0)
13+
kwargs.setdefault("editable", False)
14+
super().__init__(to, **kwargs)

iommi/models.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from django.db.models import Model
2+
3+
from iommi.model_fields import SortOrderField
4+
5+
6+
class Orderable(Model):
7+
sort_order = SortOrderField()
8+
9+
class Meta:
10+
abstract = True
11+
ordering = ["sort_order"]

0 commit comments

Comments
 (0)