Skip to content

Commit b024b6a

Browse files
committed
[deps] Added support for Django >=5.1,<5.3 and Python >=3.12, 3.14 #987
- Dropped support for Python < 3.9 - Dropped support for Django < 4.2 Closes #987
1 parent a72a8fc commit b024b6a

File tree

8 files changed

+40
-8
lines changed

8 files changed

+40
-8
lines changed

openwisp_controller/connection/base/models.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import collections
22
import logging
33

4+
import django
45
import jsonschema
56
from django.core.exceptions import ValidationError
67
from django.db import models, transaction
@@ -24,6 +25,7 @@
2425
ORGANIZATION_COMMAND_SCHEMA,
2526
ORGANIZATION_ENABLED_COMMANDS,
2627
get_command_callable,
28+
get_command_choices,
2729
get_command_schema,
2830
)
2931
from ..exceptions import NoWorkingDeviceConnectionError
@@ -408,7 +410,18 @@ class AbstractCommand(TimeStampedEditableModel):
408410
status = models.CharField(
409411
max_length=12, choices=STATUS_CHOICES, default=STATUS_CHOICES[0][0]
410412
)
411-
type = models.CharField(max_length=16, choices=COMMAND_CHOICES)
413+
type = models.CharField(
414+
max_length=16,
415+
choices=(
416+
COMMAND_CHOICES
417+
if django.VERSION < (5, 0)
418+
# In Django 5.0+, choices are normalized at model definition,
419+
# creating a static list of tuples that doesn't update when command
420+
# are dynamically registered or unregistered. Using a callable
421+
# ensures we always get the current choices from the registry.
422+
else get_command_choices
423+
),
424+
)
412425
input = JSONField(
413426
blank=True,
414427
null=True,

openwisp_controller/connection/commands.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,10 @@ def _unregister_command_choice(command):
155155
ORGANIZATION_COMMAND_SCHEMA[org_id] = OrderedDict()
156156
for command in commands:
157157
ORGANIZATION_COMMAND_SCHEMA[org_id][command] = COMMANDS[command]['schema']
158+
159+
160+
def get_command_choices():
161+
"""
162+
Returns the command choices.
163+
"""
164+
return COMMAND_CHOICES

openwisp_controller/connection/migrations/0007_command.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import collections
44
import uuid
55

6+
import django
67
import django.db.migrations.operations.special
78
import django.db.models.deletion
89
import django.utils.timezone
@@ -11,7 +12,7 @@
1112
import swapper
1213
from django.db import migrations, models
1314

14-
from ..commands import COMMAND_CHOICES
15+
from ..commands import COMMAND_CHOICES, get_command_choices
1516
from . import assign_command_permissions_to_groups
1617

1718

@@ -65,7 +66,9 @@ class Migration(migrations.Migration):
6566
(
6667
'type',
6768
models.CharField(
68-
choices=COMMAND_CHOICES,
69+
choices=COMMAND_CHOICES
70+
if django.VERSION < (5, 0)
71+
else get_command_choices,
6972
max_length=16,
7073
),
7174
),

openwisp_controller/connection/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22

33

44
def get_connection_working_notification_target_url(obj, field, absolute_url=True):
5-
url = _get_object_link(obj, field, absolute_url)
5+
url = _get_object_link(obj._related_object(field), absolute_url)
66
return f'{url}#deviceconnection_set-group'

openwisp_controller/geo/tests/test_admin_inline.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,4 @@ def test_add_mobile(self):
7878

7979

8080
del TestConfigAdmin
81+
del BaseTestAdminInline

openwisp_controller/geo/tests/test_api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,7 @@ def test_change_location_type_to_outdoor_api(self):
577577
self._create_floorplan(location=l1)
578578
path = reverse('geo_api:detail_location', args=[l1.pk])
579579
data = {'type': 'outdoor'}
580-
with self.assertNumQueries(8):
580+
with self.assertNumQueries(9):
581581
response = self.client.patch(path, data, content_type='application/json')
582582
self.assertEqual(response.status_code, 200)
583583
self.assertEqual(response.data['floorplan'], [])

tests/openwisp2/sample_connection/migrations/0001_initial.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import collections
44
import uuid
55

6+
import django
67
import django.db.models.deletion
78
import django.utils.timezone
89
import jsonfield.fields
@@ -14,7 +15,7 @@
1415
import openwisp_controller.connection.base.models
1516
import openwisp_users.mixins
1617
from openwisp_controller.connection import settings as connection_settings
17-
from openwisp_controller.connection.commands import COMMAND_CHOICES
18+
from openwisp_controller.connection.commands import COMMAND_CHOICES, get_command_choices
1819

1920

2021
class Migration(migrations.Migration):
@@ -245,7 +246,9 @@ class Migration(migrations.Migration):
245246
(
246247
'type',
247248
models.CharField(
248-
choices=COMMAND_CHOICES,
249+
choices=COMMAND_CHOICES
250+
if django.VERSION < (5, 0)
251+
else get_command_choices,
249252
max_length=16,
250253
),
251254
),

tests/openwisp2/sample_users/migrations/0001_initial.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,12 @@ class Migration(migrations.Migration):
204204
'verbose_name': 'user',
205205
'verbose_name_plural': 'users',
206206
'abstract': False,
207-
'index_together': {('id', 'email')},
207+
'indexes': [
208+
models.Index(
209+
fields=['id', 'email'],
210+
name='user_id_email_idx',
211+
)
212+
],
208213
},
209214
managers=[('objects', openwisp_users.base.models.UserManager())],
210215
),

0 commit comments

Comments
 (0)