mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-23 01:57:00 +03:00
Merge pull request #175 from izquierdo/custom_reverse
Custom reverse() and drop set_script_prefix
This commit is contained in:
commit
49ebaf106d
|
@ -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 ErrorResponse
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
@ -11,7 +11,7 @@ class MockView(View):
|
|||
permissions = ()
|
||||
|
||||
def get(self, request):
|
||||
return reverse('another')
|
||||
return 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
|
||||
|
@ -173,3 +174,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))
|
||||
|
|
|
@ -181,20 +181,12 @@ 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
|
||||
|
||||
def final(self, request, response, *args, **kargs):
|
||||
"""
|
||||
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.headers['Allow'] = ', '.join(self.allowed_methods)
|
||||
# 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
|
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(200, {'description': 'Some example content',
|
||||
'url': reverse('mixin-view')})
|
||||
'url': reverse('mixin-view', request)})
|
||||
return self.render(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 [reverse('stored-object', kwargs={'key':key}) for key in ctime_sorted_basenames]
|
||||
return [reverse('stored-object', request, kwargs={'key':key}) for key in ctime_sorted_basenames]
|
||||
|
||||
def post(self, request):
|
||||
"""
|
||||
|
@ -51,7 +51,7 @@ 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)
|
||||
return Response(status.HTTP_201_CREATED, self.CONTENT, {'Location': reverse('stored-object', kwargs={'key':key})})
|
||||
return Response(status.HTTP_201_CREATED, self.CONTENT, {'Location': reverse('stored-object', request, kwargs={'key':key})})
|
||||
|
||||
|
||||
class StoredObject(View):
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from djangorestframework.views import View
|
||||
from djangorestframework.permissions import PerUserThrottling, IsAuthenticated
|
||||
from django.core.urlresolvers import reverse
|
||||
from djangorestframework.utils import reverse
|
||||
|
||||
|
||||
class PermissionsExampleView(View):
|
||||
|
@ -12,11 +12,11 @@ class PermissionsExampleView(View):
|
|||
return [
|
||||
{
|
||||
'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 [reverse('pygments-instance', args=[unique_id]) for unique_id in unique_ids]
|
||||
return [reverse('pygments-instance', request, args=[unique_id]) for unique_id in unique_ids]
|
||||
|
||||
def post(self, request):
|
||||
"""
|
||||
|
@ -81,7 +81,7 @@ class PygmentsRoot(View):
|
|||
|
||||
remove_oldest_files(HIGHLIGHTED_CODE_DIR, MAX_FILES)
|
||||
|
||||
return Response(status.HTTP_201_CREATED, headers={'Location': reverse('pygments-instance', args=[unique_id])})
|
||||
return Response(status.HTTP_201_CREATED, headers={'Location': reverse('pygments-instance', request, args=[unique_id])})
|
||||
|
||||
|
||||
class PygmentsInstance(View):
|
||||
|
|
|
@ -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
|
||||
|
@ -16,7 +15,7 @@ class ExampleView(View):
|
|||
"""
|
||||
Handle GET requests, returning a list of URLs pointing to 3 other views.
|
||||
"""
|
||||
return {"Some other resources": [reverse('another-example', kwargs={'num':num}) for num in range(3)]}
|
||||
return {"Some other resources": [reverse('another-example', request, kwargs={'num':num}) for num in range(3)]}
|
||||
|
||||
|
||||
class AnotherExampleView(View):
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""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
|
||||
|
||||
|
||||
|
@ -27,11 +27,11 @@ class Sandbox(View):
|
|||
Please feel free to browse, create, edit and delete the resources in these examples."""
|
||||
|
||||
def get(self, request):
|
||||
return [{'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')}
|
||||
return [{'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)}
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue
Block a user