mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-10-30 23:47:53 +03:00 
			
		
		
		
	Merging master into develop
This commit is contained in:
		
							parent
							
								
									21fcd3a906
								
							
						
					
					
						commit
						af9e4f69d7
					
				
							
								
								
									
										2
									
								
								AUTHORS
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								AUTHORS
									
									
									
									
									
								
							|  | @ -31,6 +31,8 @@ Ben Timby <btimby> | |||
| Michele Lazzeri <michelelazzeri-nextage> | ||||
| Camille Harang <mammique> | ||||
| Paul Oswald <poswald> | ||||
| Sean C. Farley <scfarley> | ||||
| Daniel Izquierdo <izquierdo> | ||||
| 
 | ||||
| THANKS TO: | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,16 +1,19 @@ | |||
| Release Notes | ||||
| ============= | ||||
| 
 | ||||
| development | ||||
| ----------- | ||||
| 0.3.3 | ||||
| ----- | ||||
| 
 | ||||
| * Added DjangoModelPermissions class to support `django.contrib.auth` style permissions. | ||||
| * Use `staticfiles` for css files. | ||||
|   - Easier to override.  Won't conflict with customised admin styles (eg grappelli) | ||||
| * Templates are now nicely namespaced. | ||||
|   - Allows easier overriding. | ||||
| * Drop implied 'pk' filter if last arg in urlconf is unnamed. | ||||
|   - Too magical.  Explict is better than implicit. | ||||
| * Saner template variable autoescaping. | ||||
| * Tider setup.py | ||||
| * Updated for URLObject 2.0 | ||||
| * Bugfixes: | ||||
|   - Bug with PerUserThrottling when user contains unicode chars. | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,3 +1,3 @@ | |||
| __version__ = '0.3.3-dev' | ||||
| __version__ = '0.3.3' | ||||
| 
 | ||||
| VERSION = __version__  # synonym | ||||
|  |  | |||
|  | @ -497,12 +497,12 @@ class PaginatorMixin(object): | |||
|         """ | ||||
|         Constructs a url used for getting the next/previous urls | ||||
|         """ | ||||
|         url = URLObject.parse(self.request.get_full_path()) | ||||
|         url = url.set_query_param('page', page_number) | ||||
|         url = URLObject(self.request.get_full_path()) | ||||
|         url = url.set_query_param('page', str(page_number)) | ||||
| 
 | ||||
|         limit = self.get_limit() | ||||
|         if limit != self.limit: | ||||
|             url = url.add_query_param('limit', limit) | ||||
|             url = url.set_query_param('limit', str(limit)) | ||||
| 
 | ||||
|         return url | ||||
| 
 | ||||
|  |  | |||
|  | @ -379,7 +379,7 @@ class DocumentingHTMLRenderer(DocumentingTemplateRenderer): | |||
| 
 | ||||
|     media_type = 'text/html' | ||||
|     format = 'html' | ||||
|     template = 'renderer.html' | ||||
|     template = 'djangorestframework/api.html' | ||||
| 
 | ||||
| 
 | ||||
| class DocumentingXHTMLRenderer(DocumentingTemplateRenderer): | ||||
|  | @ -391,7 +391,7 @@ class DocumentingXHTMLRenderer(DocumentingTemplateRenderer): | |||
| 
 | ||||
|     media_type = 'application/xhtml+xml' | ||||
|     format = 'xhtml' | ||||
|     template = 'renderer.html' | ||||
|     template = 'djangorestframework/api.html' | ||||
| 
 | ||||
| 
 | ||||
| class DocumentingPlainTextRenderer(DocumentingTemplateRenderer): | ||||
|  | @ -403,7 +403,7 @@ class DocumentingPlainTextRenderer(DocumentingTemplateRenderer): | |||
| 
 | ||||
|     media_type = 'text/plain' | ||||
|     format = 'txt' | ||||
|     template = 'renderer.txt' | ||||
|     template = 'djangorestframework/api.txt' | ||||
| 
 | ||||
| 
 | ||||
| DEFAULT_RENDERERS = ( | ||||
|  |  | |||
|  | @ -1,10 +1,10 @@ | |||
| from django import forms | ||||
| from django.core.urlresolvers import reverse, get_urlconf, get_resolver, NoReverseMatch | ||||
| from django.core.urlresolvers import get_urlconf, get_resolver, NoReverseMatch | ||||
| from django.db import models | ||||
| 
 | ||||
| from djangorestframework.response import ImmediateResponse | ||||
| from djangorestframework.serializer import Serializer, _SkipField | ||||
| from djangorestframework.utils import as_tuple | ||||
| from djangorestframework.utils import as_tuple, reverse | ||||
| 
 | ||||
| 
 | ||||
| class BaseResource(Serializer): | ||||
|  | @ -354,7 +354,7 @@ class ModelResource(FormResource): | |||
|                         instance_attrs[param] = attr | ||||
| 
 | ||||
|                 try: | ||||
|                     return reverse(self.view_callable[0], kwargs=instance_attrs) | ||||
|                     return reverse(self.view_callable[0], self.view.request, kwargs=instance_attrs) | ||||
|                 except NoReverseMatch: | ||||
|                     pass | ||||
|         raise _SkipField | ||||
|  |  | |||
|  | @ -40,7 +40,7 @@ class Response(SimpleTemplateResponse): | |||
|     _ACCEPT_QUERY_PARAM = '_accept'        # Allow override of Accept header in URL query params | ||||
|     _IGNORE_IE_ACCEPT_HEADER = True | ||||
| 
 | ||||
|     def __init__(self, content=None, status=None, request=None, renderers=None): | ||||
|     def __init__(self, content=None, status=None, request=None, renderers=None, headers=None): | ||||
|         # First argument taken by `SimpleTemplateResponse.__init__` is template_name, | ||||
|         # which we don't need | ||||
|         super(Response, self).__init__(None, status=status) | ||||
|  | @ -50,6 +50,7 @@ class Response(SimpleTemplateResponse): | |||
|         self.raw_content = content | ||||
|         self.has_content_body = content is not None | ||||
|         self.request = request | ||||
|         self.headers = headers and headers[:] or [] | ||||
|         if renderers is not None: | ||||
|             self.renderers = renderers | ||||
| 
 | ||||
|  |  | |||
|  | @ -146,7 +146,7 @@ class Serializer(object): | |||
|         # then the second element of the tuple is the fields to | ||||
|         # set on the related serializer | ||||
|         if isinstance(info, (list, tuple)): | ||||
|             class OnTheFlySerializer(Serializer): | ||||
|             class OnTheFlySerializer(self.__class__): | ||||
|                 fields = info | ||||
|             return OnTheFlySerializer | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,3 @@ | |||
| {% extends "djangorestframework/base.html" %} | ||||
| 
 | ||||
| {# Override this template in your own templates directory to customize #} | ||||
|  | @ -7,26 +7,34 @@ | |||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||||
|   	<head> | ||||
|       	<link rel="stylesheet" type="text/css" href='{% get_static_prefix %}djangorestframework/css/style.css'/> | ||||
|   		<title>Django REST framework - {{ name }}</title> | ||||
|       	{% block extrastyle %}{% endblock %} | ||||
|   		<title>{% block title %}Django REST framework - {{ name }}{% endblock %}</title> | ||||
|   		{% block extrahead %}{% endblock %} | ||||
| 		{% block blockbots %}<meta name="robots" content="NONE,NOARCHIVE" />{% endblock %} | ||||
|   	</head> | ||||
|   <body> | ||||
|   <body class="{% block bodyclass %}{% endblock %}"> | ||||
|   <div id="container"> | ||||
| 
 | ||||
| 	<div id="header"> | ||||
| 		<div id="branding"> | ||||
| 		  <h1 id="site-name"><a href='http://django-rest-framework.org'>Django REST framework</a> <span class="version"> v {{ version }}</span></h1> | ||||
| 		  <h1 id="site-name">{% block branding %}<a href='http://django-rest-framework.org'>Django REST framework</a> <span class="version"> v {{ version }}</span>{% endblock %}</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 %} | ||||
| 		  {% block userlinks %}{% endblock %} | ||||
| 		</div> | ||||
| 		{% block nav-global %}{% endblock %} | ||||
| 	</div> | ||||
| 
 | ||||
| 	<div class="breadcrumbs"> | ||||
| 	{% block breadcrumbs %} | ||||
| 	{% for breadcrumb_name, breadcrumb_url in breadcrumblist %} | ||||
|     <a href="{{ breadcrumb_url }}">{{ breadcrumb_name }}</a> {% if not forloop.last %}›{% endif %} | ||||
|     {% endfor %} | ||||
|     {% endblock %} | ||||
|     </div> | ||||
| 
 | ||||
|     <!-- Content --> | ||||
|     <div id="content" class="{% block coltype %}colM{% endblock %}"> | ||||
| 
 | ||||
| 		{% if 'OPTIONS' in allowed_methods %} | ||||
|  | @ -123,7 +131,12 @@ | |||
| 
 | ||||
| 	{% endif %} | ||||
| 	</div> | ||||
| 	<!-- END content-main --> | ||||
| 
 | ||||
| 	</div> | ||||
| 	<!-- END Content --> | ||||
| 
 | ||||
|     {% block footer %}<div id="footer"></div>{% endblock %} | ||||
| 	</div> | ||||
|   </body> | ||||
| </html> | ||||
|  | @ -4,8 +4,7 @@ register = Library() | |||
| 
 | ||||
| 
 | ||||
| def add_query_param(url, param): | ||||
|     (key, sep, val) = param.partition('=') | ||||
|     return unicode(URLObject.parse(url) & (key, val)) | ||||
|     return unicode(URLObject(url).with_query(param)) | ||||
| 
 | ||||
| 
 | ||||
| register.filter('add_query_param', add_query_param) | ||||
|  |  | |||
|  | @ -1,8 +1,8 @@ | |||
| from django.conf.urls.defaults import patterns, url | ||||
| from django.core.urlresolvers import reverse | ||||
| from django.test import TestCase | ||||
| from django.utils import simplejson as json | ||||
| 
 | ||||
| from djangorestframework.utils import reverse | ||||
| from djangorestframework.views import View | ||||
| from djangorestframework.response import Response | ||||
| 
 | ||||
|  | @ -12,7 +12,7 @@ class MockView(View): | |||
|     permissions = () | ||||
| 
 | ||||
|     def get(self, request): | ||||
|         return Response(reverse('another')) | ||||
|         return Response(reverse('another', request)) | ||||
| 
 | ||||
| urlpatterns = patterns('', | ||||
|     url(r'^$', MockView.as_view()), | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| import django | ||||
| from django.utils.encoding import smart_unicode | ||||
| from django.utils.xmlutils import SimplerXMLGenerator | ||||
| from django.core.urlresolvers import resolve | ||||
| from django.core.urlresolvers import resolve, reverse as django_reverse | ||||
| from django.conf import settings | ||||
| 
 | ||||
| from djangorestframework.compat import StringIO | ||||
|  | @ -180,3 +181,21 @@ class XMLRenderer(): | |||
| 
 | ||||
| def dict2xml(input): | ||||
|     return XMLRenderer().dict2xml(input) | ||||
| 
 | ||||
| 
 | ||||
| def reverse(viewname, request, *args, **kwargs): | ||||
|     """ | ||||
|     Do the same as :py:func:`django.core.urlresolvers.reverse` but using | ||||
|     *request* to build a fully qualified URL. | ||||
|     """ | ||||
|     return request.build_absolute_uri(django_reverse(viewname, *args, **kwargs)) | ||||
| 
 | ||||
| if django.VERSION >= (1, 4): | ||||
|     from django.core.urlresolvers import reverse_lazy as django_reverse_lazy | ||||
| 
 | ||||
|     def reverse_lazy(viewname, request, *args, **kwargs): | ||||
|         """ | ||||
|         Do the same as :py:func:`django.core.urlresolvers.reverse_lazy` but using | ||||
|         *request* to build a fully qualified URL. | ||||
|         """ | ||||
|         return request.build_absolute_uri(django_reverse_lazy(viewname, *args, **kwargs)) | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ import base64 | |||
| # be making settings changes in order to accomodate django-rest-framework | ||||
| @csrf_protect | ||||
| @never_cache | ||||
| def api_login(request, template_name='api_login.html', | ||||
| def api_login(request, template_name='djangorestframework/login.html', | ||||
|           redirect_field_name=REDIRECT_FIELD_NAME, | ||||
|           authentication_form=AuthenticationForm): | ||||
|     """Displays the login form and handles the login action.""" | ||||
|  | @ -57,5 +57,5 @@ def api_login(request, template_name='api_login.html', | |||
|     }, context_instance=RequestContext(request)) | ||||
| 
 | ||||
| 
 | ||||
| def api_logout(request, next_page=None, template_name='api_login.html', redirect_field_name=REDIRECT_FIELD_NAME): | ||||
| def api_logout(request, next_page=None, template_name='djangorestframework/login.html', redirect_field_name=REDIRECT_FIELD_NAME): | ||||
|     return logout(request, next_page, template_name, redirect_field_name) | ||||
|  |  | |||
|  | @ -188,22 +188,13 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView): | |||
|         Required if you want to do things like set `request.upload_handlers` before | ||||
|         the authentication and dispatch handling is run. | ||||
|         """ | ||||
|         # Calls to 'reverse' will not be fully qualified unless we set the | ||||
|         # scheme/host/port here. | ||||
|         self.orig_prefix = get_script_prefix() | ||||
|         if not (self.orig_prefix.startswith('http:') or self.orig_prefix.startswith('https:')): | ||||
|             prefix = '%s://%s' % (request.is_secure() and 'https' or 'http', request.get_host()) | ||||
|             set_script_prefix(prefix + self.orig_prefix) | ||||
|         return request | ||||
|         pass | ||||
| 
 | ||||
|     def final(self, request, response, *args, **kargs): | ||||
|         """ | ||||
|         Returns an `HttpResponse`. This method is a hook for any code that needs to run | ||||
|         after everything else in the view. | ||||
|         """ | ||||
|         # Restore script_prefix. | ||||
|         set_script_prefix(self.orig_prefix) | ||||
| 
 | ||||
|         # Always add these headers. | ||||
|         response['Allow'] = ', '.join(allowed_methods(self)) | ||||
|         # sample to allow caching using Vary http header | ||||
|  |  | |||
							
								
								
									
										47
									
								
								docs/howto/reverse.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								docs/howto/reverse.rst
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,47 @@ | |||
| Returning URIs from your Web APIs | ||||
| ================================= | ||||
| 
 | ||||
|     "The central feature that distinguishes the REST architectural style from | ||||
|     other network-based styles is its emphasis on a uniform interface between | ||||
|     components." | ||||
| 
 | ||||
|     -- Roy Fielding, Architectural Styles and the Design of Network-based Software Architectures | ||||
| 
 | ||||
| As a rule, it's probably better practice to return absolute URIs from you web APIs, e.g. "http://example.com/foobar", rather than returning relative URIs, e.g. "/foobar". | ||||
| 
 | ||||
| The advantages of doing so are: | ||||
| 
 | ||||
| * It's more explicit. | ||||
| * It leaves less work for your API clients. | ||||
| * There's no ambiguity about the meaning of the string when it's found in representations such as JSON that do not have a native URI type. | ||||
| * It allows us to easily do things like markup HTML representations with hyperlinks. | ||||
| 
 | ||||
| Django REST framework provides two utility functions to make it simpler to return absolute URIs from your Web API. | ||||
| 
 | ||||
| There's no requirement for you to use them, but if you do then the self-describing API will be able to automatically hyperlink its output for you, which makes browsing the API much easier. | ||||
| 
 | ||||
| reverse(viewname, request, ...) | ||||
| ------------------------------- | ||||
| 
 | ||||
| The :py:func:`~utils.reverse` function has the same behavior as :py:func:`django.core.urlresolvers.reverse` [1]_, except that it takes a request object and returns a fully qualified URL, using the request to determine the host and port:: | ||||
| 
 | ||||
|     from djangorestframework.utils import reverse | ||||
|     from djangorestframework.views import View | ||||
|     | ||||
|     class MyView(View): | ||||
|         def get(self, request): | ||||
|             context = { | ||||
|                 'url': reverse('year-summary', request, args=[1945]) | ||||
|             } | ||||
| 
 | ||||
|             return Response(context) | ||||
| 
 | ||||
| reverse_lazy(viewname, request, ...) | ||||
| ------------------------------------ | ||||
| 
 | ||||
| The :py:func:`~utils.reverse_lazy` function has the same behavior as :py:func:`django.core.urlresolvers.reverse_lazy` [2]_, except that it takes a request object and returns a fully qualified URL, using the request to determine the host and port. | ||||
| 
 | ||||
| .. rubric:: Footnotes | ||||
| 
 | ||||
| .. [1] https://docs.djangoproject.com/en/dev/topics/http/urls/#reverse | ||||
| .. [2] https://docs.djangoproject.com/en/dev/topics/http/urls/#reverse-lazy | ||||
|  | @ -3,45 +3,58 @@ | |||
| Setup | ||||
| ===== | ||||
| 
 | ||||
| Installing into site-packages | ||||
| ----------------------------- | ||||
| Templates | ||||
| --------- | ||||
| 
 | ||||
| If you need to manually install Django REST framework to your ``site-packages`` directory, run the ``setup.py`` script:: | ||||
| Django REST framework uses a few templates for the HTML and plain text | ||||
| documenting renderers.  You'll need to ensure ``TEMPLATE_LOADERS`` setting | ||||
| contains ``'django.template.loaders.app_directories.Loader'``. | ||||
| This will already be the case by default. | ||||
| 
 | ||||
|     python setup.py install | ||||
| You may customize the templates by creating a new template called | ||||
| ``djangorestframework/api.html`` in your project, which should extend | ||||
| ``djangorestframework/base.html`` and override the appropriate | ||||
| block tags. For example:: | ||||
| 
 | ||||
| Template Loaders | ||||
| ---------------- | ||||
|     {% extends "djangorestframework/base.html" %} | ||||
| 
 | ||||
| Django REST framework uses a few templates for the HTML and plain text documenting renderers. | ||||
|     {% block title %}My API{% endblock %} | ||||
| 
 | ||||
| * Ensure ``TEMPLATE_LOADERS`` setting contains ``'django.template.loaders.app_directories.Loader'``. | ||||
|     {% block branding %} | ||||
|     <h1 id="site-name">My API</h1> | ||||
|     {% endblock %} | ||||
| 
 | ||||
| This will be the case by default so you shouldn't normally need to do anything here. | ||||
| 
 | ||||
| Admin Styling | ||||
| ------------- | ||||
| Styling | ||||
| ------- | ||||
| 
 | ||||
| Django REST framework uses the admin media for styling.  When running using Django's testserver this is automatically served for you,  | ||||
| but once you move onto a production server, you'll want to make sure you serve the admin media separately, exactly as you would do  | ||||
| `if using the Django admin <https://docs.djangoproject.com/en/dev/howto/deployment/modpython/#serving-the-admin-files>`_. | ||||
| Django REST framework requires `django.contrib.staticfiles`_ to serve it's css. | ||||
| If you're using Django 1.2 you'll need to use the seperate | ||||
| `django-staticfiles`_ package instead. | ||||
| 
 | ||||
| You can override the styling by creating a file in your top-level static | ||||
| directory named ``djangorestframework/css/style.css`` | ||||
| 
 | ||||
| * Ensure that the ``ADMIN_MEDIA_PREFIX`` is set appropriately and that you are serving the admin media.  | ||||
|   (Django's testserver will automatically serve the admin media for you) | ||||
| 
 | ||||
| Markdown | ||||
| -------- | ||||
| 
 | ||||
| The Python `markdown library <http://www.freewisdom.org/projects/python-markdown/>`_ is not required but comes recommended. | ||||
| `Python markdown`_ is not required but comes recommended. | ||||
| 
 | ||||
| If markdown is installed your :class:`.Resource` descriptions can include `markdown style formatting  | ||||
| <http://daringfireball.net/projects/markdown/syntax>`_ which will be rendered by the HTML documenting renderer. | ||||
| If markdown is installed your :class:`.Resource` descriptions can include | ||||
| `markdown formatting`_ which will be rendered by the self-documenting API. | ||||
| 
 | ||||
| login/logout | ||||
| --------------------------------- | ||||
| YAML | ||||
| ---- | ||||
| 
 | ||||
| Django REST framework comes with a few views that can be useful including an api | ||||
| login and logout views:: | ||||
| YAML support is optional, and requires `PyYAML`_. | ||||
| 
 | ||||
| 
 | ||||
| Login / Logout | ||||
| -------------- | ||||
| 
 | ||||
| Django REST framework includes login and logout views that are useful if | ||||
| you're using the self-documenting API:: | ||||
| 
 | ||||
|     from django.conf.urls.defaults import patterns | ||||
| 
 | ||||
|  | @ -51,3 +64,9 @@ login and logout views:: | |||
|         (r'^accounts/logout/$', 'api_logout'), | ||||
|     ) | ||||
| 
 | ||||
| .. _django.contrib.staticfiles: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/ | ||||
| .. _django-staticfiles: http://pypi.python.org/pypi/django-staticfiles/ | ||||
| .. _URLObject: http://pypi.python.org/pypi/URLObject/ | ||||
| .. _Python markdown: http://www.freewisdom.org/projects/python-markdown/ | ||||
| .. _markdown formatting: http://daringfireball.net/projects/markdown/syntax | ||||
| .. _PyYAML: http://pypi.python.org/pypi/PyYAML | ||||
|  | @ -40,8 +40,11 @@ Requirements | |||
| ------------ | ||||
| 
 | ||||
| * Python (2.5, 2.6, 2.7 supported) | ||||
| * Django (1.2, 1.3, 1.4-alpha supported) | ||||
| 
 | ||||
| * Django (1.2, 1.3, 1.4 supported) | ||||
| * `django.contrib.staticfiles`_ (or `django-staticfiles`_ for Django 1.2) | ||||
| * `URLObject`_ >= 2.0.0 | ||||
| * `Markdown`_ >= 2.1.0 (Optional) | ||||
| * `PyYAML`_ >= 3.10 (Optional) | ||||
| 
 | ||||
| Installation | ||||
| ------------ | ||||
|  | @ -54,8 +57,6 @@ Or get the latest development version using git:: | |||
| 
 | ||||
|     git clone git@github.com:tomchristie/django-rest-framework.git | ||||
| 
 | ||||
| Or you can `download the current release <http://pypi.python.org/pypi/djangorestframework>`_. | ||||
| 
 | ||||
| Setup | ||||
| ----- | ||||
| 
 | ||||
|  | @ -114,3 +115,8 @@ Indices and tables | |||
| * :ref:`modindex` | ||||
| * :ref:`search` | ||||
| 
 | ||||
| .. _django.contrib.staticfiles: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/ | ||||
| .. _django-staticfiles: http://pypi.python.org/pypi/django-staticfiles/ | ||||
| .. _URLObject: http://pypi.python.org/pypi/URLObject/ | ||||
| .. _Markdown: http://pypi.python.org/pypi/Markdown/ | ||||
| .. _PyYAML: http://pypi.python.org/pypi/PyYAML | ||||
|  |  | |||
							
								
								
									
										5
									
								
								docs/library/utils.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								docs/library/utils.rst
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | |||
| :mod:`utils` | ||||
| ============== | ||||
| 
 | ||||
| .. automodule:: utils | ||||
|    :members: | ||||
|  | @ -1,5 +1,5 @@ | |||
| from django.core.urlresolvers import reverse | ||||
| from djangorestframework.resources import ModelResource | ||||
| from djangorestframework.utils import reverse | ||||
| from blogpost.models import BlogPost, Comment | ||||
| 
 | ||||
| 
 | ||||
|  | @ -12,7 +12,7 @@ class BlogPostResource(ModelResource): | |||
|     ordering = ('-created',) | ||||
| 
 | ||||
|     def comments(self, instance): | ||||
|         return reverse('comments', kwargs={'blogpost': instance.key}) | ||||
|         return reverse('comments', request, kwargs={'blogpost': instance.key}) | ||||
| 
 | ||||
| 
 | ||||
| class CommentResource(ModelResource): | ||||
|  | @ -24,4 +24,4 @@ class CommentResource(ModelResource): | |||
|     ordering = ('-created',) | ||||
| 
 | ||||
|     def blogpost(self, instance): | ||||
|         return reverse('blog-post', kwargs={'key': instance.blogpost.key}) | ||||
|         return reverse('blog-post', request, kwargs={'key': instance.blogpost.key}) | ||||
|  |  | |||
|  | @ -1,12 +1,11 @@ | |||
| """Test a range of REST API usage of the example application. | ||||
| """ | ||||
| 
 | ||||
| from django.core.urlresolvers import reverse | ||||
| from django.test import TestCase | ||||
| from django.core.urlresolvers import reverse | ||||
| from django.utils import simplejson as json | ||||
| 
 | ||||
| from djangorestframework.compat import RequestFactory | ||||
| from djangorestframework.utils import reverse | ||||
| from djangorestframework.views import InstanceModelView, ListOrCreateModelView | ||||
| 
 | ||||
| from blogpost import models, urls | ||||
|  |  | |||
|  | @ -2,9 +2,9 @@ from djangorestframework.compat import View  # Use Django 1.3's django.views.gen | |||
| from djangorestframework.mixins import ResponseMixin | ||||
| from djangorestframework.renderers import DEFAULT_RENDERERS | ||||
| from djangorestframework.response import Response | ||||
| from djangorestframework.utils import reverse | ||||
| 
 | ||||
| from django.conf.urls.defaults import patterns, url | ||||
| from django.core.urlresolvers import reverse | ||||
| 
 | ||||
| 
 | ||||
| class ExampleView(ResponseMixin, View): | ||||
|  | @ -14,7 +14,7 @@ class ExampleView(ResponseMixin, View): | |||
| 
 | ||||
|     def get(self, request): | ||||
|         response = Response({'description': 'Some example content', | ||||
|                                   'url': reverse('mixin-view')}, status=200) | ||||
|                                   'url': reverse('mixin-view', request)}, status=200) | ||||
|         self.response = self.prepare_response(response) | ||||
|         return self.response | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| from django.conf import settings | ||||
| from django.core.urlresolvers import reverse | ||||
| 
 | ||||
| from djangorestframework.utils import reverse | ||||
| from djangorestframework.views import View | ||||
| from djangorestframework.response import Response | ||||
| from djangorestframework import status | ||||
|  | @ -41,7 +41,7 @@ class ObjectStoreRoot(View): | |||
|         filepaths = [os.path.join(OBJECT_STORE_DIR, file) for file in os.listdir(OBJECT_STORE_DIR) if not file.startswith('.')] | ||||
|         ctime_sorted_basenames = [item[0] for item in sorted([(os.path.basename(path), os.path.getctime(path)) for path in filepaths], | ||||
|                                                              key=operator.itemgetter(1), reverse=True)] | ||||
|         return Response([reverse('stored-object', kwargs={'key':key}) for key in ctime_sorted_basenames]) | ||||
|         return Response([reverse('stored-object', request, kwargs={'key':key}) for key in ctime_sorted_basenames]) | ||||
| 
 | ||||
|     def post(self, request): | ||||
|         """ | ||||
|  | @ -51,8 +51,8 @@ class ObjectStoreRoot(View): | |||
|         pathname = os.path.join(OBJECT_STORE_DIR, key) | ||||
|         pickle.dump(self.CONTENT, open(pathname, 'wb')) | ||||
|         remove_oldest_files(OBJECT_STORE_DIR, MAX_FILES) | ||||
|         self.headers['Location'] = reverse('stored-object', kwargs={'key':key}) | ||||
|         return Response(self.CONTENT, status=status.HTTP_201_CREATED) | ||||
|         url = reverse('stored-object', request, kwargs={'key':key}) | ||||
|         return Response(self.CONTENT, status.HTTP_201_CREATED, {'Location': url}) | ||||
| 
 | ||||
| 
 | ||||
| class StoredObject(View): | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| from djangorestframework.views import View | ||||
| from djangorestframework.response import Response | ||||
| from djangorestframework.permissions import PerUserThrottling, IsAuthenticated | ||||
| from django.core.urlresolvers import reverse | ||||
| from djangorestframework.utils import reverse | ||||
| 
 | ||||
| 
 | ||||
| class PermissionsExampleView(View): | ||||
|  | @ -13,11 +13,11 @@ class PermissionsExampleView(View): | |||
|         return Response([ | ||||
|             { | ||||
|                 'name': 'Throttling Example', | ||||
|                 'url': reverse('throttled-resource') | ||||
|                 'url': reverse('throttled-resource', request) | ||||
|             }, | ||||
|             { | ||||
|                 'name': 'Logged in example', | ||||
|                 'url': reverse('loggedin-resource') | ||||
|                 'url': reverse('loggedin-resource', request) | ||||
|             }, | ||||
|         ]) | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,10 +1,10 @@ | |||
| from __future__ import with_statement  # for python 2.5 | ||||
| from django.conf import settings | ||||
| from django.core.urlresolvers import reverse | ||||
| 
 | ||||
| from djangorestframework.resources import FormResource | ||||
| from djangorestframework.response import Response | ||||
| from djangorestframework.renderers import BaseRenderer | ||||
| from djangorestframework.utils import reverse | ||||
| from djangorestframework.views import View | ||||
| from djangorestframework import status | ||||
| 
 | ||||
|  | @ -61,7 +61,7 @@ class PygmentsRoot(View): | |||
|         Return a list of all currently existing snippets. | ||||
|         """ | ||||
|         unique_ids = [os.path.split(f)[1] for f in list_dir_sorted_by_ctime(HIGHLIGHTED_CODE_DIR)] | ||||
|         return Response([reverse('pygments-instance', args=[unique_id]) for unique_id in unique_ids]) | ||||
|         return Response([reverse('pygments-instance', request, args=[unique_id]) for unique_id in unique_ids]) | ||||
| 
 | ||||
|     def post(self, request): | ||||
|         """ | ||||
|  | @ -81,8 +81,8 @@ class PygmentsRoot(View): | |||
| 
 | ||||
|         remove_oldest_files(HIGHLIGHTED_CODE_DIR, MAX_FILES) | ||||
| 
 | ||||
|         self.headers['Location'] = reverse('pygments-instance', args=[unique_id]) | ||||
|         return Response(status=status.HTTP_201_CREATED) | ||||
|         location = reverse('pygments-instance', request, args=[unique_id]) | ||||
|         return Response(status=status.HTTP_201_CREATED, headers={'Location': location}) | ||||
| 
 | ||||
| 
 | ||||
| class PygmentsInstance(View): | ||||
|  | @ -98,7 +98,7 @@ class PygmentsInstance(View): | |||
|         """ | ||||
|         pathname = os.path.join(HIGHLIGHTED_CODE_DIR, unique_id) | ||||
|         if not os.path.exists(pathname): | ||||
|             return Response(status.HTTP_404_NOT_FOUND) | ||||
|             return Response(status=status.HTTP_404_NOT_FOUND) | ||||
|         return Response(open(pathname, 'r').read()) | ||||
| 
 | ||||
|     def delete(self, request, unique_id): | ||||
|  | @ -107,6 +107,7 @@ class PygmentsInstance(View): | |||
|         """ | ||||
|         pathname = os.path.join(HIGHLIGHTED_CODE_DIR, unique_id) | ||||
|         if not os.path.exists(pathname): | ||||
|             return Response(status.HTTP_404_NOT_FOUND) | ||||
|         return Response(os.remove(pathname)) | ||||
|             return Response(status=status.HTTP_404_NOT_FOUND) | ||||
|         os.remove(pathname) | ||||
|         return Response() | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,4 @@ | |||
| from django.core.urlresolvers import reverse | ||||
| 
 | ||||
| from djangorestframework.utils import reverse | ||||
| from djangorestframework.views import View | ||||
| from djangorestframework.response import Response | ||||
| from djangorestframework import status | ||||
|  | @ -14,9 +13,12 @@ class ExampleView(View): | |||
| 
 | ||||
|     def get(self, request): | ||||
|         """ | ||||
|         Handle GET requests, returning a list of URLs pointing to 3 other views. | ||||
|         Handle GET requests, returning a list of URLs pointing to | ||||
|         three other views. | ||||
|         """ | ||||
|         return Response({"Some other resources": [reverse('another-example', kwargs={'num':num}) for num in range(3)]}) | ||||
|         urls = [reverse('another-example', request, kwargs={'num': num}) | ||||
|                 for num in range(3)] | ||||
|         return Response({"Some other resources": urls}) | ||||
| 
 | ||||
| 
 | ||||
| class AnotherExampleView(View): | ||||
|  | @ -32,7 +34,7 @@ class AnotherExampleView(View): | |||
|         Returns a simple string indicating which view the GET request was for. | ||||
|         """ | ||||
|         if int(num) > 2: | ||||
|             return Response(status.HTTP_404_NOT_FOUND) | ||||
|             return Response(status=status.HTTP_404_NOT_FOUND) | ||||
|         return Response("GET request to AnotherExampleResource %s" % num) | ||||
| 
 | ||||
|     def post(self, request, num): | ||||
|  | @ -41,5 +43,5 @@ class AnotherExampleView(View): | |||
|         Returns a simple string indicating what content was supplied. | ||||
|         """ | ||||
|         if int(num) > 2: | ||||
|             return Response(status.HTTP_404_NOT_FOUND) | ||||
|             return Response(status=status.HTTP_404_NOT_FOUND) | ||||
|         return Response("POST request to AnotherExampleResource %s, with content: %s" % (num, repr(self.CONTENT))) | ||||
|  |  | |||
|  | @ -1,40 +1,67 @@ | |||
| """The root view for the examples provided with Django REST framework""" | ||||
| 
 | ||||
| from django.core.urlresolvers import reverse | ||||
| from djangorestframework.utils import reverse | ||||
| from djangorestframework.views import View | ||||
| from djangorestframework.response import Response | ||||
| 
 | ||||
| 
 | ||||
| class Sandbox(View): | ||||
|     """This is the sandbox for the examples provided with [Django REST framework](http://django-rest-framework.org). | ||||
|     """ | ||||
|     This is the sandbox for the examples provided with | ||||
|     [Django REST framework][1]. | ||||
| 
 | ||||
|     These examples are provided to help you get a better idea of some of the features of RESTful APIs created using the framework. | ||||
|     These examples are provided to help you get a better idea of some of the | ||||
|     features of RESTful APIs created using the framework. | ||||
| 
 | ||||
|     All the example APIs allow anonymous access, and can be navigated either through the browser or from the command line... | ||||
|     All the example APIs allow anonymous access, and can be navigated either | ||||
|     through the browser or from the command line. | ||||
| 
 | ||||
|         bash: curl -X GET http://api.django-rest-framework.org/                           # (Use default renderer) | ||||
|         bash: curl -X GET http://api.django-rest-framework.org/ -H 'Accept: text/plain'   # (Use plaintext documentation renderer) | ||||
|     For example, to get the default representation using curl: | ||||
| 
 | ||||
|         bash: curl -X GET http://rest.ep.io/ | ||||
|      | ||||
|     Or, to get the plaintext documentation represention: | ||||
| 
 | ||||
|         bash: curl -X GET http://rest.ep.io/ -H 'Accept: text/plain' | ||||
| 
 | ||||
|     The examples provided: | ||||
| 
 | ||||
|     1. A basic example using the [Resource](http://django-rest-framework.org/library/resource.html) class. | ||||
|     2. A basic example using the [ModelResource](http://django-rest-framework.org/library/modelresource.html) class. | ||||
|     3. An basic example using Django 1.3's [class based views](http://docs.djangoproject.com/en/dev/topics/class-based-views/) and djangorestframework's [RendererMixin](http://django-rest-framework.org/library/renderers.html). | ||||
|     1. A basic example using the [Resource][2] class. | ||||
|     2. A basic example using the [ModelResource][3] class. | ||||
|     3. An basic example using Django 1.3's [class based views][4] and | ||||
|        djangorestframework's [RendererMixin][5]. | ||||
|     4. A generic object store API. | ||||
|     5. A code highlighting API. | ||||
|     6. A blog posts and comments API. | ||||
|     7. A basic example using permissions. | ||||
|     8. A basic example using enhanced request. | ||||
| 
 | ||||
|     Please feel free to browse, create, edit and delete the resources in these examples.""" | ||||
|     Please feel free to browse, create, edit and delete the resources in | ||||
|     these examples. | ||||
| 
 | ||||
|     [1]: http://django-rest-framework.org | ||||
|     [2]: http://django-rest-framework.org/library/resource.html | ||||
|     [3]: http://django-rest-framework.org/library/modelresource.html | ||||
|     [4]: http://docs.djangoproject.com/en/dev/topics/class-based-views/ | ||||
|     [5]: http://django-rest-framework.org/library/renderers.html | ||||
|     """ | ||||
| 
 | ||||
|     def get(self, request): | ||||
|         return Response([{'name': 'Simple Resource example', 'url': reverse('example-resource')}, | ||||
|                 {'name': 'Simple ModelResource example', 'url': reverse('model-resource-root')}, | ||||
|                 {'name': 'Simple Mixin-only example', 'url': reverse('mixin-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('permissions-example')}, | ||||
|                 {'name': 'Simple request mixin example', 'url': reverse('request-example')} | ||||
|                 ]) | ||||
|         return Response([ | ||||
|             {'name': 'Simple Resource example', | ||||
|              'url': reverse('example-resource', request)}, | ||||
|             {'name': 'Simple ModelResource example', | ||||
|              'url': reverse('model-resource-root', request)}, | ||||
|             {'name': 'Simple Mixin-only example', | ||||
|              'url': reverse('mixin-view', request)}, | ||||
|             {'name': 'Object store API' | ||||
|              'url': reverse('object-store-root', request)}, | ||||
|             {'name': 'Code highlighting API', | ||||
|              'url': reverse('pygments-root', request)}, | ||||
|             {'name': 'Blog posts API', | ||||
|              'url': reverse('blog-posts-root', request)}, | ||||
|             {'name': 'Permissions example', | ||||
|              'url': reverse('permissions-example', request)}, | ||||
|             {'name': 'Simple request mixin example', | ||||
|              'url': reverse('request-example', request)} | ||||
|         ]) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user