mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-01-23 15:54:16 +03:00
Merge remote-tracking branch 'reference/master' into feature/pytest
Conflicts: tests/test_serializer.py
This commit is contained in:
commit
2aca69a946
16
.travis.yml
16
.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"
|
||||
|
||||
|
|
|
@ -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**:
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
26
tox.ini
26
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
|
||||
|
|
Loading…
Reference in New Issue
Block a user