mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-07-24 23:19:47 +03:00
changed implementation - Mixin Style
changed naming of class attributes to be more explicit
This commit is contained in:
parent
a873fef36b
commit
b98bff30f9
|
@ -213,3 +213,23 @@ class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,
|
||||||
|
|
||||||
def delete(self, request, *args, **kwargs):
|
def delete(self, request, *args, **kwargs):
|
||||||
return self.destroy(request, *args, **kwargs)
|
return self.destroy(request, *args, **kwargs)
|
||||||
|
|
||||||
|
class RedirectAPIView(mixins.RedirectMixin,
|
||||||
|
GenericAPIView):
|
||||||
|
"""
|
||||||
|
Redirect View used to redirect requests to a different/moved endpoint
|
||||||
|
"""
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
return self.redirect(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
return self.redirect(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def options(self, request, *args, **kwargs):
|
||||||
|
return self.redirect(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def delete(self, request, *args, **kwargs):
|
||||||
|
return self.redirect(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def put(self, request, *args, **kwargs):
|
||||||
|
return self.redirect(request, *args, **kwargs)
|
|
@ -7,6 +7,7 @@ which allows mixin classes to be composed in interesting ways.
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.reverse import reverse
|
||||||
|
|
||||||
|
|
||||||
class CreateModelMixin(object):
|
class CreateModelMixin(object):
|
||||||
|
@ -123,3 +124,42 @@ class DestroyModelMixin(object):
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
self.object.delete()
|
self.object.delete()
|
||||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||||
|
|
||||||
|
class RedirectMixin(object):
|
||||||
|
"""
|
||||||
|
A Mixin that provides a redirect method,
|
||||||
|
redirecting to a different resource endpoint
|
||||||
|
"""
|
||||||
|
redirect_permanent = True
|
||||||
|
redirect_with_query_string = True
|
||||||
|
redirect_to_view_name = None
|
||||||
|
redirect_to_url = None
|
||||||
|
|
||||||
|
def get_redirect_url(self, request, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Returning where to redirect to.
|
||||||
|
To url, view-name or nowhere
|
||||||
|
"""
|
||||||
|
if self.redirect_to_url:
|
||||||
|
url = self.redirect_to_url % kwargs
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
url = reverse(self.redirect_view_name, args=args, kwargs=kwargs, request=request)
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
query_string = self.request.META.get('QUERY_STRING', '')
|
||||||
|
if query_string and self.redirect_with_query_string:
|
||||||
|
url = '%(url)s?%(query_string)s' % {'url': url, 'query_string': query_string}
|
||||||
|
return url
|
||||||
|
|
||||||
|
def redirect(self, request, *args, **kwargs):
|
||||||
|
url = self.get_redirect_url(request, *args, **kwargs)
|
||||||
|
if url:
|
||||||
|
headers = {'Location': url}
|
||||||
|
if self.redirect_permanent:
|
||||||
|
return Response(status=status.HTTP_301_MOVED_PERMANENTLY, headers=headers)
|
||||||
|
else:
|
||||||
|
return Response(status=status.HTTP_302_FOUND, headers=headers)
|
||||||
|
else:
|
||||||
|
return Response(status=status.HTTP_410_GONE)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
from django.conf.urls.defaults import patterns, url
|
||||||
from django.test.client import RequestFactory
|
from django.test.client import RequestFactory
|
||||||
from django.utils import simplejson as json
|
from django.utils import simplejson as json
|
||||||
from rest_framework import generics, serializers, status
|
from rest_framework import generics, serializers, status
|
||||||
|
@ -14,13 +15,19 @@ class RootView(generics.ListCreateAPIView):
|
||||||
"""
|
"""
|
||||||
model = BasicModel
|
model = BasicModel
|
||||||
|
|
||||||
|
|
||||||
class InstanceView(generics.RetrieveUpdateDestroyAPIView):
|
class InstanceView(generics.RetrieveUpdateDestroyAPIView):
|
||||||
"""
|
"""
|
||||||
Example description for OPTIONS.
|
Example description for OPTIONS.
|
||||||
"""
|
"""
|
||||||
model = BasicModel
|
model = BasicModel
|
||||||
|
|
||||||
|
class RedirectToRootView(generics.RedirectAPIView):
|
||||||
|
redirect_permanent = False
|
||||||
|
redirect_view_name = 'root-view'
|
||||||
|
|
||||||
|
class RedirectToURL(generics.RedirectAPIView):
|
||||||
|
redirect_to_url = 'http://foo.bar'
|
||||||
|
redirect_with_query_string = False
|
||||||
|
|
||||||
class SlugSerializer(serializers.ModelSerializer):
|
class SlugSerializer(serializers.ModelSerializer):
|
||||||
slug = serializers.Field() # read only
|
slug = serializers.Field() # read only
|
||||||
|
@ -38,6 +45,10 @@ class SlugBasedInstanceView(InstanceView):
|
||||||
serializer_class = SlugSerializer
|
serializer_class = SlugSerializer
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = patterns('',
|
||||||
|
url(r'^root/$', RootView.as_view(), name='root-view'),
|
||||||
|
)
|
||||||
|
|
||||||
class TestRootView(TestCase):
|
class TestRootView(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""
|
"""
|
||||||
|
@ -301,3 +312,28 @@ class TestCreateModelWithAutoNowAddField(TestCase):
|
||||||
self.assertEquals(response.status_code, status.HTTP_201_CREATED)
|
self.assertEquals(response.status_code, status.HTTP_201_CREATED)
|
||||||
created = self.objects.get(id=1)
|
created = self.objects.get(id=1)
|
||||||
self.assertEquals(created.content, 'foobar')
|
self.assertEquals(created.content, 'foobar')
|
||||||
|
|
||||||
|
class RedirectViewTests(TestCase):
|
||||||
|
urls = 'rest_framework.tests.generics'
|
||||||
|
|
||||||
|
def test_redirect(self):
|
||||||
|
request = factory.get('/redirect_to_root/?foo=bar')
|
||||||
|
response = RedirectToRootView.as_view()(request)
|
||||||
|
|
||||||
|
self.assertEquals(response.status_code, status.HTTP_302_FOUND)
|
||||||
|
self.assertEquals(response['Location'], 'http://testserver/root/?foo=bar')
|
||||||
|
|
||||||
|
def test_redirect_to_nowhere(self):
|
||||||
|
request = factory.get('/redirect_to_nowhere/')
|
||||||
|
response = generics.RedirectAPIView.as_view()(request)
|
||||||
|
|
||||||
|
self.assertEquals(response.status_code, status.HTTP_410_GONE)
|
||||||
|
|
||||||
|
def test_redirect_to_url(self):
|
||||||
|
request = factory.get('/redirect_to_url/?foo=bar')
|
||||||
|
response = RedirectToURL.as_view()(request)
|
||||||
|
|
||||||
|
self.assertEquals(response.status_code, status.HTTP_301_MOVED_PERMANENTLY)
|
||||||
|
self.assertEquals(response['Location'], 'http://foo.bar')
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
import copy
|
import copy
|
||||||
from django.conf.urls.defaults import patterns, url
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.test.client import RequestFactory
|
from django.test.client import RequestFactory
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.decorators import api_view
|
from rest_framework.decorators import api_view
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.settings import api_settings
|
from rest_framework.settings import api_settings
|
||||||
from rest_framework.views import APIView, RedirectAPIView
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
factory = RequestFactory()
|
factory = RequestFactory()
|
||||||
|
|
||||||
|
@ -18,16 +17,6 @@ class BasicView(APIView):
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
return Response({'method': 'POST', 'data': request.DATA})
|
return Response({'method': 'POST', 'data': request.DATA})
|
||||||
|
|
||||||
class RedirectBasicView(RedirectAPIView):
|
|
||||||
permanent = False
|
|
||||||
view_name = 'basic-view'
|
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
|
||||||
url(r'^basic/$', BasicView.as_view(), name='basic-view'),
|
|
||||||
url(r'^redirect_to_basic/$', RedirectBasicView.as_view(), name='old-basic-view'),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@api_view(['GET', 'POST', 'PUT'])
|
@api_view(['GET', 'POST', 'PUT'])
|
||||||
def basic_view(request):
|
def basic_view(request):
|
||||||
|
@ -105,17 +94,4 @@ class FunctionBasedViewIntegrationTests(TestCase):
|
||||||
'detail': u'JSON parse error - No JSON object could be decoded'
|
'detail': u'JSON parse error - No JSON object could be decoded'
|
||||||
}
|
}
|
||||||
self.assertEquals(response.status_code, status.HTTP_400_BAD_REQUEST)
|
self.assertEquals(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||||
self.assertEquals(sanitise_json_error(response.data), expected)
|
self.assertEquals(sanitise_json_error(response.data), expected)
|
||||||
|
|
||||||
class RedirectViewTests(TestCase):
|
|
||||||
urls = 'rest_framework.tests.views'
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.view = RedirectBasicView.as_view()
|
|
||||||
|
|
||||||
def test_redirect(self):
|
|
||||||
request = factory.get('/redirect_to_basic/?foo=bar', content_type='application/json')
|
|
||||||
response = self.view(request)
|
|
||||||
|
|
||||||
self.assertEquals(response.status_code, status.HTTP_302_FOUND)
|
|
||||||
self.assertEquals(response['Location'], 'http://testserver/basic/?foo=bar')
|
|
|
@ -13,7 +13,6 @@ from rest_framework.compat import View, apply_markdown
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from rest_framework.settings import api_settings
|
from rest_framework.settings import api_settings
|
||||||
from rest_framework.reverse import reverse
|
|
||||||
|
|
||||||
|
|
||||||
def _remove_trailing_string(content, trailing):
|
def _remove_trailing_string(content, trailing):
|
||||||
|
@ -372,53 +371,4 @@ class APIView(View):
|
||||||
We may as well implement this as Django will otherwise provide
|
We may as well implement this as Django will otherwise provide
|
||||||
a less useful default implementation.
|
a less useful default implementation.
|
||||||
"""
|
"""
|
||||||
return Response(self.metadata(request), status=status.HTTP_200_OK)
|
return Response(self.metadata(request), status=status.HTTP_200_OK)
|
||||||
|
|
||||||
class RedirectAPIView(APIView):
|
|
||||||
"""
|
|
||||||
A view that provides a redirect to a different resource endpoint
|
|
||||||
"""
|
|
||||||
permanent = True
|
|
||||||
view_name = None
|
|
||||||
|
|
||||||
def get_redirect_url(self, request, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
Return the URL redirect to. Arguments and Keyword arguments from the
|
|
||||||
URL pattern match generating the redirect request
|
|
||||||
are provided as kwargs to this method.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
url = reverse(self.view_name, args=args, kwargs=kwargs, request=request)
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
query_string = self.request.META.get('QUERY_STRING', '')
|
|
||||||
if query_string:
|
|
||||||
url = '%(url)s?%(query_string)s' % {'url': url, 'query_string': query_string}
|
|
||||||
return url
|
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
|
||||||
url = self.get_redirect_url(request, *args, **kwargs)
|
|
||||||
if url:
|
|
||||||
headers = {'Location': url}
|
|
||||||
if self.permanent:
|
|
||||||
return Response(status=status.HTTP_301_MOVED_PERMANENTLY, headers=headers)
|
|
||||||
else:
|
|
||||||
return Response(status=status.HTTP_302_FOUND, headers=headers)
|
|
||||||
else:
|
|
||||||
return Response(status=status.HTTP_410_GONE)
|
|
||||||
|
|
||||||
def head(self, request, *args, **kwargs):
|
|
||||||
return self.get(request, *args, **kwargs)
|
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
|
||||||
return self.get(request, *args, **kwargs)
|
|
||||||
|
|
||||||
def options(self, request, *args, **kwargs):
|
|
||||||
return self.get(request, *args, **kwargs)
|
|
||||||
|
|
||||||
def delete(self, request, *args, **kwargs):
|
|
||||||
return self.get(request, *args, **kwargs)
|
|
||||||
|
|
||||||
def put(self, request, *args, **kwargs):
|
|
||||||
return self.get(request, *args, **kwargs)
|
|
Loading…
Reference in New Issue
Block a user