Skip to content

Commit 22c4435

Browse files
committed
Adds fixer: gis_admin_deprecations for Django 5.0
Allows replacement of OSMGeoAdmin and GeoModelAdmin with GISModelAdmin from the same module, those classe were removed on Django 5.0: https://docs.djangoproject.com/en/5.0/releases/5.0/#django-contrib-gis
1 parent 2eb9dea commit 22c4435

File tree

3 files changed

+174
-0
lines changed

3 files changed

+174
-0
lines changed

README.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,32 @@ Such use cases are why calling ``format_html()`` without any arguments or keywor
261261
-format_html("<marquee>{name}</marquee>".format(name=name))
262262
+format_html("<marquee>{name}</marquee>", name=name)
263263
264+
Replace deprecated ``OSMGeoAdmin`` and ``GeoModelAdmin`` classes
265+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
266+
267+
**Name:** ``gis_admin_deprecations``
268+
269+
Rewrites imports and calls for ``OSMGeoAdmin`` and ``GeoModelAdmin`` on imports and admin base classes.
270+
The new GISModelAdmin class allows customizing the widget used for GeometryField. This is encouraged instead of deprecated GeoModelAdmin and OSMGeoAdmin.
271+
This was deprecated in `Ticket #34609 <https://code.djangoproject.com/ticket/27674>`__.
272+
273+
.. code-block:: diff
274+
275+
-from django.contrib.gis.admin.options import OSMGeoAdmin
276+
+from django.contrib.gis.admin.options import GISModelAdmin
277+
278+
-class MyAdminClass(OSMGeoAdmin):
279+
+class MyAdminClass(GISModelAdmin):
280+
281+
.. code-block:: diff
282+
283+
-from django.contrib.gis.admin.options import GeoModelAdmin
284+
+from django.contrib.gis.admin.options import GISModelAdmin
285+
286+
-class MyAdminClass(GeoModelAdmin):
287+
+class MyAdminClass(GISModelAdmin):
288+
289+
264290
Django 4.2
265291
----------
266292

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
"""
2+
Rename OSMGeoAdmin to GISModelAdmin in django.contrib.gis.admin.options
3+
due to deprecation on Django 5.0:
4+
https://docs.djangoproject.com/en/5.0/releases/5.0/#features-removed-in-5-0
5+
"""
6+
7+
from __future__ import annotations
8+
9+
import ast
10+
from functools import partial
11+
from typing import Iterable
12+
13+
from tokenize_rt import Offset
14+
15+
from django_upgrade.ast import ast_start_offset
16+
from django_upgrade.ast import is_rewritable_import_from
17+
from django_upgrade.data import Fixer
18+
from django_upgrade.data import State
19+
from django_upgrade.data import TokenFunc
20+
from django_upgrade.tokens import find_and_replace_name
21+
from django_upgrade.tokens import update_import_names
22+
23+
fixer = Fixer(
24+
__name__,
25+
min_version=(5, 0),
26+
)
27+
28+
MODULE = "django.contrib.gis.admin.options"
29+
RENAMES = {
30+
"OSMGeoAdmin": "GISModelAdmin",
31+
"GeoModelAdmin": "GISModelAdmin",
32+
}
33+
34+
35+
@fixer.register(ast.ImportFrom)
36+
def visit_ImportFrom(
37+
state: State,
38+
node: ast.ImportFrom,
39+
parents: tuple[ast.AST, ...],
40+
) -> Iterable[tuple[Offset, TokenFunc]]:
41+
if node.module == MODULE and is_rewritable_import_from(node):
42+
name_map = {}
43+
for alias in node.names:
44+
if alias.name in RENAMES:
45+
name_map[alias.name] = RENAMES[alias.name]
46+
47+
if name_map:
48+
yield ast_start_offset(node), partial(
49+
update_import_names,
50+
node=node,
51+
name_map=name_map,
52+
)
53+
54+
55+
@fixer.register(ast.Name)
56+
def visit_Name(
57+
state: State,
58+
node: ast.Name,
59+
parents: tuple[ast.AST, ...],
60+
) -> Iterable[tuple[Offset, TokenFunc]]:
61+
if (name := node.id) in RENAMES and name in state.from_imports[MODULE]:
62+
new_name = RENAMES[name]
63+
yield ast_start_offset(node), partial(
64+
find_and_replace_name, name=name, new=new_name
65+
)
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
from __future__ import annotations
2+
3+
from functools import partial
4+
5+
from django_upgrade.data import Settings
6+
from tests.fixers import tools
7+
8+
settings = Settings(target_version=(5, 0))
9+
check_noop = partial(tools.check_noop, settings=settings)
10+
check_transformed = partial(tools.check_transformed, settings=settings)
11+
12+
13+
def test_no_deprecated_alias():
14+
check_noop(
15+
"""\
16+
from django.contrib.gis.admin.options import GeoAdmin
17+
18+
GeoAdmin
19+
""",
20+
)
21+
22+
23+
def test_one_local_name():
24+
check_transformed(
25+
"""\
26+
from django.contrib.gis.admin.options import OSMGeoAdmin
27+
28+
class MyModelAdmin(OSMGeoAdmin):
29+
pass
30+
""",
31+
"""\
32+
from django.contrib.gis.admin.options import GISModelAdmin
33+
34+
class MyModelAdmin(GISModelAdmin):
35+
pass
36+
""",
37+
)
38+
check_transformed(
39+
"""\
40+
from django.contrib.gis.admin.options import GeoModelAdmin
41+
42+
class MyModelAdmin(GeoModelAdmin):
43+
pass
44+
""",
45+
"""\
46+
from django.contrib.gis.admin.options import GISModelAdmin
47+
48+
class MyModelAdmin(GISModelAdmin):
49+
pass
50+
""",
51+
)
52+
53+
54+
def test_with_alias():
55+
check_transformed(
56+
"""\
57+
from django.contrib.gis.admin.options import OSMGeoAdmin as GeoAdmin
58+
59+
class MyModelAdmin(GeoAdmin):
60+
pass
61+
""",
62+
"""\
63+
from django.contrib.gis.admin.options import GISModelAdmin as GeoAdmin
64+
65+
class MyModelAdmin(GeoAdmin):
66+
pass
67+
""",
68+
)
69+
70+
check_transformed(
71+
"""\
72+
from django.contrib.gis.admin.options import GeoModelAdmin as GeoAdmin
73+
74+
class MyModelAdmin(GeoAdmin):
75+
pass
76+
""",
77+
"""\
78+
from django.contrib.gis.admin.options import GISModelAdmin as GeoAdmin
79+
80+
class MyModelAdmin(GeoAdmin):
81+
pass
82+
""",
83+
)

0 commit comments

Comments
 (0)