Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
D
django-rest-framework
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
django-rest-framework
Commits
7fa3a214
Commit
7fa3a214
authored
Jan 23, 2012
by
Ben Timby
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactored get_name()/get_description()
parent
2d873911
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
120 additions
and
157 deletions
+120
-157
djangorestframework/renderers.py
+26
-21
djangorestframework/templates/renderer.html
+3
-8
djangorestframework/tests/description.py
+27
-27
djangorestframework/utils/breadcrumbs.py
+1
-3
djangorestframework/utils/description.py
+0
-88
djangorestframework/views.py
+63
-10
No files found.
djangorestframework/renderers.py
View file @
7fa3a214
...
...
@@ -12,10 +12,9 @@ from django.template import RequestContext, loader
from
django.utils
import
simplejson
as
json
from
djangorestframework.compat
import
apply_markdown
,
yaml
from
djangorestframework.compat
import
yaml
from
djangorestframework.utils
import
dict2xml
,
url_resolves
from
djangorestframework.utils.breadcrumbs
import
get_breadcrumbs
from
djangorestframework.utils.description
import
get_name
,
get_description
from
djangorestframework.utils.mediatypes
import
get_media_type_params
,
add_media_type_param
,
media_type_matches
from
djangorestframework
import
VERSION
...
...
@@ -226,6 +225,7 @@ class DocumentingTemplateRenderer(BaseRenderer):
return
content
def
_get_form_instance
(
self
,
view
,
method
):
"""
Get a form, possibly bound to either the input or output data.
...
...
@@ -261,6 +261,7 @@ class DocumentingTemplateRenderer(BaseRenderer):
return
form_instance
def
_get_generic_content_form
(
self
,
view
):
"""
Returns a form that allows for arbitrary content types to be tunneled via standard HTML forms
...
...
@@ -296,6 +297,20 @@ class DocumentingTemplateRenderer(BaseRenderer):
# Okey doke, let's do it
return
GenericContentForm
(
view
)
def
get_name
(
self
):
try
:
return
self
.
view
.
get_name
()
except
AttributeError
:
return
self
.
view
.
__doc__
def
get_description
(
self
,
html
=
None
):
if
html
is
None
:
html
=
bool
(
'html'
in
self
.
format
)
try
:
return
self
.
view
.
get_description
(
html
)
except
AttributeError
:
return
self
.
view
.
__doc__
def
render
(
self
,
obj
=
None
,
media_type
=
None
):
"""
Renders *obj* using the :attr:`template` set on the class.
...
...
@@ -316,15 +331,8 @@ class DocumentingTemplateRenderer(BaseRenderer):
login_url
=
None
logout_url
=
None
name
=
get_name
(
self
.
view
)
description
=
get_description
(
self
.
view
)
markeddown
=
None
if
apply_markdown
:
try
:
markeddown
=
apply_markdown
(
description
)
except
AttributeError
:
markeddown
=
None
name
=
self
.
get_name
()
description
=
self
.
get_description
()
breadcrumb_list
=
get_breadcrumbs
(
self
.
view
.
request
.
path
)
...
...
@@ -332,12 +340,11 @@ class DocumentingTemplateRenderer(BaseRenderer):
context
=
RequestContext
(
self
.
view
.
request
,
{
'content'
:
content
,
'view'
:
self
.
view
,
'request'
:
self
.
view
.
request
,
# TODO: remove
'request'
:
self
.
view
.
request
,
# TODO: remove
'response'
:
self
.
view
.
response
,
'description'
:
description
,
'name'
:
name
,
'version'
:
VERSION
,
'markeddown'
:
markeddown
,
'breadcrumblist'
:
breadcrumb_list
,
'available_formats'
:
self
.
view
.
_rendered_formats
,
'put_form'
:
put_form_instance
,
...
...
@@ -395,14 +402,12 @@ class DocumentingPlainTextRenderer(DocumentingTemplateRenderer):
template
=
'renderer.txt'
DEFAULT_RENDERERS
=
(
JSONRenderer
,
JSONPRenderer
,
DocumentingHTMLRenderer
,
DocumentingXHTMLRenderer
,
DocumentingPlainTextRenderer
,
XMLRenderer
)
DEFAULT_RENDERERS
=
(
JSONRenderer
,
JSONPRenderer
,
DocumentingHTMLRenderer
,
DocumentingXHTMLRenderer
,
DocumentingPlainTextRenderer
,
XMLRenderer
)
if
YAMLRenderer
:
DEFAULT_RENDERERS
+=
(
YAMLRenderer
,)
djangorestframework/templates/renderer.html
View file @
7fa3a214
...
...
@@ -11,13 +11,8 @@
/* Custom styles */
.version
{
font-size
:
8px
;}
</style>
{% if ADMIN_MEDIA_PREFIX %}
<link
rel=
"stylesheet"
type=
"text/css"
href=
'{{ADMIN_MEDIA_PREFIX}}css/base.css'
/>
<link
rel=
"stylesheet"
type=
"text/css"
href=
'{{ADMIN_MEDIA_PREFIX}}css/forms.css'
/>
{% else %}
<link
rel=
"stylesheet"
type=
"text/css"
href=
'{{STATIC_URL}}admin/css/base.css'
/>
<link
rel=
"stylesheet"
type=
"text/css"
href=
'{{STATIC_URL}}admin/css/forms.css'
/>
{% endif %}
<link
rel=
"stylesheet"
type=
"text/css"
href=
'{{ADMIN_MEDIA_PREFIX}}css/base.css'
/>
<link
rel=
"stylesheet"
type=
"text/css"
href=
'{{ADMIN_MEDIA_PREFIX}}css/forms.css'
/>
<title>
Django REST framework - {{ name }}
</title>
</head>
<body>
...
...
@@ -50,7 +45,7 @@
<div
class=
'content-main'
>
<h1>
{{ name }}
</h1>
<p>
{%
if markeddown %}{% autoescape off %}{{ markeddown }}{% endautoescape %}{% else %}{{ description|linebreaksbr }}{% endif
%}
</p>
<p>
{%
autoescape off %}{{ description }}{% endautoescape
%}
</p>
<div
class=
'module'
>
<pre><b>
{{ response.status }} {{ response.status_text }}
</b>
{% autoescape off %}
{% for key, val in response.headers.items %}
<b>
{{ key }}:
</b>
{{ val|urlize_quoted_links }}
...
...
djangorestframework/tests/description.py
View file @
7fa3a214
from
django.test
import
TestCase
from
djangorestframework.views
import
View
from
djangorestframework.compat
import
apply_markdown
from
djangorestframework.utils.description
import
get_name
,
get_description
# We check that docstrings get nicely un-indented.
DESCRIPTION
=
"""an example docstring
...
...
@@ -51,15 +50,15 @@ class TestViewNamesAndDescriptions(TestCase):
"""Ensure Resource names are based on the classname by default."""
class
MockView
(
View
):
pass
self
.
assertEquals
(
get_name
(
MockView
()
),
'Mock'
)
self
.
assertEquals
(
MockView
()
.
get_name
(
),
'Mock'
)
# This has been turned off now.
#def test_resource_name_can_be_set_explicitly(self):
# """Ensure Resource names can be set using the 'name' class attribute."""
# example = 'Some Other Name'
# class MockView(View
):
# name =
example
# self.assertEquals(get_name(MockView()
), example)
def
test_resource_name_can_be_set_explicitly
(
self
):
"""Ensure Resource names can be set using the 'get_name' method."""
example
=
'Some Other Name'
class
MockView
(
View
):
def
get_name
(
self
):
return
example
self
.
assertEquals
(
MockView
()
.
get_name
(
),
example
)
def
test_resource_description_uses_docstring_by_default
(
self
):
"""Ensure Resource names are based on the docstring by default."""
...
...
@@ -79,29 +78,30 @@ class TestViewNamesAndDescriptions(TestCase):
# hash style header #"""
self
.
assertEquals
(
get_description
(
MockView
()),
DESCRIPTION
)
# This has been turned off now
#def test_resource_description_can_be_set_explicitly(self):
# """Ensure Resource descriptions can be set using the 'description' class attribute."""
# example = 'Some other description'
# class MockView(View):
# """docstring"""
# description = example
# self.assertEquals(get_description(MockView()), example)
self
.
assertEquals
(
MockView
()
.
get_description
(),
DESCRIPTION
)
#def test_resource_description_does_not_require_docstring(self):
# """Ensure that empty docstrings do not affect the Resource's description if it has been set using the 'description' class attribute."""
# example = 'Some other description'
# class MockView(View):
# description = example
# self.assertEquals(get_description(MockView()), example)
def
test_resource_description_can_be_set_explicitly
(
self
):
"""Ensure Resource descriptions can be set using the 'get_description' method."""
example
=
'Some other description'
class
MockView
(
View
):
"""docstring"""
def
get_description
(
self
):
return
example
self
.
assertEquals
(
MockView
()
.
get_description
(),
example
)
def
test_resource_description_does_not_require_docstring
(
self
):
"""Ensure that empty docstrings do not affect the Resource's description if it has been set using the 'get_description' method."""
example
=
'Some other description'
class
MockView
(
View
):
def
get_description
(
self
):
return
example
self
.
assertEquals
(
MockView
()
.
get_description
(),
example
)
def
test_resource_description_can_be_empty
(
self
):
"""Ensure that if a resource has no doctring or 'description' class attribute, then it's description is the empty string"""
"""Ensure that if a resource has no doctring or 'description' class attribute, then it's description is the empty string
.
"""
class
MockView
(
View
):
pass
self
.
assertEquals
(
get_description
(
MockView
()
),
''
)
self
.
assertEquals
(
MockView
()
.
get_description
(
),
''
)
def
test_markdown
(
self
):
"""Ensure markdown to HTML works as expected"""
...
...
djangorestframework/utils/breadcrumbs.py
View file @
7fa3a214
from
django.core.urlresolvers
import
resolve
from
djangorestframework.utils.description
import
get_name
def
get_breadcrumbs
(
url
):
"""Given a url returns a list of breadcrumbs, which are each a tuple of (name, url)."""
...
...
@@ -17,7 +15,7 @@ def get_breadcrumbs(url):
else
:
# Check if this is a REST framework view, and if so add it to the breadcrumbs
if
isinstance
(
getattr
(
view
,
'cls_instance'
,
None
),
View
):
breadcrumbs_list
.
insert
(
0
,
(
get_name
(
view
),
url
))
breadcrumbs_list
.
insert
(
0
,
(
view
.
cls_instance
.
get_name
(
),
url
))
if
url
==
''
:
# All done
...
...
djangorestframework/utils/description.py
deleted
100644 → 0
View file @
2d873911
"""
Get a descriptive name and description for a view.
"""
import
re
from
djangorestframework.resources
import
Resource
,
FormResource
,
ModelResource
# These a a bit Grungy, but they do the job.
def
get_name
(
view
):
"""
Return a name for the view.
If view has a name attribute, use that, otherwise use the view's class name, with 'CamelCaseNames' converted to 'Camel Case Names'.
"""
# If we're looking up the name of a view callable, as found by reverse,
# grok the class instance that we stored when as_view was called.
if
getattr
(
view
,
'cls_instance'
,
None
):
view
=
view
.
cls_instance
# If this view has a resource that's been overridden, then use that resource for the name
if
getattr
(
view
,
'resource'
,
None
)
not
in
(
None
,
Resource
,
FormResource
,
ModelResource
):
name
=
view
.
resource
.
__name__
# Chomp of any non-descriptive trailing part of the resource class name
if
name
.
endswith
(
'Resource'
)
and
name
!=
'Resource'
:
name
=
name
[:
-
len
(
'Resource'
)]
# If the view has a descriptive suffix, eg '*** List', '*** Instance'
if
getattr
(
view
,
'_suffix'
,
None
):
name
+=
view
.
_suffix
# Otherwise if it's a function view use the function's name
elif
getattr
(
view
,
'__name__'
,
None
)
is
not
None
:
name
=
view
.
__name__
# If it's a view class with no resource then grok the name from the class name
elif
getattr
(
view
,
'__class__'
,
None
)
is
not
None
:
name
=
view
.
__class__
.
__name__
# Chomp of any non-descriptive trailing part of the view class name
if
name
.
endswith
(
'View'
)
and
name
!=
'View'
:
name
=
name
[:
-
len
(
'View'
)]
# I ain't got nuthin fo' ya
else
:
return
''
return
re
.
sub
(
'(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))'
,
'
\\
1'
,
name
)
.
strip
()
def
get_description
(
view
):
"""
Provide a description for the view.
By default this is the view's docstring with nice unindention applied.
"""
# If we're looking up the name of a view callable, as found by reverse,
# grok the class instance that we stored when as_view was called.
if
getattr
(
view
,
'cls_instance'
,
None
):
view
=
view
.
cls_instance
# If this view has a resource that's been overridden, then use the resource's doctring
if
getattr
(
view
,
'resource'
,
None
)
not
in
(
None
,
Resource
,
FormResource
,
ModelResource
):
doc
=
view
.
resource
.
__doc__
# Otherwise use the view doctring
elif
getattr
(
view
,
'__doc__'
,
None
):
doc
=
view
.
__doc__
# I ain't got nuthin fo' ya
else
:
return
''
if
not
doc
:
return
''
whitespace_counts
=
[
len
(
line
)
-
len
(
line
.
lstrip
(
' '
))
for
line
in
doc
.
splitlines
()[
1
:]
if
line
.
lstrip
()]
# unindent the docstring if needed
if
whitespace_counts
:
whitespace_pattern
=
'^'
+
(
' '
*
min
(
whitespace_counts
))
return
re
.
sub
(
re
.
compile
(
whitespace_pattern
,
re
.
MULTILINE
),
''
,
doc
)
# otherwise return it as-is
return
doc
djangorestframework/views.py
View file @
7fa3a214
...
...
@@ -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,7 @@ __all__ = (
)
class
View
(
ResourceMixin
,
RequestMixin
,
ResponseMixin
,
AuthMixin
,
DjangoView
):
"""
Handles incoming requests and maps them to REST operations.
...
...
@@ -47,13 +50,13 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
List of parsers the resource can parse the request with.
"""
authentication
=
(
authentication
.
UserLoggedInAuthentication
,
authentication
.
BasicAuthentication
)
authentication
=
(
authentication
.
UserLoggedInAuthentication
,
authentication
.
BasicAuthentication
)
"""
List of all authenticating methods to attempt.
"""
permissions
=
(
permissions
.
FullAnonAccess
,
)
permissions
=
(
permissions
.
FullAnonAccess
,
)
"""
List of all permissions that must be checked.
"""
...
...
@@ -76,6 +79,59 @@ 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
(
None
,
resources
.
Resource
,
resources
.
FormResource
,
resources
.
ModelResource
):
name
=
self
.
resource
.
__name__
# Chomp of any non-descriptive trailing part of the resource class name
if
name
.
endswith
(
'Resource'
)
and
name
!=
'Resource'
:
name
=
name
[:
-
len
(
'Resource'
)]
# If the view has a descriptive suffix, eg '*** List', '*** Instance'
if
getattr
(
self
,
'_suffix'
,
None
):
name
+=
self
.
_suffix
# If it's a view class with no resource then grok the name from the class name
elif
getattr
(
self
,
'__class__'
,
None
)
is
not
None
:
name
=
self
.
__class__
.
__name__
# Chomp of any non-descriptive trailing part of the view class name
if
name
.
endswith
(
'View'
)
and
name
!=
'View'
:
name
=
name
[:
-
len
(
'View'
)]
else
:
name
=
''
return
re
.
sub
(
'(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))'
,
'
\\
1'
,
name
)
.
strip
()
def
get_description
(
self
,
html
=
False
):
"""
Return the resource or view docstring for use as this view's description.
Override to customize.
"""
# If this view has a resource that's been overridden, then use the resource's doctring
if
getattr
(
self
,
'resource'
,
None
)
not
in
(
None
,
resources
.
Resource
,
resources
.
FormResource
,
resources
.
ModelResource
):
doc
=
self
.
resource
.
__doc__
# Otherwise use the view doctring
elif
getattr
(
self
,
'__doc__'
,
None
):
doc
=
self
.
__doc__
else
:
doc
=
''
whitespace_counts
=
[
len
(
line
)
-
len
(
line
.
lstrip
(
' '
))
for
line
in
doc
.
splitlines
()[
1
:]
if
line
.
lstrip
()]
# unindent the docstring if needed
if
whitespace_counts
:
whitespace_pattern
=
'^'
+
(
' '
*
min
(
whitespace_counts
))
doc
=
re
.
sub
(
re
.
compile
(
whitespace_pattern
,
re
.
MULTILINE
),
''
,
doc
)
if
doc
and
html
:
if
apply_markdown
:
doc
=
apply_markdown
(
doc
)
else
:
doc
=
escape
(
doc
)
doc
=
mark_safe
(
doc
.
replace
(
'
\n
'
,
'<br />'
))
return
doc
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.
...
...
@@ -161,8 +217,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'
:
self
.
_parsed_media_types
,
}
...
...
@@ -184,21 +240,18 @@ class ModelView(View):
"""
resource
=
resources
.
ModelResource
class
InstanceModelView
(
InstanceMixin
,
ReadModelMixin
,
UpdateModelMixin
,
DeleteModelMixin
,
ModelView
):
"""
A view which provides default operations for read/update/delete against a model instance.
"""
_suffix
=
'Instance'
class
ListModelView
(
ListModelMixin
,
ModelView
):
"""
A view which provides default operations for list, against a model in the database.
"""
_suffix
=
'List'
class
ListOrCreateModelView
(
ListModelMixin
,
CreateModelMixin
,
ModelView
):
"""
A view which provides default operations for list and create, against a model in the database.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment