2
2
3
3
from django .conf .urls import include , url
4
4
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
+ )
6
8
from rest_framework .settings import api_settings
7
9
8
10
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 ):
10
38
ret = []
11
39
for urlpattern in urlpatterns :
12
40
if isinstance (urlpattern , URLResolver ):
@@ -18,8 +46,18 @@ def apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required):
18
46
# Add in the included patterns, after applying the suffixes
19
47
patterns = apply_suffix_patterns (urlpattern .url_patterns ,
20
48
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 )
23
61
else :
24
62
# Regular URL pattern
25
63
regex = get_regex_pattern (urlpattern ).rstrip ('$' ).rstrip ('/' ) + suffix_pattern
@@ -29,7 +67,17 @@ def apply_suffix_patterns(urlpatterns, suffix_pattern, suffix_required):
29
67
# Add in both the existing and the new urlpattern
30
68
if not suffix_required :
31
69
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 )
33
81
34
82
return ret
35
83
@@ -60,4 +108,12 @@ def format_suffix_patterns(urlpatterns, suffix_required=False, allowed=None):
60
108
else :
61
109
suffix_pattern = r'\.(?P<%s>[a-z0-9]+)/?$' % suffix_kwarg
62
110
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