5
5
from django .conf import settings
6
6
from django .core .exceptions import MiddlewareNotUsed
7
7
8
+ from rest_framework .versioning import BaseVersioning
9
+
8
10
from pulpcore .metrics import init_otel_meter
9
11
from pulpcore .app .models import Domain
10
12
from pulpcore .app .util import (
@@ -168,3 +170,52 @@ def __call__(self, request):
168
170
x_task_diagnostics_var .reset (ctx_token )
169
171
else :
170
172
return self .get_response (request )
173
+
174
+
175
+ class NamespaceVersioning (BaseVersioning ):
176
+ """
177
+ To the client this is the same style as `URLPathVersioning`.
178
+ The difference is in the backend - this implementation uses
179
+ Django's URL namespaces to determine the version.
180
+
181
+ An example URL conf that is namespaced into two separate versions
182
+
183
+ # users/urls.py
184
+ urlpatterns = [
185
+ path('/users/', users_list, name='users-list'),
186
+ path('/users/<int:pk>/', users_detail, name='users-detail')
187
+ ]
188
+
189
+ # urls.py
190
+ urlpatterns = [
191
+ path('v1/', include('users.urls', namespace='v1')),
192
+ path('v2/', include('users.urls', namespace='v2'))
193
+ ]
194
+
195
+ GET /1.0/something/ HTTP/1.1
196
+ Host: example.com
197
+ Accept: application/json
198
+ """
199
+ invalid_version_message = 'Invalid version in URL path. Does not match any version namespace.'
200
+
201
+ def determine_version (self , request , * args , ** kwargs ):
202
+ resolver_match = getattr (request , 'resolver_match' , None )
203
+ if resolver_match is None or not resolver_match .namespace :
204
+ return self .default_version
205
+
206
+ # Allow for possibly nested namespaces.
207
+ possible_versions = resolver_match .namespace .split (':' )
208
+ for version in possible_versions :
209
+ if self .is_allowed_version (version ):
210
+ return version
211
+ raise exceptions .NotFound (self .invalid_version_message )
212
+
213
+ def reverse (self , viewname , args = None , kwargs = None , request = None , format = None , ** extra ):
214
+ if request .version is not None :
215
+ viewname = self .get_versioned_viewname (viewname , request )
216
+ return super ().reverse (
217
+ viewname , args , kwargs , request , format , ** extra
218
+ )
219
+
220
+ def get_versioned_viewname (self , viewname , request ):
221
+ return request .version + ':' + viewname
0 commit comments