Skip to content

Commit 879ff04

Browse files
authored
Merge pull request #214 from eadwinCode/controller_route_order
fix: Controller Operation Order
2 parents 58c5fe3 + 050004e commit 879ff04

File tree

3 files changed

+49
-5
lines changed

3 files changed

+49
-5
lines changed

ninja_extra/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Django Ninja Extra - Class Based Utility and more for Django Ninja(Fast Django REST framework)"""
22

3-
__version__ = "0.21.7"
3+
__version__ = "0.21.8"
44

55
import django
66

ninja_extra/controllers/base.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import inspect
22
import re
33
import uuid
4+
from abc import ABC
45
from typing import (
56
TYPE_CHECKING,
67
Any,
@@ -62,9 +63,24 @@ class MissingAPIControllerDecoratorException(Exception):
6263

6364

6465
def get_route_functions(cls: Type) -> Iterable[RouteFunction]:
65-
for _, method in inspect.getmembers(cls, predicate=inspect.isfunction):
66-
if hasattr(method, ROUTE_FUNCTION):
67-
yield getattr(method, ROUTE_FUNCTION)
66+
"""
67+
Get all route functions from a controller class.
68+
This function will recursively search for route functions in the base classes of the controller class
69+
in order that they are defined.
70+
71+
Args:
72+
cls (Type): The controller class.
73+
74+
Returns:
75+
Iterable[RouteFunction]: An iterable of route functions.
76+
"""
77+
78+
bases = inspect.getmro(cls)
79+
for base_cls in reversed(bases):
80+
if base_cls not in [ControllerBase, ABC, object]:
81+
for method in base_cls.__dict__.values():
82+
if hasattr(method, ROUTE_FUNCTION):
83+
yield getattr(method, ROUTE_FUNCTION)
6884

6985

7086
def get_all_controller_route_function(

tests/test_operation.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import uuid
2+
13
import django
24
import pytest
35

4-
from ninja_extra import api_controller, route
6+
from ninja_extra import api_controller, http_delete, http_get, route, status
57
from ninja_extra.controllers import AsyncRouteFunction, RouteFunction
68
from ninja_extra.helper import get_route_function
79
from ninja_extra.operation import AsyncOperation, Operation
@@ -113,3 +115,29 @@ async def test_async_route_operation_execution_should_log_execution(self):
113115
client = TestAsyncClient(self.SomeTestController)
114116
with pytest.raises(CustomException):
115117
await client.get("/example_exception")
118+
119+
120+
def test_controller_operation_order():
121+
@api_controller("/my/api/users", tags=["User"])
122+
class UserAPIController:
123+
@http_get("/me")
124+
def get_current_user(self, request):
125+
return {"debug": "ok", "message": "Current user"}
126+
127+
@http_get("/{user_id}")
128+
def get_user(self, request, user_id: uuid.UUID):
129+
return {"debug": "ok", "message": "User"}
130+
131+
@http_delete("/{user_id}", response={status.HTTP_204_NO_CONTENT: None})
132+
def delete_user_from_clinic(self, request, user_id: uuid.UUID):
133+
return {"debug": "ok", "message": "User deleted"}
134+
135+
client = TestClient(UserAPIController)
136+
response = client.get("/me")
137+
assert response.json() == {"debug": "ok", "message": "Current user"}
138+
139+
response = client.get(f"/{uuid.uuid4()}")
140+
assert response.json() == {"debug": "ok", "message": "User"}
141+
142+
response = client.delete(f"/{uuid.uuid4()}")
143+
assert response.content == b""

0 commit comments

Comments
 (0)