22
33from django .conf .urls import include , url
44
5- from rest_framework .compat import URLResolver , get_regex_pattern
5+ from rest_framework .compat import (
6+ URLResolver , get_regex_pattern , is_route_pattern , path , register_converter
7+ )
68from rest_framework .settings import api_settings
79
810
9- def apply_suffix_patterns (urlpatterns , suffix_pattern , suffix_required ):
11+ def _get_format_path_converter (suffix_kwarg , allowed ):
12+ if allowed :
13+ if len (allowed ) == 1 :
14+ allowed_pattern = allowed [0 ]
15+ else :
16+ allowed_pattern = '(?:%s)' % '|' .join (allowed )
17+ suffix_pattern = r"\.%s/?" % allowed_pattern
18+ else :
19+ suffix_pattern = r"\.[a-z0-9]+/?"
20+
21+ class FormatSuffixConverter :
22+ regex = suffix_pattern
23+
24+ def to_python (self , value ):
25+ return value .strip ('./' )
26+
27+ def to_url (self , value ):
28+ return '.' + value + '/'
29+
30+ converter_name = 'drf_format_suffix'
31+ if allowed :
32+ converter_name += '_' + '_' .join (allowed )
33+
34+ return converter_name , FormatSuffixConverter
35+
36+
37+ def apply_suffix_patterns (urlpatterns , suffix_pattern , suffix_required , suffix_route = None ):
1038 ret = []
1139 for urlpattern in urlpatterns :
1240 if isinstance (urlpattern , URLResolver ):
@@ -18,8 +46,18 @@ def apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required):
1846 # Add in the included patterns, after applying the suffixes
1947 patterns = apply_suffix_patterns (urlpattern .url_patterns ,
2048 suffix_pattern ,
21- suffix_required )
22- ret .append (url (regex , include ((patterns , app_name ), namespace ), kwargs ))
49+ suffix_required ,
50+ suffix_route )
51+
52+ # if the original pattern was a RoutePattern we need to preserve it
53+ if is_route_pattern (urlpattern ):
54+ assert path is not None
55+ route = str (urlpattern .pattern )
56+ new_pattern = path (route , include ((patterns , app_name ), namespace ), kwargs )
57+ else :
58+ new_pattern = url (regex , include ((patterns , app_name ), namespace ), kwargs )
59+
60+ ret .append (new_pattern )
2361 else :
2462 # Regular URL pattern
2563 regex = get_regex_pattern (urlpattern ).rstrip ('$' ).rstrip ('/' ) + suffix_pattern
@@ -29,7 +67,17 @@ def apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required):
2967 # Add in both the existing and the new urlpattern
3068 if not suffix_required :
3169 ret .append (urlpattern )
32- ret .append (url (regex , view , kwargs , name ))
70+
71+ # if the original pattern was a RoutePattern we need to preserve it
72+ if is_route_pattern (urlpattern ):
73+ assert path is not None
74+ assert suffix_route is not None
75+ route = str (urlpattern .pattern ).rstrip ('$' ).rstrip ('/' ) + suffix_route
76+ new_pattern = path (route , view , kwargs , name )
77+ else :
78+ new_pattern = url (regex , view , kwargs , name )
79+
80+ ret .append (new_pattern )
3381
3482 return ret
3583
@@ -60,4 +108,12 @@ def format_suffix_patterns(urlpatterns, suffix_required=False, allowed=None):
60108 else :
61109 suffix_pattern = r'\.(?P<%s>[a-z0-9]+)/?$' % suffix_kwarg
62110
63- return apply_suffix_patterns (urlpatterns , suffix_pattern , suffix_required )
111+ if path and register_converter :
112+ converter_name , suffix_converter = _get_format_path_converter (suffix_kwarg , allowed )
113+ register_converter (suffix_converter , converter_name )
114+
115+ suffix_route = '<%s:%s>' % (converter_name , suffix_kwarg )
116+ else :
117+ suffix_route = None
118+
119+ return apply_suffix_patterns (urlpatterns , suffix_pattern , suffix_required , suffix_route )
0 commit comments