1
1
from importlib import import_module
2
+ from types import ModuleType
2
3
from django .conf import settings
3
4
from django .core .urlresolvers import RegexURLResolver , RegexURLPattern
4
5
from django .utils .module_loading import import_string
5
6
from rest_framework .views import APIView
6
- from rest_framework_docs .api_endpoint import ApiEndpoint
7
+ from rest_framework .routers import BaseRouter
8
+ from rest_framework_docs .api_endpoint import ApiNode , ApiEndpoint
9
+ from rest_framework_docs .settings import DRFSettings
10
+
11
+
12
+ drf_settings = DRFSettings ().settings
7
13
8
14
9
15
class ApiDocumentation (object ):
10
16
11
17
def __init__ (self , drf_router = None ):
12
18
self .endpoints = []
13
19
self .drf_router = drf_router
20
+
14
21
try :
15
22
root_urlconf = import_string (settings .ROOT_URLCONF )
16
23
except ImportError :
@@ -21,26 +28,113 @@ def __init__(self, drf_router=None):
21
28
else :
22
29
self .get_all_view_names (root_urlconf .urlpatterns )
23
30
24
- def get_all_view_names (self , urlpatterns , parent_pattern = None ):
31
+ def get_all_view_names (self , urlpatterns , parent_api_node = None ):
25
32
for pattern in urlpatterns :
26
33
if isinstance (pattern , RegexURLResolver ):
27
- parent_pattern = None if pattern ._regex == "^" else pattern
28
- self .get_all_view_names (urlpatterns = pattern .url_patterns , parent_pattern = parent_pattern )
29
- elif isinstance (pattern , RegexURLPattern ) and self ._is_drf_view (pattern ) and not self ._is_format_endpoint (pattern ):
30
- api_endpoint = ApiEndpoint (pattern , parent_pattern , self .drf_router )
34
+ # Try to get router from settings, if no router is found,
35
+ # Use the instance drf_router property.
36
+ router = get_router (pattern )
37
+ if router is None :
38
+ parent_router = None
39
+ if parent_api_node is not None :
40
+ parent_router = parent_api_node .drf_router
41
+ if parent_router is not None :
42
+ router = parent_router
43
+ else :
44
+ router = self .drf_router
45
+ if pattern ._regex == "^" :
46
+ parent = parent_api_node
47
+ else :
48
+ parent = ApiNode (
49
+ pattern ,
50
+ parent_node = parent_api_node ,
51
+ drf_router = router
52
+ )
53
+ self .get_all_view_names (urlpatterns = pattern .url_patterns , parent_api_node = parent )
54
+ elif isinstance (pattern , RegexURLPattern ) and _is_drf_view (pattern ) and not _is_format_endpoint (pattern ):
55
+ router = parent_api_node .drf_router
56
+ router = self .drf_router if router is None else router
57
+ api_endpoint = ApiEndpoint (pattern , parent_api_node , router )
31
58
self .endpoints .append (api_endpoint )
32
59
33
- def _is_drf_view (self , pattern ):
34
- """
35
- Should check whether a pattern inherits from DRF's APIView
36
- """
37
- return hasattr (pattern .callback , 'cls' ) and issubclass (pattern .callback .cls , APIView )
60
+ def get_endpoints (self ):
61
+ return self .endpoints
38
62
39
- def _is_format_endpoint (self , pattern ):
40
- """
41
- Exclude endpoints with a "format" parameter
63
+
64
+ def _is_drf_view (pattern ):
65
+ """
66
+ Should check whether a pattern inherits from DRF's APIView
67
+ """
68
+ return hasattr (pattern .callback , 'cls' ) and issubclass (pattern .callback .cls ,
69
+ APIView )
70
+
71
+
72
+ def _is_format_endpoint (pattern ):
73
+ """
74
+ Exclude endpoints with a "format" parameter
75
+ """
76
+ return '?P<format>' in pattern ._regex
77
+
78
+
79
+ def get_router (pattern ):
80
+ urlconf = pattern .urlconf_name
81
+ router = None
82
+ if isinstance (urlconf , ModuleType ):
83
+ # First: try MODULE_ROUTERS setting - Don't ignore errors
84
+ router = get_module_router (urlconf )
85
+ if router is not None :
86
+ return router
87
+ # Second: try DEFAULT_MODULE_ROUTER setting - Ignore errors
88
+ try :
89
+ router = get_default_module_router (urlconf )
90
+ if router is not None :
91
+ return router
92
+ except :
93
+ pass
94
+ # Third: try DEFAULT_ROUTER setting - Don't ignore errors
95
+ router = get_default_router ()
96
+ if router is not None :
97
+ return router
98
+ return router
99
+
100
+
101
+ def get_module_router (module ):
102
+ routers = drf_settings ['MODULE_ROUTERS' ]
103
+ if routers is None :
104
+ return None
105
+ if module .__name__ in routers :
106
+ router_name = routers [module .__name__ ]
107
+ router = getattr (module , router_name )
108
+ assert isinstance (router , BaseRouter ), \
109
+ """
110
+ drfdocs 'ROUTERS' setting does not correspond to
111
+ a router instance for module {}.
112
+ """ .format (module .__name__ )
113
+ return router
114
+ return None
115
+
116
+
117
+ def get_default_module_router (module ):
118
+ default_module_router = drf_settings ['DEFAULT_MODULE_ROUTER' ]
119
+ if default_module_router is None :
120
+ return None
121
+ router = getattr (module , default_module_router )
122
+ assert isinstance (router , BaseRouter ), \
42
123
"""
43
- return '?P<format>' in pattern ._regex
124
+ drfdocs 'DEFAULT_MODULE_ROUTER' setting does not correspond to
125
+ a router instance for module {}.
126
+ """ .format (module .__name__ )
127
+ return router
44
128
45
- def get_endpoints (self ):
46
- return self .endpoints
129
+
130
+ def get_default_router ():
131
+ default_router_path = drf_settings ['DEFAULT_ROUTER' ]
132
+ if default_router_path is None :
133
+ return None
134
+ router = import_string (default_router_path )
135
+ assert isinstance (router , BaseRouter ), \
136
+ """
137
+ drfdocs 'DEFAULT_ROUTER_NAME' setting does not correspond to
138
+ a router instance {}.
139
+ """ .format (router .__name__ )
140
+ return router
0 commit comments