Skip to content

Commit 489038f

Browse files
authored
Path component: do not allow unnamed patterns (#137)
1 parent 5abe7b7 commit 489038f

File tree

3 files changed

+32
-2
lines changed

3 files changed

+32
-2
lines changed

django_modern_rest/components.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,12 @@ class Path(ComponentParser, Generic[_PathT]):
172172
parsed paths parameters as ``self.parsed_path`` attribute.
173173
174174
It is way stricter than the original Django's routing system.
175-
For example, django allows to
175+
For example, django allows to such cases:
176+
- ``user_id`` is defined as ``int`` in the ``path('user/<int:user_id>')``
177+
- ``user_id`` is defined as ``str`` in the view function:
178+
``def get(self, request, user_id: str): ...``
179+
180+
In ``django-modern-rest`` there's now a way to validate this in runtime.
176181
"""
177182

178183
parsed_path: _PathT
@@ -187,4 +192,9 @@ def provide_context_data(
187192
*args: Any,
188193
**kwargs: Any,
189194
) -> Any:
195+
if args:
196+
raise RequestSerializationError(
197+
f'Path {type(self)} with {model=} does not allow '
198+
f'unnamed path parameters {args=}',
199+
)
190200
return kwargs

django_test_app/django_test_app/urls.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
1717
"""
1818

19-
from django.urls import include, path
19+
from django.urls import include, path, re_path
2020

2121
from django_modern_rest import Router, compose_controllers
2222
from django_modern_rest.openapi import (
@@ -55,6 +55,11 @@
5555
).as_view(),
5656
name='user_update',
5757
),
58+
re_path(
59+
r'user/direct/re/(\d+)',
60+
UserUpdateController.as_view(),
61+
name='user_update_direct_re',
62+
),
5863
path(
5964
'user/direct/<int:user_id>',
6065
UserUpdateController.as_view(),

tests/test_integration/test_contollers/test_user_direct_controller.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,18 @@ async def test_user_update_direct_view_async(self) -> None:
8181

8282
assert response.status_code == HTTPStatus.OK
8383
assert response.headers['Content-Type'] == 'application/json'
84+
85+
86+
def test_user_update_direct_re(dmr_client: DMRClient, faker: Faker) -> None:
87+
"""Ensure that path unnamed path parameters are not allowed."""
88+
email = faker.email()
89+
user_id = faker.unique.random_int()
90+
91+
response = dmr_client.patch(
92+
reverse('api:user_update_direct_re', args=(user_id,)),
93+
data={'email': email, 'age': faker.unique.random_int()},
94+
)
95+
96+
assert response.status_code == HTTPStatus.UNPROCESSABLE_ENTITY
97+
assert response.headers['Content-Type'] == 'application/json'
98+
assert response.json()['detail']

0 commit comments

Comments
 (0)