diff options
Diffstat (limited to 'rest_framework/tests')
| -rw-r--r-- | rest_framework/tests/fields.py | 124 | ||||
| -rw-r--r-- | rest_framework/tests/generics.py | 42 | ||||
| -rw-r--r-- | rest_framework/tests/htmlrenderer.py | 10 | ||||
| -rw-r--r-- | rest_framework/tests/negotiation.py | 9 | ||||
| -rw-r--r-- | rest_framework/tests/permissions.py | 45 | ||||
| -rw-r--r-- | rest_framework/tests/relations_pk.py | 64 | ||||
| -rw-r--r-- | rest_framework/tests/renderers.py | 20 | ||||
| -rw-r--r-- | rest_framework/tests/response.py | 59 | ||||
| -rw-r--r-- | rest_framework/tests/serializer.py | 266 |
9 files changed, 623 insertions, 16 deletions
diff --git a/rest_framework/tests/fields.py b/rest_framework/tests/fields.py index 6a180cb8..7a5ed718 100644 --- a/rest_framework/tests/fields.py +++ b/rest_framework/tests/fields.py @@ -13,6 +13,7 @@ from django.test import TestCase from django.core import validators from rest_framework import serializers from rest_framework.serializers import Serializer +from rest_framework.tests.models import RESTFrameworkModel from rest_framework.fields import Field from collections import namedtuple from uuid import uuid4 @@ -693,6 +694,129 @@ class ChoiceFieldTests(TestCase): self.assertEqual(f.choices, models.fields.BLANK_CHOICE_DASH + self.SAMPLE_CHOICES) +class EmailFieldTests(TestCase): + """ + Tests for EmailField attribute values + """ + + class EmailFieldModel(RESTFrameworkModel): + email_field = models.EmailField(blank=True) + + class EmailFieldWithGivenMaxLengthModel(RESTFrameworkModel): + email_field = models.EmailField(max_length=150, blank=True) + + def test_default_model_value(self): + class EmailFieldSerializer(serializers.ModelSerializer): + class Meta: + model = self.EmailFieldModel + + serializer = EmailFieldSerializer(data={}) + self.assertEqual(serializer.is_valid(), True) + self.assertEqual(getattr(serializer.fields['email_field'], 'max_length'), 75) + + def test_given_model_value(self): + class EmailFieldSerializer(serializers.ModelSerializer): + class Meta: + model = self.EmailFieldWithGivenMaxLengthModel + + serializer = EmailFieldSerializer(data={}) + self.assertEqual(serializer.is_valid(), True) + self.assertEqual(getattr(serializer.fields['email_field'], 'max_length'), 150) + + def test_given_serializer_value(self): + class EmailFieldSerializer(serializers.ModelSerializer): + email_field = serializers.EmailField(source='email_field', max_length=20, required=False) + + class Meta: + model = self.EmailFieldModel + + serializer = EmailFieldSerializer(data={}) + self.assertEqual(serializer.is_valid(), True) + self.assertEqual(getattr(serializer.fields['email_field'], 'max_length'), 20) + + +class SlugFieldTests(TestCase): + """ + Tests for SlugField attribute values + """ + + class SlugFieldModel(RESTFrameworkModel): + slug_field = models.SlugField(blank=True) + + class SlugFieldWithGivenMaxLengthModel(RESTFrameworkModel): + slug_field = models.SlugField(max_length=84, blank=True) + + def test_default_model_value(self): + class SlugFieldSerializer(serializers.ModelSerializer): + class Meta: + model = self.SlugFieldModel + + serializer = SlugFieldSerializer(data={}) + self.assertEqual(serializer.is_valid(), True) + self.assertEqual(getattr(serializer.fields['slug_field'], 'max_length'), 50) + + def test_given_model_value(self): + class SlugFieldSerializer(serializers.ModelSerializer): + class Meta: + model = self.SlugFieldWithGivenMaxLengthModel + + serializer = SlugFieldSerializer(data={}) + self.assertEqual(serializer.is_valid(), True) + self.assertEqual(getattr(serializer.fields['slug_field'], 'max_length'), 84) + + def test_given_serializer_value(self): + class SlugFieldSerializer(serializers.ModelSerializer): + slug_field = serializers.SlugField(source='slug_field', max_length=20, required=False) + + class Meta: + model = self.SlugFieldModel + + serializer = SlugFieldSerializer(data={}) + self.assertEqual(serializer.is_valid(), True) + self.assertEqual(getattr(serializer.fields['slug_field'], 'max_length'), 20) + + +class URLFieldTests(TestCase): + """ + Tests for URLField attribute values + """ + + class URLFieldModel(RESTFrameworkModel): + url_field = models.URLField(blank=True) + + class URLFieldWithGivenMaxLengthModel(RESTFrameworkModel): + url_field = models.URLField(max_length=128, blank=True) + + def test_default_model_value(self): + class URLFieldSerializer(serializers.ModelSerializer): + class Meta: + model = self.URLFieldModel + + serializer = URLFieldSerializer(data={}) + self.assertEqual(serializer.is_valid(), True) + self.assertEqual(getattr(serializer.fields['url_field'], 'max_length'), 200) + + def test_given_model_value(self): + class URLFieldSerializer(serializers.ModelSerializer): + class Meta: + model = self.URLFieldWithGivenMaxLengthModel + + serializer = URLFieldSerializer(data={}) + self.assertEqual(serializer.is_valid(), True) + self.assertEqual(getattr(serializer.fields['url_field'], 'max_length'), 128) + + def test_given_serializer_value(self): + class URLFieldSerializer(serializers.ModelSerializer): + url_field = serializers.URLField(source='url_field', max_length=20, required=False) + + class Meta: + model = self.URLFieldWithGivenMaxLengthModel + + serializer = URLFieldSerializer(data={}) + self.assertEqual(serializer.is_valid(), True) + self.assertEqual(getattr(serializer.fields['url_field'], 'max_length'), 20) + + class HumanizedFieldType(TestCase): def test_standard_type_classes(self): for field_type_name in forms.fields.__all__: diff --git a/rest_framework/tests/generics.py b/rest_framework/tests/generics.py index 15d87e86..a1edd28d 100644 --- a/rest_framework/tests/generics.py +++ b/rest_framework/tests/generics.py @@ -121,8 +121,27 @@ class TestRootView(TestCase): 'text/html' ], 'name': 'Root', - 'description': 'Example description for OPTIONS.' + 'description': 'Example description for OPTIONS.', + 'actions': {} } + # TODO: this is just a draft for fields' metadata - needs review and decision + for method in ('GET', 'POST',): + expected['actions'][method] = { + 'text': { + #'description': '', + 'label': None, + 'read_only': False, + 'required': True, + 'type': 'Single Character', + }, + 'id': { + #'description': '', + 'label': None, + 'read_only': True, + 'required': False, + 'type': 'Integer', + }, + } self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data, expected) @@ -238,8 +257,27 @@ class TestInstanceView(TestCase): 'text/html' ], 'name': 'Instance', - 'description': 'Example description for OPTIONS.' + 'description': 'Example description for OPTIONS.', + 'actions': {} } + # TODO: this is just a draft idea for fields' metadata - needs review and decision + for method in ('GET', 'PATCH', 'PUT', 'DELETE'): + expected['actions'][method] = { + 'text': { + #'description': '', + 'label': None, + 'read_only': False, + 'required': True, + 'type': 'Single Character', + }, + 'id': { + #'description': '', + 'label': None, + 'read_only': True, + 'required': False, + 'type': 'Integer', + }, + } self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data, expected) diff --git a/rest_framework/tests/htmlrenderer.py b/rest_framework/tests/htmlrenderer.py index 8f2e2b5a..5d18a6e8 100644 --- a/rest_framework/tests/htmlrenderer.py +++ b/rest_framework/tests/htmlrenderer.py @@ -66,19 +66,19 @@ class TemplateHTMLRendererTests(TestCase): def test_simple_html_view(self): response = self.client.get('/') self.assertContains(response, "example: foobar") - self.assertEqual(response['Content-Type'], 'text/html') + self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8') def test_not_found_html_view(self): response = self.client.get('/not_found') self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.assertEqual(response.content, six.b("404 Not Found")) - self.assertEqual(response['Content-Type'], 'text/html') + self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8') def test_permission_denied_html_view(self): response = self.client.get('/permission_denied') self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertEqual(response.content, six.b("403 Forbidden")) - self.assertEqual(response['Content-Type'], 'text/html') + self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8') class TemplateHTMLRendererExceptionTests(TestCase): @@ -109,10 +109,10 @@ class TemplateHTMLRendererExceptionTests(TestCase): response = self.client.get('/not_found') self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) self.assertEqual(response.content, six.b("404: Not found")) - self.assertEqual(response['Content-Type'], 'text/html') + self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8') def test_permission_denied_html_view_with_template(self): response = self.client.get('/permission_denied') self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) self.assertEqual(response.content, six.b("403: Permission denied")) - self.assertEqual(response['Content-Type'], 'text/html') + self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8') diff --git a/rest_framework/tests/negotiation.py b/rest_framework/tests/negotiation.py index 43721b84..7f84827f 100644 --- a/rest_framework/tests/negotiation.py +++ b/rest_framework/tests/negotiation.py @@ -3,19 +3,24 @@ from django.test import TestCase from django.test.client import RequestFactory from rest_framework.negotiation import DefaultContentNegotiation from rest_framework.request import Request +from rest_framework.renderers import BaseRenderer factory = RequestFactory() -class MockJSONRenderer(object): +class MockJSONRenderer(BaseRenderer): media_type = 'application/json' -class MockHTMLRenderer(object): +class MockHTMLRenderer(BaseRenderer): media_type = 'text/html' +class NoCharsetSpecifiedRenderer(BaseRenderer): + media_type = 'my/media' + + class TestAcceptedMediaType(TestCase): def setUp(self): self.renderers = [MockJSONRenderer(), MockHTMLRenderer()] diff --git a/rest_framework/tests/permissions.py b/rest_framework/tests/permissions.py index b3993be5..5a18182b 100644 --- a/rest_framework/tests/permissions.py +++ b/rest_framework/tests/permissions.py @@ -108,6 +108,51 @@ class ModelPermissionsIntegrationTests(TestCase): response = instance_view(request, pk='2') self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + def test_options_permitted(self): + request = factory.options('/', content_type='application/json', + HTTP_AUTHORIZATION=self.permitted_credentials) + response = root_view(request, pk='1') + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertIn('actions', response.data) + self.assertEquals(response.data['actions'].keys(), ['POST', 'GET',]) + + request = factory.options('/1', content_type='application/json', + HTTP_AUTHORIZATION=self.permitted_credentials) + response = instance_view(request, pk='1') + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertIn('actions', response.data) + self.assertEquals(response.data['actions'].keys(), ['PUT', 'PATCH', 'DELETE', 'GET',]) + + def test_options_disallowed(self): + request = factory.options('/', content_type='application/json', + HTTP_AUTHORIZATION=self.disallowed_credentials) + response = root_view(request, pk='1') + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertIn('actions', response.data) + self.assertEquals(response.data['actions'].keys(), ['GET',]) + + request = factory.options('/1', content_type='application/json', + HTTP_AUTHORIZATION=self.disallowed_credentials) + response = instance_view(request, pk='1') + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertIn('actions', response.data) + self.assertEquals(response.data['actions'].keys(), ['GET',]) + + def test_options_updateonly(self): + request = factory.options('/', content_type='application/json', + HTTP_AUTHORIZATION=self.updateonly_credentials) + response = root_view(request, pk='1') + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertIn('actions', response.data) + self.assertEquals(response.data['actions'].keys(), ['GET',]) + + request = factory.options('/1', content_type='application/json', + HTTP_AUTHORIZATION=self.updateonly_credentials) + response = instance_view(request, pk='1') + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertIn('actions', response.data) + self.assertEquals(response.data['actions'].keys(), ['PUT', 'PATCH', 'GET',]) + class OwnerModel(models.Model): text = models.CharField(max_length=100) diff --git a/rest_framework/tests/relations_pk.py b/rest_framework/tests/relations_pk.py index 0f8c5247..e2a1b815 100644 --- a/rest_framework/tests/relations_pk.py +++ b/rest_framework/tests/relations_pk.py @@ -1,4 +1,5 @@ from __future__ import unicode_literals +from django.db import models from django.test import TestCase from rest_framework import serializers from rest_framework.tests.models import ( @@ -127,6 +128,7 @@ class PKManyToManyTests(TestCase): # Ensure source 4 is added, and everything else is as expected queryset = ManyToManySource.objects.all() serializer = ManyToManySourceSerializer(queryset, many=True) + self.assertFalse(serializer.fields['targets'].read_only) expected = [ {'id': 1, 'name': 'source-1', 'targets': [1]}, {'id': 2, 'name': 'source-2', 'targets': [1, 2]}, @@ -138,6 +140,7 @@ class PKManyToManyTests(TestCase): def test_reverse_many_to_many_create(self): data = {'id': 4, 'name': 'target-4', 'sources': [1, 3]} serializer = ManyToManyTargetSerializer(data=data) + self.assertFalse(serializer.fields['sources'].read_only) self.assertTrue(serializer.is_valid()) obj = serializer.save() self.assertEqual(serializer.data, data) @@ -426,8 +429,69 @@ class PKNullableOneToOneTests(TestCase): self.assertEqual(serializer.data, expected) +# The below models and tests ensure that serializer fields corresponding +# to a ManyToManyField field with a user-specified ``through`` model are +# set to read only + + +class ManyToManyThroughTarget(models.Model): + name = models.CharField(max_length=100) + + +class ManyToManyThrough(models.Model): + source = models.ForeignKey('ManyToManyThroughSource') + target = models.ForeignKey(ManyToManyThroughTarget) + + +class ManyToManyThroughSource(models.Model): + name = models.CharField(max_length=100) + targets = models.ManyToManyField(ManyToManyThroughTarget, + related_name='sources', + through='ManyToManyThrough') + + +class ManyToManyThroughTargetSerializer(serializers.ModelSerializer): + class Meta: + model = ManyToManyThroughTarget + fields = ('id', 'name', 'sources') + + +class ManyToManyThroughSourceSerializer(serializers.ModelSerializer): + class Meta: + model = ManyToManyThroughSource + fields = ('id', 'name', 'targets') + + +class PKManyToManyThroughTests(TestCase): + def setUp(self): + self.source = ManyToManyThroughSource.objects.create( + name='through-source-1') + self.target = ManyToManyThroughTarget.objects.create( + name='through-target-1') + + def test_many_to_many_create(self): + data = {'id': 2, 'name': 'source-2', 'targets': [self.target.pk]} + serializer = ManyToManyThroughSourceSerializer(data=data) + self.assertTrue(serializer.fields['targets'].read_only) + self.assertTrue(serializer.is_valid()) + obj = serializer.save() + self.assertEqual(obj.name, 'source-2') + self.assertEqual(obj.targets.count(), 0) + + def test_many_to_many_reverse_create(self): + data = {'id': 2, 'name': 'target-2', 'sources': [self.source.pk]} + serializer = ManyToManyThroughTargetSerializer(data=data) + self.assertTrue(serializer.fields['sources'].read_only) + self.assertTrue(serializer.is_valid()) + serializer.save() + obj = serializer.save() + self.assertEqual(obj.name, 'target-2') + self.assertEqual(obj.sources.count(), 0) + + # Regression tests for #694 (`source` attribute on related fields) + class PrimaryKeyRelatedFieldSourceTests(TestCase): def test_related_manager_source(self): """ diff --git a/rest_framework/tests/renderers.py b/rest_framework/tests/renderers.py index 40bac9cb..739f9184 100644 --- a/rest_framework/tests/renderers.py +++ b/rest_framework/tests/renderers.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- from decimal import Decimal from django.core.cache import cache from django.test import TestCase @@ -8,7 +9,7 @@ from rest_framework.compat import yaml, etree, patterns, url, include from rest_framework.response import Response from rest_framework.views import APIView from rest_framework.renderers import BaseRenderer, JSONRenderer, YAMLRenderer, \ - XMLRenderer, JSONPRenderer, BrowsableAPIRenderer + XMLRenderer, JSONPRenderer, BrowsableAPIRenderer, UnicodeJSONRenderer from rest_framework.parsers import YAMLParser, XMLParser from rest_framework.settings import api_settings from rest_framework.compat import StringIO @@ -254,6 +255,23 @@ class JSONRendererTests(TestCase): content = renderer.render(obj, 'application/json; indent=2') self.assertEqual(strip_trailing_whitespace(content), _indented_repr) + def test_check_ascii(self): + obj = {'countries': ['United Kingdom', 'France', 'España']} + renderer = JSONRenderer() + content = renderer.render(obj, 'application/json') + self.assertEqual(content, '{"countries": ["United Kingdom", "France", "Espa\\u00f1a"]}') + + +class UnicodeJSONRendererTests(TestCase): + """ + Tests specific for the Unicode JSON Renderer + """ + def test_proper_encoding(self): + obj = {'countries': ['United Kingdom', 'France', 'España']} + renderer = UnicodeJSONRenderer() + content = renderer.render(obj, 'application/json') + self.assertEqual(content, '{"countries": ["United Kingdom", "France", "España"]}') + class JSONPRendererTests(TestCase): """ diff --git a/rest_framework/tests/response.py b/rest_framework/tests/response.py index aecf83f4..8f1163e8 100644 --- a/rest_framework/tests/response.py +++ b/rest_framework/tests/response.py @@ -21,6 +21,9 @@ class MockJsonRenderer(BaseRenderer): media_type = 'application/json' +class MockTextMediaRenderer(BaseRenderer): + media_type = 'text/html' + DUMMYSTATUS = status.HTTP_200_OK DUMMYCONTENT = 'dummycontent' @@ -44,13 +47,26 @@ class RendererB(BaseRenderer): return RENDERER_B_SERIALIZER(data) +class RendererC(RendererB): + media_type = 'mock/rendererc' + format = 'formatc' + charset = "rendererc" + + class MockView(APIView): - renderer_classes = (RendererA, RendererB) + renderer_classes = (RendererA, RendererB, RendererC) def get(self, request, **kwargs): return Response(DUMMYCONTENT, status=DUMMYSTATUS) +class MockViewSettingCharset(APIView): + renderer_classes = (RendererA, RendererB, RendererC) + + def get(self, request, **kwargs): + return Response(DUMMYCONTENT, status=DUMMYSTATUS, charset='setbyview') + + class HTMLView(APIView): renderer_classes = (BrowsableAPIRenderer, ) @@ -64,10 +80,10 @@ class HTMLView1(APIView): def get(self, request, **kwargs): return Response('text') - urlpatterns = patterns('', - url(r'^.*\.(?P<format>.+)$', MockView.as_view(renderer_classes=[RendererA, RendererB])), - url(r'^$', MockView.as_view(renderer_classes=[RendererA, RendererB])), + url(r'^setbyview$', MockViewSettingCharset.as_view(renderer_classes=[RendererA, RendererB, RendererC])), + url(r'^.*\.(?P<format>.+)$', MockView.as_view(renderer_classes=[RendererA, RendererB, RendererC])), + url(r'^$', MockView.as_view(renderer_classes=[RendererA, RendererB, RendererC])), url(r'^html$', HTMLView.as_view()), url(r'^html1$', HTMLView1.as_view()), url(r'^restframework', include('rest_framework.urls', namespace='rest_framework')) @@ -173,3 +189,38 @@ class Issue122Tests(TestCase): Test if no infinite recursion occurs. """ self.client.get('/html1') + + +class Issue807Testts(TestCase): + """ + Covers #807 + """ + + urls = 'rest_framework.tests.response' + + def test_does_not_append_charset_by_default(self): + """ + Renderers don't include a charset unless set explicitly. + """ + headers = {"HTTP_ACCEPT": RendererA.media_type} + resp = self.client.get('/', **headers) + self.assertEqual(RendererA.media_type, resp['Content-Type']) + + def test_if_there_is_charset_specified_on_renderer_it_gets_appended(self): + """ + If renderer class has charset attribute declared, it gets appended + to Response's Content-Type + """ + headers = {"HTTP_ACCEPT": RendererC.media_type} + resp = self.client.get('/', **headers) + expected = "{0}; charset={1}".format(RendererC.media_type, RendererC.charset) + self.assertEqual(expected, resp['Content-Type']) + + def test_charset_set_explictly_on_response(self): + """ + The charset may be set explictly on the response. + """ + headers = {"HTTP_ACCEPT": RendererC.media_type} + resp = self.client.get('/setbyview', **headers) + expected = "{0}; charset={1}".format(RendererC.media_type, 'setbyview') + self.assertEqual(expected, resp['Content-Type']) diff --git a/rest_framework/tests/serializer.py b/rest_framework/tests/serializer.py index d0a8570c..fd6cf6da 100644 --- a/rest_framework/tests/serializer.py +++ b/rest_framework/tests/serializer.py @@ -1,12 +1,13 @@ from __future__ import unicode_literals from django.db import models from django.db.models.fields import BLANK_CHOICE_DASH -from django.utils.datastructures import MultiValueDict from django.test import TestCase +from django.utils.datastructures import MultiValueDict +from django.utils.translation import ugettext_lazy as _ from rest_framework import serializers from rest_framework.tests.models import (HasPositiveIntegerAsChoice, Album, ActionItem, Anchor, BasicModel, BlankFieldModel, BlogPost, BlogPostComment, Book, CallableDefaultValueModel, DefaultValueModel, - ManyToManyModel, Person, ReadOnlyManyToManyModel, Photo) + ManyToManyModel, Person, ReadOnlyManyToManyModel, Photo, RESTFrameworkModel) import datetime import pickle @@ -91,6 +92,17 @@ class PersonSerializer(serializers.ModelSerializer): read_only_fields = ('age',) +class NestedSerializer(serializers.Serializer): + info = serializers.Field() + + +class ModelSerializerWithNestedSerializer(serializers.ModelSerializer): + nested = NestedSerializer(source='*') + + class Meta: + model = Person + + class PersonSerializerInvalidReadOnly(serializers.ModelSerializer): """ Testing for #652. @@ -418,6 +430,17 @@ class ValidationTests(TestCase): except: self.fail('Wrong exception type thrown.') + def test_writable_star_source_on_nested_serializer(self): + """ + Assert that a nested serializer instantiated with source='*' correctly + expands the data into the outer serializer. + """ + serializer = ModelSerializerWithNestedSerializer(data={ + 'name': 'marko', + 'nested': {'info': 'hi'}}, + ) + self.assertEqual(serializer.is_valid(), True) + class CustomValidationTests(TestCase): class CommentSerializerWithFieldValidator(CommentSerializer): @@ -1117,6 +1140,63 @@ class SerializerChoiceFields(TestCase): ) +# Regression tests for #675 +class Ticket(models.Model): + assigned = models.ForeignKey( + Person, related_name='assigned_tickets') + reviewer = models.ForeignKey( + Person, blank=True, null=True, related_name='reviewed_tickets') + + +class SerializerRelatedChoicesTest(TestCase): + + def setUp(self): + super(SerializerRelatedChoicesTest, self).setUp() + + class RelatedChoicesSerializer(serializers.ModelSerializer): + class Meta: + model = Ticket + fields = ('assigned', 'reviewer') + + self.related_fields_serializer = RelatedChoicesSerializer + + def test_empty_queryset_required(self): + serializer = self.related_fields_serializer() + self.assertEqual(serializer.fields['assigned'].queryset.count(), 0) + self.assertEqual( + [x for x in serializer.fields['assigned'].widget.choices], + [] + ) + + def test_empty_queryset_not_required(self): + serializer = self.related_fields_serializer() + self.assertEqual(serializer.fields['reviewer'].queryset.count(), 0) + self.assertEqual( + [x for x in serializer.fields['reviewer'].widget.choices], + [('', '---------')] + ) + + def test_with_some_persons_required(self): + Person.objects.create(name="Lionel Messi") + Person.objects.create(name="Xavi Hernandez") + serializer = self.related_fields_serializer() + self.assertEqual(serializer.fields['assigned'].queryset.count(), 2) + self.assertEqual( + [x for x in serializer.fields['assigned'].widget.choices], + [(1, 'Person object - 1'), (2, 'Person object - 2')] + ) + + def test_with_some_persons_not_required(self): + Person.objects.create(name="Lionel Messi") + Person.objects.create(name="Xavi Hernandez") + serializer = self.related_fields_serializer() + self.assertEqual(serializer.fields['reviewer'].queryset.count(), 2) + self.assertEqual( + [x for x in serializer.fields['reviewer'].widget.choices], + [('', '---------'), (1, 'Person object - 1'), (2, 'Person object - 2')] + ) + + class DepthTest(TestCase): def test_implicit_nesting(self): @@ -1242,3 +1322,185 @@ class DeserializeListTestCase(TestCase): self.assertFalse(serializer.is_valid()) expected = [{}, {'email': ['This field is required.']}, {}] self.assertEqual(serializer.errors, expected) + + +# test for issue 747 + + +class LazyStringModel(object): + def __init__(self, lazystring): + self.lazystring = lazystring + + +class LazyStringSerializer(serializers.Serializer): + lazystring = serializers.Field() + + def restore_object(self, attrs, instance=None): + if instance is not None: + instance.lazystring = attrs.get('lazystring', instance.lazystring) + return instance + return LazyStringModel(**attrs) + + +class LazyStringsTestCase(TestCase): + def setUp(self): + self.model = LazyStringModel(lazystring=_('lazystring')) + + def test_lazy_strings_are_translated(self): + serializer = LazyStringSerializer(self.model) + self.assertEqual(type(serializer.data['lazystring']), + type('lazystring')) + + +class AttributeMappingOnAutogeneratedFieldsTests(TestCase): + + def setUp(self): + class AMOAFModel(RESTFrameworkModel): + char_field = models.CharField(max_length=1024, blank=True) + comma_separated_integer_field = models.CommaSeparatedIntegerField(max_length=1024, blank=True) + decimal_field = models.DecimalField(max_digits=64, decimal_places=32, blank=True) + email_field = models.EmailField(max_length=1024, blank=True) + file_field = models.FileField(max_length=1024, blank=True) + image_field = models.ImageField(max_length=1024, blank=True) + slug_field = models.SlugField(max_length=1024, blank=True) + url_field = models.URLField(max_length=1024, blank=True) + + class AMOAFSerializer(serializers.ModelSerializer): + class Meta: + model = AMOAFModel + + self.serializer_class = AMOAFSerializer + self.fields_attributes = { + 'char_field': [ + ('max_length', 1024), + ], + 'comma_separated_integer_field': [ + ('max_length', 1024), + ], + 'decimal_field': [ + ('max_digits', 64), + ('decimal_places', 32), + ], + 'email_field': [ + ('max_length', 1024), + ], + 'file_field': [ + ('max_length', 1024), + ], + 'image_field': [ + ('max_length', 1024), + ], + 'slug_field': [ + ('max_length', 1024), + ], + 'url_field': [ + ('max_length', 1024), + ], + } + + def field_test(self, field): + serializer = self.serializer_class(data={}) + self.assertEqual(serializer.is_valid(), True) + + for attribute in self.fields_attributes[field]: + self.assertEqual( + getattr(serializer.fields[field], attribute[0]), + attribute[1] + ) + + def test_char_field(self): + self.field_test('char_field') + + def test_comma_separated_integer_field(self): + self.field_test('comma_separated_integer_field') + + def test_decimal_field(self): + self.field_test('decimal_field') + + def test_email_field(self): + self.field_test('email_field') + + def test_file_field(self): + self.field_test('file_field') + + def test_image_field(self): + self.field_test('image_field') + + def test_slug_field(self): + self.field_test('slug_field') + + def test_url_field(self): + self.field_test('url_field') + + +class DefaultValuesOnAutogeneratedFieldsTests(TestCase): + + def setUp(self): + class DVOAFModel(RESTFrameworkModel): + positive_integer_field = models.PositiveIntegerField(blank=True) + positive_small_integer_field = models.PositiveSmallIntegerField(blank=True) + email_field = models.EmailField(blank=True) + file_field = models.FileField(blank=True) + image_field = models.ImageField(blank=True) + slug_field = models.SlugField(blank=True) + url_field = models.URLField(blank=True) + + class DVOAFSerializer(serializers.ModelSerializer): + class Meta: + model = DVOAFModel + + self.serializer_class = DVOAFSerializer + self.fields_attributes = { + 'positive_integer_field': [ + ('min_value', 0), + ], + 'positive_small_integer_field': [ + ('min_value', 0), + ], + 'email_field': [ + ('max_length', 75), + ], + 'file_field': [ + ('max_length', 100), + ], + 'image_field': [ + ('max_length', 100), + ], + 'slug_field': [ + ('max_length', 50), + ], + 'url_field': [ + ('max_length', 200), + ], + } + + def field_test(self, field): + serializer = self.serializer_class(data={}) + self.assertEqual(serializer.is_valid(), True) + + for attribute in self.fields_attributes[field]: + self.assertEqual( + getattr(serializer.fields[field], attribute[0]), + attribute[1] + ) + + def test_positive_integer_field(self): + self.field_test('positive_integer_field') + + def test_positive_small_integer_field(self): + self.field_test('positive_small_integer_field') + + def test_email_field(self): + self.field_test('email_field') + + def test_file_field(self): + self.field_test('file_field') + + def test_image_field(self): + self.field_test('image_field') + + def test_slug_field(self): + self.field_test('slug_field') + + def test_url_field(self): + self.field_test('url_field') |
