aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml16
-rwxr-xr-xdocs/api-guide/generic-views.md2
-rw-r--r--docs/api-guide/pagination.md3
-rw-r--r--docs/api-guide/permissions.md2
-rw-r--r--docs/topics/release-notes.md19
-rw-r--r--rest_framework/authtoken/models.py2
-rw-r--r--rest_framework/fields.py2
-rw-r--r--rest_framework/serializers.py8
-rw-r--r--tests/models.py3
-rw-r--r--tests/test_authentication.py8
-rw-r--r--tests/test_serializer.py26
-rw-r--r--tox.ini26
12 files changed, 88 insertions, 29 deletions
diff --git a/.travis.yml b/.travis.yml
index 4f4d0c30..d2f20e2b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -7,10 +7,10 @@ python:
- "3.3"
env:
- - DJANGO="https://www.djangoproject.com/download/1.7b1/tarball/"
- - DJANGO="django==1.6.2"
- - DJANGO="django==1.5.5"
- - DJANGO="django==1.4.10"
+ - 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="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.7b1/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.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"
- export PYTHONPATH=.
script:
@@ -33,13 +33,13 @@ script:
matrix:
exclude:
- python: "2.6"
- env: DJANGO="https://www.djangoproject.com/download/1.7b1/tarball/"
+ env: DJANGO="https://www.djangoproject.com/download/1.7b2/tarball/"
- python: "3.2"
- env: DJANGO="django==1.4.10"
+ env: DJANGO="django==1.4.11"
- python: "3.2"
env: DJANGO="django==1.3.7"
- python: "3.3"
- env: DJANGO="django==1.4.10"
+ env: DJANGO="django==1.4.11"
- python: "3.3"
env: DJANGO="django==1.3.7"
diff --git a/docs/api-guide/generic-views.md b/docs/api-guide/generic-views.md
index fb927ea8..7d06f246 100755
--- a/docs/api-guide/generic-views.md
+++ b/docs/api-guide/generic-views.md
@@ -70,7 +70,7 @@ The following attributes control the basic view behavior.
**Shortcuts**:
-* `model` - This shortcut may be used instead of setting either (or both) of the `queryset`/`serializer_class` attributes, although using the explicit style is generally preferred. If used instead of `serializer_class`, then then `DEFAULT_MODEL_SERIALIZER_CLASS` setting will determine the base serializer class. Note that `model` is only ever used for generating a default queryset or serializer class - the `queryset` and `serializer_class` attributes are always preferred if provided.
+* `model` - This shortcut may be used instead of setting either (or both) of the `queryset`/`serializer_class` attributes, although using the explicit style is generally preferred. If used instead of `serializer_class`, then `DEFAULT_MODEL_SERIALIZER_CLASS` setting will determine the base serializer class. Note that `model` is only ever used for generating a default queryset or serializer class - the `queryset` and `serializer_class` attributes are always preferred if provided.
**Pagination**:
diff --git a/docs/api-guide/pagination.md b/docs/api-guide/pagination.md
index efc4ae7f..e57aed1a 100644
--- a/docs/api-guide/pagination.md
+++ b/docs/api-guide/pagination.md
@@ -103,6 +103,7 @@ You can also set the pagination style on a per-view basis, using the `ListAPIVie
max_paginate_by = 100
Note that using a `paginate_by` value of `None` will turn off pagination for the view.
+Note if you use the `PAGINATE_BY_PARAM` settings, you also have to set the `paginate_by_param` attribute in your view to `None` in order to turn off pagination for those requests that contain the `paginate_by_param` parameter.
For more complex requirements such as serialization that differs depending on the requested media type you can override the `.get_paginate_by()` and `.get_pagination_serializer_class()` methods.
@@ -157,4 +158,4 @@ The [`DRF-extensions` package][drf-extensions] includes a [`PaginateByMaxMixin`
[cite]: https://docs.djangoproject.com/en/dev/topics/pagination/
[drf-extensions]: http://chibisov.github.io/drf-extensions/docs/
-[paginate-by-max-mixin]: http://chibisov.github.io/drf-extensions/docs/#paginatebymaxmixin \ No newline at end of file
+[paginate-by-max-mixin]: http://chibisov.github.io/drf-extensions/docs/#paginatebymaxmixin
diff --git a/docs/api-guide/permissions.md b/docs/api-guide/permissions.md
index 6a0f48f4..50f669a2 100644
--- a/docs/api-guide/permissions.md
+++ b/docs/api-guide/permissions.md
@@ -56,7 +56,7 @@ You can also set the authentication policy on a per-view, or per-viewset basis,
using the `APIView` class based views.
from rest_framework.permissions import IsAuthenticated
- from rest_framework.responses import Response
+ from rest_framework.response import Response
from rest_framework.views import APIView
class ExampleView(APIView):
diff --git a/docs/topics/release-notes.md b/docs/topics/release-notes.md
index 2bc8b2d6..335497ee 100644
--- a/docs/topics/release-notes.md
+++ b/docs/topics/release-notes.md
@@ -40,6 +40,25 @@ You can determine your currently installed version using `pip freeze`:
## 2.3.x series
+### 2.3.x
+
+**Date**: April 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
+
### 2.3.13
**Date**: 6th March 2014
diff --git a/rest_framework/authtoken/models.py b/rest_framework/authtoken/models.py
index 8eac2cc4..167fa531 100644
--- a/rest_framework/authtoken/models.py
+++ b/rest_framework/authtoken/models.py
@@ -34,7 +34,7 @@ class Token(models.Model):
return super(Token, self).save(*args, **kwargs)
def generate_key(self):
- return binascii.hexlify(os.urandom(20))
+ return binascii.hexlify(os.urandom(20)).decode()
def __unicode__(self):
return self.key
diff --git a/rest_framework/fields.py b/rest_framework/fields.py
index 946a5954..8cdc5551 100644
--- a/rest_framework/fields.py
+++ b/rest_framework/fields.py
@@ -289,7 +289,7 @@ class WritableField(Field):
self.validators = self.default_validators + validators
self.default = default if default is not None else self.default
- # Widgets are ony used for HTML forms.
+ # Widgets are only used for HTML forms.
widget = widget or self.widget
if isinstance(widget, type):
widget = widget()
diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py
index ea9509bf..9cb548a5 100644
--- a/rest_framework/serializers.py
+++ b/rest_framework/serializers.py
@@ -828,6 +828,10 @@ class ModelSerializer(Serializer):
if model_field:
kwargs['required'] = not(model_field.null or model_field.blank)
+ if model_field.help_text is not None:
+ kwargs['help_text'] = model_field.help_text
+ if model_field.verbose_name is not None:
+ kwargs['label'] = model_field.verbose_name
return PrimaryKeyRelatedField(**kwargs)
@@ -1088,6 +1092,10 @@ class HyperlinkedModelSerializer(ModelSerializer):
if model_field:
kwargs['required'] = not(model_field.null or model_field.blank)
+ if model_field.help_text is not None:
+ kwargs['help_text'] = model_field.help_text
+ if model_field.verbose_name is not None:
+ kwargs['label'] = model_field.verbose_name
if self.opts.lookup_field:
kwargs['lookup_field'] = self.opts.lookup_field
diff --git a/tests/models.py b/tests/models.py
index 6c8f2342..0256697a 100644
--- a/tests/models.py
+++ b/tests/models.py
@@ -143,7 +143,8 @@ class ForeignKeyTarget(RESTFrameworkModel):
class ForeignKeySource(RESTFrameworkModel):
name = models.CharField(max_length=100)
- target = models.ForeignKey(ForeignKeyTarget, related_name='sources')
+ target = models.ForeignKey(ForeignKeyTarget, related_name='sources',
+ help_text='Target', verbose_name='Target')
# Nullable ForeignKey
diff --git a/tests/test_authentication.py b/tests/test_authentication.py
index 1d90493e..d0290eac 100644
--- a/tests/test_authentication.py
+++ b/tests/test_authentication.py
@@ -19,7 +19,7 @@ from rest_framework.authentication import (
OAuth2Authentication
)
from rest_framework.authtoken.models import Token
-from rest_framework.compat import patterns, url, include
+from rest_framework.compat import patterns, url, include, six
from rest_framework.compat import oauth2_provider, oauth2_provider_scope
from rest_framework.compat import oauth, oauth_provider
from rest_framework.test import APIRequestFactory, APIClient
@@ -195,6 +195,12 @@ class TokenAuthTests(TestCase):
token = Token.objects.create(user=self.user)
self.assertTrue(bool(token.key))
+ def test_generate_key_returns_string(self):
+ """Ensure generate_key returns a string"""
+ token = Token()
+ key = token.generate_key()
+ self.assertTrue(isinstance(key, six.string_types))
+
def test_token_login_json(self):
"""Ensure token login view using JSON POST works."""
client = APIClient(enforce_csrf_checks=True)
diff --git a/tests/test_serializer.py b/tests/test_serializer.py
index f8966886..73eb5c79 100644
--- a/tests/test_serializer.py
+++ b/tests/test_serializer.py
@@ -9,7 +9,8 @@ from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers, fields, relations
from tests.models import (HasPositiveIntegerAsChoice, Album, ActionItem, Anchor, BasicModel,
BlankFieldModel, BlogPost, BlogPostComment, Book, CallableDefaultValueModel, DefaultValueModel,
- ManyToManyModel, Person, ReadOnlyManyToManyModel, Photo, RESTFrameworkModel)
+ ManyToManyModel, Person, ReadOnlyManyToManyModel, Photo, RESTFrameworkModel,
+ ForeignKeySource, ManyToManySource)
from tests.models import BasicModelSerializer
import datetime
import pickle
@@ -176,6 +177,16 @@ class PositiveIntegerAsChoiceSerializer(serializers.ModelSerializer):
fields = ['some_integer']
+class ForeignKeySourceSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = ForeignKeySource
+
+
+class HyperlinkedForeignKeySourceSerializer(serializers.HyperlinkedModelSerializer):
+ class Meta:
+ model = ForeignKeySource
+
+
class BasicTests(TestCase):
def setUp(self):
self.comment = Comment(
@@ -1600,6 +1611,19 @@ class ManyFieldHelpTextTest(TestCase):
self.assertEqual('Some help text.', rel_field.help_text)
+class AttributeMappingOnAutogeneratedRelatedFields(TestCase):
+
+ def test_primary_key_related_field(self):
+ serializer = ForeignKeySourceSerializer()
+ self.assertEqual(serializer.fields['target'].help_text, 'Target')
+ self.assertEqual(serializer.fields['target'].label, 'Target')
+
+ def test_hyperlinked_related_field(self):
+ serializer = HyperlinkedForeignKeySourceSerializer()
+ self.assertEqual(serializer.fields['target'].help_text, 'Target')
+ self.assertEqual(serializer.fields['target'].label, 'Target')
+
+
@unittest.skipUnless(PIL is not None, 'PIL is not installed')
class AttributeMappingOnAutogeneratedFieldsTests(TestCase):
diff --git a/tox.ini b/tox.ini
index 2f6f1612..6212a6b2 100644
--- a/tox.ini
+++ b/tox.ini
@@ -7,7 +7,7 @@ commands = py.test -q
[testenv:py3.3-django1.7]
basepython = python3.3
-deps = https://www.djangoproject.com/download/1.7b1/tarball/
+deps = https://www.djangoproject.com/download/1.7b2/tarball/
django-filter==0.7
defusedxml==0.3
Pillow==2.3.0
@@ -15,7 +15,7 @@ deps = https://www.djangoproject.com/download/1.7b1/tarball/
[testenv:py3.2-django1.7]
basepython = python3.2
-deps = https://www.djangoproject.com/download/1.7b1/tarball/
+deps = https://www.djangoproject.com/download/1.7b2/tarball/
django-filter==0.7
defusedxml==0.3
Pillow==2.3.0
@@ -23,7 +23,7 @@ deps = https://www.djangoproject.com/download/1.7b1/tarball/
[testenv:py2.7-django1.7]
basepython = python2.7
-deps = https://www.djangoproject.com/download/1.7b1/tarball/
+deps = https://www.djangoproject.com/download/1.7b2/tarball/
django-filter==0.7
defusedxml==0.3
django-oauth-plus==2.2.1
@@ -35,7 +35,7 @@ deps = https://www.djangoproject.com/download/1.7b1/tarball/
[testenv:py3.3-django1.6]
basepython = python3.3
-deps = Django==1.6
+deps = Django==1.6.3
django-filter==0.7
defusedxml==0.3
Pillow==2.3.0
@@ -43,7 +43,7 @@ deps = Django==1.6
[testenv:py3.2-django1.6]
basepython = python3.2
-deps = Django==1.6
+deps = Django==1.6.3
django-filter==0.7
defusedxml==0.3
Pillow==2.3.0
@@ -51,7 +51,7 @@ deps = Django==1.6
[testenv:py2.7-django1.6]
basepython = python2.7
-deps = Django==1.6
+deps = Django==1.6.3
django-filter==0.7
defusedxml==0.3
django-oauth-plus==2.2.1
@@ -63,7 +63,7 @@ deps = Django==1.6
[testenv:py2.6-django1.6]
basepython = python2.6
-deps = Django==1.6
+deps = Django==1.6.3
django-filter==0.7
defusedxml==0.3
django-oauth-plus==2.2.1
@@ -75,7 +75,7 @@ deps = Django==1.6
[testenv:py3.3-django1.5]
basepython = python3.3
-deps = django==1.5.5
+deps = django==1.5.6
django-filter==0.7
defusedxml==0.3
Pillow==2.3.0
@@ -83,7 +83,7 @@ deps = django==1.5.5
[testenv:py3.2-django1.5]
basepython = python3.2
-deps = django==1.5.5
+deps = django==1.5.6
django-filter==0.7
defusedxml==0.3
Pillow==2.3.0
@@ -91,7 +91,7 @@ deps = django==1.5.5
[testenv:py2.7-django1.5]
basepython = python2.7
-deps = django==1.5.5
+deps = django==1.5.6
django-filter==0.7
defusedxml==0.3
django-oauth-plus==2.2.1
@@ -103,7 +103,7 @@ deps = django==1.5.5
[testenv:py2.6-django1.5]
basepython = python2.6
-deps = django==1.5.5
+deps = django==1.5.6
django-filter==0.7
defusedxml==0.3
django-oauth-plus==2.2.1
@@ -115,7 +115,7 @@ deps = django==1.5.5
[testenv:py2.7-django1.4]
basepython = python2.7
-deps = django==1.4.10
+deps = django==1.4.11
django-filter==0.7
defusedxml==0.3
django-oauth-plus==2.2.1
@@ -127,7 +127,7 @@ deps = django==1.4.10
[testenv:py2.6-django1.4]
basepython = python2.6
-deps = django==1.4.10
+deps = django==1.4.11
django-filter==0.7
defusedxml==0.3
django-oauth-plus==2.2.1