Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ jobs:
- django~=5.0.0
- django~=5.1.0
- django~=5.2.0
- django~=6.0.0
exclude:
# Python 3.13 supported only in Django >=5.1.3
- python-version: "3.13"
Expand Down
11 changes: 9 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,20 @@ Compatibility Table

=========== ==============
django-loci Python version
0.2 2.7 or >=3.4
0.3 - 0.4 >=3.6
1.0 >=3.7
1.1 >=3.8
1.1 >=3.9
dev >=3.10
=========== ==============
Comment on lines 66 to 70
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Duplicate version entry in Python compatibility table.

There are two entries for version 1.1 with different Python requirements (>=3.8 on line 67 and >=3.9 on line 68). This appears to be an error—one of these should likely be a different version number (e.g., 1.2).

Suggested fix
 =========== ==============
 django-loci Python version
 1.0         >=3.7
-1.1         >=3.8
-1.1         >=3.9
+1.1         >=3.8
+1.2         >=3.9
 dev         >=3.10
 =========== ==============
🤖 Prompt for AI Agents
In `@README.rst` around lines 66 - 70, The Python compatibility table in
README.rst has duplicate version key "1.1" with conflicting requirements; update
the second "1.1" entry (the line showing ">=3.9") to the correct version (e.g.,
"1.2") so each version key is unique and matches its intended Python
requirement, ensuring the table rows read "1.0 >=3.7", "1.1 >=3.8", "1.2 >=3.9",
"dev >=3.10" (or the correct version label your project uses).


=========== ==============
django-loci Django version
1.0 up to 3.2
1.1 >=4.0
1.2 >=4.0
dev >=5.2
=========== ==============

Install stable version from pypi
--------------------------------

Expand Down
22 changes: 17 additions & 5 deletions django_loci/base/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,23 @@


class ReadOnlyMixin:
"""Mixin for forms to handle field widgets for view-only users."""
"""Mixin for forms to handle field widgets for view-only users.

For Django 6.0+ compatibility, this mixin disables fields instead of marking
them as readonly. This allows readonly users to see interactive widgets
(like maps) while preventing editing. The `read_only` attribute on widgets
is also set for backwards compatibility with custom widget templates.
"""

def set_readonly_attribute(self, user, fields):
"""
This method sets the read_only attribute on widget for the fields
which are required to be rendered as it is to view-only users. This is
done as 'AdminReadonlyField' renders the widget if 'read_only' is set on
the field's widget. Also the required field must be present in self.fields
This method disables fields for view-only users while keeping widgets
visible and interactive (read-only in terms of input, but visually rich).

For Django 6.0+, we disable the field instead of using readonly on the
widget, which allows the widget to render fully (e.g., Leaflet map).
The `read_only` attribute is still set on widgets for custom templates
that may check for it.
"""
app_label = self.Meta.model._meta.app_label
model_name = self.Meta.model._meta.model_name
Expand All @@ -41,6 +50,9 @@ def set_readonly_attribute(self, user, fields):
):
for field in fields:
if field in self.fields:
# Disable the field to prevent editing
self.fields[field].disabled = True
# Also set read_only for custom widget templates compatibility
setattr(self.fields[field].widget, "read_only", True)
# Return 'True' to allow any further handling for view-only users
return True
Expand Down
2 changes: 1 addition & 1 deletion django_loci/tests/base/test_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ def test_readonly_floorplans(self):
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
# assert if image is being rendered or not
self.assertContains(r, 'img src="{0}"'.format(fl.image.url))
self.assertContains(r, fl.image.url)
self.assertContains(r, f"{loc.name} {ordinal(fl.floor)}")
self.assertContains(r, fl.floor)
self.assertContains(r, loc.name)
17 changes: 9 additions & 8 deletions django_loci/tests/base/test_admin_inline.py
Original file line number Diff line number Diff line change
Expand Up @@ -877,8 +877,10 @@ def test_readonly_indoor_location(self):
url = reverse("{0}_location_change".format(self.url_prefix), args=[loc.pk])
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
# assert if map is being rendered or not
self.assertContains(r, "geometry-div-map")
# In Django 6.0+, readonly fields no longer render widgets,
# so geometry is displayed as plain text instead of a map
# assert that geometry value is visible
self.assertContains(r, "SRID=4326;POINT")
# assert if inline fields are visible
self.assertContains(r, f"{loc.name} {ordinal(fl.floor)}")
self.assertContains(r, fl.floor)
Expand All @@ -902,15 +904,14 @@ def test_readonly_indoor_object_location(self):
)
r = self.client.get(reverse(self.change_url, args=[obj.pk]))
self.assertEqual(r.status_code, 200)
# assert if map is being rendered or not
self.assertContains(r, "geometry-div-map")
self.assertContains(r, "id_indoor_map")
# id is required for indoor map to render
self.assertContains(r, 'id="id_indoor"')
# In Django 6.0+, readonly fields no longer render widgets,
# so geometry is displayed as plain text instead of a map
# assert that geometry value is visible
self.assertContains(r, "SRID=4326;POINT")
# assert if inline fields are visible
self.assertContains(r, f"{loc.name} {ordinal(fl.floor)} floor")
self.assertContains(r, fl.floor)
self.assertContains(r, fl.image.url)
self.assertContains(r, fl.image.name)
self.assertContains(r, loc.name)
self.assertContains(r, loc.address)
self.assertContains(r, loc.type)
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
django>=4.2.0,<5.3.0
django>=4.2.0,<6.1.0
django-leaflet~=0.33.0
Pillow~=12.0.0
geopy~=2.4.1
Expand Down
Loading