Skip to content

Commit b4edaff

Browse files
committed
fix(generic-relations): Pass parent model metadata explicitly
1 parent a27e8d4 commit b4edaff

5 files changed

Lines changed: 86 additions & 13 deletions

File tree

src/django_smartbase_admin/admin/admin_base.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@
162162
SBADMIN_PARENT_INSTANCE_PK_VAR,
163163
SBADMIN_PARENT_INSTANCE_LABEL_VAR,
164164
SBADMIN_PARENT_INSTANCE_FIELD_NAME_VAR,
165+
SBADMIN_PARENT_INSTANCE_MODEL_VAR,
165166
SBADMIN_RELOAD_ON_SAVE_VAR,
166167
)
167168
from django_smartbase_admin.engine.const import (
@@ -1301,17 +1302,18 @@ def response_change(self, request, obj):
13011302
def set_generic_relation_from_parent(cls, request, obj):
13021303
from django_smartbase_admin.admin.site import sb_admin_site
13031304

1304-
parent_path = cls.get_request_parameter(
1305+
parent_field = cls.get_request_parameter(
13051306
request, SBADMIN_PARENT_INSTANCE_FIELD_NAME_VAR
13061307
)
1308+
parent_model_path = cls.get_request_parameter(
1309+
request, SBADMIN_PARENT_INSTANCE_MODEL_VAR
1310+
)
13071311
parent_pk = cls.get_request_parameter(request, SBADMIN_PARENT_INSTANCE_PK_VAR)
1308-
if not (parent_path and parent_pk):
1312+
if not (parent_field and parent_model_path and parent_pk):
13091313
return
13101314

1311-
# Token: ``modal_<app>_<model>_<field>_<parent_model>``; rsplit
1312-
# tolerates underscores in app labels / model names.
13131315
try:
1314-
_, _, app_label, model_name = parent_path.rsplit("_", 3)
1316+
app_label, model_name = parent_model_path.split(".", 1)
13151317
content_type = ContentType.objects.get(
13161318
app_label=app_label, model=model_name
13171319
)
@@ -1529,14 +1531,20 @@ def get_context_data(self, request) -> dict[str, Any]:
15291531
"add_url": add_url,
15301532
}
15311533
if self.parent_instance:
1534+
parent_field_name = "{}_{}_id_{}".format(
1535+
self.model._meta.app_label,
1536+
self.model._meta.model_name,
1537+
self.parent_model._meta.model_name,
1538+
)
1539+
parent_model_path = "{}.{}".format(
1540+
self.parent_model._meta.app_label,
1541+
self.parent_model._meta.model_name,
1542+
)
15321543
context_data["parent_data"] = {
15331544
SBADMIN_PARENT_INSTANCE_PK_VAR: self.parent_instance.pk,
15341545
SBADMIN_PARENT_INSTANCE_LABEL_VAR: str(self.parent_instance),
1535-
SBADMIN_PARENT_INSTANCE_FIELD_NAME_VAR: "{}_{}_id_{}".format(
1536-
self.model._meta.app_label,
1537-
self.model._meta.model_name,
1538-
self.parent_model._meta.model_name,
1539-
),
1546+
SBADMIN_PARENT_INSTANCE_FIELD_NAME_VAR: parent_field_name,
1547+
SBADMIN_PARENT_INSTANCE_MODEL_VAR: parent_model_path,
15401548
}
15411549
return context_data
15421550

src/django_smartbase_admin/engine/admin_base_view.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969

7070
SBADMIN_IS_MODAL_VAR = "sbadmin_is_modal"
7171
SBADMIN_PARENT_INSTANCE_FIELD_NAME_VAR = "sbadmin_parent_instance_field"
72+
SBADMIN_PARENT_INSTANCE_MODEL_VAR = "sbadmin_parent_instance_model"
7273
SBADMIN_PARENT_INSTANCE_PK_VAR = "sbadmin_parent_instance_pk"
7374
SBADMIN_PARENT_INSTANCE_LABEL_VAR = "sbadmin_parent_instance_label"
7475
SBADMIN_RELOAD_ON_SAVE_VAR = "sbadmin_reload_on_save"

src/django_smartbase_admin/templates/sb_admin/inlines/table_inline.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
class="btn btn-icon ml-auto {{ inline_admin_formset.handler_classes|join:" " }}"
5959
data-bs-toggle="modal"
6060
data-bs-target="#sb-admin-modal"
61-
hx-get="{{ context_data.add_url }}?_popup=1&sbadmin_is_modal=1&sbadmin_reload_on_save=1&sbadmin_parent_instance_field=modal_{{ context_data.parent_data.sbadmin_parent_instance_field|urlencode }}&sbadmin_parent_instance_pk={{ context_data.parent_data.sbadmin_parent_instance_pk|urlencode }}&sbadmin_parent_instance_label={{ context_data.parent_data.sbadmin_parent_instance_label|urlencode }}"
61+
hx-get="{{ context_data.add_url }}?_popup=1&sbadmin_is_modal=1&sbadmin_reload_on_save=1&sbadmin_parent_instance_field=modal_{{ context_data.parent_data.sbadmin_parent_instance_field|urlencode }}&sbadmin_parent_instance_model={{ context_data.parent_data.sbadmin_parent_instance_model|urlencode }}&sbadmin_parent_instance_pk={{ context_data.parent_data.sbadmin_parent_instance_pk|urlencode }}&sbadmin_parent_instance_label={{ context_data.parent_data.sbadmin_parent_instance_label|urlencode }}"
6262
hx-target="#sb-admin-modal"
6363
hx-select="#modal-content"
6464
hx-swap="innerHTML"

src/django_smartbase_admin/tests/test_generic_relation_parent.py

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
from types import SimpleNamespace
22
from unittest.mock import MagicMock, patch
33

4+
from django.contrib.auth.models import Group
45
from django.contrib.contenttypes.models import ContentType
56
from django.core.exceptions import PermissionDenied
67
from django.test import RequestFactory, TestCase
78
from filer.models import Folder
89

9-
from django_smartbase_admin.admin.admin_base import SBAdmin
10+
from django_smartbase_admin.admin.admin_base import SBAdmin, SBAdminInline
11+
from django_smartbase_admin.admin.widgets import SBAdminAutocompleteWidget
1012
from django_smartbase_admin.engine.admin_base_view import (
1113
SBADMIN_PARENT_INSTANCE_FIELD_NAME_VAR,
14+
SBADMIN_PARENT_INSTANCE_MODEL_VAR,
1215
SBADMIN_PARENT_INSTANCE_PK_VAR,
1316
)
1417

@@ -28,7 +31,10 @@ def _request(self, pk):
2831
return self.factory.post(
2932
"/",
3033
data={
31-
SBADMIN_PARENT_INSTANCE_FIELD_NAME_VAR: f"modal_inline_{self.ct.app_label}_{self.ct.model}",
34+
SBADMIN_PARENT_INSTANCE_FIELD_NAME_VAR: "modal_inline",
35+
SBADMIN_PARENT_INSTANCE_MODEL_VAR: (
36+
f"{self.ct.app_label}.{self.ct.model}"
37+
),
3238
SBADMIN_PARENT_INSTANCE_PK_VAR: str(pk),
3339
},
3440
)
@@ -54,3 +60,59 @@ def test_forged_parent_pk_outside_restricted_queryset_is_denied(self):
5460
self._request(self.visible.pk), obj
5561
)
5662
self.assertEqual(obj.object_id, self.visible.pk)
63+
64+
def test_generated_inline_parent_token_round_trips_through_parser(self):
65+
inline = SBAdminInline.__new__(SBAdminInline)
66+
inline.model = Group
67+
inline.parent_model = Folder
68+
inline.parent_instance = self.visible
69+
inline.sortable_field_name = None
70+
inline.sb_admin_add_modal = False
71+
with patch.object(
72+
inline, "get_sbadmin_inline_list_actions_processed", return_value=[]
73+
):
74+
parent_data = inline.get_context_data(self.factory.get("/"))["parent_data"]
75+
76+
request = self.factory.post(
77+
"/",
78+
data={
79+
SBADMIN_PARENT_INSTANCE_FIELD_NAME_VAR: (
80+
f"modal_{parent_data[SBADMIN_PARENT_INSTANCE_FIELD_NAME_VAR]}"
81+
),
82+
SBADMIN_PARENT_INSTANCE_MODEL_VAR: parent_data[
83+
SBADMIN_PARENT_INSTANCE_MODEL_VAR
84+
],
85+
SBADMIN_PARENT_INSTANCE_PK_VAR: str(self.visible.pk),
86+
},
87+
)
88+
parent_admin = MagicMock()
89+
parent_admin.has_view_permission.return_value = True
90+
parent_admin.get_queryset.return_value = Folder.objects.all()
91+
obj = SimpleNamespace()
92+
93+
with patch.dict(
94+
"django_smartbase_admin.admin.site.sb_admin_site._registry",
95+
{Folder: parent_admin},
96+
):
97+
_ChildAdmin.set_generic_relation_from_parent(request, obj)
98+
99+
self.assertEqual(obj.content_type, self.ct)
100+
self.assertEqual(obj.object_id, self.visible.pk)
101+
102+
def test_parent_model_metadata_does_not_change_widget_target(self):
103+
input_id = "modal_auth_group_id_folder"
104+
request = self.factory.get(
105+
"/",
106+
data={
107+
SBADMIN_PARENT_INSTANCE_FIELD_NAME_VAR: input_id,
108+
SBADMIN_PARENT_INSTANCE_MODEL_VAR: "filer.folder",
109+
SBADMIN_PARENT_INSTANCE_PK_VAR: str(self.visible.pk),
110+
},
111+
)
112+
widget = SimpleNamespace(input_id=input_id)
113+
114+
is_parent_widget = SBAdminAutocompleteWidget._should_preselect_parent_instance(
115+
widget, request
116+
)
117+
118+
self.assertIs(is_parent_widget, True)

src/django_smartbase_admin/tests/test_modal_parent_context.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
SBADMIN_IS_MODAL_VAR,
1414
SBADMIN_PARENT_INSTANCE_FIELD_NAME_VAR,
1515
SBADMIN_PARENT_INSTANCE_LABEL_VAR,
16+
SBADMIN_PARENT_INSTANCE_MODEL_VAR,
1617
SBADMIN_PARENT_INSTANCE_PK_VAR,
1718
SBADMIN_RELOAD_ON_SAVE_VAR,
1819
)
@@ -76,6 +77,7 @@ def test_invalid_modal_post_keeps_parent_context_in_next_post_url(self):
7677
SBADMIN_PARENT_INSTANCE_FIELD_NAME_VAR: (
7778
"modal_app_attachment_id_parent"
7879
),
80+
SBADMIN_PARENT_INSTANCE_MODEL_VAR: "app.parent",
7981
SBADMIN_PARENT_INSTANCE_PK_VAR: "42",
8082
SBADMIN_PARENT_INSTANCE_LABEL_VAR: "Parent #42",
8183
}

0 commit comments

Comments
 (0)