|
21 | 21 | fromdjango.urlsimportNoReverseMatch |
22 | 22 |
|
23 | 23 | fromrest_frameworkimportviews |
| 24 | +fromrest_framework.compatimportpath |
24 | 25 | fromrest_framework.responseimportResponse |
25 | 26 | fromrest_framework.reverseimportreverse |
26 | 27 | fromrest_framework.schemasimportSchemaGenerator |
@@ -79,50 +80,10 @@ def urls(self): |
79 | 80 | returnself._urls |
80 | 81 |
|
81 | 82 |
|
82 | | -classSimpleRouter(BaseRouter): |
83 | | - |
84 | | -routes= [ |
85 | | -# List route. |
86 | | -Route( |
87 | | -url=r'^{prefix}{trailing_slash}$', |
88 | | -mapping={ |
89 | | -'get':'list', |
90 | | -'post':'create' |
91 | | - }, |
92 | | -name='{basename}-list', |
93 | | -detail=False, |
94 | | -initkwargs={'suffix':'List'} |
95 | | - ), |
96 | | -# Dynamically generated list routes. Generated using |
97 | | -# @action(detail=False) decorator on methods of the viewset. |
98 | | -DynamicRoute( |
99 | | -url=r'^{prefix}/{url_path}{trailing_slash}$', |
100 | | -name='{basename}-{url_name}', |
101 | | -detail=False, |
102 | | -initkwargs={} |
103 | | - ), |
104 | | -# Detail route. |
105 | | -Route( |
106 | | -url=r'^{prefix}/{lookup}{trailing_slash}$', |
107 | | -mapping={ |
108 | | -'get':'retrieve', |
109 | | -'put':'update', |
110 | | -'patch':'partial_update', |
111 | | -'delete':'destroy' |
112 | | - }, |
113 | | -name='{basename}-detail', |
114 | | -detail=True, |
115 | | -initkwargs={'suffix':'Instance'} |
116 | | - ), |
117 | | -# Dynamically generated detail routes. Generated using |
118 | | -# @action(detail=True) decorator on methods of the viewset. |
119 | | -DynamicRoute( |
120 | | -url=r'^{prefix}/{lookup}/{url_path}{trailing_slash}$', |
121 | | -name='{basename}-{url_name}', |
122 | | -detail=True, |
123 | | -initkwargs={} |
124 | | - ), |
125 | | - ] |
| 83 | +classAbstractSimpleRouter(BaseRouter): |
| 84 | +""" |
| 85 | + Base class for SimpleRouter and SimplePathRouter. |
| 86 | + """ |
126 | 87 |
|
127 | 88 | def__init__(self,trailing_slash=True): |
128 | 89 | self.trailing_slash='/'iftrailing_slashelse'' |
@@ -203,6 +164,52 @@ def get_method_map(self, viewset, method_map): |
203 | 164 | bound_methods[method]=action |
204 | 165 | returnbound_methods |
205 | 166 |
|
| 167 | + |
| 168 | +classSimpleRouter(AbstractSimpleRouter): |
| 169 | + |
| 170 | +routes= [ |
| 171 | +# List route. |
| 172 | +Route( |
| 173 | +url=r'^{prefix}{trailing_slash}$', |
| 174 | +mapping={ |
| 175 | +'get':'list', |
| 176 | +'post':'create' |
| 177 | + }, |
| 178 | +name='{basename}-list', |
| 179 | +detail=False, |
| 180 | +initkwargs={'suffix':'List'} |
| 181 | + ), |
| 182 | +# Dynamically generated list routes. Generated using |
| 183 | +# @action(detail=False) decorator on methods of the viewset. |
| 184 | +DynamicRoute( |
| 185 | +url=r'^{prefix}/{url_path}{trailing_slash}$', |
| 186 | +name='{basename}-{url_name}', |
| 187 | +detail=False, |
| 188 | +initkwargs={} |
| 189 | + ), |
| 190 | +# Detail route. |
| 191 | +Route( |
| 192 | +url=r'^{prefix}/{lookup}{trailing_slash}$', |
| 193 | +mapping={ |
| 194 | +'get':'retrieve', |
| 195 | +'put':'update', |
| 196 | +'patch':'partial_update', |
| 197 | +'delete':'destroy' |
| 198 | + }, |
| 199 | +name='{basename}-detail', |
| 200 | +detail=True, |
| 201 | +initkwargs={'suffix':'Instance'} |
| 202 | + ), |
| 203 | +# Dynamically generated detail routes. Generated using |
| 204 | +# @action(detail=True) decorator on methods of the viewset. |
| 205 | +DynamicRoute( |
| 206 | +url=r'^{prefix}/{lookup}/{url_path}{trailing_slash}$', |
| 207 | +name='{basename}-{url_name}', |
| 208 | +detail=True, |
| 209 | +initkwargs={} |
| 210 | + ), |
| 211 | + ] |
| 212 | + |
206 | 213 | defget_lookup_regex(self,viewset,lookup_prefix=''): |
207 | 214 | """ |
208 | 215 | Given a viewset, return the portion of URL regex that is used |
@@ -270,6 +277,122 @@ def get_urls(self): |
270 | 277 | returnret |
271 | 278 |
|
272 | 279 |
|
| 280 | +classSimplePathRouter(AbstractSimpleRouter): |
| 281 | +""" |
| 282 | + Router which uses Django 2.x path to build urls |
| 283 | + """ |
| 284 | + |
| 285 | +routes= [ |
| 286 | +# List route. |
| 287 | +Route( |
| 288 | +url='{prefix}{trailing_slash}', |
| 289 | +mapping={ |
| 290 | +'get':'list', |
| 291 | +'post':'create' |
| 292 | + }, |
| 293 | +name='{basename}-list', |
| 294 | +detail=False, |
| 295 | +initkwargs={'suffix':'List'} |
| 296 | + ), |
| 297 | +# Dynamically generated list routes. Generated using |
| 298 | +# @action(detail=False) decorator on methods of the viewset. |
| 299 | +DynamicRoute( |
| 300 | +url='{prefix}/{url_path}{trailing_slash}', |
| 301 | +name='{basename}-{url_name}', |
| 302 | +detail=False, |
| 303 | +initkwargs={} |
| 304 | + ), |
| 305 | +# Detail route. |
| 306 | +Route( |
| 307 | +url='{prefix}/{lookup}{trailing_slash}', |
| 308 | +mapping={ |
| 309 | +'get':'retrieve', |
| 310 | +'put':'update', |
| 311 | +'patch':'partial_update', |
| 312 | +'delete':'destroy' |
| 313 | + }, |
| 314 | +name='{basename}-detail', |
| 315 | +detail=True, |
| 316 | +initkwargs={'suffix':'Instance'} |
| 317 | + ), |
| 318 | +# Dynamically generated detail routes. Generated using |
| 319 | +# @action(detail=True) decorator on methods of the viewset. |
| 320 | +DynamicRoute( |
| 321 | +url='{prefix}/{lookup}/{url_path}{trailing_slash}', |
| 322 | +name='{basename}-{url_name}', |
| 323 | +detail=True, |
| 324 | +initkwargs={} |
| 325 | + ), |
| 326 | + ] |
| 327 | + |
| 328 | +defget_lookup_path(self,viewset,lookup_prefix=''): |
| 329 | +""" |
| 330 | + Given a viewset, return the portion of URL path that is used |
| 331 | + to match against a single instance. |
| 332 | +
|
| 333 | + Note that lookup_prefix is not used directly inside REST rest_framework |
| 334 | + itself, but is required in order to nicely support nested router |
| 335 | + implementations, such as drf-nested-routers. |
| 336 | +
|
| 337 | + https://github.com/alanjds/drf-nested-routers |
| 338 | + """ |
| 339 | +base_converter='<{lookup_converter}:{lookup_prefix}{lookup_url_kwarg}>' |
| 340 | +# Use `pk` as default field, unset set. Default regex should not |
| 341 | +# consume `.json` style suffixes and should break at '/' boundaries. |
| 342 | +lookup_field=getattr(viewset,'lookup_field','pk') |
| 343 | +lookup_url_kwarg=getattr(viewset,'lookup_url_kwarg',None)orlookup_field |
| 344 | +lookup_converter=getattr(viewset,'lookup_converter','path') |
| 345 | +returnbase_converter.format( |
| 346 | +lookup_prefix=lookup_prefix, |
| 347 | +lookup_url_kwarg=lookup_url_kwarg, |
| 348 | +lookup_converter=lookup_converter |
| 349 | + ) |
| 350 | + |
| 351 | +defget_urls(self): |
| 352 | +""" |
| 353 | + Use the registered viewsets to generate a list of URL patterns. |
| 354 | + """ |
| 355 | +assertpathisnotNone,'SimplePathRouter requires Django 2.x path' |
| 356 | +ret= [] |
| 357 | + |
| 358 | +forprefix,viewset,basenameinself.registry: |
| 359 | +lookup=self.get_lookup_path(viewset) |
| 360 | +routes=self.get_routes(viewset) |
| 361 | + |
| 362 | +forrouteinroutes: |
| 363 | + |
| 364 | +# Only actions which actually exist on the viewset will be bound |
| 365 | +mapping=self.get_method_map(viewset,route.mapping) |
| 366 | +ifnotmapping: |
| 367 | +continue |
| 368 | + |
| 369 | +# Build the url pattern |
| 370 | +url_path=route.url.format( |
| 371 | +prefix=prefix, |
| 372 | +lookup=lookup, |
| 373 | +trailing_slash=self.trailing_slash |
| 374 | + ) |
| 375 | + |
| 376 | +# If there is no prefix, the first part of the url is probably |
| 377 | +# controlled by project's urls.py and the router is in an app, |
| 378 | +# so a slash in the beginning will (A) cause Django to give |
| 379 | +# warnings and (B) generate URLS that will require using '//'. |
| 380 | +ifnotprefixandurl_path[0]=='/': |
| 381 | +url_path=url_path[1:] |
| 382 | + |
| 383 | +initkwargs=route.initkwargs.copy() |
| 384 | +initkwargs.update({ |
| 385 | +'basename':basename, |
| 386 | +'detail':route.detail, |
| 387 | + }) |
| 388 | + |
| 389 | +view=viewset.as_view(mapping,**initkwargs) |
| 390 | +name=route.name.format(basename=basename) |
| 391 | +ret.append(path(url_path,view,name=name)) |
| 392 | + |
| 393 | +returnret |
| 394 | + |
| 395 | + |
273 | 396 | classAPIRootView(views.APIView): |
274 | 397 | """ |
275 | 398 | The default basic root view for DefaultRouter |
|