mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-08-04 20:40:14 +03:00
Merge remote-tracking branch 'reference/master' into bugfix/1936
This commit is contained in:
commit
b523524d8e
|
@ -1,6 +1,7 @@
|
|||
# Django REST framework
|
||||
|
||||
[![build-status-image]][travis]
|
||||
[![pypi-version]][pypi]
|
||||
|
||||
**Awesome web-browseable Web APIs.**
|
||||
|
||||
|
@ -181,6 +182,8 @@ 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
|
||||
[pypi-version]: https://pypip.in/version/djangorestframework/badge.svg
|
||||
[pypi]: https://pypi.python.org/pypi/djangorestframework
|
||||
[twitter]: https://twitter.com/_tomchristie
|
||||
[group]: https://groups.google.com/forum/?fromgroups#!forum/django-rest-framework
|
||||
[0.4]: https://github.com/tomchristie/django-rest-framework/tree/0.4.X
|
||||
|
|
|
@ -506,9 +506,9 @@ We now use the following:
|
|||
|
||||
REST framework now has more explicit and clear control over validating empty values for fields.
|
||||
|
||||
Previously the meaning of the `required=False` keyword argument was underspecified. In practice its use meant that a field could either be not included in the input, or it could be included, but be `None`.
|
||||
Previously the meaning of the `required=False` keyword argument was underspecified. In practice its use meant that a field could either be not included in the input, or it could be included, but be `None` or the empty string.
|
||||
|
||||
We now have a better separation, with separate `required` and `allow_none` arguments.
|
||||
We now have a better separation, with separate `required`, `allow_none` and `allow_blank` arguments.
|
||||
|
||||
The following set of arguments are used to control validation of empty values:
|
||||
|
||||
|
@ -519,7 +519,7 @@ The following set of arguments are used to control validation of empty values:
|
|||
|
||||
Typically you'll want to use `required=False` if the corresponding model field has a default value, and additionally set either `allow_none=True` or `allow_blank=True` if required.
|
||||
|
||||
The `default` argument is there if you need it, but you'll more typically want defaults to be set on model fields, rather than serializer fields.
|
||||
The `default` argument is also available and always implies that the field is not required to be in the input. It is unnecessary to use the `required` argument when a default is specified, and doing so will result in an error.
|
||||
|
||||
#### Coercing output types.
|
||||
|
||||
|
|
|
@ -10,9 +10,17 @@ from django.utils.translation import ugettext_lazy as _
|
|||
|
||||
|
||||
class PKOnlyObject(object):
|
||||
"""
|
||||
This is a mock object, used for when we only need the pk of the object
|
||||
instance, but still want to return an object with a .pk attribute,
|
||||
in order to keep the same interface as a regular model instance.
|
||||
"""
|
||||
def __init__(self, pk):
|
||||
self.pk = pk
|
||||
|
||||
|
||||
# We assume that 'validators' are intended for the child serializer,
|
||||
# rather than the parent serializer.
|
||||
MANY_RELATION_KWARGS = (
|
||||
'read_only', 'write_only', 'required', 'default', 'initial', 'source',
|
||||
'label', 'help_text', 'style', 'error_messages'
|
||||
|
@ -34,15 +42,19 @@ class RelatedField(Field):
|
|||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
# We override this method in order to automagically create
|
||||
# `ManyRelation` classes instead when `many=True` is set.
|
||||
# `ManyRelatedField` classes instead when `many=True` is set.
|
||||
if kwargs.pop('many', False):
|
||||
list_kwargs = {'child_relation': cls(*args, **kwargs)}
|
||||
for key in kwargs.keys():
|
||||
if key in MANY_RELATION_KWARGS:
|
||||
list_kwargs[key] = kwargs[key]
|
||||
return ManyRelation(**list_kwargs)
|
||||
return cls.many_init(*args, **kwargs)
|
||||
return super(RelatedField, cls).__new__(cls, *args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def many_init(cls, *args, **kwargs):
|
||||
list_kwargs = {'child_relation': cls(*args, **kwargs)}
|
||||
for key in kwargs.keys():
|
||||
if key in MANY_RELATION_KWARGS:
|
||||
list_kwargs[key] = kwargs[key]
|
||||
return ManyRelatedField(**list_kwargs)
|
||||
|
||||
def run_validation(self, data=empty):
|
||||
# We force empty strings to None values for relational fields.
|
||||
if data == '':
|
||||
|
@ -286,12 +298,12 @@ class SlugRelatedField(RelatedField):
|
|||
return getattr(obj, self.slug_field)
|
||||
|
||||
|
||||
class ManyRelation(Field):
|
||||
class ManyRelatedField(Field):
|
||||
"""
|
||||
Relationships with `many=True` transparently get coerced into instead being
|
||||
a ManyRelation with a child relationship.
|
||||
a ManyRelatedField with a child relationship.
|
||||
|
||||
The `ManyRelation` class is responsible for handling iterating through
|
||||
The `ManyRelatedField` class is responsible for handling iterating through
|
||||
the values and passing each one to the child relationship.
|
||||
|
||||
You shouldn't need to be using this class directly yourself.
|
||||
|
@ -302,7 +314,7 @@ class ManyRelation(Field):
|
|||
def __init__(self, child_relation=None, *args, **kwargs):
|
||||
self.child_relation = child_relation
|
||||
assert child_relation is not None, '`child_relation` is a required argument.'
|
||||
super(ManyRelation, self).__init__(*args, **kwargs)
|
||||
super(ManyRelatedField, self).__init__(*args, **kwargs)
|
||||
self.child_relation.bind(field_name='', parent=self)
|
||||
|
||||
def get_value(self, dictionary):
|
||||
|
|
|
@ -383,7 +383,10 @@ class HTMLFormRenderer(BaseRenderer):
|
|||
serializers.MultipleChoiceField: {
|
||||
'base_template': 'select_multiple.html', # Also valid: 'checkbox_multiple.html'
|
||||
},
|
||||
serializers.ManyRelation: {
|
||||
serializers.RelatedField: {
|
||||
'base_template': 'select.html', # Also valid: 'radio.html'
|
||||
},
|
||||
serializers.ManyRelatedField: {
|
||||
'base_template': 'select_multiple.html', # Also valid: 'checkbox_multiple.html'
|
||||
},
|
||||
serializers.Serializer: {
|
||||
|
|
|
@ -46,6 +46,9 @@ import warnings
|
|||
from rest_framework.relations import * # NOQA
|
||||
from rest_framework.fields import * # NOQA
|
||||
|
||||
|
||||
# We assume that 'validators' are intended for the child serializer,
|
||||
# rather than the parent serializer.
|
||||
LIST_SERIALIZER_KWARGS = (
|
||||
'read_only', 'write_only', 'required', 'default', 'initial', 'source',
|
||||
'label', 'help_text', 'style', 'error_messages',
|
||||
|
@ -73,13 +76,25 @@ class BaseSerializer(Field):
|
|||
# We override this method in order to automagically create
|
||||
# `ListSerializer` classes instead when `many=True` is set.
|
||||
if kwargs.pop('many', False):
|
||||
list_kwargs = {'child': cls(*args, **kwargs)}
|
||||
for key in kwargs.keys():
|
||||
if key in LIST_SERIALIZER_KWARGS:
|
||||
list_kwargs[key] = kwargs[key]
|
||||
return ListSerializer(*args, **list_kwargs)
|
||||
return cls.many_init(*args, **kwargs)
|
||||
return super(BaseSerializer, cls).__new__(cls, *args, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def many_init(cls, *args, **kwargs):
|
||||
"""
|
||||
This method implements the creation of a `ListSerializer` parent
|
||||
class when `many=True` is used. You can customize it if you need to
|
||||
control which keyword arguments are passed to the parent, and
|
||||
which are passed to the child.
|
||||
"""
|
||||
child_serializer = cls(*args, **kwargs)
|
||||
list_kwargs = {'child': child_serializer}
|
||||
list_kwargs.update(dict([
|
||||
(key, value) for key, value in kwargs.items()
|
||||
if key in LIST_SERIALIZER_KWARGS
|
||||
]))
|
||||
return ListSerializer(*args, **list_kwargs)
|
||||
|
||||
def to_internal_value(self, data):
|
||||
raise NotImplementedError('`to_internal_value()` must be implemented.')
|
||||
|
||||
|
@ -230,18 +245,18 @@ class Serializer(BaseSerializer):
|
|||
|
||||
def get_initial(self):
|
||||
if self._initial_data is not None:
|
||||
return ReturnDict([
|
||||
return OrderedDict([
|
||||
(field_name, field.get_value(self._initial_data))
|
||||
for field_name, field in self.fields.items()
|
||||
if field.get_value(self._initial_data) is not empty
|
||||
and not field.read_only
|
||||
], serializer=self)
|
||||
])
|
||||
|
||||
return ReturnDict([
|
||||
return OrderedDict([
|
||||
(field.field_name, field.get_initial())
|
||||
for field in self.fields.values()
|
||||
if not field.read_only
|
||||
], serializer=self)
|
||||
])
|
||||
|
||||
def get_value(self, dictionary):
|
||||
# We override the default field access in order to support
|
||||
|
@ -304,8 +319,8 @@ class Serializer(BaseSerializer):
|
|||
"""
|
||||
Dict of native values <- Dict of primitive datatypes.
|
||||
"""
|
||||
ret = {}
|
||||
errors = ReturnDict(serializer=self)
|
||||
ret = OrderedDict()
|
||||
errors = OrderedDict()
|
||||
fields = [
|
||||
field for field in self.fields.values()
|
||||
if (not field.read_only) or (field.default is not empty)
|
||||
|
@ -334,7 +349,7 @@ class Serializer(BaseSerializer):
|
|||
"""
|
||||
Object instance -> Dict of primitive datatypes.
|
||||
"""
|
||||
ret = ReturnDict(serializer=self)
|
||||
ret = OrderedDict()
|
||||
fields = [field for field in self.fields.values() if not field.write_only]
|
||||
|
||||
for field in fields:
|
||||
|
@ -373,6 +388,19 @@ class Serializer(BaseSerializer):
|
|||
return NestedBoundField(field, value, error)
|
||||
return BoundField(field, value, error)
|
||||
|
||||
# Include a backlink to the serializer class on return objects.
|
||||
# Allows renderers such as HTMLFormRenderer to get the full field info.
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
ret = super(Serializer, self).data
|
||||
return ReturnDict(ret, serializer=self)
|
||||
|
||||
@property
|
||||
def errors(self):
|
||||
ret = super(Serializer, self).errors
|
||||
return ReturnDict(ret, serializer=self)
|
||||
|
||||
|
||||
# There's some replication of `ListField` here,
|
||||
# but that's probably better than obfuscating the call hierarchy.
|
||||
|
@ -395,7 +423,7 @@ class ListSerializer(BaseSerializer):
|
|||
def get_initial(self):
|
||||
if self._initial_data is not None:
|
||||
return self.to_representation(self._initial_data)
|
||||
return ReturnList(serializer=self)
|
||||
return []
|
||||
|
||||
def get_value(self, dictionary):
|
||||
"""
|
||||
|
@ -423,7 +451,7 @@ class ListSerializer(BaseSerializer):
|
|||
})
|
||||
|
||||
ret = []
|
||||
errors = ReturnList(serializer=self)
|
||||
errors = []
|
||||
|
||||
for item in data:
|
||||
try:
|
||||
|
@ -444,37 +472,64 @@ class ListSerializer(BaseSerializer):
|
|||
List of object instances -> List of dicts of primitive datatypes.
|
||||
"""
|
||||
iterable = data.all() if (hasattr(data, 'all')) else data
|
||||
return ReturnList(
|
||||
[self.child.to_representation(item) for item in iterable],
|
||||
serializer=self
|
||||
return [
|
||||
self.child.to_representation(item) for item in iterable
|
||||
]
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
raise NotImplementedError(
|
||||
"Serializers with many=True do not support multiple update by "
|
||||
"default, only multiple create. For updates it is unclear how to "
|
||||
"deal with insertions and deletions. If you need to support "
|
||||
"multiple update, use a `ListSerializer` class and override "
|
||||
"`.update()` so you can specify the behavior exactly."
|
||||
)
|
||||
|
||||
def create(self, validated_data):
|
||||
return [
|
||||
self.child.create(attrs) for attrs in validated_data
|
||||
]
|
||||
|
||||
def save(self, **kwargs):
|
||||
"""
|
||||
Save and return a list of object instances.
|
||||
"""
|
||||
assert self.instance is None, (
|
||||
"Serializers do not support multiple update by default, only "
|
||||
"multiple create. For updates it is unclear how to deal with "
|
||||
"insertions and deletions. If you need to support multiple update, "
|
||||
"use a `ListSerializer` class and override `.save()` so you can "
|
||||
"specify the behavior exactly."
|
||||
)
|
||||
|
||||
validated_data = [
|
||||
dict(list(attrs.items()) + list(kwargs.items()))
|
||||
for attrs in self.validated_data
|
||||
]
|
||||
|
||||
self.instance = [
|
||||
self.child.create(attrs) for attrs in validated_data
|
||||
]
|
||||
if self.instance is not None:
|
||||
self.instance = self.update(self.instance, validated_data)
|
||||
assert self.instance is not None, (
|
||||
'`update()` did not return an object instance.'
|
||||
)
|
||||
else:
|
||||
self.instance = self.create(validated_data)
|
||||
assert self.instance is not None, (
|
||||
'`create()` did not return an object instance.'
|
||||
)
|
||||
|
||||
return self.instance
|
||||
|
||||
def __repr__(self):
|
||||
return representation.list_repr(self, indent=1)
|
||||
|
||||
# Include a backlink to the serializer class on return objects.
|
||||
# Allows renderers such as HTMLFormRenderer to get the full field info.
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
ret = super(ListSerializer, self).data
|
||||
return ReturnList(ret, serializer=self)
|
||||
|
||||
@property
|
||||
def errors(self):
|
||||
ret = super(ListSerializer, self).errors
|
||||
if isinstance(ret, dict):
|
||||
return ReturnDict(ret, serializer=self)
|
||||
return ReturnList(ret, serializer=self)
|
||||
|
||||
|
||||
# ModelSerializer & HyperlinkedModelSerializer
|
||||
# --------------------------------------------
|
||||
|
|
|
@ -88,7 +88,7 @@ def get_field_kwargs(field_name, model_field):
|
|||
kwargs['read_only'] = True
|
||||
return kwargs
|
||||
|
||||
if model_field.has_default():
|
||||
if model_field.has_default() or model_field.blank or model_field.null:
|
||||
kwargs['required'] = False
|
||||
|
||||
if model_field.flatchoices:
|
||||
|
@ -215,7 +215,7 @@ def get_relation_kwargs(field_name, relation_info):
|
|||
# If this field is read-only, then return early.
|
||||
# No further keyword arguments are valid.
|
||||
return kwargs
|
||||
if model_field.has_default():
|
||||
if model_field.has_default() or model_field.null:
|
||||
kwargs['required'] = False
|
||||
if model_field.null:
|
||||
kwargs['allow_null'] = True
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
from django.db import models
|
||||
|
||||
from tests.users.models import User
|
||||
|
||||
|
||||
class Account(models.Model):
|
||||
owner = models.ForeignKey(User, related_name='accounts_owned')
|
||||
admins = models.ManyToManyField(User, blank=True, null=True, related_name='accounts_administered')
|
|
@ -1,11 +0,0 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from tests.accounts.models import Account
|
||||
from tests.users.serializers import UserSerializer
|
||||
|
||||
|
||||
class AccountSerializer(serializers.ModelSerializer):
|
||||
admins = UserSerializer(many=True)
|
||||
|
||||
class Meta:
|
||||
model = Account
|
|
@ -33,9 +33,6 @@ def pytest_configure():
|
|||
'rest_framework',
|
||||
'rest_framework.authtoken',
|
||||
'tests',
|
||||
'tests.accounts',
|
||||
'tests.records',
|
||||
'tests.users',
|
||||
),
|
||||
PASSWORD_HASHERS=(
|
||||
'django.contrib.auth.hashers.SHA1PasswordHasher',
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
# From test_validation...
|
||||
|
||||
class TestPreSaveValidationExclusions(TestCase):
|
||||
def test_pre_save_validation_exclusions(self):
|
||||
"""
|
||||
Somewhat weird test case to ensure that we don't perform model
|
||||
validation on read only fields.
|
||||
"""
|
||||
obj = ValidationModel.objects.create(blank_validated_field='')
|
||||
request = factory.put('/', {}, format='json')
|
||||
view = UpdateValidationModel().as_view()
|
||||
response = view(request, pk=obj.pk).render()
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
|
||||
# From test_permissions...
|
||||
|
||||
class ModelPermissionsIntegrationTests(TestCase):
|
||||
def setUp(...):
|
||||
...
|
||||
|
||||
def test_has_put_as_create_permissions(self):
|
||||
# User only has update permissions - should be able to update an entity.
|
||||
request = factory.put('/1', {'text': 'foobar'}, format='json',
|
||||
HTTP_AUTHORIZATION=self.updateonly_credentials)
|
||||
response = instance_view(request, pk='1')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
# But if PUTing to a new entity, permission should be denied.
|
||||
request = factory.put('/2', {'text': 'foobar'}, format='json',
|
||||
HTTP_AUTHORIZATION=self.updateonly_credentials)
|
||||
response = instance_view(request, pk='2')
|
||||
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
|
@ -1,6 +0,0 @@
|
|||
from django.db import models
|
||||
|
||||
|
||||
class Record(models.Model):
|
||||
account = models.ForeignKey('accounts.Account', blank=True, null=True)
|
||||
owner = models.ForeignKey('users.User', blank=True, null=True)
|
|
@ -1,165 +0,0 @@
|
|||
# Django settings for testproject project.
|
||||
|
||||
DEBUG = True
|
||||
TEMPLATE_DEBUG = DEBUG
|
||||
DEBUG_PROPAGATE_EXCEPTIONS = True
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
ADMINS = (
|
||||
# ('Your Name', 'your_email@domain.com'),
|
||||
)
|
||||
|
||||
MANAGERS = ADMINS
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
|
||||
'NAME': 'sqlite.db', # Or path to database file if using sqlite3.
|
||||
'USER': '', # Not used with sqlite3.
|
||||
'PASSWORD': '', # Not used with sqlite3.
|
||||
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
|
||||
'PORT': '', # Set to empty string for default. Not used with sqlite3.
|
||||
}
|
||||
}
|
||||
|
||||
CACHES = {
|
||||
'default': {
|
||||
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
|
||||
}
|
||||
}
|
||||
|
||||
# Local time zone for this installation. Choices can be found here:
|
||||
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
|
||||
# although not all choices may be available on all operating systems.
|
||||
# On Unix systems, a value of None will cause Django to use the same
|
||||
# timezone as the operating system.
|
||||
# If running in a Windows environment this must be set to the same as your
|
||||
# system time zone.
|
||||
TIME_ZONE = 'Europe/London'
|
||||
|
||||
# Language code for this installation. All choices can be found here:
|
||||
# http://www.i18nguy.com/unicode/language-identifiers.html
|
||||
LANGUAGE_CODE = 'en-uk'
|
||||
|
||||
SITE_ID = 1
|
||||
|
||||
# If you set this to False, Django will make some optimizations so as not
|
||||
# to load the internationalization machinery.
|
||||
USE_I18N = True
|
||||
|
||||
# If you set this to False, Django will not format dates, numbers and
|
||||
# calendars according to the current locale
|
||||
USE_L10N = True
|
||||
|
||||
# Absolute filesystem path to the directory that will hold user-uploaded files.
|
||||
# Example: "/home/media/media.lawrence.com/"
|
||||
MEDIA_ROOT = ''
|
||||
|
||||
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
|
||||
# trailing slash if there is a path component (optional in other cases).
|
||||
# Examples: "http://media.lawrence.com", "http://example.com/media/"
|
||||
MEDIA_URL = ''
|
||||
|
||||
# Make this unique, and don't share it with anybody.
|
||||
SECRET_KEY = 'u@x-aj9(hoh#rb-^ymf#g2jx_hp0vj7u5#b@ag1n^seu9e!%cy'
|
||||
|
||||
# List of callables that know how to import templates from various sources.
|
||||
TEMPLATE_LOADERS = (
|
||||
'django.template.loaders.filesystem.Loader',
|
||||
'django.template.loaders.app_directories.Loader',
|
||||
)
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
)
|
||||
|
||||
ROOT_URLCONF = 'tests.urls'
|
||||
|
||||
TEMPLATE_DIRS = (
|
||||
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
|
||||
# Always use forward slashes, even on Windows.
|
||||
# Don't forget to use absolute paths, not relative paths.
|
||||
)
|
||||
|
||||
INSTALLED_APPS = (
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.sites',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'rest_framework',
|
||||
'rest_framework.authtoken',
|
||||
'tests',
|
||||
'tests.accounts',
|
||||
'tests.records',
|
||||
'tests.users',
|
||||
)
|
||||
|
||||
# OAuth is optional and won't work if there is no oauth_provider & oauth2
|
||||
try:
|
||||
import oauth_provider # NOQA
|
||||
import oauth2 # NOQA
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
INSTALLED_APPS += (
|
||||
'oauth_provider',
|
||||
)
|
||||
|
||||
try:
|
||||
import provider # NOQA
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
INSTALLED_APPS += (
|
||||
'provider',
|
||||
'provider.oauth2',
|
||||
)
|
||||
|
||||
# guardian is optional
|
||||
try:
|
||||
import guardian # NOQA
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
ANONYMOUS_USER_ID = -1
|
||||
AUTHENTICATION_BACKENDS = (
|
||||
'django.contrib.auth.backends.ModelBackend', # default
|
||||
'guardian.backends.ObjectPermissionBackend',
|
||||
)
|
||||
INSTALLED_APPS += (
|
||||
'guardian',
|
||||
)
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
PASSWORD_HASHERS = (
|
||||
'django.contrib.auth.hashers.SHA1PasswordHasher',
|
||||
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
|
||||
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
|
||||
'django.contrib.auth.hashers.BCryptPasswordHasher',
|
||||
'django.contrib.auth.hashers.MD5PasswordHasher',
|
||||
'django.contrib.auth.hashers.CryptPasswordHasher',
|
||||
)
|
||||
|
||||
AUTH_USER_MODEL = 'auth.User'
|
||||
|
||||
import django
|
||||
|
||||
if django.VERSION < (1, 3):
|
||||
INSTALLED_APPS += ('staticfiles',)
|
||||
|
||||
|
||||
# If we're running on the Jenkins server we want to archive the coverage reports as XML.
|
||||
import os
|
||||
if os.environ.get('HUDSON_URL', None):
|
||||
TEST_RUNNER = 'xmlrunner.extra.djangotestrunner.XMLTestRunner'
|
||||
TEST_OUTPUT_VERBOSE = True
|
||||
TEST_OUTPUT_DESCRIPTIONS = True
|
||||
TEST_OUTPUT_DIR = 'xmlrunner'
|
|
@ -90,7 +90,7 @@ class TestRegularFieldMappings(TestCase):
|
|||
email_field = EmailField(max_length=100)
|
||||
float_field = FloatField()
|
||||
integer_field = IntegerField()
|
||||
null_boolean_field = NullBooleanField()
|
||||
null_boolean_field = NullBooleanField(required=False)
|
||||
positive_integer_field = IntegerField()
|
||||
positive_small_integer_field = IntegerField()
|
||||
slug_field = SlugField(max_length=100)
|
||||
|
@ -112,8 +112,8 @@ class TestRegularFieldMappings(TestCase):
|
|||
id = IntegerField(label='ID', read_only=True)
|
||||
value_limit_field = IntegerField(max_value=10, min_value=1)
|
||||
length_limit_field = CharField(max_length=12, min_length=3)
|
||||
blank_field = CharField(allow_blank=True, max_length=10)
|
||||
null_field = IntegerField(allow_null=True)
|
||||
blank_field = CharField(allow_blank=True, max_length=10, required=False)
|
||||
null_field = IntegerField(allow_null=True, required=False)
|
||||
default_field = IntegerField(required=False)
|
||||
descriptive_field = IntegerField(help_text='Some help text', label='A label')
|
||||
choices_field = ChoiceField(choices=[('red', 'Red'), ('blue', 'Blue'), ('green', 'Green')])
|
||||
|
|
|
@ -95,59 +95,59 @@ class ModelPermissionsIntegrationTests(TestCase):
|
|||
response = instance_view(request, pk=1)
|
||||
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
|
||||
|
||||
# def test_options_permitted(self):
|
||||
# request = factory.options(
|
||||
# '/',
|
||||
# HTTP_AUTHORIZATION=self.permitted_credentials
|
||||
# )
|
||||
# response = root_view(request, pk='1')
|
||||
# self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
# self.assertIn('actions', response.data)
|
||||
# self.assertEqual(list(response.data['actions'].keys()), ['POST'])
|
||||
def test_options_permitted(self):
|
||||
request = factory.options(
|
||||
'/',
|
||||
HTTP_AUTHORIZATION=self.permitted_credentials
|
||||
)
|
||||
response = root_view(request, pk='1')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertIn('actions', response.data)
|
||||
self.assertEqual(list(response.data['actions'].keys()), ['POST'])
|
||||
|
||||
# request = factory.options(
|
||||
# '/1',
|
||||
# HTTP_AUTHORIZATION=self.permitted_credentials
|
||||
# )
|
||||
# response = instance_view(request, pk='1')
|
||||
# self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
# self.assertIn('actions', response.data)
|
||||
# self.assertEqual(list(response.data['actions'].keys()), ['PUT'])
|
||||
request = factory.options(
|
||||
'/1',
|
||||
HTTP_AUTHORIZATION=self.permitted_credentials
|
||||
)
|
||||
response = instance_view(request, pk='1')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertIn('actions', response.data)
|
||||
self.assertEqual(list(response.data['actions'].keys()), ['PUT'])
|
||||
|
||||
# def test_options_disallowed(self):
|
||||
# request = factory.options(
|
||||
# '/',
|
||||
# HTTP_AUTHORIZATION=self.disallowed_credentials
|
||||
# )
|
||||
# response = root_view(request, pk='1')
|
||||
# self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
# self.assertNotIn('actions', response.data)
|
||||
def test_options_disallowed(self):
|
||||
request = factory.options(
|
||||
'/',
|
||||
HTTP_AUTHORIZATION=self.disallowed_credentials
|
||||
)
|
||||
response = root_view(request, pk='1')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertNotIn('actions', response.data)
|
||||
|
||||
# request = factory.options(
|
||||
# '/1',
|
||||
# HTTP_AUTHORIZATION=self.disallowed_credentials
|
||||
# )
|
||||
# response = instance_view(request, pk='1')
|
||||
# self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
# self.assertNotIn('actions', response.data)
|
||||
request = factory.options(
|
||||
'/1',
|
||||
HTTP_AUTHORIZATION=self.disallowed_credentials
|
||||
)
|
||||
response = instance_view(request, pk='1')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertNotIn('actions', response.data)
|
||||
|
||||
# def test_options_updateonly(self):
|
||||
# request = factory.options(
|
||||
# '/',
|
||||
# HTTP_AUTHORIZATION=self.updateonly_credentials
|
||||
# )
|
||||
# response = root_view(request, pk='1')
|
||||
# self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
# self.assertNotIn('actions', response.data)
|
||||
def test_options_updateonly(self):
|
||||
request = factory.options(
|
||||
'/',
|
||||
HTTP_AUTHORIZATION=self.updateonly_credentials
|
||||
)
|
||||
response = root_view(request, pk='1')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertNotIn('actions', response.data)
|
||||
|
||||
# request = factory.options(
|
||||
# '/1',
|
||||
# HTTP_AUTHORIZATION=self.updateonly_credentials
|
||||
# )
|
||||
# response = instance_view(request, pk='1')
|
||||
# self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
# self.assertIn('actions', response.data)
|
||||
# self.assertEqual(list(response.data['actions'].keys()), ['PUT'])
|
||||
request = factory.options(
|
||||
'/1',
|
||||
HTTP_AUTHORIZATION=self.updateonly_credentials
|
||||
)
|
||||
response = instance_view(request, pk='1')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertIn('actions', response.data)
|
||||
self.assertEqual(list(response.data['actions'].keys()), ['PUT'])
|
||||
|
||||
|
||||
class BasicPermModel(models.Model):
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
# from django.test import TestCase
|
||||
|
||||
# from rest_framework import serializers
|
||||
# from tests.accounts.serializers import AccountSerializer
|
||||
|
||||
|
||||
# class ImportingModelSerializerTests(TestCase):
|
||||
# """
|
||||
# In some situations like, GH #1225, it is possible, especially in
|
||||
# testing, to import a serializer who's related models have not yet
|
||||
# been resolved by Django. `AccountSerializer` is an example of such
|
||||
# a serializer (imported at the top of this file).
|
||||
# """
|
||||
# def test_import_model_serializer(self):
|
||||
# """
|
||||
# The serializer at the top of this file should have been
|
||||
# imported successfully, and we should be able to instantiate it.
|
||||
# """
|
||||
# self.assertIsInstance(AccountSerializer(), serializers.ModelSerializer)
|
|
@ -1,6 +0,0 @@
|
|||
from django.db import models
|
||||
|
||||
|
||||
class User(models.Model):
|
||||
account = models.ForeignKey('accounts.Account', blank=True, null=True, related_name='users')
|
||||
active_record = models.ForeignKey('records.Record', blank=True, null=True)
|
|
@ -1,8 +0,0 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from tests.users.models import User
|
||||
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
Loading…
Reference in New Issue
Block a user