mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-07-24 23:19:47 +03:00
Merge ec29d44df3
into 50f4612404
This commit is contained in:
commit
c7d3469aea
|
@ -322,6 +322,7 @@ By default, `HyperlinkedRelatedField` is read-write, although you can change thi
|
||||||
* `pk_url_kwarg` - The named url parameter for the pk field lookup. Default is `pk`.
|
* `pk_url_kwarg` - The named url parameter for the pk field lookup. Default is `pk`.
|
||||||
* `slug_url_kwarg` - The named url parameter for the slug field lookup. Default is to use the same value as given for `slug_field`.
|
* `slug_url_kwarg` - The named url parameter for the slug field lookup. Default is to use the same value as given for `slug_field`.
|
||||||
* `null` - If set to `True`, the field will accept values of `None` or the emptystring for nullable relationships.
|
* `null` - If set to `True`, the field will accept values of `None` or the emptystring for nullable relationships.
|
||||||
|
* `use_absolute_urls` - This option will overwrite the serializer option `use_absolute_urls`.
|
||||||
|
|
||||||
## HyperLinkedIdentityField
|
## HyperLinkedIdentityField
|
||||||
|
|
||||||
|
|
|
@ -189,6 +189,14 @@ As an example, let's create a field that can be used represent the class name of
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
## Meta options
|
||||||
|
|
||||||
|
**TODO** add remaining serializer meta options
|
||||||
|
|
||||||
|
### `use_absolute_urls`
|
||||||
|
|
||||||
|
This setting will overwrite the `REST_FRAMEWORK` option `USE_ABSOLUTE_URLS` and can also be overwritten by the field attribute `use_absolute_urls`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# ModelSerializers
|
# ModelSerializers
|
||||||
|
|
|
@ -166,4 +166,10 @@ Default: `'format'`
|
||||||
|
|
||||||
Default: `'format'`
|
Default: `'format'`
|
||||||
|
|
||||||
|
## USE_ABSOLUTE_URLS
|
||||||
|
|
||||||
|
Default: `True`
|
||||||
|
|
||||||
|
This setting can overwritten by the serializer meta option `use_absolute_urls` which also can be overwritten by the field attribute `use_absolute_urls`.
|
||||||
|
|
||||||
[cite]: http://www.python.org/dev/peps/pep-0020/
|
[cite]: http://www.python.org/dev/peps/pep-0020/
|
||||||
|
|
|
@ -4,6 +4,11 @@
|
||||||
>
|
>
|
||||||
> — Eric S. Raymond, [The Cathedral and the Bazaar][cite].
|
> — Eric S. Raymond, [The Cathedral and the Bazaar][cite].
|
||||||
|
|
||||||
|
## Master
|
||||||
|
|
||||||
|
* Added support for absolute/relative url switching
|
||||||
|
* Bugfix: Fix absolute/relative url mix
|
||||||
|
|
||||||
## 2.1.9
|
## 2.1.9
|
||||||
|
|
||||||
**Date**: 11th Dec 2012
|
**Date**: 11th Dec 2012
|
||||||
|
|
|
@ -543,8 +543,14 @@ class HyperlinkedRelatedField(RelatedField):
|
||||||
self.slug_url_kwarg = kwargs.pop('slug_url_kwarg', default_slug_kwarg)
|
self.slug_url_kwarg = kwargs.pop('slug_url_kwarg', default_slug_kwarg)
|
||||||
|
|
||||||
self.format = kwargs.pop('format', None)
|
self.format = kwargs.pop('format', None)
|
||||||
|
|
||||||
|
self.use_absolute_urls = kwargs.pop('use_absolute_urls', None)
|
||||||
super(HyperlinkedRelatedField, self).__init__(*args, **kwargs)
|
super(HyperlinkedRelatedField, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def initialize(self, parent, field_name):
|
||||||
|
super(HyperlinkedRelatedField, self).initialize(parent, field_name)
|
||||||
|
self.use_absolute_urls = self.use_absolute_urls or self.parent.use_absolute_urls
|
||||||
|
|
||||||
def get_slug_field(self):
|
def get_slug_field(self):
|
||||||
"""
|
"""
|
||||||
Get the name of a slug field to be used to look up by slug.
|
Get the name of a slug field to be used to look up by slug.
|
||||||
|
@ -555,12 +561,13 @@ class HyperlinkedRelatedField(RelatedField):
|
||||||
view_name = self.view_name
|
view_name = self.view_name
|
||||||
request = self.context.get('request', None)
|
request = self.context.get('request', None)
|
||||||
format = self.format or self.context.get('format', None)
|
format = self.format or self.context.get('format', None)
|
||||||
|
use_absolute_urls = self.use_absolute_urls
|
||||||
pk = getattr(obj, 'pk', None)
|
pk = getattr(obj, 'pk', None)
|
||||||
if pk is None:
|
if pk is None:
|
||||||
return
|
return
|
||||||
kwargs = {self.pk_url_kwarg: pk}
|
kwargs = {self.pk_url_kwarg: pk}
|
||||||
try:
|
try:
|
||||||
return reverse(view_name, kwargs=kwargs, request=request, format=format)
|
return reverse(view_name, kwargs=kwargs, request=request, format=format, use_absolute_urls=use_absolute_urls)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -571,13 +578,13 @@ class HyperlinkedRelatedField(RelatedField):
|
||||||
|
|
||||||
kwargs = {self.slug_url_kwarg: slug}
|
kwargs = {self.slug_url_kwarg: slug}
|
||||||
try:
|
try:
|
||||||
return reverse(self.view_name, kwargs=kwargs, request=request, format=format)
|
return reverse(self.view_name, kwargs=kwargs, request=request, format=format, use_absolute_urls=use_absolute_urls)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
kwargs = {self.pk_url_kwarg: obj.pk, self.slug_url_kwarg: slug}
|
kwargs = {self.pk_url_kwarg: obj.pk, self.slug_url_kwarg: slug}
|
||||||
try:
|
try:
|
||||||
return reverse(self.view_name, kwargs=kwargs, request=request, format=format)
|
return reverse(self.view_name, kwargs=kwargs, request=request, format=format, use_absolute_urls=use_absolute_urls)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -651,15 +658,21 @@ class HyperlinkedIdentityField(Field):
|
||||||
self.pk_url_kwarg = kwargs.pop('pk_url_kwarg', self.pk_url_kwarg)
|
self.pk_url_kwarg = kwargs.pop('pk_url_kwarg', self.pk_url_kwarg)
|
||||||
self.slug_url_kwarg = kwargs.pop('slug_url_kwarg', default_slug_kwarg)
|
self.slug_url_kwarg = kwargs.pop('slug_url_kwarg', default_slug_kwarg)
|
||||||
|
|
||||||
|
self.use_absolute_urls = kwargs.pop('use_absolute_urls', None)
|
||||||
super(HyperlinkedIdentityField, self).__init__(*args, **kwargs)
|
super(HyperlinkedIdentityField, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def initialize(self, parent, field_name):
|
||||||
|
super(HyperlinkedIdentityField, self).initialize(parent, field_name)
|
||||||
|
self.use_absolute_urls = self.use_absolute_urls or self.parent.use_absolute_urls
|
||||||
|
|
||||||
def field_to_native(self, obj, field_name):
|
def field_to_native(self, obj, field_name):
|
||||||
request = self.context.get('request', None)
|
request = self.context.get('request', None)
|
||||||
format = self.format or self.context.get('format', None)
|
format = self.format or self.context.get('format', None)
|
||||||
view_name = self.view_name or self.parent.opts.view_name
|
view_name = self.view_name or self.parent.opts.view_name
|
||||||
kwargs = {self.pk_url_kwarg: obj.pk}
|
kwargs = {self.pk_url_kwarg: obj.pk}
|
||||||
|
use_absolute_urls = self.use_absolute_urls
|
||||||
try:
|
try:
|
||||||
return reverse(view_name, kwargs=kwargs, request=request, format=format)
|
return reverse(view_name, kwargs=kwargs, request=request, format=format, use_absolute_urls=use_absolute_urls)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -670,13 +683,13 @@ class HyperlinkedIdentityField(Field):
|
||||||
|
|
||||||
kwargs = {self.slug_url_kwarg: slug}
|
kwargs = {self.slug_url_kwarg: slug}
|
||||||
try:
|
try:
|
||||||
return reverse(self.view_name, kwargs=kwargs, request=request, format=format)
|
return reverse(self.view_name, kwargs=kwargs, request=request, format=format, use_absolute_urls=use_absolute_urls)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
kwargs = {self.pk_url_kwarg: obj.pk, self.slug_url_kwarg: slug}
|
kwargs = {self.pk_url_kwarg: obj.pk, self.slug_url_kwarg: slug}
|
||||||
try:
|
try:
|
||||||
return reverse(self.view_name, kwargs=kwargs, request=request, format=format)
|
return reverse(self.view_name, kwargs=kwargs, request=request, format=format, use_absolute_urls=use_absolute_urls)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,11 @@ class NextPageField(serializers.Field):
|
||||||
return None
|
return None
|
||||||
page = value.next_page_number()
|
page = value.next_page_number()
|
||||||
request = self.context.get('request')
|
request = self.context.get('request')
|
||||||
url = request and request.build_absolute_uri() or ''
|
if self.parent.use_absolute_urls:
|
||||||
|
assert request, "request is required for building absolute url"
|
||||||
|
url = request.build_absolute_uri()
|
||||||
|
else:
|
||||||
|
url = request and request.get_full_path() or ''
|
||||||
return replace_query_param(url, self.page_field, page)
|
return replace_query_param(url, self.page_field, page)
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,7 +34,11 @@ class PreviousPageField(serializers.Field):
|
||||||
return None
|
return None
|
||||||
page = value.previous_page_number()
|
page = value.previous_page_number()
|
||||||
request = self.context.get('request')
|
request = self.context.get('request')
|
||||||
url = request and request.build_absolute_uri() or ''
|
if self.parent.use_absolute_urls:
|
||||||
|
assert request, "request is required for building absolute url"
|
||||||
|
url = request.build_absolute_uri()
|
||||||
|
else:
|
||||||
|
url = request and request.get_full_path() or ''
|
||||||
return replace_query_param(url, self.page_field, page)
|
return replace_query_param(url, self.page_field, page)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,10 @@ Provide reverse functions that return fully qualified URLs
|
||||||
"""
|
"""
|
||||||
from django.core.urlresolvers import reverse as django_reverse
|
from django.core.urlresolvers import reverse as django_reverse
|
||||||
from django.utils.functional import lazy
|
from django.utils.functional import lazy
|
||||||
|
from rest_framework.settings import api_settings
|
||||||
|
|
||||||
|
|
||||||
def reverse(viewname, args=None, kwargs=None, request=None, format=None, **extra):
|
def reverse(viewname, args=None, kwargs=None, request=None, format=None, use_absolute_urls=api_settings.USE_ABSOLUTE_URLS, **extra):
|
||||||
"""
|
"""
|
||||||
Same as `django.core.urlresolvers.reverse`, but optionally takes a request
|
Same as `django.core.urlresolvers.reverse`, but optionally takes a request
|
||||||
and returns a fully qualified URL, using the request to get the base URL.
|
and returns a fully qualified URL, using the request to get the base URL.
|
||||||
|
@ -14,8 +15,9 @@ def reverse(viewname, args=None, kwargs=None, request=None, format=None, **extra
|
||||||
kwargs = kwargs or {}
|
kwargs = kwargs or {}
|
||||||
kwargs['format'] = format
|
kwargs['format'] = format
|
||||||
url = django_reverse(viewname, args=args, kwargs=kwargs, **extra)
|
url = django_reverse(viewname, args=args, kwargs=kwargs, **extra)
|
||||||
if request:
|
if use_absolute_urls:
|
||||||
return request.build_absolute_uri(url)
|
assert request, "request is required for building absolute url"
|
||||||
|
url = request.build_absolute_uri(url)
|
||||||
return url
|
return url
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ from rest_framework.compat import get_concrete_model
|
||||||
|
|
||||||
|
|
||||||
from rest_framework.fields import *
|
from rest_framework.fields import *
|
||||||
|
from rest_framework.settings import api_settings
|
||||||
|
|
||||||
|
|
||||||
class DictWithMetadata(dict):
|
class DictWithMetadata(dict):
|
||||||
|
@ -91,6 +92,7 @@ class SerializerOptions(object):
|
||||||
self.depth = getattr(meta, 'depth', 0)
|
self.depth = getattr(meta, 'depth', 0)
|
||||||
self.fields = getattr(meta, 'fields', ())
|
self.fields = getattr(meta, 'fields', ())
|
||||||
self.exclude = getattr(meta, 'exclude', ())
|
self.exclude = getattr(meta, 'exclude', ())
|
||||||
|
self.use_absolute_urls = getattr(meta, 'use_absolute_urls', api_settings.USE_ABSOLUTE_URLS)
|
||||||
|
|
||||||
|
|
||||||
class BaseSerializer(Field):
|
class BaseSerializer(Field):
|
||||||
|
@ -101,12 +103,13 @@ class BaseSerializer(Field):
|
||||||
_dict_class = SortedDictWithMetadata # Set to unsorted dict for backwards compatibility with unsorted implementations.
|
_dict_class = SortedDictWithMetadata # Set to unsorted dict for backwards compatibility with unsorted implementations.
|
||||||
|
|
||||||
def __init__(self, instance=None, data=None, files=None,
|
def __init__(self, instance=None, data=None, files=None,
|
||||||
context=None, partial=False, **kwargs):
|
context=None, partial=False, use_absolute_urls=None, **kwargs):
|
||||||
super(BaseSerializer, self).__init__(**kwargs)
|
super(BaseSerializer, self).__init__(**kwargs)
|
||||||
self.opts = self._options_class(self.Meta)
|
self.opts = self._options_class(self.Meta)
|
||||||
self.parent = None
|
self.parent = None
|
||||||
self.root = None
|
self.root = None
|
||||||
self.partial = partial
|
self.partial = partial
|
||||||
|
self.use_absolute_urls = use_absolute_urls if use_absolute_urls is not None else self.opts.use_absolute_urls
|
||||||
|
|
||||||
self.context = context or {}
|
self.context = context or {}
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,8 @@ DEFAULTS = {
|
||||||
'URL_FORMAT_OVERRIDE': 'format',
|
'URL_FORMAT_OVERRIDE': 'format',
|
||||||
|
|
||||||
'FORMAT_SUFFIX_KWARG': 'format',
|
'FORMAT_SUFFIX_KWARG': 'format',
|
||||||
|
|
||||||
|
'USE_ABSOLUTE_URLS': True,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,14 @@ class PhotoSerializer(serializers.Serializer):
|
||||||
return Photo(**attrs)
|
return Photo(**attrs)
|
||||||
|
|
||||||
|
|
||||||
|
class PhotoUrlSerializer(PhotoSerializer):
|
||||||
|
url = serializers.HyperlinkedIdentityField(view_name='photoswithmixedurls-detail', use_absolute_urls=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Photo
|
||||||
|
use_absolute_urls = False
|
||||||
|
|
||||||
|
|
||||||
class BasicList(generics.ListCreateAPIView):
|
class BasicList(generics.ListCreateAPIView):
|
||||||
model = BasicModel
|
model = BasicModel
|
||||||
model_serializer_class = serializers.HyperlinkedModelSerializer
|
model_serializer_class = serializers.HyperlinkedModelSerializer
|
||||||
|
@ -74,6 +82,16 @@ class AlbumDetail(generics.RetrieveAPIView):
|
||||||
model = Album
|
model = Album
|
||||||
|
|
||||||
|
|
||||||
|
class PhotoUrlList(generics.ListAPIView):
|
||||||
|
model = Photo
|
||||||
|
serializer_class = PhotoUrlSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class PhotoUrlDetail(generics.RetrieveAPIView):
|
||||||
|
model = Photo
|
||||||
|
serializer_class = PhotoUrlSerializer
|
||||||
|
|
||||||
|
|
||||||
class OptionalRelationDetail(generics.RetrieveUpdateDestroyAPIView):
|
class OptionalRelationDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||||
model = OptionalRelationModel
|
model = OptionalRelationModel
|
||||||
model_serializer_class = serializers.HyperlinkedModelSerializer
|
model_serializer_class = serializers.HyperlinkedModelSerializer
|
||||||
|
@ -90,6 +108,8 @@ urlpatterns = patterns('',
|
||||||
url(r'^comments/(?P<pk>\d+)/$', BlogPostCommentDetail.as_view(), name='blogpostcomment-detail'),
|
url(r'^comments/(?P<pk>\d+)/$', BlogPostCommentDetail.as_view(), name='blogpostcomment-detail'),
|
||||||
url(r'^albums/(?P<title>\w[\w-]*)/$', AlbumDetail.as_view(), name='album-detail'),
|
url(r'^albums/(?P<title>\w[\w-]*)/$', AlbumDetail.as_view(), name='album-detail'),
|
||||||
url(r'^photos/$', PhotoListCreate.as_view(), name='photo-list'),
|
url(r'^photos/$', PhotoListCreate.as_view(), name='photo-list'),
|
||||||
|
url(r'^photos-with-mixed-urls/$', PhotoUrlList.as_view(), name='photoswithmixedurls-list'),
|
||||||
|
url(r'^photos-with-mixed-urls/(?P<pk>\d+)/$', PhotoUrlDetail.as_view(), name='photoswithmixedurls-detail'),
|
||||||
url(r'^optionalrelation/(?P<pk>\d+)/$', OptionalRelationDetail.as_view(), name='optionalrelationmodel-detail'),
|
url(r'^optionalrelation/(?P<pk>\d+)/$', OptionalRelationDetail.as_view(), name='optionalrelationmodel-detail'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -260,3 +280,47 @@ class TestOptionalRelationHyperlinkedView(TestCase):
|
||||||
data=json.dumps(self.data),
|
data=json.dumps(self.data),
|
||||||
content_type='application/json')
|
content_type='application/json')
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
|
|
||||||
|
class TestUrlOptionsView(TestCase):
|
||||||
|
urls = 'rest_framework.tests.hyperlinkedserializers'
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
"""
|
||||||
|
Create a album and photos
|
||||||
|
"""
|
||||||
|
self.album = Album.objects.create(title="test-album")
|
||||||
|
items = ['beach', 'sunset', 'moon']
|
||||||
|
for item in items:
|
||||||
|
Photo(description=item, album=self.album).save()
|
||||||
|
self.objects = Photo.objects
|
||||||
|
self.data = [
|
||||||
|
{
|
||||||
|
'url': 'http://testserver/photos-with-mixed-urls/%d/' % obj.id,
|
||||||
|
'description': obj.description,
|
||||||
|
'album_url': '/albums/%s/' % obj.album.title
|
||||||
|
}
|
||||||
|
for obj in self.objects.all()
|
||||||
|
]
|
||||||
|
self.list_view = PhotoUrlList.as_view()
|
||||||
|
self.detail_view = PhotoUrlDetail.as_view()
|
||||||
|
|
||||||
|
def test_get_list_view(self):
|
||||||
|
"""
|
||||||
|
GET requests to RetrieveAPIView with optional relations should return None
|
||||||
|
for non existing relations.
|
||||||
|
"""
|
||||||
|
request = factory.get('/photos-with-mixed-urls/')
|
||||||
|
response = self.list_view(request)
|
||||||
|
self.assertEquals(response.status_code, status.HTTP_200_OK)
|
||||||
|
self.assertEquals(response.data, self.data[:])
|
||||||
|
|
||||||
|
def test_get_detail_view(self):
|
||||||
|
"""
|
||||||
|
GET requests to RetrieveAPIView with optional relations should return None
|
||||||
|
for non existing relations.
|
||||||
|
"""
|
||||||
|
request = factory.get('/photos-with-mixed-urls/1/')
|
||||||
|
response = self.detail_view(request, pk=1)
|
||||||
|
self.assertEquals(response.status_code, status.HTTP_200_OK)
|
||||||
|
self.assertEquals(response.data, self.data[0])
|
|
@ -4,7 +4,7 @@ from django.core.paginator import Paginator
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.test.client import RequestFactory
|
from django.test.client import RequestFactory
|
||||||
from django.utils import unittest
|
from django.utils import unittest
|
||||||
from rest_framework import generics, status, pagination, filters
|
from rest_framework import generics, status, pagination, filters, serializers
|
||||||
from rest_framework.compat import django_filters
|
from rest_framework.compat import django_filters
|
||||||
from rest_framework.tests.models import BasicModel, FilterableItem
|
from rest_framework.tests.models import BasicModel, FilterableItem
|
||||||
|
|
||||||
|
@ -34,6 +34,23 @@ if django_filters:
|
||||||
filter_backend = filters.DjangoFilterBackend
|
filter_backend = filters.DjangoFilterBackend
|
||||||
|
|
||||||
|
|
||||||
|
class AbsoluteUrlsSerializer(serializers.ModelSerializer):
|
||||||
|
"""
|
||||||
|
Serializer for testing absolute urls
|
||||||
|
"""
|
||||||
|
class Meta:
|
||||||
|
use_absolute_urls = True
|
||||||
|
|
||||||
|
|
||||||
|
class AbsoluteUrlsView(generics.ListAPIView):
|
||||||
|
"""
|
||||||
|
View for testing absolute urls
|
||||||
|
"""
|
||||||
|
model = BasicModel
|
||||||
|
paginate_by = 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DefaultPageSizeKwargView(generics.ListAPIView):
|
class DefaultPageSizeKwargView(generics.ListAPIView):
|
||||||
"""
|
"""
|
||||||
View for testing default paginate_by_param usage
|
View for testing default paginate_by_param usage
|
||||||
|
@ -160,19 +177,59 @@ class UnitTestPagination(TestCase):
|
||||||
self.last_page = paginator.page(3)
|
self.last_page = paginator.page(3)
|
||||||
|
|
||||||
def test_native_pagination(self):
|
def test_native_pagination(self):
|
||||||
serializer = pagination.PaginationSerializer(self.first_page)
|
serializer = pagination.PaginationSerializer(self.first_page, use_absolute_urls=False)
|
||||||
self.assertEquals(serializer.data['count'], 26)
|
self.assertEquals(serializer.data['count'], 26)
|
||||||
self.assertEquals(serializer.data['next'], '?page=2')
|
self.assertEquals(serializer.data['next'], '?page=2')
|
||||||
self.assertEquals(serializer.data['previous'], None)
|
self.assertEquals(serializer.data['previous'], None)
|
||||||
self.assertEquals(serializer.data['results'], self.objects[:10])
|
self.assertEquals(serializer.data['results'], self.objects[:10])
|
||||||
|
|
||||||
serializer = pagination.PaginationSerializer(self.last_page)
|
serializer = pagination.PaginationSerializer(self.last_page, use_absolute_urls=False)
|
||||||
self.assertEquals(serializer.data['count'], 26)
|
self.assertEquals(serializer.data['count'], 26)
|
||||||
self.assertEquals(serializer.data['next'], None)
|
self.assertEquals(serializer.data['next'], None)
|
||||||
self.assertEquals(serializer.data['previous'], '?page=2')
|
self.assertEquals(serializer.data['previous'], '?page=2')
|
||||||
self.assertEquals(serializer.data['results'], self.objects[20:])
|
self.assertEquals(serializer.data['results'], self.objects[20:])
|
||||||
|
|
||||||
|
|
||||||
|
class TestPaginationWithAbsoluteUrls(TestCase):
|
||||||
|
"""
|
||||||
|
Tests for using absolute urls
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
items = ['foo', 'bar', 'baz']
|
||||||
|
for item in items:
|
||||||
|
BasicModel(text=item).save()
|
||||||
|
self.objects = BasicModel.objects
|
||||||
|
self.data = [
|
||||||
|
{'id': obj.id, 'text': obj.text}
|
||||||
|
for obj in self.objects.all()
|
||||||
|
]
|
||||||
|
self.view = AbsoluteUrlsView.as_view()
|
||||||
|
|
||||||
|
def test_paginated_root_view_urls(self):
|
||||||
|
"""
|
||||||
|
Tests absolute/relative url switch
|
||||||
|
"""
|
||||||
|
request = factory.get('/')
|
||||||
|
response = self.view(request).render()
|
||||||
|
self.assertEquals(response.data['count'], 3)
|
||||||
|
self.assertEquals(response.data['next'], 'http://testserver/?page=2')
|
||||||
|
self.assertEquals(response.data['previous'], None)
|
||||||
|
self.assertEquals(response.data['results'], self.data[0:1])
|
||||||
|
request = factory.get('/?page=2')
|
||||||
|
response = self.view(request).render()
|
||||||
|
self.assertEquals(response.data['count'], 3)
|
||||||
|
self.assertEquals(response.data['next'], 'http://testserver/?page=3')
|
||||||
|
self.assertEquals(response.data['previous'], 'http://testserver/?page=1')
|
||||||
|
self.assertEquals(response.data['results'], self.data[1:2])
|
||||||
|
request = factory.get('/?page=3')
|
||||||
|
response = self.view(request).render()
|
||||||
|
self.assertEquals(response.data['count'], 3)
|
||||||
|
self.assertEquals(response.data['next'], None)
|
||||||
|
self.assertEquals(response.data['previous'], 'http://testserver/?page=2')
|
||||||
|
self.assertEquals(response.data['results'], self.data[2:3])
|
||||||
|
|
||||||
|
|
||||||
class TestUnpaginated(TestCase):
|
class TestUnpaginated(TestCase):
|
||||||
"""
|
"""
|
||||||
Tests for list views without pagination.
|
Tests for list views without pagination.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user