mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-22 09:36:49 +03:00
Minor bit of tidy up (all the stuff I noticed when demoing to francis)
This commit is contained in:
parent
2e9fd9c6b9
commit
40f47a9fb3
|
@ -1,8 +1,6 @@
|
||||||
:mod:`emitters`
|
:mod:`emitters`
|
||||||
===============
|
===============
|
||||||
|
|
||||||
.. module:: emitters
|
|
||||||
|
|
||||||
The emitters module provides a set of emitters that can be plugged in to a :class:`.Resource`. An emitter is responsible for taking the output of a and serializing it to a given media type. A :class:`.Resource` can have a number of emitters, allow the same content to be serialized in a number of different formats depending on the requesting client's preferences, as specified in the HTTP Request's Accept header.
|
The emitters module provides a set of emitters that can be plugged in to a :class:`.Resource`. An emitter is responsible for taking the output of a and serializing it to a given media type. A :class:`.Resource` can have a number of emitters, allow the same content to be serialized in a number of different formats depending on the requesting client's preferences, as specified in the HTTP Request's Accept header.
|
||||||
|
|
||||||
.. automodule:: emitters
|
.. automodule:: emitters
|
||||||
|
|
|
@ -13,8 +13,30 @@ Some of FlyWheel's features:
|
||||||
* Optional support for forms as input validation.
|
* Optional support for forms as input validation.
|
||||||
* Modular architecture - Easy to extend and modify.
|
* Modular architecture - Easy to extend and modify.
|
||||||
|
|
||||||
|
Installation & Setup
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
blah di blah
|
||||||
|
|
||||||
|
Getting Started
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Blah di blah
|
||||||
|
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
|
||||||
|
Blah blah blah, examples here.
|
||||||
|
|
||||||
|
Add a toctree for examples
|
||||||
|
|
||||||
|
|
||||||
|
Library Reference
|
||||||
|
-----------------
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 2
|
||||||
|
|
||||||
resource
|
resource
|
||||||
modelresource
|
modelresource
|
||||||
|
|
|
@ -15,57 +15,11 @@ class PygmentsForm(forms.Form):
|
||||||
The code to be highlighted can be specified either in a text field, or by URL.
|
The code to be highlighted can be specified either in a text field, or by URL.
|
||||||
We do some additional form validation to ensure clients see helpful error responses."""
|
We do some additional form validation to ensure clients see helpful error responses."""
|
||||||
|
|
||||||
code_url = forms.URLField(required=False, label='Code URL',
|
code = forms.CharField(widget=forms.Textarea, label='Code Text', max_length=1000000,
|
||||||
help_text='eg. https://bitbucket.org/tomchristie/flywheel/raw/cc266285d879/flywheel/resource.py')
|
help_text='(Copy and paste the code text here.)')
|
||||||
code_text = forms.CharField(widget=forms.Textarea, required=False, label='Code Text',
|
title = forms.CharField(required=False, help_text='(Optional)', max_length=100)
|
||||||
help_text='Either supply a URL for the code to be highlighted or copy and paste the code text here.')
|
|
||||||
title = forms.CharField(required=False, help_text='(Optional)')
|
|
||||||
linenos = forms.BooleanField(label='Show Line Numbers', required=False)
|
linenos = forms.BooleanField(label='Show Line Numbers', required=False)
|
||||||
lexer = forms.ChoiceField(choices=LEXER_CHOICES, initial='python')
|
lexer = forms.ChoiceField(choices=LEXER_CHOICES, initial='python')
|
||||||
style = forms.ChoiceField(choices=STYLE_CHOICES, initial='friendly')
|
style = forms.ChoiceField(choices=STYLE_CHOICES, initial='friendly')
|
||||||
|
|
||||||
|
|
||||||
def clean_code_url(self):
|
|
||||||
"""Custom field validation.
|
|
||||||
Ensure that code URLs really are valid, and return the content they point to in the cleaned_data,
|
|
||||||
rather than returning the URL itself."""
|
|
||||||
cleaned_data = self.cleaned_data
|
|
||||||
url = cleaned_data.get('code_url')
|
|
||||||
if not url:
|
|
||||||
return ''
|
|
||||||
|
|
||||||
try:
|
|
||||||
http = httplib.Http('.cache')
|
|
||||||
resp, content = http.request(url)
|
|
||||||
except:
|
|
||||||
raise forms.ValidationError('The URL supplied cannot be reached')
|
|
||||||
|
|
||||||
if int(resp.status/100) != 2:
|
|
||||||
raise forms.ValidationError('The URL supplied does not return successfully')
|
|
||||||
if not content:
|
|
||||||
raise forms.ValidationError('The URL supplied returns no content')
|
|
||||||
|
|
||||||
return content
|
|
||||||
|
|
||||||
|
|
||||||
def clean(self):
|
|
||||||
"""Custom form validation.
|
|
||||||
Ensure that only one of code_url and code_text is set, and return the content of whichever is set in 'code'."""
|
|
||||||
cleaned_data = self.cleaned_data
|
|
||||||
code_url = cleaned_data.get('code_url')
|
|
||||||
code_text = cleaned_data.get('code_text')
|
|
||||||
|
|
||||||
if not code_url and not code_text:
|
|
||||||
raise forms.ValidationError('Either the URL or the code text must be supplied')
|
|
||||||
if code_url and code_text:
|
|
||||||
raise forms.ValidationError('You may not specify both the URL and the code text')
|
|
||||||
|
|
||||||
if code_url:
|
|
||||||
cleaned_data['code'] = code_url
|
|
||||||
del cleaned_data['code_url']
|
|
||||||
else:
|
|
||||||
cleaned_data['code'] = code_text
|
|
||||||
del cleaned_data['code_text']
|
|
||||||
|
|
||||||
return cleaned_data
|
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ class HTMLEmitter(BaseEmitter):
|
||||||
|
|
||||||
class PygmentsRoot(Resource):
|
class PygmentsRoot(Resource):
|
||||||
"""This example demonstrates a simple RESTful Web API aound the awesome pygments library.
|
"""This example demonstrates a simple RESTful Web API aound the awesome pygments library.
|
||||||
This top level resource is used to create """
|
This top level resource is used to create highlighted code snippets."""
|
||||||
form = PygmentsForm
|
form = PygmentsForm
|
||||||
allowed_methods = anon_allowed_methods = ('POST',)
|
allowed_methods = anon_allowed_methods = ('POST',)
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ urlpatterns = patterns('',
|
||||||
(r'^pygments-example/', include('pygments_api.urls')),
|
(r'^pygments-example/', include('pygments_api.urls')),
|
||||||
(r'^blog-post-example/', include('blogpost.urls')),
|
(r'^blog-post-example/', include('blogpost.urls')),
|
||||||
(r'^object-store-example/', include('objectstore.urls')),
|
(r'^object-store-example/', include('objectstore.urls')),
|
||||||
|
(r'^testarchive-example/', include('testarchive.urls')),
|
||||||
(r'^accounts/login/$', 'django.contrib.auth.views.login'),
|
(r'^accounts/login/$', 'django.contrib.auth.views.login'),
|
||||||
(r'^accounts/logout/$', 'django.contrib.auth.views.logout'),
|
(r'^accounts/logout/$', 'django.contrib.auth.views.logout'),
|
||||||
(r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
(r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
||||||
|
|
|
@ -32,6 +32,8 @@ class BaseEmitter(object):
|
||||||
self.resource = resource
|
self.resource = resource
|
||||||
|
|
||||||
def emit(self, output=NoContent, verbose=False):
|
def emit(self, output=NoContent, verbose=False):
|
||||||
|
"""By default emit simply returns the ouput as-is.
|
||||||
|
Override this method to provide for other behaviour."""
|
||||||
if output is NoContent:
|
if output is NoContent:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
|
@ -81,7 +83,8 @@ class DocumentingTemplateEmitter(BaseEmitter):
|
||||||
provide a form that can be used to submit arbitrary content."""
|
provide a form that can be used to submit arbitrary content."""
|
||||||
# Get the form instance if we have one bound to the input
|
# Get the form instance if we have one bound to the input
|
||||||
form_instance = resource.form_instance
|
form_instance = resource.form_instance
|
||||||
|
print form_instance
|
||||||
|
|
||||||
# Otherwise if this isn't an error response
|
# Otherwise if this isn't an error response
|
||||||
# then attempt to get a form bound to the response object
|
# then attempt to get a form bound to the response object
|
||||||
if not form_instance and resource.response.has_content_body:
|
if not form_instance and resource.response.has_content_body:
|
||||||
|
@ -89,6 +92,8 @@ class DocumentingTemplateEmitter(BaseEmitter):
|
||||||
form_instance = resource.get_form(resource.response.raw_content)
|
form_instance = resource.get_form(resource.response.raw_content)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
if form_instance and not form_instance.is_valid():
|
||||||
|
form_instance = None
|
||||||
|
|
||||||
# If we still don't have a form instance then try to get an unbound form
|
# If we still don't have a form instance then try to get an unbound form
|
||||||
if not form_instance:
|
if not form_instance:
|
||||||
|
|
|
@ -58,14 +58,19 @@ class Resource(object):
|
||||||
CSRF_PARAM = 'csrfmiddlewaretoken' # Django's CSRF token used in form params
|
CSRF_PARAM = 'csrfmiddlewaretoken' # Django's CSRF token used in form params
|
||||||
|
|
||||||
|
|
||||||
def __new__(cls, request, *args, **kwargs):
|
def __new__(cls, *args, **kwargs):
|
||||||
"""Make the class callable so it can be used as a Django view."""
|
"""Make the class callable so it can be used as a Django view."""
|
||||||
self = object.__new__(cls)
|
self = object.__new__(cls)
|
||||||
self.__init__(request)
|
if args:
|
||||||
return self._handle_request(request, *args, **kwargs)
|
request = args[0]
|
||||||
|
self.__init__(request)
|
||||||
|
return self._handle_request(request, *args[1:], **kwargs)
|
||||||
|
else:
|
||||||
|
self.__init__()
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, request):
|
def __init__(self, request=None):
|
||||||
""""""
|
""""""
|
||||||
# Setup the resource context
|
# Setup the resource context
|
||||||
self.request = request
|
self.request = request
|
||||||
|
|
|
@ -30,9 +30,9 @@
|
||||||
<h1>{{ resource.name }}</h1>
|
<h1>{{ resource.name }}</h1>
|
||||||
<p>{{ resource.description|linebreaksbr }}</p>
|
<p>{{ resource.description|linebreaksbr }}</p>
|
||||||
<pre><b>{{ response.status }} {{ response.status_text }}</b>{% autoescape off %}
|
<pre><b>{{ response.status }} {{ response.status_text }}</b>{% autoescape off %}
|
||||||
{% for key, val in response.headers.items %}<b>{{ key }}:</b> {{ val|urlize_quoted_links }}
|
{% for key, val in response.headers.items %}<b>{{ key }}:</b> {{ val|urlize_quoted_links }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{{ content|urlize_quoted_links }}</pre>{% endautoescape %}
|
{{ content|urlize_quoted_links }}</pre>{% endautoescape %}
|
||||||
|
|
||||||
{% if 'GET' in resource.allowed_methods %}
|
{% if 'GET' in resource.allowed_methods %}
|
||||||
<div class='action'>
|
<div class='action'>
|
||||||
|
@ -40,7 +40,7 @@
|
||||||
<ul class="accepttypes">
|
<ul class="accepttypes">
|
||||||
{% for media_type in resource.emitted_media_types %}
|
{% for media_type in resource.emitted_media_types %}
|
||||||
{% with resource.ACCEPT_QUERY_PARAM|add:"="|add:media_type as param %}
|
{% with resource.ACCEPT_QUERY_PARAM|add:"="|add:media_type as param %}
|
||||||
<li>[<a href='{{ request.path|add_query_param:param }} rel="nofollow"'>{{ media_type }}</a>]</li>
|
<li>[<a href='{{ request.path|add_query_param:param }}' rel="nofollow">{{ media_type }}</a>]</li>
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user