From 6c108c459d8cfeda46b8e045ef750c01dd0ffcaa Mon Sep 17 00:00:00 2001 From: Ian Foote Date: Wed, 16 Apr 2014 12:32:04 +0100 Subject: [PATCH 01/39] Allow customising ChoiceField blank display value --- rest_framework/fields.py | 8 ++++++-- rest_framework/tests/test_fields.py | 9 +++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 946a59545..d9521cd46 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -509,12 +509,16 @@ class ChoiceField(WritableField): 'the available choices.'), } - def __init__(self, choices=(), *args, **kwargs): + def __init__(self, choices=(), blank_display_value=None, *args, **kwargs): self.empty = kwargs.pop('empty', '') super(ChoiceField, self).__init__(*args, **kwargs) self.choices = choices if not self.required: - self.choices = BLANK_CHOICE_DASH + self.choices + if blank_display_value is None: + blank_choice = BLANK_CHOICE_DASH + else: + blank_choice = [('', blank_display_value)] + self.choices = blank_choice + self.choices def _get_choices(self): return self._choices diff --git a/rest_framework/tests/test_fields.py b/rest_framework/tests/test_fields.py index e127feef9..63dff7182 100644 --- a/rest_framework/tests/test_fields.py +++ b/rest_framework/tests/test_fields.py @@ -706,6 +706,15 @@ class ChoiceFieldTests(TestCase): f = serializers.ChoiceField(required=False, choices=SAMPLE_CHOICES) self.assertEqual(f.choices, models.fields.BLANK_CHOICE_DASH + SAMPLE_CHOICES) + def test_blank_choice_display(self): + blank = 'No Preference' + f = serializers.ChoiceField( + required=False, + choices=SAMPLE_CHOICES, + blank_display_value=blank, + ) + self.assertEqual(f.choices, [('', blank)] + SAMPLE_CHOICES) + def test_invalid_choice_model(self): s = ChoiceFieldModelSerializer(data={'choice': 'wrong_value'}) self.assertFalse(s.is_valid()) From 98cc8210990e3307a89d745acbbc2bcf6c665645 Mon Sep 17 00:00:00 2001 From: Serhiy Voyt Date: Tue, 6 May 2014 20:34:30 +0300 Subject: [PATCH 02/39] Extended test with case of saveing model with blank not null field. --- rest_framework/tests/test_serializer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rest_framework/tests/test_serializer.py b/rest_framework/tests/test_serializer.py index e688c8239..d770c6375 100644 --- a/rest_framework/tests/test_serializer.py +++ b/rest_framework/tests/test_serializer.py @@ -1236,6 +1236,8 @@ class BlankFieldTests(TestCase): def test_create_model_null_field(self): serializer = self.model_serializer_class(data={'title': None}) self.assertEqual(serializer.is_valid(), True) + serializer.save() + self.assertTrue(serializer.object.pk is not None) def test_create_not_blank_field(self): """ From 1ce1f387b031c368e0ad315964b78f93d6be9a19 Mon Sep 17 00:00:00 2001 From: Serhiy Voyt Date: Tue, 6 May 2014 21:57:25 +0300 Subject: [PATCH 03/39] Charfied from_native method returns default instead of None. Updated tests. --- rest_framework/fields.py | 9 ++++++++- rest_framework/tests/models.py | 4 +++- rest_framework/tests/test_serializer.py | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 8cdc55515..7858d9510 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -469,8 +469,15 @@ class CharField(WritableField): self.validators.append(validators.MaxLengthValidator(max_length)) def from_native(self, value): - if isinstance(value, six.string_types) or value is None: + if isinstance(value, six.string_types): return value + + if value is None: + if self.default: + return self.default + else: + value + return smart_text(value) diff --git a/rest_framework/tests/models.py b/rest_framework/tests/models.py index e171d3bd9..fba3f8f7c 100644 --- a/rest_framework/tests/models.py +++ b/rest_framework/tests/models.py @@ -105,6 +105,7 @@ class Album(RESTFrameworkModel): title = models.CharField(max_length=100, unique=True) ref = models.CharField(max_length=10, unique=True, null=True, blank=True) + class Photo(RESTFrameworkModel): description = models.TextField() album = models.ForeignKey(Album) @@ -112,7 +113,8 @@ class Photo(RESTFrameworkModel): # Model for issue #324 class BlankFieldModel(RESTFrameworkModel): - title = models.CharField(max_length=100, blank=True, null=False) + title = models.CharField(max_length=100, blank=True, null=False, + default="title") # Model for issue #380 diff --git a/rest_framework/tests/test_serializer.py b/rest_framework/tests/test_serializer.py index d770c6375..82e1a89ca 100644 --- a/rest_framework/tests/test_serializer.py +++ b/rest_framework/tests/test_serializer.py @@ -1238,6 +1238,7 @@ class BlankFieldTests(TestCase): self.assertEqual(serializer.is_valid(), True) serializer.save() self.assertTrue(serializer.object.pk is not None) + self.assertEqual(serializer.object.title, 'title') def test_create_not_blank_field(self): """ From 27be31bd8a58fc4f37b966c36d1cebe83b80ebea Mon Sep 17 00:00:00 2001 From: Serhiy Voyt Date: Wed, 7 May 2014 18:37:08 +0300 Subject: [PATCH 04/39] In case of None value returns empty string instead of NoneType. --- rest_framework/fields.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 7858d9510..aed38d5e2 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -473,10 +473,7 @@ class CharField(WritableField): return value if value is None: - if self.default: - return self.default - else: - value + return '' return smart_text(value) From 4e6a21344fd1fda28d1d63c5aa697fac5e9f8029 Mon Sep 17 00:00:00 2001 From: Serhiy Voyt Date: Wed, 7 May 2014 18:42:02 +0300 Subject: [PATCH 05/39] Fixed test. --- rest_framework/tests/test_serializer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rest_framework/tests/test_serializer.py b/rest_framework/tests/test_serializer.py index 82e1a89ca..91248ce7c 100644 --- a/rest_framework/tests/test_serializer.py +++ b/rest_framework/tests/test_serializer.py @@ -1237,8 +1237,8 @@ class BlankFieldTests(TestCase): serializer = self.model_serializer_class(data={'title': None}) self.assertEqual(serializer.is_valid(), True) serializer.save() - self.assertTrue(serializer.object.pk is not None) - self.assertEqual(serializer.object.title, 'title') + self.assertIsNot(serializer.object.pk, None) + self.assertEqual(serializer.object.title, '') def test_create_not_blank_field(self): """ From 5c12b0768166376783d62632e562f0c1301ee847 Mon Sep 17 00:00:00 2001 From: Xavier Ordoquy Date: Fri, 16 May 2014 19:40:02 +0200 Subject: [PATCH 06/39] Added missing import. --- rest_framework/serializers.py | 1 + 1 file changed, 1 insertion(+) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 2a0d5263e..6dd09f68b 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -21,6 +21,7 @@ from django.core.paginator import Page from django.db import models from django.forms import widgets from django.utils.datastructures import SortedDict +from django.core.exceptions import ObjectDoesNotExist from rest_framework.compat import get_concrete_model, six from rest_framework.settings import api_settings From a2e1024f8b0447a712d1f486172d38cfe56535fe Mon Sep 17 00:00:00 2001 From: Xavier Ordoquy Date: Sun, 18 May 2014 09:27:23 +0200 Subject: [PATCH 07/39] Updated Django versions. --- .travis.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0c9b44553..638d14998 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,10 +8,10 @@ python: - "3.4" env: - - DJANGO="https://www.djangoproject.com/download/1.7b2/tarball/" - - DJANGO="django==1.6.3" - - DJANGO="django==1.5.6" - - DJANGO="django==1.4.11" + - DJANGO="https://www.djangoproject.com/download/1.7b4/tarball/" + - DJANGO="django==1.6.5" + - DJANGO="django==1.5.8" + - DJANGO="django==1.4.13" - DJANGO="django==1.3.7" install: @@ -24,7 +24,7 @@ install: - "if [[ ${DJANGO::11} == 'django==1.3' ]]; then pip install django-filter==0.5.4; fi" - "if [[ ${DJANGO::11} != 'django==1.3' ]]; then pip install django-filter==0.7; fi" - "if [[ ${TRAVIS_PYTHON_VERSION::1} == '3' ]]; then pip install -e git+https://github.com/linovia/django-guardian.git@feature/django_1_7#egg=django-guardian-1.2.0; fi" - - "if [[ ${DJANGO} == 'https://www.djangoproject.com/download/1.7b2/tarball/' ]]; then pip install -e git+https://github.com/linovia/django-guardian.git@feature/django_1_7#egg=django-guardian-1.2.0; fi" + - "if [[ ${DJANGO} == 'https://www.djangoproject.com/download/1.7b4/tarball/' ]]; then pip install -e git+https://github.com/linovia/django-guardian.git@feature/django_1_7#egg=django-guardian-1.2.0; fi" - export PYTHONPATH=. script: @@ -33,16 +33,16 @@ script: matrix: exclude: - python: "2.6" - env: DJANGO="https://www.djangoproject.com/download/1.7b2/tarball/" + env: DJANGO="https://www.djangoproject.com/download/1.7b4/tarball/" - python: "3.2" - env: DJANGO="django==1.4.11" + env: DJANGO="django==1.4.13" - python: "3.2" env: DJANGO="django==1.3.7" - python: "3.3" - env: DJANGO="django==1.4.11" + env: DJANGO="django==1.4.13" - python: "3.3" env: DJANGO="django==1.3.7" - python: "3.4" - env: DJANGO="django==1.4.11" + env: DJANGO="django==1.4.13" - python: "3.4" env: DJANGO="django==1.3.7" From af1ee3e63175d2b1fd30ab18091bed1019ac5de6 Mon Sep 17 00:00:00 2001 From: Xavier Ordoquy Date: Sun, 18 May 2014 09:38:46 +0200 Subject: [PATCH 08/39] Fixed a small change in the 1.7 beta url. --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 638d14998..b2da9e816 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ python: - "3.4" env: - - DJANGO="https://www.djangoproject.com/download/1.7b4/tarball/" + - DJANGO="https://www.djangoproject.com/download/1.7.b4/tarball/" - DJANGO="django==1.6.5" - DJANGO="django==1.5.8" - DJANGO="django==1.4.13" @@ -24,7 +24,7 @@ install: - "if [[ ${DJANGO::11} == 'django==1.3' ]]; then pip install django-filter==0.5.4; fi" - "if [[ ${DJANGO::11} != 'django==1.3' ]]; then pip install django-filter==0.7; fi" - "if [[ ${TRAVIS_PYTHON_VERSION::1} == '3' ]]; then pip install -e git+https://github.com/linovia/django-guardian.git@feature/django_1_7#egg=django-guardian-1.2.0; fi" - - "if [[ ${DJANGO} == 'https://www.djangoproject.com/download/1.7b4/tarball/' ]]; then pip install -e git+https://github.com/linovia/django-guardian.git@feature/django_1_7#egg=django-guardian-1.2.0; fi" + - "if [[ ${DJANGO} == 'https://www.djangoproject.com/download/1.7.b4/tarball/' ]]; then pip install -e git+https://github.com/linovia/django-guardian.git@feature/django_1_7#egg=django-guardian-1.2.0; fi" - export PYTHONPATH=. script: @@ -33,7 +33,7 @@ script: matrix: exclude: - python: "2.6" - env: DJANGO="https://www.djangoproject.com/download/1.7b4/tarball/" + env: DJANGO="https://www.djangoproject.com/download/1.7.b4/tarball/" - python: "3.2" env: DJANGO="django==1.4.13" - python: "3.2" From a1a3ad763996b9ab5535bc5d442c2d6fab10b7cc Mon Sep 17 00:00:00 2001 From: allenhu Date: Sat, 17 May 2014 06:05:33 +0800 Subject: [PATCH 09/39] fix pep8 --- rest_framework/serializers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 6dd09f68b..87d20cfce 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -33,8 +33,8 @@ from rest_framework.settings import api_settings # This helps keep the separation between model fields, form fields, and # serializer fields more explicit. -from rest_framework.relations import * -from rest_framework.fields import * +from rest_framework.relations import * # NOQA +from rest_framework.fields import * # NOQA def _resolve_model(obj): @@ -345,7 +345,7 @@ class BaseSerializer(WritableField): for field_name, field in self.fields.items(): if field.read_only and obj is None: - continue + continue field.initialize(parent=self, field_name=field_name) key = self.get_field_key(field_name) value = field.field_to_native(obj, field_name) From 1e7b5fd2c04e587e30cf29e15ca3074b8d33b92e Mon Sep 17 00:00:00 2001 From: Ian Foote Date: Tue, 20 May 2014 14:55:00 +0100 Subject: [PATCH 10/39] Document ChoiceField blank_display_value parameter --- docs/api-guide/fields.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index 67fa65d2d..58dbf977e 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -184,7 +184,9 @@ Corresponds to `django.db.models.fields.SlugField`. ## ChoiceField -A field that can accept a value out of a limited set of choices. +A field that can accept a value out of a limited set of choices. Optionally takes a `blank_display_value` parameter that customizes the display value of an empty choice. + +**Signature:** `ChoiceField(choices=(), blank_display_value=None)` ## EmailField From 04c820b8e5e4ae153eacd1cbf19b39286c374e87 Mon Sep 17 00:00:00 2001 From: John Spray Date: Thu, 22 May 2014 15:24:35 +0100 Subject: [PATCH 11/39] fields: allow help_text on SerializerMethodField ...by passing through any extra *args and **kwargs to the parent constructor. Previously one couldn't assign help_text to a SerializerMethodField during construction. --- rest_framework/fields.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 2da895500..4ac5285e8 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -1027,9 +1027,9 @@ class SerializerMethodField(Field): A field that gets its value by calling a method on the serializer it's attached to. """ - def __init__(self, method_name): + def __init__(self, method_name, *args, **kwargs): self.method_name = method_name - super(SerializerMethodField, self).__init__() + super(SerializerMethodField, self).__init__(*args, **kwargs) def field_to_native(self, obj, field_name): value = getattr(self.parent, self.method_name)(obj) From 807f7a6bb9e36321f3487b5ac31ef5fdc8f4b3fb Mon Sep 17 00:00:00 2001 From: Piper Merriam Date: Thu, 22 May 2014 13:51:20 -0600 Subject: [PATCH 12/39] Fix _resolve_model to work with unicode strings --- rest_framework/serializers.py | 14 +++++++------- rest_framework/tests/test_serializers.py | 5 +++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 87d20cfce..c2b414d7a 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -49,7 +49,7 @@ def _resolve_model(obj): String representations should have the format: 'appname.ModelName' """ - if type(obj) == str and len(obj.split('.')) == 2: + if isinstance(obj, six.string_types) and len(obj.split('.')) == 2: app_name, model_name = obj.split('.') return models.get_model(app_name, model_name) elif inspect.isclass(obj) and issubclass(obj, models.Model): @@ -759,9 +759,9 @@ class ModelSerializer(Serializer): field.read_only = True ret[accessor_name] = field - + # Ensure that 'read_only_fields' is an iterable - assert isinstance(self.opts.read_only_fields, (list, tuple)), '`read_only_fields` must be a list or tuple' + assert isinstance(self.opts.read_only_fields, (list, tuple)), '`read_only_fields` must be a list or tuple' # Add the `read_only` flag to any fields that have been specified # in the `read_only_fields` option @@ -776,10 +776,10 @@ class ModelSerializer(Serializer): "on serializer '%s'." % (field_name, self.__class__.__name__)) ret[field_name].read_only = True - + # Ensure that 'write_only_fields' is an iterable - assert isinstance(self.opts.write_only_fields, (list, tuple)), '`write_only_fields` must be a list or tuple' - + assert isinstance(self.opts.write_only_fields, (list, tuple)), '`write_only_fields` must be a list or tuple' + for field_name in self.opts.write_only_fields: assert field_name not in self.base_fields.keys(), ( "field '%s' on serializer '%s' specified in " @@ -790,7 +790,7 @@ class ModelSerializer(Serializer): "Non-existant field '%s' specified in `write_only_fields` " "on serializer '%s'." % (field_name, self.__class__.__name__)) - ret[field_name].write_only = True + ret[field_name].write_only = True return ret diff --git a/rest_framework/tests/test_serializers.py b/rest_framework/tests/test_serializers.py index 082a400ca..120510ace 100644 --- a/rest_framework/tests/test_serializers.py +++ b/rest_framework/tests/test_serializers.py @@ -3,6 +3,7 @@ from django.test import TestCase from rest_framework.serializers import _resolve_model from rest_framework.tests.models import BasicModel +from rest_framework.compat import six class ResolveModelTests(TestCase): @@ -19,6 +20,10 @@ class ResolveModelTests(TestCase): resolved_model = _resolve_model('tests.BasicModel') self.assertEqual(resolved_model, BasicModel) + def test_resolve_unicode_representation(self): + resolved_model = _resolve_model(six.text_type('tests.BasicModel')) + self.assertEqual(resolved_model, BasicModel) + def test_resolve_non_django_model(self): with self.assertRaises(ValueError): _resolve_model(TestCase) From eab5933070d5df9078a6b88e85ee933cbfa28955 Mon Sep 17 00:00:00 2001 From: khamaileon Date: Mon, 26 May 2014 18:43:50 +0200 Subject: [PATCH 13/39] Add the allow_add_remove parameter to the get_serializer method --- docs/api-guide/generic-views.md | 2 +- rest_framework/generics.py | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/api-guide/generic-views.md b/docs/api-guide/generic-views.md index 7d06f246c..bb748981e 100755 --- a/docs/api-guide/generic-views.md +++ b/docs/api-guide/generic-views.md @@ -187,7 +187,7 @@ Remember that the `pre_save()` method is not called by `GenericAPIView` itself, You won't typically need to override the following methods, although you might need to call into them if you're writing custom views using `GenericAPIView`. * `get_serializer_context(self)` - Returns a dictionary containing any extra context that should be supplied to the serializer. Defaults to including `'request'`, `'view'` and `'format'` keys. -* `get_serializer(self, instance=None, data=None, files=None, many=False, partial=False)` - Returns a serializer instance. +* `get_serializer(self, instance=None, data=None, files=None, many=False, partial=False, allow_add_remove=False)` - Returns a serializer instance. * `get_pagination_serializer(self, page)` - Returns a serializer instance to use with paginated data. * `paginate_queryset(self, queryset)` - Paginate a queryset if required, either returning a page object, or `None` if pagination is not configured for this view. * `filter_queryset(self, queryset)` - Given a queryset, filter it with whichever filter backends are in use, returning a new queryset. diff --git a/rest_framework/generics.py b/rest_framework/generics.py index 7bac510f7..7fc9db364 100644 --- a/rest_framework/generics.py +++ b/rest_framework/generics.py @@ -90,8 +90,8 @@ class GenericAPIView(views.APIView): 'view': self } - def get_serializer(self, instance=None, data=None, - files=None, many=False, partial=False): + def get_serializer(self, instance=None, data=None, files=None, many=False, + partial=False, allow_add_remove=False): """ Return the serializer instance that should be used for validating and deserializing input, and for serializing output. @@ -99,7 +99,9 @@ class GenericAPIView(views.APIView): serializer_class = self.get_serializer_class() context = self.get_serializer_context() return serializer_class(instance, data=data, files=files, - many=many, partial=partial, context=context) + many=many, partial=partial, + allow_add_remove=allow_add_remove, + context=context) def get_pagination_serializer(self, page): """ From a7ff51118f8c8d696219ea7723b283a0ee680457 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Thu, 29 May 2014 14:33:16 +0100 Subject: [PATCH 14/39] Note on configuring TokenAuthentication --- docs/api-guide/authentication.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api-guide/authentication.md b/docs/api-guide/authentication.md index 88a7a0119..1cb37d67f 100755 --- a/docs/api-guide/authentication.md +++ b/docs/api-guide/authentication.md @@ -119,7 +119,7 @@ Unauthenticated responses that are denied permission will result in an `HTTP 401 This authentication scheme uses a simple token-based HTTP Authentication scheme. Token authentication is appropriate for client-server setups, such as native desktop and mobile clients. -To use the `TokenAuthentication` scheme, include `rest_framework.authtoken` in your `INSTALLED_APPS` setting: +To use the `TokenAuthentication` scheme you'll need to [configure the authentication classes](#setting-the-authentication-scheme) to include `TokenAuthentication`, and additionally include `rest_framework.authtoken` in your `INSTALLED_APPS` setting: INSTALLED_APPS = ( ... From 6cb6bfae1b83c8682fa3c3d208c732c8ea49606e Mon Sep 17 00:00:00 2001 From: Danilo Bargen Date: Fri, 30 May 2014 17:53:26 +0200 Subject: [PATCH 15/39] Always use specified content type in APIRequestFactory If `content_type` is specified in the `APIRequestFactory`, always include it in the request, even if data is empty. --- rest_framework/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest_framework/test.py b/rest_framework/test.py index df5a5b3b3..284bcee07 100644 --- a/rest_framework/test.py +++ b/rest_framework/test.py @@ -36,7 +36,7 @@ class APIRequestFactory(DjangoRequestFactory): """ if not data: - return ('', None) + return ('', content_type) assert format is None or content_type is None, ( 'You may not set both `format` and `content_type`.' From 31f63e1e5502d45f414df400679c238346137b10 Mon Sep 17 00:00:00 2001 From: Rodolfo Carvalho Date: Mon, 2 Jun 2014 11:06:03 +0200 Subject: [PATCH 16/39] Fix typo in docs --- docs/api-guide/viewsets.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api-guide/viewsets.md b/docs/api-guide/viewsets.md index 23b16575f..b3085f75c 100644 --- a/docs/api-guide/viewsets.md +++ b/docs/api-guide/viewsets.md @@ -137,7 +137,7 @@ The `@action` and `@link` decorators can additionally take extra arguments that def set_password(self, request, pk=None): ... -The `@action` decorator will route `POST` requests by default, but may also accept other HTTP methods, by using the `method` argument. For example: +The `@action` decorator will route `POST` requests by default, but may also accept other HTTP methods, by using the `methods` argument. For example: @action(methods=['POST', 'DELETE']) def unset_password(self, request, pk=None): From 08c4594145a7219a14fafc87db0b9d61483d70d0 Mon Sep 17 00:00:00 2001 From: khamaileon Date: Thu, 5 Jun 2014 12:49:02 +0200 Subject: [PATCH 17/39] Replace ChoiceField type_label --- rest_framework/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 4ac5285e8..86e8fd9df 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -506,7 +506,7 @@ class SlugField(CharField): class ChoiceField(WritableField): type_name = 'ChoiceField' - type_label = 'multiple choice' + type_label = 'choice' form_field_class = forms.ChoiceField widget = widgets.Select default_error_messages = { From e8ec81f5e985f9cc9f524f77ec23013be918b990 Mon Sep 17 00:00:00 2001 From: Xavier Ordoquy Date: Sun, 8 Jun 2014 09:03:21 +0200 Subject: [PATCH 18/39] Fixed #1624 (thanks @abraithwaite) --- rest_framework/compat.py | 1 + 1 file changed, 1 insertion(+) diff --git a/rest_framework/compat.py b/rest_framework/compat.py index d155f5542..fdf12448a 100644 --- a/rest_framework/compat.py +++ b/rest_framework/compat.py @@ -51,6 +51,7 @@ except ImportError: # guardian is optional try: import guardian + import guardian.shortcuts # Fixes #1624 except ImportError: guardian = None From be84f71bc906c926c9955a4cf47630b24461067d Mon Sep 17 00:00:00 2001 From: Greg Barker Date: Tue, 10 Jun 2014 15:20:45 -0700 Subject: [PATCH 19/39] Fix #1614 - Corrected reference to serializers.CharField --- docs/api-guide/serializers.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md index 0044f0701..cedf1ff7b 100644 --- a/docs/api-guide/serializers.md +++ b/docs/api-guide/serializers.md @@ -73,8 +73,8 @@ Sometimes when serializing objects, you may not want to represent everything exa If you need to customize the serialized value of a particular field, you can do this by creating a `transform_` method. For example if you needed to render some markdown from a text field: - description = serializers.TextField() - description_html = serializers.TextField(source='description', read_only=True) + description = serializers.CharField() + description_html = serializers.CharField(source='description', read_only=True) def transform_description_html(self, obj, value): from django.contrib.markup.templatetags.markup import markdown From 1386767013d044d337b8e08dd2f9b0197197cccf Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Thu, 12 Jun 2014 11:47:26 +0100 Subject: [PATCH 20/39] Version 2.3.14 --- docs/api-guide/content-negotiation.md | 2 -- docs/topics/release-notes.md | 36 ++++++++++--------- rest_framework/__init__.py | 2 +- rest_framework/templatetags/rest_framework.py | 4 +-- 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/docs/api-guide/content-negotiation.md b/docs/api-guide/content-negotiation.md index 94dd59cac..58b2a2ce0 100644 --- a/docs/api-guide/content-negotiation.md +++ b/docs/api-guide/content-negotiation.md @@ -1,5 +1,3 @@ - - # Content negotiation > HTTP has provisions for several mechanisms for "content negotiation" - the process of selecting the best representation for a given response when there are multiple representations available. diff --git a/docs/topics/release-notes.md b/docs/topics/release-notes.md index 335497eec..ea4c912c9 100644 --- a/docs/topics/release-notes.md +++ b/docs/topics/release-notes.md @@ -40,24 +40,28 @@ You can determine your currently installed version using `pip freeze`: ## 2.3.x series -### 2.3.x +### 2.3.14 -**Date**: April 2014 +**Date**: 12th June 2014 -* Fix nested serializers linked through a backward foreign key relation -* Fix bad links for the `BrowsableAPIRenderer` with `YAMLRenderer` -* Add `UnicodeYAMLRenderer` that extends `YAMLRenderer` with unicode -* Fix `parse_header` argument convertion -* Fix mediatype detection under Python3 -* Web browseable API now offers blank option on dropdown when the field is not required -* `APIException` representation improved for logging purposes -* Allow source="*" within nested serializers -* Better support for custom oauth2 provider backends -* Fix field validation if it's optional and has no value -* Add `SEARCH_PARAM` and `ORDERING_PARAM` -* Fix `APIRequestFactory` to support arguments within the url string for GET -* Allow three transport modes for access tokens when accessing a protected resource -* Fix `Request`'s `QueryDict` encoding +* **Security fix**: Escape request path when it is include as part of the login and logout links in the browsable API. +* `help_text` and `verbose_name` automatically set for related fields on `ModelSerializer`. +* Fix nested serializers linked through a backward foreign key relation. +* Fix bad links for the `BrowsableAPIRenderer` with `YAMLRenderer`. +* Add `UnicodeYAMLRenderer` that extends `YAMLRenderer` with unicode. +* Fix `parse_header` argument convertion. +* Fix mediatype detection under Python 3. +* Web browseable API now offers blank option on dropdown when the field is not required. +* `APIException` representation improved for logging purposes. +* Allow source="*" within nested serializers. +* Better support for custom oauth2 provider backends. +* Fix field validation if it's optional and has no value. +* Add `SEARCH_PARAM` and `ORDERING_PARAM`. +* Fix `APIRequestFactory` to support arguments within the url string for GET. +* Allow three transport modes for access tokens when accessing a protected resource. +* Fix `QueryDict` encoding on request objects. +* Ensure throttle keys do not contain spaces, as those are invalid if using `memcached`. +* Support `blank_display_value` on `ChoiceField`. ### 2.3.13 diff --git a/rest_framework/__init__.py b/rest_framework/__init__.py index 2d76b55d5..01036cefa 100644 --- a/rest_framework/__init__.py +++ b/rest_framework/__init__.py @@ -8,7 +8,7 @@ ______ _____ _____ _____ __ _ """ __title__ = 'Django REST framework' -__version__ = '2.3.13' +__version__ = '2.3.14' __author__ = 'Tom Christie' __license__ = 'BSD 2-Clause' __copyright__ = 'Copyright 2011-2014 Tom Christie' diff --git a/rest_framework/templatetags/rest_framework.py b/rest_framework/templatetags/rest_framework.py index dff176d62..a155d8d25 100644 --- a/rest_framework/templatetags/rest_framework.py +++ b/rest_framework/templatetags/rest_framework.py @@ -122,7 +122,7 @@ def optional_login(request): except NoReverseMatch: return '' - snippet = "Log in" % (login_url, request.path) + snippet = "Log in" % (login_url, escape(request.path)) return snippet @@ -136,7 +136,7 @@ def optional_logout(request): except NoReverseMatch: return '' - snippet = "Log out" % (logout_url, request.path) + snippet = "Log out" % (logout_url, escape(request.path)) return snippet From 82659873c9d3e3058b7e7ea63e4c4b190c7fc19c Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Thu, 12 Jun 2014 11:48:58 +0100 Subject: [PATCH 21/39] Fix accidental docs change --- docs/api-guide/content-negotiation.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/api-guide/content-negotiation.md b/docs/api-guide/content-negotiation.md index 58b2a2ce0..94dd59cac 100644 --- a/docs/api-guide/content-negotiation.md +++ b/docs/api-guide/content-negotiation.md @@ -1,3 +1,5 @@ + + # Content negotiation > HTTP has provisions for several mechanisms for "content negotiation" - the process of selecting the best representation for a given response when there are multiple representations available. From 544183f64ff115398ae62c916d58f8369263d47c Mon Sep 17 00:00:00 2001 From: TankorSmash Date: Mon, 16 Jun 2014 19:13:02 -0400 Subject: [PATCH 22/39] typo in the docs --- rest_framework/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 86e8fd9df..d5c8134b0 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -187,7 +187,7 @@ class Field(object): def field_to_native(self, obj, field_name): """ - Given and object and a field name, returns the value that should be + Given an object and a field name, returns the value that should be serialized for that field. """ if obj is None: From c1426d1078a40de521aeec6c4099538efa6b24c7 Mon Sep 17 00:00:00 2001 From: Chibisov Gennady Date: Thu, 26 Jun 2014 23:29:00 +0400 Subject: [PATCH 23/39] Fixes #1651. Add link to drf-extensions nested routers to docs --- docs/api-guide/routers.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/api-guide/routers.md b/docs/api-guide/routers.md index 7efc140a5..64f05af39 100644 --- a/docs/api-guide/routers.md +++ b/docs/api-guide/routers.md @@ -179,7 +179,16 @@ The [wq.db package][wq.db] provides an advanced [Router][wq.db-router] class (an app.router.register_model(MyModel) +## DRF-extensions + +The [`DRF-extensions` package][drf-extensions] provides [routers][drf-extensions-routers] for creating [nested viewsets][drf-extensions-nested-viewsets], [collection level controllers][drf-extensions-collection-level-controllers] with [customizable endpoint names][drf-extensions-customizable-endpoint-names]. + [cite]: http://guides.rubyonrails.org/routing.html [drf-nested-routers]: https://github.com/alanjds/drf-nested-routers [wq.db]: http://wq.io/wq.db [wq.db-router]: http://wq.io/docs/app.py +[drf-extensions]: http://chibisov.github.io/drf-extensions/docs/ +[drf-extensions-routers]: http://chibisov.github.io/drf-extensions/docs/#routers +[drf-extensions-nested-viewsets]: http://chibisov.github.io/drf-extensions/docs/#nested-routes +[drf-extensions-collection-level-controllers]: http://chibisov.github.io/drf-extensions/docs/#collection-level-controllers +[drf-extensions-customizable-endpoint-names]: http://chibisov.github.io/drf-extensions/docs/#controller-endpoint-name \ No newline at end of file From 91eabd54bbc42e8a2540db2ff070097db7a0f4a0 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 1 Jul 2014 14:34:23 +0100 Subject: [PATCH 24/39] Docs tweak --- docs/api-guide/filtering.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/api-guide/filtering.md b/docs/api-guide/filtering.md index 6a8a267b2..ec5ab61fe 100644 --- a/docs/api-guide/filtering.md +++ b/docs/api-guide/filtering.md @@ -199,8 +199,7 @@ This enables us to make queries like: http://example.com/api/products?manufacturer__name=foo -This is nice, but it shows underlying model structure in REST API, which may -be undesired, but you can use: +This is nice, but it exposes the Django's double underscore convention as part of the API. If you instead want to explicitly name the filter argument you can instead explicitly include it on the `FilterSet` class: import django_filters from myapp.models import Product @@ -208,7 +207,6 @@ be undesired, but you can use: from rest_framework import generics class ProductFilter(django_filters.FilterSet): - manufacturer = django_filters.CharFilter(name="manufacturer__name") class Meta: From a5e628bf8b4cf26227d4ee0cbef45049aa0632d5 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 7 Jul 2014 09:42:50 +0100 Subject: [PATCH 25/39] Kick travis --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 73e4b13fc..da5f27aef 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,7 @@ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + [build-status-image]: https://secure.travis-ci.org/tomchristie/django-rest-framework.png?branch=master [travis]: http://travis-ci.org/tomchristie/django-rest-framework?branch=master [twitter]: https://twitter.com/_tomchristie From b51901812596aa478cc8cb1046e42049214bc9ff Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 7 Jul 2014 09:51:23 +0100 Subject: [PATCH 26/39] Docs on object level permissions and filters. Closes #1683 --- docs/api-guide/permissions.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/api-guide/permissions.md b/docs/api-guide/permissions.md index 50f669a2d..c44b22de8 100644 --- a/docs/api-guide/permissions.md +++ b/docs/api-guide/permissions.md @@ -36,6 +36,12 @@ For example: self.check_object_permissions(self.request, obj) return obj +#### Limitations of object level permissions + +For performance reasons the generic views will not automatically apply object level permissions to each instance in a queryset when returning a list of objects. + +Often when you're using object level permissions you'll also want to [filter the queryset][filtering] appropriately, to ensure that users only have visibility onto instances that they are permitted to view. + ## Setting the permission policy The default permission policy may be set globally, using the `DEFAULT_PERMISSION_CLASSES` setting. For example. @@ -237,6 +243,7 @@ The [REST Condition][rest-condition] package is another extension for building c [cite]: https://developer.apple.com/library/mac/#documentation/security/Conceptual/AuthenticationAndAuthorizationGuide/Authorization/Authorization.html [authentication]: authentication.md [throttling]: throttling.md +[filtering]: filtering.md [contribauth]: https://docs.djangoproject.com/en/1.0/topics/auth/#permissions [objectpermissions]: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#handling-object-permissions [guardian]: https://github.com/lukaszb/django-guardian From dd2e950cde5fc7078303925fa936e59ea4fe363b Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 15 Jul 2014 15:02:09 +0100 Subject: [PATCH 27/39] Fusion ads --- docs/template.html | 24 +++++++++++++++++++----- mkdocs.py | 4 ++-- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/docs/template.html b/docs/template.html index a397d067b..6009b1510 100644 --- a/docs/template.html +++ b/docs/template.html @@ -33,6 +33,21 @@ })(); + @@ -169,11 +184,9 @@
@@ -199,6 +212,7 @@ + """) else: output = output.replace('{{ ad_block }}', '') From 6bf0f81b0b911eb3d2bf3dd3fbaaf44570a58b28 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Thu, 17 Jul 2014 13:41:19 +0100 Subject: [PATCH 28/39] Kickstarter note on front page --- docs/index.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/index.md b/docs/index.md index 2a4ad8859..a870a8280 100644 --- a/docs/index.md +++ b/docs/index.md @@ -9,6 +9,10 @@ --- +**Project announcement:** We are currently running a Kickstart campaign to help fund the development of Django REST framework 3. If you want to help make sustainable open source development please [check out the Kickstarter project](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3), and consider funding us! + +--- +

2.0 Announcement
  • 2.2 Announcement
  • 2.3 Announcement
  • +
  • Kickstarter Announcement
  • Release Notes
  • Credits
  • diff --git a/docs/topics/kickstarter-announcement.md b/docs/topics/kickstarter-announcement.md new file mode 100644 index 000000000..98cf12e3b --- /dev/null +++ b/docs/topics/kickstarter-announcement.md @@ -0,0 +1,31 @@ +# Kickstarting Django REST framework 3 + +--- + + + +--- + +In order to continue to drive the project forward, I'm launching a Kickstarter campaign to help fund the development of a major new release - Django REST framework 3. + +## Project details + +This new release will allow us to comprehensively address some of the shortcomings of the framework, and will aim to include the following: + +* Faster, simpler and easier-to-use serializers. +* An alternative admin-style interface for the browsable API. +* Search and filtering controls made accessible in the browsable API. +* Alternative API pagination styles. +* Documentation around API versioning. +* Triage of outstanding tickets. +* Improving the ongoing quality and maintainability of the project. + +Full details are available now on the [project page](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3). + +If you're interested in helping make sustainable open source development a reality please [visit the Kickstarter page](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3) and consider funding the project. + +I can't wait to see where this takes us! + +Many thanks to everyone for your support so far, + + Tom Christie :) From 550243fd2649195f6433bf07354880d86bfedde9 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 18 Jul 2014 11:51:48 +0100 Subject: [PATCH 30/39] Beef up the kickstarter announcement --- docs/index.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index c1f60097e..c07a56457 100644 --- a/docs/index.md +++ b/docs/index.md @@ -9,7 +9,11 @@ --- -**Project announcement:** We are currently running a Kickstarter campaign to help fund the development of Django REST framework 3. If you want to help make sustainable open source development please [check out the Kickstarter project](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3), and consider funding us! +#### Django REST framework 3 - Kickstarter announcement! + +We are currently running a Kickstarter campaign to help fund the development of Django REST framework 3. + +If you want to help make sustainable open source development **please [check out the Kickstarter project](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3) and consider funding us.** --- From ab34ddcf2f734ca5f1a6e43ff1280283b9a171e5 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 18 Jul 2014 11:53:23 +0100 Subject: [PATCH 31/39] Typo --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index c07a56457..5b5a62eba 100644 --- a/docs/index.md +++ b/docs/index.md @@ -13,7 +13,7 @@ We are currently running a Kickstarter campaign to help fund the development of Django REST framework 3. -If you want to help make sustainable open source development **please [check out the Kickstarter project](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3) and consider funding us.** +If you want to help make sustainable open-source development a reality **please [check out the Kickstarter project](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3) and consider funding us.** --- From 4324f504375f7f118297fa9694bd6cee56bc050e Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 18 Jul 2014 11:54:51 +0100 Subject: [PATCH 32/39] Phrasing tweak --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 5b5a62eba..d9c686c4a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -13,7 +13,7 @@ We are currently running a Kickstarter campaign to help fund the development of Django REST framework 3. -If you want to help make sustainable open-source development a reality **please [check out the Kickstarter project](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3) and consider funding us.** +If you want to help drive sustainable open-source development **please [check out the Kickstarter project](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3) and consider funding us.** --- From 0782640415e665caef7b76b349a7d1e59dec25df Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 18 Jul 2014 13:19:28 +0100 Subject: [PATCH 33/39] Kickstarter announcement --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index da5f27aef..0f81f3ae4 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,16 @@ **Note**: Full documentation for the project is available at [http://www.django-rest-framework.org][docs]. +--- + +#### Django REST framework 3 - Kickstarter announcement! + +We are currently running a Kickstarter campaign to help fund the development of Django REST framework 3. + +If you want to help drive sustainable open-source development **please [check out the Kickstarter project](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3) and consider funding us.** + +--- + # Overview Django REST framework is a powerful and flexible toolkit that makes it easy to build Web APIs. From d059b6d6c391099ded2abd8fa0cf06821f971a5e Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 18 Jul 2014 13:20:03 +0100 Subject: [PATCH 34/39] Change positioning of announcement. --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 0f81f3ae4..1d7eefcff 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,3 @@ -# Django REST framework - -[![build-status-image]][travis] - -**Awesome web-browseable Web APIs.** - -**Note**: Full documentation for the project is available at [http://www.django-rest-framework.org][docs]. - --- #### Django REST framework 3 - Kickstarter announcement! @@ -16,6 +8,14 @@ If you want to help drive sustainable open-source development **please [check ou --- +# Django REST framework + +[![build-status-image]][travis] + +**Awesome web-browseable Web APIs.** + +**Note**: Full documentation for the project is available at [http://www.django-rest-framework.org][docs]. + # Overview Django REST framework is a powerful and flexible toolkit that makes it easy to build Web APIs. From 30bf55bf8da2be8ae0228c8d0dee3a523ae5eba5 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 18 Jul 2014 13:20:55 +0100 Subject: [PATCH 35/39] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1d7eefcff..e58ec8ae5 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ We are currently running a Kickstarter campaign to help fund the development of Django REST framework 3. -If you want to help drive sustainable open-source development **please [check out the Kickstarter project](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3) and consider funding us.** +If you want to help drive sustainable open-source development forward **please [cconsider funding the Kickstarter project](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3).** --- From 591e67f5405d6a8f59b2e52b1050752faa906c52 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 18 Jul 2014 13:21:03 +0100 Subject: [PATCH 36/39] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e58ec8ae5..a1bfa91df 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ We are currently running a Kickstarter campaign to help fund the development of Django REST framework 3. -If you want to help drive sustainable open-source development forward **please [cconsider funding the Kickstarter project](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3).** +If you want to help drive sustainable open-source development forward **please [consider funding the Kickstarter project](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3).** --- From bf7371fbc5a05b359cee03b8cbadd8229e563070 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 18 Jul 2014 13:21:19 +0100 Subject: [PATCH 37/39] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a1bfa91df..e0d421c00 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ We are currently running a Kickstarter campaign to help fund the development of Django REST framework 3. -If you want to help drive sustainable open-source development forward **please [consider funding the Kickstarter project](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3).** +If you want to help drive sustainable open-source development forward **please consider funding [the Kickstarter project](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3).** --- From 08772799d466907a16f02aec990396736be3c022 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 18 Jul 2014 13:22:29 +0100 Subject: [PATCH 38/39] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e0d421c00..eea002b4a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ We are currently running a Kickstarter campaign to help fund the development of Django REST framework 3. -If you want to help drive sustainable open-source development forward **please consider funding [the Kickstarter project](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3).** +If you want to help drive sustainable open-source development forward, then **please check out [the Kickstarter project](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3) and consider funding us.** --- From 81d15aa9be72ac8b805fc728bd86f930ff1b17e7 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sun, 20 Jul 2014 15:45:45 +0100 Subject: [PATCH 39/39] Add link to drf-extra-fields. Closes #1698 --- docs/api-guide/fields.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index 58dbf977e..cebfaac92 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -357,9 +357,16 @@ The following third party packages are also available. The [drf-compound-fields][drf-compound-fields] package provides "compound" serializer fields, such as lists of simple values, which can be described by other fields rather than serializers with the `many=True` option. Also provided are fields for typed dictionaries and values that can be either a specific type or a list of items of that type. +## DRF Extra Fields + +The [drf-extra-fields][drf-extra-fields] package provides extra serializer fields for REST framework, including `Base64ImageField` and `PointField` classes. + + + [cite]: https://docs.djangoproject.com/en/dev/ref/forms/api/#django.forms.Form.cleaned_data [FILE_UPLOAD_HANDLERS]: https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FILE_UPLOAD_HANDLERS [ecma262]: http://ecma-international.org/ecma-262/5.1/#sec-15.9.1.15 [strftime]: http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior [iso8601]: http://www.w3.org/TR/NOTE-datetime [drf-compound-fields]: http://drf-compound-fields.readthedocs.org +[drf-extra-fields]: https://github.com/Hipo/drf-extra-fields \ No newline at end of file