From 1956948c15844a0043d900f37b1cda37aabffd57 Mon Sep 17 00:00:00 2001 From: Thomas Gak Deluen Date: Wed, 13 May 2015 12:38:36 +0100 Subject: [PATCH 1/6] Added JinjaTemplateRenderer --- rest_framework/renderers.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 6c7cdf537..c2e761f09 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -200,6 +200,42 @@ class TemplateHTMLRenderer(BaseRenderer): response.status_text.title())) +class JinjaTemplateRenderer(TemplateHTMLRenderer): + """ + Renders data to HTML for use with the Jinja2 template engine. + + The template name is determined by (in order of preference): + + 1. An explicit .template_name set on the response. + 2. An explicit .template_name set on this class. + 3. The return result of calling view.get_template_names(). + """ + + def render(self, data, accepted_media_type=None, renderer_context=None): + + renderer_context = renderer_context or {} + view = renderer_context['view'] + request = renderer_context['request'] + response = renderer_context['response'] + + # add the current user to the context + # otherwise it won't be available in templates + renderer_context['user'] = request.user + + # get template (jinja2) + if response.exception: + template = self.get_exception_template(response) + else: + template_names = self.get_template_names(response, view) + template = self.resolve_template(template_names) + + # return the dict containing the context + # for jinja2 to process. + # Would throw a value error if a + # RequestContext was returned + return template.render(renderer_context) + + # Note, subclass TemplateHTMLRenderer simply for the exception behavior class StaticHTMLRenderer(TemplateHTMLRenderer): """ From b32238bae87a3f043081e396aaa21709f856adb1 Mon Sep 17 00:00:00 2001 From: Thomas Gak Deluen Date: Wed, 13 May 2015 12:56:00 +0100 Subject: [PATCH 2/6] Added MultipleNamespaceVersioning --- rest_framework/versioning.py | 77 ++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/rest_framework/versioning.py b/rest_framework/versioning.py index 51b886f38..3e25af1a3 100644 --- a/rest_framework/versioning.py +++ b/rest_framework/versioning.py @@ -131,6 +131,83 @@ class NamespaceVersioning(BaseVersioning): return request.version + ':' + viewname +class MultipleNamespaceVersioning(versioning.NamespaceVersioning): + + """ + This is the same as NamespaceVersioning, the difference is that + multiple namespaces can be used for bigger projects. + + In settings.py, REST_FRAMEWORK should include + ALLOWED_VERSIONS: a list of all available versions + DEFAULT_VERSION: a string containing the default version to use + + An example URL conf that is namespaced using different namespaces + + # item/urls.py + urlpatterns = [ + url(r'^/(?P[\d]+)/$', item_detail, name='detail'), + ] + + # urls.py + api_patterns = [ + url(r'^items', include('mysite.item.urls', namespace='items')), + ] + + urlpatterns = [ + url(r'^', include(api_patterns)), + url(r'^json/', include(api_patterns, namespace='json')), + ] + + They can then be accessed in templates such as + + - to get the default version + {% url 'items:detail' pk=2 %} + --> /items/2/ + + - to get the json version or any other version + {% url 'json:items:detail' pk=2 } + --> /json/items/2/ + + + allowed versions must be set as it will be used to compare its + contents with the given namespaces of the url + """ + + def determine_version(self, request, *args, **kwargs): + + resolver_match = getattr(request, 'resolver_match', None) + version = None + + if (resolver_match is None or not resolver_match.namespaces): + if (not resolver_match.namespace): + version = self.default_version + else: + version = resolver_match.namespace + + for namespace in resolver_match.namespaces: + if namespace in self.allowed_versions: + version = namespace + + if version is None: + version = self.default_version + + return version + + def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra): + if request.version is not None: + viewname = self.get_versioned_viewname(viewname, request) + return super(NamespaceVersioning, self).reverse( + viewname, args, kwargs, request, format, **extra + ) + + def get_versioned_viewname(self, viewname, request): + if request.resolver_match is not None and request.resolver_match.namespaces: + return ':'.join(request.resolver_match.namespaces) + + return request.version + ':' + viewname + + + class HostNameVersioning(BaseVersioning): """ GET /something/ HTTP/1.1 From ff28ac995e3adb9bbb94b855d3a017b805606ccc Mon Sep 17 00:00:00 2001 From: Thomas Gak Deluen Date: Wed, 13 May 2015 13:02:32 +0100 Subject: [PATCH 3/6] fixed versioning --- rest_framework/versioning.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest_framework/versioning.py b/rest_framework/versioning.py index 3e25af1a3..3e3024866 100644 --- a/rest_framework/versioning.py +++ b/rest_framework/versioning.py @@ -131,7 +131,7 @@ class NamespaceVersioning(BaseVersioning): return request.version + ':' + viewname -class MultipleNamespaceVersioning(versioning.NamespaceVersioning): +class MultipleNamespaceVersioning(NamespaceVersioning): """ This is the same as NamespaceVersioning, the difference is that From ea44238b71166facc31e98fa02feebf45ffba14e Mon Sep 17 00:00:00 2001 From: Thomas Gak Deluen Date: Wed, 13 May 2015 13:03:47 +0100 Subject: [PATCH 4/6] fixed blank lines --- rest_framework/versioning.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/rest_framework/versioning.py b/rest_framework/versioning.py index 3e3024866..b9556baa0 100644 --- a/rest_framework/versioning.py +++ b/rest_framework/versioning.py @@ -132,7 +132,6 @@ class NamespaceVersioning(BaseVersioning): class MultipleNamespaceVersioning(NamespaceVersioning): - """ This is the same as NamespaceVersioning, the difference is that multiple namespaces can be used for bigger projects. @@ -168,13 +167,11 @@ class MultipleNamespaceVersioning(NamespaceVersioning): {% url 'json:items:detail' pk=2 } --> /json/items/2/ - allowed versions must be set as it will be used to compare its contents with the given namespaces of the url """ def determine_version(self, request, *args, **kwargs): - resolver_match = getattr(request, 'resolver_match', None) version = None @@ -187,10 +184,8 @@ class MultipleNamespaceVersioning(NamespaceVersioning): for namespace in resolver_match.namespaces: if namespace in self.allowed_versions: version = namespace - if version is None: version = self.default_version - return version def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra): From 5ba3de2237d5017045f20839ceb7f1d38b648f0f Mon Sep 17 00:00:00 2001 From: Thomas Gak Deluen Date: Wed, 13 May 2015 13:04:49 +0100 Subject: [PATCH 5/6] fixed blank lines --- rest_framework/versioning.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rest_framework/versioning.py b/rest_framework/versioning.py index b9556baa0..6a4756f8c 100644 --- a/rest_framework/versioning.py +++ b/rest_framework/versioning.py @@ -184,8 +184,10 @@ class MultipleNamespaceVersioning(NamespaceVersioning): for namespace in resolver_match.namespaces: if namespace in self.allowed_versions: version = namespace + if version is None: version = self.default_version + return version def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra): @@ -202,7 +204,6 @@ class MultipleNamespaceVersioning(NamespaceVersioning): return request.version + ':' + viewname - class HostNameVersioning(BaseVersioning): """ GET /something/ HTTP/1.1 From a21ee8ea458a252c9135bba8ce716f7bfde98037 Mon Sep 17 00:00:00 2001 From: Thomas Gak Deluen Date: Wed, 13 May 2015 13:05:22 +0100 Subject: [PATCH 6/6] fixed white space --- rest_framework/versioning.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest_framework/versioning.py b/rest_framework/versioning.py index 6a4756f8c..cdd350726 100644 --- a/rest_framework/versioning.py +++ b/rest_framework/versioning.py @@ -187,7 +187,7 @@ class MultipleNamespaceVersioning(NamespaceVersioning): if version is None: version = self.default_version - + return version def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):