mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-26 11:33:59 +03:00
commit
65d6cba75f
|
@ -33,7 +33,7 @@ Some tips on good issue reporting:
|
||||||
* When describing issues try to phrase your ticket in terms of the *behavior* you think needs changing rather than the *code* you think need changing.
|
* When describing issues try to phrase your ticket in terms of the *behavior* you think needs changing rather than the *code* you think need changing.
|
||||||
* Search the issue list first for related items, and make sure you're running the latest version of REST framework before reporting an issue.
|
* Search the issue list first for related items, and make sure you're running the latest version of REST framework before reporting an issue.
|
||||||
* If reporting a bug, then try to include a pull request with a failing test case. This will help us quickly identify if there is a valid issue, and make sure that it gets fixed more quickly if there is one.
|
* If reporting a bug, then try to include a pull request with a failing test case. This will help us quickly identify if there is a valid issue, and make sure that it gets fixed more quickly if there is one.
|
||||||
* Feature requests will often be closed with a recommendation that they be implemented outside of the core REST framework library. Keeping new feature requests implemented as third party libraries allows us to keep down the maintainence overhead of REST framework, so that the focus can be on continued stability, bugfixes, and great documentation.
|
* Feature requests will often be closed with a recommendation that they be implemented outside of the core REST framework library. Keeping new feature requests implemented as third party libraries allows us to keep down the maintenance overhead of REST framework, so that the focus can be on continued stability, bugfixes, and great documentation.
|
||||||
* Closing an issue doesn't necessarily mean the end of a discussion. If you believe your issue has been closed incorrectly, explain why and we'll consider if it needs to be reopened.
|
* Closing an issue doesn't necessarily mean the end of a discussion. If you believe your issue has been closed incorrectly, explain why and we'll consider if it needs to be reopened.
|
||||||
|
|
||||||
## Triaging issues
|
## Triaging issues
|
||||||
|
@ -82,7 +82,7 @@ GitHub's documentation for working on pull requests is [available here][pull-req
|
||||||
|
|
||||||
Always run the tests before submitting pull requests, and ideally run `tox` in order to check that your modifications are compatible with both Python 2 and Python 3, and that they run properly on all supported versions of Django.
|
Always run the tests before submitting pull requests, and ideally run `tox` in order to check that your modifications are compatible with both Python 2 and Python 3, and that they run properly on all supported versions of Django.
|
||||||
|
|
||||||
Once you've made a pull request take a look at the travis build status in the GitHub interface and make sure the tests are runnning as you'd expect.
|
Once you've made a pull request take a look at the travis build status in the GitHub interface and make sure the tests are running as you'd expect.
|
||||||
|
|
||||||
![Travis status][travis-status]
|
![Travis status][travis-status]
|
||||||
|
|
||||||
|
|
|
@ -267,7 +267,7 @@ class OAuthAuthentication(BaseAuthentication):
|
||||||
def authenticate_header(self, request):
|
def authenticate_header(self, request):
|
||||||
"""
|
"""
|
||||||
If permission is denied, return a '401 Unauthorized' response,
|
If permission is denied, return a '401 Unauthorized' response,
|
||||||
with an appropraite 'WWW-Authenticate' header.
|
with an appropriate 'WWW-Authenticate' header.
|
||||||
"""
|
"""
|
||||||
return 'OAuth realm="%s"' % self.www_authenticate_realm
|
return 'OAuth realm="%s"' % self.www_authenticate_realm
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import binascii
|
import binascii
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
|
|
||||||
# Prior to Django 1.5, the AUTH_USER_MODEL setting does not exist.
|
# Prior to Django 1.5, the AUTH_USER_MODEL setting does not exist.
|
||||||
|
@ -11,6 +13,7 @@ from django.db import models
|
||||||
AUTH_USER_MODEL = getattr(settings, 'AUTH_USER_MODEL', 'auth.User')
|
AUTH_USER_MODEL = getattr(settings, 'AUTH_USER_MODEL', 'auth.User')
|
||||||
|
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class Token(models.Model):
|
class Token(models.Model):
|
||||||
"""
|
"""
|
||||||
The default authorization token model.
|
The default authorization token model.
|
||||||
|
@ -35,5 +38,5 @@ class Token(models.Model):
|
||||||
def generate_key(self):
|
def generate_key(self):
|
||||||
return binascii.hexlify(os.urandom(20)).decode()
|
return binascii.hexlify(os.urandom(20)).decode()
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return self.key
|
return self.key
|
||||||
|
|
|
@ -6,24 +6,14 @@ versions of django/python, and compatibility wrappers around optional packages.
|
||||||
# flake8: noqa
|
# flake8: noqa
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import inspect
|
||||||
|
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
|
from django.utils.encoding import force_text
|
||||||
|
from django.utils.six.moves.urllib import parse as urlparse
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
import django
|
import django
|
||||||
import inspect
|
|
||||||
|
|
||||||
|
|
||||||
# Handle django.utils.encoding rename in 1.5 onwards.
|
|
||||||
# smart_unicode -> smart_text
|
|
||||||
# force_unicode -> force_text
|
|
||||||
try:
|
|
||||||
from django.utils.encoding import smart_text
|
|
||||||
except ImportError:
|
|
||||||
from django.utils.encoding import smart_unicode as smart_text
|
|
||||||
try:
|
|
||||||
from django.utils.encoding import force_text
|
|
||||||
except ImportError:
|
|
||||||
from django.utils.encoding import force_unicode as force_text
|
|
||||||
|
|
||||||
|
|
||||||
# OrderedDict only available in Python 2.7.
|
# OrderedDict only available in Python 2.7.
|
||||||
|
@ -32,7 +22,7 @@ except ImportError:
|
||||||
# For Django <= 1.6 and Python 2.6 fall back to OrderedDict.
|
# For Django <= 1.6 and Python 2.6 fall back to OrderedDict.
|
||||||
try:
|
try:
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
except:
|
except ImportError:
|
||||||
from django.utils.datastructures import SortedDict as OrderedDict
|
from django.utils.datastructures import SortedDict as OrderedDict
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,7 +39,6 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
django_filters = None
|
django_filters = None
|
||||||
|
|
||||||
|
|
||||||
if django.VERSION >= (1, 6):
|
if django.VERSION >= (1, 6):
|
||||||
def clean_manytomany_helptext(text):
|
def clean_manytomany_helptext(text):
|
||||||
return text
|
return text
|
||||||
|
@ -72,30 +61,6 @@ if 'guardian' in settings.INSTALLED_APPS:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
# cStringIO only if it's available, otherwise StringIO
|
|
||||||
try:
|
|
||||||
import cStringIO.StringIO as StringIO
|
|
||||||
except ImportError:
|
|
||||||
StringIO = six.StringIO
|
|
||||||
|
|
||||||
BytesIO = six.BytesIO
|
|
||||||
|
|
||||||
|
|
||||||
# urlparse compat import (Required because it changed in python 3.x)
|
|
||||||
try:
|
|
||||||
from urllib import parse as urlparse
|
|
||||||
except ImportError:
|
|
||||||
import urlparse
|
|
||||||
|
|
||||||
# UserDict moves in Python 3
|
|
||||||
try:
|
|
||||||
from UserDict import UserDict
|
|
||||||
from UserDict import DictMixin
|
|
||||||
except ImportError:
|
|
||||||
from collections import UserDict
|
|
||||||
from collections import MutableMapping as DictMixin
|
|
||||||
|
|
||||||
|
|
||||||
def get_model_name(model_cls):
|
def get_model_name(model_cls):
|
||||||
try:
|
try:
|
||||||
return model_cls._meta.model_name
|
return model_cls._meta.model_name
|
||||||
|
@ -104,14 +69,6 @@ def get_model_name(model_cls):
|
||||||
return model_cls._meta.module_name
|
return model_cls._meta.module_name
|
||||||
|
|
||||||
|
|
||||||
def get_concrete_model(model_cls):
|
|
||||||
try:
|
|
||||||
return model_cls._meta.concrete_model
|
|
||||||
except AttributeError:
|
|
||||||
# 1.3 does not include concrete model
|
|
||||||
return model_cls
|
|
||||||
|
|
||||||
|
|
||||||
# View._allowed_methods only present from 1.5 onwards
|
# View._allowed_methods only present from 1.5 onwards
|
||||||
if django.VERSION >= (1, 5):
|
if django.VERSION >= (1, 5):
|
||||||
from django.views.generic import View
|
from django.views.generic import View
|
||||||
|
@ -123,7 +80,6 @@ else:
|
||||||
return [m.upper() for m in self.http_method_names if hasattr(self, m)]
|
return [m.upper() for m in self.http_method_names if hasattr(self, m)]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# MinValueValidator, MaxValueValidator et al. only accept `message` in 1.8+
|
# MinValueValidator, MaxValueValidator et al. only accept `message` in 1.8+
|
||||||
if django.VERSION >= (1, 8):
|
if django.VERSION >= (1, 8):
|
||||||
from django.core.validators import MinValueValidator, MaxValueValidator
|
from django.core.validators import MinValueValidator, MaxValueValidator
|
||||||
|
@ -187,6 +143,7 @@ if 'patch' not in View.http_method_names:
|
||||||
# RequestFactory only provides `generic` from 1.5 onwards
|
# RequestFactory only provides `generic` from 1.5 onwards
|
||||||
from django.test.client import RequestFactory as DjangoRequestFactory
|
from django.test.client import RequestFactory as DjangoRequestFactory
|
||||||
from django.test.client import FakePayload
|
from django.test.client import FakePayload
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# In 1.5 the test client uses force_bytes
|
# In 1.5 the test client uses force_bytes
|
||||||
from django.utils.encoding import force_bytes as force_bytes_or_smart_bytes
|
from django.utils.encoding import force_bytes as force_bytes_or_smart_bytes
|
||||||
|
@ -194,6 +151,7 @@ except ImportError:
|
||||||
# In 1.4 the test client just uses smart_str
|
# In 1.4 the test client just uses smart_str
|
||||||
from django.utils.encoding import smart_str as force_bytes_or_smart_bytes
|
from django.utils.encoding import smart_str as force_bytes_or_smart_bytes
|
||||||
|
|
||||||
|
|
||||||
class RequestFactory(DjangoRequestFactory):
|
class RequestFactory(DjangoRequestFactory):
|
||||||
def generic(self, method, path,
|
def generic(self, method, path,
|
||||||
data='', content_type='application/octet-stream', **extra):
|
data='', content_type='application/octet-stream', **extra):
|
||||||
|
@ -210,11 +168,6 @@ class RequestFactory(DjangoRequestFactory):
|
||||||
'CONTENT_TYPE': six.text_type(content_type),
|
'CONTENT_TYPE': six.text_type(content_type),
|
||||||
'wsgi.input': FakePayload(data),
|
'wsgi.input': FakePayload(data),
|
||||||
})
|
})
|
||||||
elif django.VERSION <= (1, 4):
|
|
||||||
# For 1.3 we need an empty WSGI payload
|
|
||||||
r.update({
|
|
||||||
'wsgi.input': FakePayload('')
|
|
||||||
})
|
|
||||||
r.update(extra)
|
r.update(extra)
|
||||||
return self.request(**r)
|
return self.request(**r)
|
||||||
|
|
||||||
|
@ -287,10 +240,12 @@ try:
|
||||||
import provider as oauth2_provider
|
import provider as oauth2_provider
|
||||||
from provider import scope as oauth2_provider_scope
|
from provider import scope as oauth2_provider_scope
|
||||||
from provider import constants as oauth2_constants
|
from provider import constants as oauth2_constants
|
||||||
|
|
||||||
if oauth2_provider.__version__ in ('0.2.3', '0.2.4'):
|
if oauth2_provider.__version__ in ('0.2.3', '0.2.4'):
|
||||||
# 0.2.3 and 0.2.4 are supported version that do not support
|
# 0.2.3 and 0.2.4 are supported version that do not support
|
||||||
# timezone aware datetimes
|
# timezone aware datetimes
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
provider_now = datetime.datetime.now
|
provider_now = datetime.datetime.now
|
||||||
else:
|
else:
|
||||||
# Any other supported version does use timezone aware datetimes
|
# Any other supported version does use timezone aware datetimes
|
||||||
|
@ -301,7 +256,7 @@ except ImportError:
|
||||||
oauth2_constants = None
|
oauth2_constants = None
|
||||||
provider_now = None
|
provider_now = None
|
||||||
|
|
||||||
# `seperators` argument to `json.dumps()` differs between 2.x and 3.x
|
# `separators` argument to `json.dumps()` differs between 2.x and 3.x
|
||||||
# See: http://bugs.python.org/issue22767
|
# See: http://bugs.python.org/issue22767
|
||||||
if six.PY3:
|
if six.PY3:
|
||||||
SHORT_SEPARATORS = (',', ':')
|
SHORT_SEPARATORS = (',', ':')
|
||||||
|
@ -309,37 +264,3 @@ if six.PY3:
|
||||||
else:
|
else:
|
||||||
SHORT_SEPARATORS = (b',', b':')
|
SHORT_SEPARATORS = (b',', b':')
|
||||||
LONG_SEPARATORS = (b', ', b': ')
|
LONG_SEPARATORS = (b', ', b': ')
|
||||||
|
|
||||||
|
|
||||||
# Handle lazy strings across Py2/Py3
|
|
||||||
from django.utils.functional import Promise
|
|
||||||
|
|
||||||
if six.PY3:
|
|
||||||
def is_non_str_iterable(obj):
|
|
||||||
if (isinstance(obj, str) or
|
|
||||||
(isinstance(obj, Promise) and obj._delegate_text)):
|
|
||||||
return False
|
|
||||||
return hasattr(obj, '__iter__')
|
|
||||||
else:
|
|
||||||
def is_non_str_iterable(obj):
|
|
||||||
return hasattr(obj, '__iter__')
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
|
||||||
except ImportError:
|
|
||||||
def python_2_unicode_compatible(klass):
|
|
||||||
"""
|
|
||||||
A decorator that defines __unicode__ and __str__ methods under Python 2.
|
|
||||||
Under Python 3 it does nothing.
|
|
||||||
|
|
||||||
To support Python 2 and 3 with a single code base, define a __str__ method
|
|
||||||
returning text and apply this decorator to the class.
|
|
||||||
"""
|
|
||||||
if '__str__' not in klass.__dict__:
|
|
||||||
raise ValueError("@python_2_unicode_compatible cannot be applied "
|
|
||||||
"to %s because it doesn't define __str__()." %
|
|
||||||
klass.__name__)
|
|
||||||
klass.__unicode__ = klass.__str__
|
|
||||||
klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
|
|
||||||
return klass
|
|
||||||
|
|
|
@ -5,11 +5,11 @@ In addition Django's built in 403 and 404 exceptions are handled.
|
||||||
(`django.http.Http404` and `django.core.exceptions.PermissionDenied`)
|
(`django.http.Http404` and `django.core.exceptions.PermissionDenied`)
|
||||||
"""
|
"""
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
from django.utils.encoding import force_text
|
||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.utils.translation import ungettext_lazy
|
from django.utils.translation import ungettext_lazy
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.compat import force_text
|
|
||||||
import math
|
import math
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,11 @@ from django.core.validators import RegexValidator
|
||||||
from django.forms import ImageField as DjangoImageField
|
from django.forms import ImageField as DjangoImageField
|
||||||
from django.utils import six, timezone
|
from django.utils import six, timezone
|
||||||
from django.utils.dateparse import parse_date, parse_datetime, parse_time
|
from django.utils.dateparse import parse_date, parse_datetime, parse_time
|
||||||
from django.utils.encoding import is_protected_type
|
from django.utils.encoding import is_protected_type, smart_text
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from rest_framework import ISO_8601
|
from rest_framework import ISO_8601
|
||||||
from rest_framework.compat import (
|
from rest_framework.compat import (
|
||||||
smart_text, EmailValidator, MinValueValidator, MaxValueValidator,
|
EmailValidator, MinValueValidator, MaxValueValidator,
|
||||||
MinLengthValidator, MaxLengthValidator, URLValidator, OrderedDict
|
MinLengthValidator, MaxLengthValidator, URLValidator, OrderedDict
|
||||||
)
|
)
|
||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.exceptions import ValidationError
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
"""
|
"""
|
||||||
The metadata API is used to allow cusomization of how `OPTIONS` requests
|
The metadata API is used to allow customization of how `OPTIONS` requests
|
||||||
are handled. We currently provide a single default implementation that returns
|
are handled. We currently provide a single default implementation that returns
|
||||||
some fairly ad-hoc information about the view.
|
some fairly ad-hoc information about the view.
|
||||||
|
|
||||||
Future implementations might use JSON schema or other definations in order
|
Future implementations might use JSON schema or other definitions in order
|
||||||
to return this information in a more standardized way.
|
to return this information in a more standardized way.
|
||||||
"""
|
"""
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
|
from django.utils.encoding import force_text
|
||||||
from rest_framework import exceptions, serializers
|
from rest_framework import exceptions, serializers
|
||||||
from rest_framework.compat import force_text, OrderedDict
|
from rest_framework.compat import OrderedDict
|
||||||
from rest_framework.request import clone_request
|
from rest_framework.request import clone_request
|
||||||
from rest_framework.utils.field_mapping import ClassLookupDict
|
from rest_framework.utils.field_mapping import ClassLookupDict
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,9 @@ from django.http import QueryDict
|
||||||
from django.http.multipartparser import MultiPartParser as DjangoMultiPartParser
|
from django.http.multipartparser import MultiPartParser as DjangoMultiPartParser
|
||||||
from django.http.multipartparser import MultiPartParserError, parse_header, ChunkIter
|
from django.http.multipartparser import MultiPartParserError, parse_header, ChunkIter
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from rest_framework.compat import etree, yaml, force_text, urlparse
|
from django.utils.six.moves.urllib import parse as urlparse
|
||||||
|
from django.utils.encoding import force_text
|
||||||
|
from rest_framework.compat import etree, yaml
|
||||||
from rest_framework.exceptions import ParseError
|
from rest_framework.exceptions import ParseError
|
||||||
from rest_framework import renderers
|
from rest_framework import renderers
|
||||||
import json
|
import json
|
||||||
|
|
|
@ -184,7 +184,7 @@ class DjangoObjectPermissions(DjangoModelPermissions):
|
||||||
if not user.has_perms(perms, obj):
|
if not user.has_perms(perms, obj):
|
||||||
# If the user does not have permissions we need to determine if
|
# If the user does not have permissions we need to determine if
|
||||||
# they have read permissions to see 403, or not, and simply see
|
# they have read permissions to see 403, or not, and simply see
|
||||||
# a 404 reponse.
|
# a 404 response.
|
||||||
|
|
||||||
if request.method in ('GET', 'OPTIONS', 'HEAD'):
|
if request.method in ('GET', 'OPTIONS', 'HEAD'):
|
||||||
# Read permissions already checked and failed, no need
|
# Read permissions already checked and failed, no need
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from rest_framework.compat import smart_text, urlparse
|
from django.utils.encoding import smart_text
|
||||||
from rest_framework.fields import get_attribute, empty, Field
|
from rest_framework.fields import get_attribute, empty, Field
|
||||||
from rest_framework.reverse import reverse
|
from rest_framework.reverse import reverse
|
||||||
from rest_framework.utils import html
|
from rest_framework.utils import html
|
||||||
|
@ -6,6 +6,7 @@ from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
|
||||||
from django.core.urlresolvers import resolve, get_script_prefix, NoReverseMatch, Resolver404
|
from django.core.urlresolvers import resolve, get_script_prefix, NoReverseMatch, Resolver404
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
from django.utils.six.moves.urllib import parse as urlparse
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
@ -141,7 +142,7 @@ class PrimaryKeyRelatedField(RelatedField):
|
||||||
def get_iterable(self, instance, source_attrs):
|
def get_iterable(self, instance, source_attrs):
|
||||||
# For consistency with `get_attribute` we're using `serializable_value()`
|
# For consistency with `get_attribute` we're using `serializable_value()`
|
||||||
# here. Typically there won't be any difference, but some custom field
|
# here. Typically there won't be any difference, but some custom field
|
||||||
# types might return a non-primative value for the pk otherwise.
|
# types might return a non-primitive value for the pk otherwise.
|
||||||
#
|
#
|
||||||
# We could try to get smart with `values_list('pk', flat=True)`, which
|
# We could try to get smart with `values_list('pk', flat=True)`, which
|
||||||
# would be better in some case, but would actually end up with *more*
|
# would be better in some case, but would actually end up with *more*
|
||||||
|
|
|
@ -16,11 +16,11 @@ from django.http.multipartparser import parse_header
|
||||||
from django.template import Context, RequestContext, loader, Template
|
from django.template import Context, RequestContext, loader, Template
|
||||||
from django.test.client import encode_multipart
|
from django.test.client import encode_multipart
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
from django.utils.encoding import smart_text
|
||||||
from django.utils.xmlutils import SimplerXMLGenerator
|
from django.utils.xmlutils import SimplerXMLGenerator
|
||||||
|
from django.utils.six.moves import StringIO
|
||||||
from rest_framework import exceptions, serializers, status, VERSION
|
from rest_framework import exceptions, serializers, status, VERSION
|
||||||
from rest_framework.compat import (
|
from rest_framework.compat import SHORT_SEPARATORS, LONG_SEPARATORS, yaml
|
||||||
SHORT_SEPARATORS, LONG_SEPARATORS, StringIO, smart_text, yaml
|
|
||||||
)
|
|
||||||
from rest_framework.exceptions import ParseError
|
from rest_framework.exceptions import ParseError
|
||||||
from rest_framework.settings import api_settings
|
from rest_framework.settings import api_settings
|
||||||
from rest_framework.request import is_form_media_type, override_method
|
from rest_framework.request import is_form_media_type, override_method
|
||||||
|
@ -287,7 +287,9 @@ class TemplateHTMLRenderer(BaseRenderer):
|
||||||
return view.get_template_names()
|
return view.get_template_names()
|
||||||
elif hasattr(view, 'template_name'):
|
elif hasattr(view, 'template_name'):
|
||||||
return [view.template_name]
|
return [view.template_name]
|
||||||
raise ImproperlyConfigured('Returned a template response with no `template_name` attribute set on either the view or response')
|
raise ImproperlyConfigured(
|
||||||
|
'Returned a template response with no `template_name` attribute set on either the view or response'
|
||||||
|
)
|
||||||
|
|
||||||
def get_exception_template(self, response):
|
def get_exception_template(self, response):
|
||||||
template_names = [name % {'status_code': response.status_code}
|
template_names = [name % {'status_code': response.status_code}
|
||||||
|
|
|
@ -14,9 +14,9 @@ from django.http import QueryDict
|
||||||
from django.http.multipartparser import parse_header
|
from django.http.multipartparser import parse_header
|
||||||
from django.utils.datastructures import MultiValueDict
|
from django.utils.datastructures import MultiValueDict
|
||||||
from django.utils.datastructures import MergeDict as DjangoMergeDict
|
from django.utils.datastructures import MergeDict as DjangoMergeDict
|
||||||
|
from django.utils.six import BytesIO
|
||||||
from rest_framework import HTTP_HEADER_ENCODING
|
from rest_framework import HTTP_HEADER_ENCODING
|
||||||
from rest_framework import exceptions
|
from rest_framework import exceptions
|
||||||
from rest_framework.compat import BytesIO
|
|
||||||
from rest_framework.settings import api_settings
|
from rest_framework.settings import api_settings
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
|
|
|
@ -10,17 +10,13 @@ python primitives.
|
||||||
2. The process of marshalling between python primitives and request and
|
2. The process of marshalling between python primitives and request and
|
||||||
response content is handled by parsers and renderers.
|
response content is handled by parsers and renderers.
|
||||||
"""
|
"""
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
import warnings
|
||||||
from django.core.exceptions import ValidationError as DjangoValidationError
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models.fields import FieldDoesNotExist
|
from django.db.models.fields import FieldDoesNotExist
|
||||||
from django.utils import six
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from rest_framework.compat import OrderedDict
|
|
||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.utils import model_meta
|
||||||
from rest_framework.fields import empty, set_value, Field, SkipField
|
|
||||||
from rest_framework.settings import api_settings
|
|
||||||
from rest_framework.utils import html, model_meta, representation
|
|
||||||
from rest_framework.utils.field_mapping import (
|
from rest_framework.utils.field_mapping import (
|
||||||
get_url_kwargs, get_field_kwargs,
|
get_url_kwargs, get_field_kwargs,
|
||||||
get_relation_kwargs, get_nested_relation_kwargs,
|
get_relation_kwargs, get_nested_relation_kwargs,
|
||||||
|
@ -33,9 +29,7 @@ from rest_framework.validators import (
|
||||||
UniqueForDateValidator, UniqueForMonthValidator, UniqueForYearValidator,
|
UniqueForDateValidator, UniqueForMonthValidator, UniqueForYearValidator,
|
||||||
UniqueTogetherValidator
|
UniqueTogetherValidator
|
||||||
)
|
)
|
||||||
import copy
|
|
||||||
import inspect
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
# Note: We do the following so that users of the framework can use this style:
|
# Note: We do the following so that users of the framework can use this style:
|
||||||
#
|
#
|
||||||
|
@ -65,6 +59,7 @@ class BaseSerializer(Field):
|
||||||
The BaseSerializer class provides a minimal class which may be used
|
The BaseSerializer class provides a minimal class which may be used
|
||||||
for writing custom serializer implementations.
|
for writing custom serializer implementations.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, instance=None, data=None, **kwargs):
|
def __init__(self, instance=None, data=None, **kwargs):
|
||||||
self.instance = instance
|
self.instance = instance
|
||||||
self._initial_data = data
|
self._initial_data = data
|
||||||
|
@ -245,7 +240,7 @@ class Serializer(BaseSerializer):
|
||||||
"""
|
"""
|
||||||
A dictionary of {field_name: field_instance}.
|
A dictionary of {field_name: field_instance}.
|
||||||
"""
|
"""
|
||||||
# `fields` is evalutated lazily. We do this to ensure that we don't
|
# `fields` is evaluated lazily. We do this to ensure that we don't
|
||||||
# have issues importing modules that use ModelSerializers as fields,
|
# have issues importing modules that use ModelSerializers as fields,
|
||||||
# even if Django's app-loading stage has not yet run.
|
# even if Django's app-loading stage has not yet run.
|
||||||
if not hasattr(self, '_fields'):
|
if not hasattr(self, '_fields'):
|
||||||
|
@ -343,7 +338,7 @@ class Serializer(BaseSerializer):
|
||||||
# Normally you should raise `serializers.ValidationError`
|
# Normally you should raise `serializers.ValidationError`
|
||||||
# inside your codebase, but we handle Django's validation
|
# inside your codebase, but we handle Django's validation
|
||||||
# exception class as well for simpler compat.
|
# exception class as well for simpler compat.
|
||||||
# Eg. Calling Model.clean() explictily inside Serializer.validate()
|
# Eg. Calling Model.clean() explicitly inside Serializer.validate()
|
||||||
raise ValidationError({
|
raise ValidationError({
|
||||||
api_settings.NON_FIELD_ERRORS_KEY: list(exc.messages)
|
api_settings.NON_FIELD_ERRORS_KEY: list(exc.messages)
|
||||||
})
|
})
|
||||||
|
@ -576,7 +571,7 @@ class ModelSerializer(Serializer):
|
||||||
|
|
||||||
The process of automatically determining a set of serializer fields
|
The process of automatically determining a set of serializer fields
|
||||||
based on the model fields is reasonably complex, but you almost certainly
|
based on the model fields is reasonably complex, but you almost certainly
|
||||||
don't need to dig into the implemention.
|
don't need to dig into the implementation.
|
||||||
|
|
||||||
If the `ModelSerializer` class *doesn't* generate the set of fields that
|
If the `ModelSerializer` class *doesn't* generate the set of fields that
|
||||||
you need you should either declare the extra/differing fields explicitly on
|
you need you should either declare the extra/differing fields explicitly on
|
||||||
|
@ -636,7 +631,7 @@ class ModelSerializer(Serializer):
|
||||||
isinstance(field, BaseSerializer) and (key in validated_attrs)
|
isinstance(field, BaseSerializer) and (key in validated_attrs)
|
||||||
for key, field in self.fields.items()
|
for key, field in self.fields.items()
|
||||||
), (
|
), (
|
||||||
'The `.create()` method does not suport nested writable fields '
|
'The `.create()` method does not support nested writable fields '
|
||||||
'by default. Write an explicit `.create()` method for serializer '
|
'by default. Write an explicit `.create()` method for serializer '
|
||||||
'`%s.%s`, or set `read_only=True` on nested serializer fields.' %
|
'`%s.%s`, or set `read_only=True` on nested serializer fields.' %
|
||||||
(self.__class__.__module__, self.__class__.__name__)
|
(self.__class__.__module__, self.__class__.__name__)
|
||||||
|
@ -684,7 +679,7 @@ class ModelSerializer(Serializer):
|
||||||
isinstance(field, BaseSerializer) and (key in validated_attrs)
|
isinstance(field, BaseSerializer) and (key in validated_attrs)
|
||||||
for key, field in self.fields.items()
|
for key, field in self.fields.items()
|
||||||
), (
|
), (
|
||||||
'The `.update()` method does not suport nested writable fields '
|
'The `.update()` method does not support nested writable fields '
|
||||||
'by default. Write an explicit `.update()` method for serializer '
|
'by default. Write an explicit `.update()` method for serializer '
|
||||||
'`%s.%s`, or set `read_only=True` on nested serializer fields.' %
|
'`%s.%s`, or set `read_only=True` on nested serializer fields.' %
|
||||||
(self.__class__.__module__, self.__class__.__name__)
|
(self.__class__.__module__, self.__class__.__name__)
|
||||||
|
@ -824,7 +819,7 @@ class ModelSerializer(Serializer):
|
||||||
# applied, we can add the extra 'required=...' or 'default=...'
|
# applied, we can add the extra 'required=...' or 'default=...'
|
||||||
# arguments that are appropriate to these fields, or add a `HiddenField` for it.
|
# arguments that are appropriate to these fields, or add a `HiddenField` for it.
|
||||||
for unique_constraint_name in unique_constraint_names:
|
for unique_constraint_name in unique_constraint_names:
|
||||||
# Get the model field that is refered too.
|
# Get the model field that is referred too.
|
||||||
unique_constraint_field = model._meta.get_field(unique_constraint_name)
|
unique_constraint_field = model._meta.get_field(unique_constraint_name)
|
||||||
|
|
||||||
if getattr(unique_constraint_field, 'auto_now_add', None):
|
if getattr(unique_constraint_field, 'auto_now_add', None):
|
||||||
|
@ -907,7 +902,7 @@ class ModelSerializer(Serializer):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check that any fields declared on the class are
|
# Check that any fields declared on the class are
|
||||||
# also explicity included in `Meta.fields`.
|
# also explicitly included in `Meta.fields`.
|
||||||
missing_fields = set(declared_fields.keys()) - set(fields)
|
missing_fields = set(declared_fields.keys()) - set(fields)
|
||||||
if missing_fields:
|
if missing_fields:
|
||||||
missing_field = list(missing_fields)[0]
|
missing_field = list(missing_fields)[0]
|
||||||
|
@ -1001,6 +996,7 @@ class ModelSerializer(Serializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = relation_info.related
|
model = relation_info.related
|
||||||
depth = nested_depth
|
depth = nested_depth
|
||||||
|
|
||||||
return NestedSerializer
|
return NestedSerializer
|
||||||
|
|
||||||
|
|
||||||
|
@ -1027,4 +1023,5 @@ class HyperlinkedModelSerializer(ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = relation_info.related
|
model = relation_info.related
|
||||||
depth = nested_depth
|
depth = nested_depth
|
||||||
|
|
||||||
return NestedSerializer
|
return NestedSerializer
|
||||||
|
|
|
@ -47,7 +47,7 @@ DEFAULTS = {
|
||||||
'DEFAULT_CONTENT_NEGOTIATION_CLASS': 'rest_framework.negotiation.DefaultContentNegotiation',
|
'DEFAULT_CONTENT_NEGOTIATION_CLASS': 'rest_framework.negotiation.DefaultContentNegotiation',
|
||||||
'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata',
|
'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata',
|
||||||
|
|
||||||
# Genric view behavior
|
# Generic view behavior
|
||||||
'DEFAULT_MODEL_SERIALIZER_CLASS': 'rest_framework.serializers.ModelSerializer',
|
'DEFAULT_MODEL_SERIALIZER_CLASS': 'rest_framework.serializers.ModelSerializer',
|
||||||
'DEFAULT_PAGINATION_SERIALIZER_CLASS': 'rest_framework.pagination.PaginationSerializer',
|
'DEFAULT_PAGINATION_SERIALIZER_CLASS': 'rest_framework.pagination.PaginationSerializer',
|
||||||
'DEFAULT_FILTER_BACKENDS': (),
|
'DEFAULT_FILTER_BACKENDS': (),
|
||||||
|
|
|
@ -3,11 +3,11 @@ from django import template
|
||||||
from django.core.urlresolvers import reverse, NoReverseMatch
|
from django.core.urlresolvers import reverse, NoReverseMatch
|
||||||
from django.http import QueryDict
|
from django.http import QueryDict
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.encoding import iri_to_uri
|
from django.utils.six.moves.urllib import parse as urlparse
|
||||||
|
from django.utils.encoding import iri_to_uri, force_text
|
||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
from django.utils.safestring import SafeData, mark_safe
|
from django.utils.safestring import SafeData, mark_safe
|
||||||
from django.utils.html import smart_urlquote
|
from django.utils.html import smart_urlquote
|
||||||
from rest_framework.compat import urlparse, force_text
|
|
||||||
from rest_framework.renderers import HTMLFormRenderer
|
from rest_framework.renderers import HTMLFormRenderer
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,9 @@ Helper classes for parsers.
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
from django.utils import six, timezone
|
from django.utils import six, timezone
|
||||||
|
from django.utils.encoding import force_text
|
||||||
from django.utils.functional import Promise
|
from django.utils.functional import Promise
|
||||||
from rest_framework.compat import force_text, OrderedDict
|
from rest_framework.compat import OrderedDict
|
||||||
import datetime
|
import datetime
|
||||||
import decimal
|
import decimal
|
||||||
import types
|
import types
|
||||||
|
|
|
@ -5,6 +5,7 @@ See http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7
|
||||||
"""
|
"""
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
from django.http.multipartparser import parse_header
|
from django.http.multipartparser import parse_header
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
from rest_framework import HTTP_HEADER_ENCODING
|
from rest_framework import HTTP_HEADER_ENCODING
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,6 +44,7 @@ def order_by_precedence(media_type_lst):
|
||||||
return [media_types for media_types in ret if media_types]
|
return [media_types for media_types in ret if media_types]
|
||||||
|
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class _MediaType(object):
|
class _MediaType(object):
|
||||||
def __init__(self, media_type_str):
|
def __init__(self, media_type_str):
|
||||||
if media_type_str is None:
|
if media_type_str is None:
|
||||||
|
@ -79,9 +81,6 @@ class _MediaType(object):
|
||||||
return 3
|
return 3
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.__unicode__().encode('utf-8')
|
|
||||||
|
|
||||||
def __unicode__(self):
|
|
||||||
ret = "%s/%s" % (self.main_type, self.sub_type)
|
ret = "%s/%s" % (self.main_type, self.sub_type)
|
||||||
for key, val in self.params.items():
|
for key, val in self.params.items():
|
||||||
ret += "; %s=%s" % (key, val)
|
ret += "; %s=%s" % (key, val)
|
||||||
|
|
|
@ -3,8 +3,8 @@ Helper functions for creating user-friendly representations
|
||||||
of serializer classes and serializer fields.
|
of serializer classes and serializer fields.
|
||||||
"""
|
"""
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.utils.encoding import force_text
|
||||||
from django.utils.functional import Promise
|
from django.utils.functional import Promise
|
||||||
from rest_framework.compat import force_text
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ the using Django's `.full_clean()`.
|
||||||
|
|
||||||
This gives us better separation of concerns, allows us to use single-step
|
This gives us better separation of concerns, allows us to use single-step
|
||||||
object creation, and makes it possible to switch between using the implicit
|
object creation, and makes it possible to switch between using the implicit
|
||||||
`ModelSerializer` class and an equivelent explicit `Serializer` class.
|
`ModelSerializer` class and an equivalent explicit `Serializer` class.
|
||||||
"""
|
"""
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.exceptions import ValidationError
|
||||||
|
|
|
@ -5,9 +5,10 @@ from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
|
from django.utils.encoding import smart_text
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from rest_framework import status, exceptions
|
from rest_framework import status, exceptions
|
||||||
from rest_framework.compat import smart_text, HttpResponseBase, View
|
from rest_framework.compat import HttpResponseBase, View
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.settings import api_settings
|
from rest_framework.settings import api_settings
|
||||||
|
|
|
@ -44,7 +44,7 @@ class ViewSetMixin(object):
|
||||||
instantiated view, we need to totally reimplement `.as_view`,
|
instantiated view, we need to totally reimplement `.as_view`,
|
||||||
and slightly modify the view function that is created and returned.
|
and slightly modify the view function that is created and returned.
|
||||||
"""
|
"""
|
||||||
# The suffix initkwarg is reserved for identifing the viewset type
|
# The suffix initkwarg is reserved for identifying the viewset type
|
||||||
# eg. 'List' or 'Instance'.
|
# eg. 'List' or 'Instance'.
|
||||||
cls.suffix = None
|
cls.suffix = None
|
||||||
|
|
||||||
|
@ -98,12 +98,12 @@ class ViewSetMixin(object):
|
||||||
view.suffix = initkwargs.get('suffix', None)
|
view.suffix = initkwargs.get('suffix', None)
|
||||||
return csrf_exempt(view)
|
return csrf_exempt(view)
|
||||||
|
|
||||||
def initialize_request(self, request, *args, **kargs):
|
def initialize_request(self, request, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Set the `.action` attribute on the view,
|
Set the `.action` attribute on the view,
|
||||||
depending on the request method.
|
depending on the request method.
|
||||||
"""
|
"""
|
||||||
request = super(ViewSetMixin, self).initialize_request(request, *args, **kargs)
|
request = super(ViewSetMixin, self).initialize_request(request, *args, **kwargs)
|
||||||
self.action = self.action_map.get(request.method.lower())
|
self.action = self.action_map.get(request.method.lower())
|
||||||
return request
|
return request
|
||||||
|
|
||||||
|
|
|
@ -17,24 +17,29 @@ FLAKE8_ARGS = ['rest_framework', 'tests', '--ignore=E501']
|
||||||
|
|
||||||
sys.path.append(os.path.dirname(__file__))
|
sys.path.append(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
|
||||||
def exit_on_failure(ret, message=None):
|
def exit_on_failure(ret, message=None):
|
||||||
if ret:
|
if ret:
|
||||||
sys.exit(ret)
|
sys.exit(ret)
|
||||||
|
|
||||||
|
|
||||||
def flake8_main(args):
|
def flake8_main(args):
|
||||||
print('Running flake8 code linting')
|
print('Running flake8 code linting')
|
||||||
ret = subprocess.call(['flake8'] + args)
|
ret = subprocess.call(['flake8'] + args)
|
||||||
print('flake8 failed' if ret else 'flake8 passed')
|
print('flake8 failed' if ret else 'flake8 passed')
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def split_class_and_function(string):
|
def split_class_and_function(string):
|
||||||
class_string, function_string = string.split('.', 1)
|
class_string, function_string = string.split('.', 1)
|
||||||
return "%s and %s" % (class_string, function_string)
|
return "%s and %s" % (class_string, function_string)
|
||||||
|
|
||||||
|
|
||||||
def is_function(string):
|
def is_function(string):
|
||||||
# `True` if it looks like a test function is included in the string.
|
# `True` if it looks like a test function is included in the string.
|
||||||
return string.startswith('test_') or '.test_' in string
|
return string.startswith('test_') or '.test_' in string
|
||||||
|
|
||||||
|
|
||||||
def is_class(string):
|
def is_class(string):
|
||||||
# `True` if first character is uppercase - assume it's a class name.
|
# `True` if first character is uppercase - assume it's a class name.
|
||||||
return string[0] == string[0].upper()
|
return string[0] == string[0].upper()
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from rest_framework.compat import apply_markdown, smart_text
|
from django.utils.encoding import python_2_unicode_compatible, smart_text
|
||||||
|
from rest_framework.compat import apply_markdown
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from .description import ViewWithNonASCIICharactersInDocstring
|
from .description import ViewWithNonASCIICharactersInDocstring
|
||||||
from .description import UTF8_TEST_DOCSTRING
|
from .description import UTF8_TEST_DOCSTRING
|
||||||
|
@ -107,6 +108,7 @@ class TestViewNamesAndDescriptions(TestCase):
|
||||||
"""
|
"""
|
||||||
# use a mock object instead of gettext_lazy to ensure that we can't end
|
# use a mock object instead of gettext_lazy to ensure that we can't end
|
||||||
# up with a test case string in our l10n catalog
|
# up with a test case string in our l10n catalog
|
||||||
|
@python_2_unicode_compatible
|
||||||
class MockLazyStr(object):
|
class MockLazyStr(object):
|
||||||
def __init__(self, string):
|
def __init__(self, string):
|
||||||
self.s = string
|
self.s = string
|
||||||
|
@ -114,9 +116,6 @@ class TestViewNamesAndDescriptions(TestCase):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.s
|
return self.s
|
||||||
|
|
||||||
def __unicode__(self):
|
|
||||||
return self.s
|
|
||||||
|
|
||||||
class MockView(APIView):
|
class MockView(APIView):
|
||||||
__doc__ = MockLazyStr("a gettext string")
|
__doc__ = MockLazyStr("a gettext string")
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ class AssociatedModelSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
|
|
||||||
# Tests
|
# Tests
|
||||||
class IneritedModelSerializationTests(TestCase):
|
class InheritedModelSerializationTests(TestCase):
|
||||||
|
|
||||||
def test_multitable_inherited_model_fields_as_expected(self):
|
def test_multitable_inherited_model_fields_as_expected(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -5,8 +5,8 @@ from django import forms
|
||||||
from django.core.files.uploadhandler import MemoryFileUploadHandler
|
from django.core.files.uploadhandler import MemoryFileUploadHandler
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.utils import unittest
|
from django.utils import unittest
|
||||||
|
from django.utils.six.moves import StringIO
|
||||||
from rest_framework.compat import etree
|
from rest_framework.compat import etree
|
||||||
from rest_framework.compat import StringIO
|
|
||||||
from rest_framework.exceptions import ParseError
|
from rest_framework.exceptions import ParseError
|
||||||
from rest_framework.parsers import FormParser, FileUploadParser
|
from rest_framework.parsers import FormParser, FileUploadParser
|
||||||
from rest_framework.parsers import XMLParser
|
from rest_framework.parsers import XMLParser
|
||||||
|
|
|
@ -3,8 +3,8 @@ from django.contrib.contenttypes.models import ContentType
|
||||||
from django.contrib.contenttypes.generic import GenericRelation, GenericForeignKey
|
from django.contrib.contenttypes.generic import GenericRelation, GenericForeignKey
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.compat import python_2_unicode_compatible
|
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
|
|
|
@ -7,9 +7,11 @@ from django.core.cache import cache
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.utils import six, unittest
|
from django.utils import six, unittest
|
||||||
|
from django.utils.six import BytesIO
|
||||||
|
from django.utils.six.moves import StringIO
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from rest_framework import status, permissions
|
from rest_framework import status, permissions
|
||||||
from rest_framework.compat import yaml, etree, StringIO, BytesIO
|
from rest_framework.compat import yaml, etree
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from rest_framework.renderers import BaseRenderer, JSONRenderer, YAMLRenderer, \
|
from rest_framework.renderers import BaseRenderer, JSONRenderer, YAMLRenderer, \
|
||||||
|
|
|
@ -187,7 +187,7 @@ class MockView(APIView):
|
||||||
if request.POST.get('example') is not None:
|
if request.POST.get('example') is not None:
|
||||||
return Response(status=status.HTTP_200_OK)
|
return Response(status=status.HTTP_200_OK)
|
||||||
|
|
||||||
return Response(status=status.INTERNAL_SERVER_ERROR)
|
return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||||
|
|
||||||
urlpatterns = patterns(
|
urlpatterns = patterns(
|
||||||
'',
|
'',
|
||||||
|
|
|
@ -148,7 +148,7 @@ class TestUniquenessTogetherValidation(TestCase):
|
||||||
def test_ignore_excluded_fields(self):
|
def test_ignore_excluded_fields(self):
|
||||||
"""
|
"""
|
||||||
When model fields are not included in a serializer, then uniqueness
|
When model fields are not included in a serializer, then uniqueness
|
||||||
validtors should not be added for that field.
|
validators should not be added for that field.
|
||||||
"""
|
"""
|
||||||
class ExcludedFieldSerializer(serializers.ModelSerializer):
|
class ExcludedFieldSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
6
tox.ini
6
tox.ini
|
@ -1,6 +1,6 @@
|
||||||
[tox]
|
[tox]
|
||||||
envlist =
|
envlist =
|
||||||
py27-flake8,
|
py27-{flake8,docs},
|
||||||
{py26,py27}-django14,
|
{py26,py27}-django14,
|
||||||
{py26,py27,py32,py33,py34}-django{15,16},
|
{py26,py27,py32,py33,py34}-django{15,16},
|
||||||
{py27,py32,py33,py34}-django{17,master}
|
{py27,py32,py33,py34}-django{17,master}
|
||||||
|
@ -10,8 +10,8 @@ commands = ./runtests.py --fast
|
||||||
setenv =
|
setenv =
|
||||||
PYTHONDONTWRITEBYTECODE=1
|
PYTHONDONTWRITEBYTECODE=1
|
||||||
deps =
|
deps =
|
||||||
django14: Django==1.4.16
|
django14: Django==1.4.11
|
||||||
django15: Django==1.5.11
|
django15: Django==1.5.5
|
||||||
django16: Django==1.6.8
|
django16: Django==1.6.8
|
||||||
django17: Django==1.7.1
|
django17: Django==1.7.1
|
||||||
djangomaster: https://github.com/django/django/zipball/master
|
djangomaster: https://github.com/django/django/zipball/master
|
||||||
|
|
Loading…
Reference in New Issue
Block a user