mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-22 09:36:49 +03:00
pull in markos changes, minor tweaks to yaml stuff
This commit is contained in:
commit
f7b7778a79
|
@ -156,6 +156,7 @@ except ImportError:
|
|||
def head(self, request, *args, **kwargs):
|
||||
return self.get(request, *args, **kwargs)
|
||||
|
||||
# Markdown is optional
|
||||
try:
|
||||
import markdown
|
||||
import re
|
||||
|
@ -204,3 +205,9 @@ try:
|
|||
|
||||
except ImportError:
|
||||
apply_markdown = None
|
||||
|
||||
# Yaml is optional
|
||||
try:
|
||||
import yaml
|
||||
except ImportError:
|
||||
yaml = None
|
||||
|
|
|
@ -16,15 +16,18 @@ from django.http.multipartparser import MultiPartParser as DjangoMultiPartParser
|
|||
from django.http.multipartparser import MultiPartParserError
|
||||
from django.utils import simplejson as json
|
||||
from djangorestframework import status
|
||||
from djangorestframework.compat import yaml
|
||||
from djangorestframework.response import ErrorResponse
|
||||
from djangorestframework.utils.mediatypes import media_type_matches
|
||||
|
||||
|
||||
__all__ = (
|
||||
'BaseParser',
|
||||
'JSONParser',
|
||||
'PlainTextParser',
|
||||
'FormParser',
|
||||
'MultiPartParser',
|
||||
'YAMLParser',
|
||||
)
|
||||
|
||||
|
||||
|
@ -85,6 +88,27 @@ class JSONParser(BaseParser):
|
|||
{'detail': 'JSON parse error - %s' % unicode(exc)})
|
||||
|
||||
|
||||
if yaml:
|
||||
class YAMLParser(BaseParser):
|
||||
"""
|
||||
Parses YAML-serialized data.
|
||||
"""
|
||||
|
||||
media_type = 'application/yaml'
|
||||
|
||||
def parse(self, stream):
|
||||
"""
|
||||
Returns a 2-tuple of `(data, files)`.
|
||||
|
||||
`data` will be an object which is the parsed content of the response.
|
||||
`files` will always be `None`.
|
||||
"""
|
||||
try:
|
||||
return (yaml.safe_load(stream), None)
|
||||
except ValueError, exc:
|
||||
raise ErrorResponse(status.HTTP_400_BAD_REQUEST,
|
||||
{'detail': 'YAML parse error - %s' % unicode(exc)})
|
||||
|
||||
|
||||
class PlainTextParser(BaseParser):
|
||||
"""
|
||||
|
|
|
@ -11,16 +11,14 @@ from django.core.serializers.json import DateTimeAwareJSONEncoder
|
|||
from django.template import RequestContext, loader
|
||||
from django.utils import simplejson as json
|
||||
|
||||
from djangorestframework import status
|
||||
from djangorestframework.compat import apply_markdown
|
||||
|
||||
from djangorestframework.compat import apply_markdown, 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
|
||||
|
||||
from decimal import Decimal
|
||||
import re
|
||||
import string
|
||||
from urllib import quote_plus
|
||||
|
||||
|
@ -31,7 +29,8 @@ __all__ = (
|
|||
'DocumentingHTMLRenderer',
|
||||
'DocumentingXHTMLRenderer',
|
||||
'DocumentingPlainTextRenderer',
|
||||
'XMLRenderer'
|
||||
'XMLRenderer',
|
||||
'YAMLRenderer'
|
||||
)
|
||||
|
||||
|
||||
|
@ -131,6 +130,27 @@ class XMLRenderer(BaseRenderer):
|
|||
return dict2xml(obj)
|
||||
|
||||
|
||||
if yaml:
|
||||
class YAMLRenderer(BaseRenderer):
|
||||
"""
|
||||
Renderer which serializes to YAML.
|
||||
"""
|
||||
|
||||
media_type = 'application/yaml'
|
||||
format = 'yaml'
|
||||
|
||||
def render(self, obj=None, media_type=None):
|
||||
"""
|
||||
Renders *obj* into serialized YAML.
|
||||
"""
|
||||
if obj is None:
|
||||
return ''
|
||||
|
||||
return yaml.dump(obj)
|
||||
else:
|
||||
YAMLRenderer = None
|
||||
|
||||
|
||||
class TemplateRenderer(BaseRenderer):
|
||||
"""
|
||||
A Base class provided for convenience.
|
||||
|
@ -361,4 +381,5 @@ DEFAULT_RENDERERS = ( JSONRenderer,
|
|||
DocumentingPlainTextRenderer,
|
||||
XMLRenderer )
|
||||
|
||||
|
||||
if YAMLRenderer:
|
||||
DEFAULT_RENDERERS += (YAMLRenderer,)
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#site-name a {color: #F4F379 !important;}
|
||||
.errorlist {display: inline !important}
|
||||
.errorlist li {display: inline !important; background: white !important; color: black !important; border: 0 !important;}
|
||||
/* Custom styles */
|
||||
.version{font-size:8px;}
|
||||
</style>
|
||||
<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'/>
|
||||
|
@ -18,7 +20,7 @@
|
|||
|
||||
<div id="header">
|
||||
<div id="branding">
|
||||
<h1 id="site-name"><a href='http://django-rest-framework.org'>Django REST framework</a> <small>{{ version }}</small></h1>
|
||||
<h1 id="site-name"><a href='http://django-rest-framework.org'>Django REST framework</a> <span class="version"> v {{ version }}</span></h1>
|
||||
</div>
|
||||
<div id="user-tools">
|
||||
{% if user.is_active %}Welcome, {{ user }}.{% if logout_url %} <a href='{{ logout_url }}'>Log out</a>{% endif %}{% else %}Anonymous {% if login_url %}<a href='{{ login_url }}'>Log in</a>{% endif %}{% endif %}
|
||||
|
@ -58,8 +60,8 @@
|
|||
</form>
|
||||
{% endif %}
|
||||
|
||||
{# Only display the POST/PUT/DELETE forms if method tunneling via POST forms is enabled. #}
|
||||
{% if METHOD_PARAM %}
|
||||
{# Only display the POST/PUT/DELETE forms if method tunneling via POST forms is enabled and the user has permissions on this view. #}
|
||||
{% if METHOD_PARAM and response.status != 403 %}
|
||||
|
||||
{% if 'POST' in view.allowed_methods %}
|
||||
<form action="{{ request.get_full_path }}" method="post" {% if post_form.is_multipart %}enctype="multipart/form-data"{% endif %}>
|
||||
|
|
|
@ -4,8 +4,8 @@ from django.test import TestCase
|
|||
|
||||
from djangorestframework import status
|
||||
from djangorestframework.compat import View as DjangoView
|
||||
from djangorestframework.renderers import BaseRenderer, JSONRenderer
|
||||
from djangorestframework.parsers import JSONParser
|
||||
from djangorestframework.renderers import BaseRenderer, JSONRenderer, YAMLRenderer
|
||||
from djangorestframework.parsers import JSONParser, YAMLParser
|
||||
from djangorestframework.mixins import ResponseMixin
|
||||
from djangorestframework.response import Response
|
||||
from djangorestframework.utils.mediatypes import add_media_type_param
|
||||
|
@ -189,3 +189,38 @@ class JSONRendererTests(TestCase):
|
|||
content = renderer.render(obj, 'application/json')
|
||||
(data, files) = parser.parse(StringIO(content))
|
||||
self.assertEquals(obj, data)
|
||||
|
||||
|
||||
|
||||
if YAMLRenderer:
|
||||
_yaml_repr = 'foo: [bar, baz]\n'
|
||||
|
||||
|
||||
class YAMLRendererTests(TestCase):
|
||||
"""
|
||||
Tests specific to the JSON Renderer
|
||||
"""
|
||||
|
||||
def test_render(self):
|
||||
"""
|
||||
Test basic YAML rendering.
|
||||
"""
|
||||
obj = {'foo':['bar','baz']}
|
||||
renderer = YAMLRenderer(None)
|
||||
content = renderer.render(obj, 'application/yaml')
|
||||
self.assertEquals(content, _yaml_repr)
|
||||
|
||||
|
||||
def test_render_and_parse(self):
|
||||
"""
|
||||
Test rendering and then parsing returns the original object.
|
||||
IE obj -> render -> parse -> obj.
|
||||
"""
|
||||
obj = {'foo':['bar','baz']}
|
||||
|
||||
renderer = YAMLRenderer(None)
|
||||
parser = YAMLParser(None)
|
||||
|
||||
content = renderer.render(obj, 'application/yaml')
|
||||
(data, files) = parser.parse(StringIO(content))
|
||||
self.assertEquals(obj, data)
|
|
@ -44,7 +44,8 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
|
|||
renderers.DocumentingHTMLRenderer,
|
||||
renderers.DocumentingXHTMLRenderer,
|
||||
renderers.DocumentingPlainTextRenderer,
|
||||
renderers.XMLRenderer )
|
||||
renderers.XMLRenderer,
|
||||
renderers.YAMLRenderer )
|
||||
|
||||
"""
|
||||
List of parsers the resource can parse the request with.
|
||||
|
|
12
examples/permissionsexample/fixtures/initial_data.yaml
Normal file
12
examples/permissionsexample/fixtures/initial_data.yaml
Normal file
|
@ -0,0 +1,12 @@
|
|||
- fields:
|
||||
first_name: ''
|
||||
groups: []
|
||||
is_active: true
|
||||
is_staff: true
|
||||
is_superuser: true
|
||||
last_name: ''
|
||||
password: sha1$b3dff$671b4ab97f2714446da32670d27576614e176758
|
||||
user_permissions: []
|
||||
username: test
|
||||
model: auth.user
|
||||
pk: 2
|
1
examples/permissionsexample/models.py
Normal file
1
examples/permissionsexample/models.py
Normal file
|
@ -0,0 +1 @@
|
|||
#for fixture loading
|
|
@ -1,6 +1,8 @@
|
|||
from django.conf.urls.defaults import patterns, url
|
||||
from permissionsexample.views import ThrottlingExampleView
|
||||
from permissionsexample.views import PermissionsExampleView, ThrottlingExampleView, LoggedInExampleView
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^$', ThrottlingExampleView.as_view(), name='throttled-resource'),
|
||||
url(r'^$', PermissionsExampleView.as_view(), name='permissions-example'),
|
||||
url(r'^throttling$', ThrottlingExampleView.as_view(), name='throttled-resource'),
|
||||
url(r'^loggedin$', LoggedInExampleView.as_view(), name='loggedin-resource'),
|
||||
)
|
||||
|
|
|
@ -1,6 +1,16 @@
|
|||
from djangorestframework.views import View
|
||||
from djangorestframework.permissions import PerUserThrottling
|
||||
from djangorestframework.permissions import PerUserThrottling, IsAuthenticated
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
class PermissionsExampleView(View):
|
||||
"""
|
||||
A container view for permissions examples.
|
||||
"""
|
||||
|
||||
def get(self, request):
|
||||
return [{'name': 'Throttling Example', 'url': reverse('throttled-resource')},
|
||||
{'name': 'Logged in example', 'url': reverse('loggedin-resource')},]
|
||||
|
||||
|
||||
class ThrottlingExampleView(View):
|
||||
"""
|
||||
|
@ -17,4 +27,12 @@ class ThrottlingExampleView(View):
|
|||
"""
|
||||
Handle GET requests.
|
||||
"""
|
||||
return "Successful response to GET request because throttle is not yet active."
|
||||
return "Successful response to GET request because throttle is not yet active."
|
||||
|
||||
class LoggedInExampleView(View):
|
||||
"""
|
||||
You can login with **'test', 'test'.**
|
||||
"""
|
||||
permissions = (IsAuthenticated, )
|
||||
def get(self, request):
|
||||
return 'Logged in or not?'
|
|
@ -4,3 +4,4 @@
|
|||
Pygments==1.4
|
||||
Markdown==2.0.3
|
||||
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ class Sandbox(View):
|
|||
4. A generic object store API.
|
||||
5. A code highlighting API.
|
||||
6. A blog posts and comments API.
|
||||
7. A basic example using permissions.
|
||||
|
||||
Please feel free to browse, create, edit and delete the resources in these examples."""
|
||||
|
||||
|
@ -32,5 +33,5 @@ class Sandbox(View):
|
|||
{'name': 'Object store API', 'url': reverse('object-store-root')},
|
||||
{'name': 'Code highlighting API', 'url': reverse('pygments-root')},
|
||||
{'name': 'Blog posts API', 'url': reverse('blog-posts-root')},
|
||||
{'name': 'Permissions example', 'url': reverse('throttled-resource')}
|
||||
{'name': 'Permissions example', 'url': reverse('permissions-example')}
|
||||
]
|
||||
|
|
|
@ -89,6 +89,12 @@ TEMPLATE_DIRS = (
|
|||
# Don't forget to use absolute paths, not relative paths.
|
||||
)
|
||||
|
||||
# for loading initial data
|
||||
##SERIALIZATION_MODULES = {
|
||||
# 'yml': "django.core.serializers.pyyaml"
|
||||
|
||||
#}
|
||||
|
||||
|
||||
INSTALLED_APPS = (
|
||||
'django.contrib.auth',
|
||||
|
@ -104,6 +110,7 @@ INSTALLED_APPS = (
|
|||
'objectstore',
|
||||
'pygments_api',
|
||||
'blogpost',
|
||||
'permissionsexample',
|
||||
)
|
||||
|
||||
import os
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# We need Django. Duh.
|
||||
# coverage isn't strictly a requirement, but it's useful.
|
||||
|
||||
Django==1.2.4
|
||||
wsgiref==0.1.2
|
||||
coverage==3.4
|
||||
|
||||
|
|
32
tox.ini
32
tox.ini
|
@ -29,6 +29,7 @@ deps=
|
|||
django==1.2.4
|
||||
coverage==3.4
|
||||
unittest-xml-reporting==1.2
|
||||
Pyyaml==3.10
|
||||
|
||||
[testenv:py26-django12]
|
||||
basepython=python2.6
|
||||
|
@ -36,6 +37,7 @@ deps=
|
|||
django==1.2.4
|
||||
coverage==3.4
|
||||
unittest-xml-reporting==1.2
|
||||
Pyyaml==3.10
|
||||
|
||||
[testenv:py27-django12]
|
||||
basepython=python2.7
|
||||
|
@ -43,28 +45,32 @@ deps=
|
|||
django==1.2.4
|
||||
coverage==3.4
|
||||
unittest-xml-reporting==1.2
|
||||
|
||||
Pyyaml==3.10
|
||||
|
||||
[testenv:py25-django13]
|
||||
basepython=python2.5
|
||||
deps=
|
||||
django==1.3
|
||||
coverage==3.4
|
||||
unittest-xml-reporting==1.2
|
||||
|
||||
Pyyaml==3.10
|
||||
|
||||
[testenv:py26-django13]
|
||||
basepython=python2.6
|
||||
deps=
|
||||
django==1.3
|
||||
coverage==3.4
|
||||
unittest-xml-reporting==1.2
|
||||
|
||||
Pyyaml==3.10
|
||||
|
||||
[testenv:py27-django13]
|
||||
basepython=python2.7
|
||||
deps=
|
||||
django==1.3
|
||||
coverage==3.4
|
||||
unittest-xml-reporting==1.2
|
||||
|
||||
Pyyaml==3.10
|
||||
|
||||
####################################### EXAMPLES ################################################
|
||||
|
||||
[testenv:py25-django12e]
|
||||
|
@ -79,7 +85,8 @@ deps=
|
|||
httplib2==0.6.0
|
||||
Markdown==2.0.3
|
||||
unittest-xml-reporting==1.2
|
||||
|
||||
Pyyaml==3.10
|
||||
|
||||
[testenv:py26-django12e]
|
||||
basepython=python2.6
|
||||
commands=
|
||||
|
@ -92,7 +99,8 @@ deps=
|
|||
httplib2==0.6.0
|
||||
Markdown==2.0.3
|
||||
unittest-xml-reporting==1.2
|
||||
|
||||
Pyyaml==3.10
|
||||
|
||||
[testenv:py27-django12e]
|
||||
basepython=python2.7
|
||||
commands=
|
||||
|
@ -105,7 +113,8 @@ deps=
|
|||
httplib2==0.6.0
|
||||
Markdown==2.0.3
|
||||
unittest-xml-reporting==1.2
|
||||
|
||||
Pyyaml==3.10
|
||||
|
||||
[testenv:py25-django13e]
|
||||
basepython=python2.5
|
||||
commands=
|
||||
|
@ -118,7 +127,8 @@ deps=
|
|||
httplib2==0.6.0
|
||||
Markdown==2.0.3
|
||||
unittest-xml-reporting==1.2
|
||||
|
||||
Pyyaml==3.10
|
||||
|
||||
[testenv:py26-django13e]
|
||||
basepython=python2.6
|
||||
commands=
|
||||
|
@ -131,7 +141,8 @@ deps=
|
|||
httplib2==0.6.0
|
||||
Markdown==2.0.3
|
||||
unittest-xml-reporting==1.2
|
||||
|
||||
Pyyaml==3.10
|
||||
|
||||
[testenv:py27-django13e]
|
||||
basepython=python2.7
|
||||
commands=
|
||||
|
@ -143,4 +154,5 @@ deps=
|
|||
Pygments==1.4
|
||||
httplib2==0.6.0
|
||||
Markdown==2.0.3
|
||||
unittest-xml-reporting==1.2
|
||||
unittest-xml-reporting==1.2
|
||||
Pyyaml==3.10
|
Loading…
Reference in New Issue
Block a user