aboutsummaryrefslogtreecommitdiffstats
path: root/djangorestframework/views.py
diff options
context:
space:
mode:
authorSébastien Piquemal2012-02-02 08:39:15 +0200
committerSébastien Piquemal2012-02-02 08:39:15 +0200
commit5f59d90645dfddc293bbbbc4ca9b4c3f3125b590 (patch)
treeaa3d091a1f61f5717f7f1a9e96334308bb13c7d9 /djangorestframework/views.py
parent152c385f4de37558fe4e522abad5b97f0cf7ddce (diff)
parent894f63259880252ed5317ce485eb13c4429b65c1 (diff)
downloaddjango-rest-framework-5f59d90645dfddc293bbbbc4ca9b4c3f3125b590.tar.bz2
merged with trunk's master
Diffstat (limited to 'djangorestframework/views.py')
-rw-r--r--djangorestframework/views.py102
1 files changed, 97 insertions, 5 deletions
diff --git a/djangorestframework/views.py b/djangorestframework/views.py
index 37eec89f..86be4fba 100644
--- a/djangorestframework/views.py
+++ b/djangorestframework/views.py
@@ -5,15 +5,17 @@ be subclassing in your implementation.
By setting or modifying class attributes on your view, you change it's predefined behaviour.
"""
+import re
from django.core.urlresolvers import set_script_prefix, get_script_prefix
from django.http import HttpResponse
+from django.utils.html import escape
+from django.utils.safestring import mark_safe
from django.views.decorators.csrf import csrf_exempt
-from djangorestframework.compat import View as DjangoView
+from djangorestframework.compat import View as DjangoView, apply_markdown
from djangorestframework.response import Response, ErrorResponse
from djangorestframework.mixins import *
from djangorestframework import resources, renderers, parsers, authentication, permissions, status
-from djangorestframework.utils.description import get_name, get_description
__all__ = (
@@ -25,6 +27,48 @@ __all__ = (
)
+def _remove_trailing_string(content, trailing):
+ """
+ Strip trailing component `trailing` from `content` if it exists.
+ Used when generating names from view/resource classes.
+ """
+ if content.endswith(trailing) and content != trailing:
+ return content[:-len(trailing)]
+ return content
+
+
+def _remove_leading_indent(content):
+ """
+ Remove leading indent from a block of text.
+ Used when generating descriptions from docstrings.
+ """
+ whitespace_counts = [len(line) - len(line.lstrip(' '))
+ for line in content.splitlines()[1:] if line.lstrip()]
+
+ # unindent the content if needed
+ if whitespace_counts:
+ whitespace_pattern = '^' + (' ' * min(whitespace_counts))
+ return re.sub(re.compile(whitespace_pattern, re.MULTILINE), '', content)
+ return content
+
+
+def _camelcase_to_spaces(content):
+ """
+ Translate 'CamelCaseNames' to 'Camel Case Names'.
+ Used when generating names from view/resource classes.
+ """
+ camelcase_boundry = '(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))'
+ return re.sub(camelcase_boundry, ' \\1', content).strip()
+
+
+_resource_classes = (
+ None,
+ resources.Resource,
+ resources.FormResource,
+ resources.ModelResource
+)
+
+
class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
"""
Handles incoming requests and maps them to REST operations.
@@ -48,7 +92,7 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
"""
authentication = (authentication.UserLoggedInAuthentication,
- authentication.BasicAuthentication)
+ authentication.BasicAuthentication)
"""
List of all authenticating methods to attempt.
"""
@@ -76,6 +120,54 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
"""
return [method.upper() for method in self.http_method_names if hasattr(self, method)]
+ def get_name(self):
+ """
+ Return the resource or view class name for use as this view's name.
+ Override to customize.
+ """
+ # If this view has a resource that's been overridden, then use that resource for the name
+ if getattr(self, 'resource', None) not in _resource_classes:
+ name = self.resource.__name__
+ name = _remove_trailing_string(name, 'Resource')
+ name += getattr(self, '_suffix', '')
+
+ # If it's a view class with no resource then grok the name from the class name
+ else:
+ name = self.__class__.__name__
+ name = _remove_trailing_string(name, 'View')
+
+ return _camelcase_to_spaces(name)
+
+ def get_description(self, html=False):
+ """
+ Return the resource or view docstring for use as this view's description.
+ Override to customize.
+ """
+
+ description = None
+
+ # If this view has a resource that's been overridden,
+ # then try to use the resource's docstring
+ if getattr(self, 'resource', None) not in _resource_classes:
+ description = self.resource.__doc__
+
+ # Otherwise use the view docstring
+ if not description:
+ description = self.__doc__ or ''
+
+ description = _remove_leading_indent(description)
+
+ if html:
+ return self.markup_description(description)
+ return description
+
+ def markup_description(self, description):
+ if apply_markdown:
+ description = apply_markdown(description)
+ else:
+ description = escape(description).replace('\n', '<br />')
+ return mark_safe(description)
+
def http_method_not_allowed(self, request, *args, **kwargs):
"""
Return an HTTP 405 error if an operation is called which does not have a handler method.
@@ -164,8 +256,8 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
def options(self, request, *args, **kwargs):
response_obj = {
- 'name': get_name(self),
- 'description': get_description(self),
+ 'name': self.get_name(),
+ 'description': self.get_description(),
'renders': self._rendered_media_types,
'parses': request._parsed_media_types,
}