Skip to content
Merged
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
2 changes: 1 addition & 1 deletion ninja_extra/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Django Ninja Extra - Class Based Utility and more for Django Ninja(Fast Django REST framework)"""

__version__ = "0.21.7"
__version__ = "0.21.8"

import django

Expand Down
22 changes: 19 additions & 3 deletions ninja_extra/controllers/base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import inspect
import re
import uuid
from abc import ABC
from typing import (
TYPE_CHECKING,
Any,
Expand Down Expand Up @@ -62,9 +63,24 @@ class MissingAPIControllerDecoratorException(Exception):


def get_route_functions(cls: Type) -> Iterable[RouteFunction]:
for _, method in inspect.getmembers(cls, predicate=inspect.isfunction):
if hasattr(method, ROUTE_FUNCTION):
yield getattr(method, ROUTE_FUNCTION)
"""
Get all route functions from a controller class.
This function will recursively search for route functions in the base classes of the controller class
in order that they are defined.

Args:
cls (Type): The controller class.

Returns:
Iterable[RouteFunction]: An iterable of route functions.
"""

bases = inspect.getmro(cls)
for base_cls in reversed(bases):
if base_cls not in [ControllerBase, ABC, object]:
for method in base_cls.__dict__.values():
if hasattr(method, ROUTE_FUNCTION):
yield getattr(method, ROUTE_FUNCTION)


def get_all_controller_route_function(
Expand Down
30 changes: 29 additions & 1 deletion tests/test_operation.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import uuid

import django
import pytest

from ninja_extra import api_controller, route
from ninja_extra import api_controller, http_delete, http_get, route, status
from ninja_extra.controllers import AsyncRouteFunction, RouteFunction
from ninja_extra.helper import get_route_function
from ninja_extra.operation import AsyncOperation, Operation
Expand Down Expand Up @@ -113,3 +115,29 @@ async def test_async_route_operation_execution_should_log_execution(self):
client = TestAsyncClient(self.SomeTestController)
with pytest.raises(CustomException):
await client.get("/example_exception")


def test_controller_operation_order():
@api_controller("/my/api/users", tags=["User"])
class UserAPIController:
@http_get("/me")
def get_current_user(self, request):
return {"debug": "ok", "message": "Current user"}

@http_get("/{user_id}")
def get_user(self, request, user_id: uuid.UUID):
return {"debug": "ok", "message": "User"}

@http_delete("/{user_id}", response={status.HTTP_204_NO_CONTENT: None})
def delete_user_from_clinic(self, request, user_id: uuid.UUID):
return {"debug": "ok", "message": "User deleted"}

client = TestClient(UserAPIController)
response = client.get("/me")
assert response.json() == {"debug": "ok", "message": "Current user"}

response = client.get(f"/{uuid.uuid4()}")
assert response.json() == {"debug": "ok", "message": "User"}

response = client.delete(f"/{uuid.uuid4()}")
assert response.content == b""
Loading