Merge remote-tracking branch 'upstream/master' into related-required

This commit is contained in:
Mark Aaron Shirley 2012-12-19 15:24:22 -08:00
commit 2f5582a1a6
20 changed files with 64 additions and 39 deletions

View File

@ -79,6 +79,7 @@ The following people have helped make REST framework great.
* Colin Murtaugh - [cmurtaugh]
* Simon Pantzare - [pilt]
* Szymon Teżewski - [sunscrapers]
* Joel Marcotte - [joual]
Many thanks to everyone who's contributed to the project.
@ -193,3 +194,4 @@ You can also contact [@_tomchristie][twitter] directly on twitter.
[cmurtaugh]: https://github.com/cmurtaugh
[pilt]: https://github.com/pilt
[sunscrapers]: https://github.com/sunscrapers
[joual]: https://github.com/joual

View File

@ -8,6 +8,8 @@
### Master
* Bugfix: Fix bug that could occur using ChoiceField.
* Bugfix: Fix exception in browseable API on DELETE.
* Bugfix: Fix issue where pk was was being set to a string if set by URL kwarg.
### 2.1.11

View File

@ -5,6 +5,12 @@ versions of django/python, and compatibility wrappers around optional packages.
# flake8: noqa
import django
# location of patterns, url, include changes in 1.4 onwards
try:
from django.conf.urls import patterns, url, include
except:
from django.conf.urls.defaults import patterns, url, include
# django-filter is optional
try:
import django_filters

View File

@ -801,7 +801,7 @@ class ChoiceField(WritableField):
if value == smart_unicode(k2):
return True
else:
if value == smart_unicode(k):
if value == smart_unicode(k) or value == k:
return True
return False

View File

@ -124,6 +124,6 @@ class DestroyModelMixin(object):
Should be mixed in with `SingleObjectBaseView`.
"""
def destroy(self, request, *args, **kwargs):
self.object = self.get_object()
self.object.delete()
obj = self.get_object()
obj.delete()
return Response(status=status.HTTP_204_NO_CONTENT)

View File

@ -1,15 +1,13 @@
from django.conf.urls.defaults import patterns
from django.contrib.auth.models import User
from django.test import Client, TestCase
from django.utils import simplejson as json
from django.http import HttpResponse
from django.test import Client, TestCase
from django.utils import simplejson as json
from rest_framework.views import APIView
from rest_framework import permissions
from rest_framework.authtoken.models import Token
from rest_framework.authentication import TokenAuthentication
from rest_framework.compat import patterns
from rest_framework.views import APIView
import base64

View File

@ -1,5 +1,5 @@
from django.conf.urls.defaults import patterns, url
from django.test import TestCase
from rest_framework.compat import patterns, url
from rest_framework.utils.breadcrumbs import get_breadcrumbs
from rest_framework.views import APIView

View File

@ -1,7 +1,7 @@
from django.test import TestCase
from django.test.client import RequestFactory
from rest_framework import status
from rest_framework.response import Response
from django.test.client import RequestFactory
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
from rest_framework.authentication import BasicAuthentication

View File

@ -1,9 +1,9 @@
from django.core.exceptions import PermissionDenied
from django.conf.urls.defaults import patterns, url
from django.http import Http404
from django.test import TestCase
from django.template import TemplateDoesNotExist, Template
import django.template.loader
from rest_framework.compat import patterns, url
from rest_framework.decorators import api_view, renderer_classes
from rest_framework.renderers import TemplateHTMLRenderer
from rest_framework.response import Response

View File

@ -1,7 +1,7 @@
from django.conf.urls import patterns, url
from django.db import models
from django.test import TestCase
from rest_framework import serializers
from rest_framework.compat import patterns, url
def dummy_view(request, pk):

View File

@ -1,8 +1,8 @@
from django.conf.urls.defaults import patterns, url
from django.test import TestCase
from django.test.client import RequestFactory
from django.utils import simplejson as json
from rest_framework import generics, status, serializers
from rest_framework.compat import patterns, url
from rest_framework.tests.models import Anchor, BasicModel, ManyToManyModel, BlogPost, BlogPostComment, Album, Photo, OptionalRelationModel
factory = RequestFactory()

View File

@ -51,6 +51,11 @@ class RESTFrameworkModel(models.Model):
abstract = True
class HasPositiveIntegerAsChoice(RESTFrameworkModel):
some_choices = ((1, 'A'), (2, 'B'), (3, 'C'))
some_integer = models.PositiveIntegerField(choices=some_choices)
class Anchor(RESTFrameworkModel):
text = models.CharField(max_length=100, default='anchor')
@ -160,7 +165,7 @@ class Photo(RESTFrameworkModel):
# Model for issue #324
class BlankFieldModel(RESTFrameworkModel):
title = models.CharField(max_length=100, blank=True, null=True)
title = models.CharField(max_length=100, blank=True, null=False)
# Model for issue #380

View File

@ -1,13 +1,12 @@
import pickle
import re
from django.conf.urls.defaults import patterns, url, include
from django.core.cache import cache
from django.test import TestCase
from django.test.client import RequestFactory
from rest_framework import status, permissions
from rest_framework.compat import yaml
from rest_framework.compat import yaml, patterns, url, include
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.renderers import BaseRenderer, JSONRenderer, YAMLRenderer, \
@ -444,19 +443,19 @@ class CacheRenderTest(TestCase):
return
if state == None:
return
if isinstance(state,tuple):
if not isinstance(state[0],dict):
state=state[1]
if isinstance(state, tuple):
if not isinstance(state[0], dict):
state = state[1]
else:
state=state[0].update(state[1])
state = state[0].update(state[1])
result = {}
for i in state:
try:
pickle.dumps(state[i],protocol=2)
pickle.dumps(state[i], protocol=2)
except pickle.PicklingError:
if not state[i] in seen:
seen.append(state[i])
result[i] = cls._get_pickling_errors(state[i],seen)
result[i] = cls._get_pickling_errors(state[i], seen)
return result
def http_resp(self, http_method, url):

View File

@ -1,16 +1,15 @@
"""
Tests for content parsing, and form-overloaded content parsing.
"""
from django.conf.urls.defaults import patterns
from django.contrib.auth.models import User
from django.contrib.auth import authenticate, login, logout
from django.contrib.sessions.middleware import SessionMiddleware
from django.test import TestCase, Client
from django.test.client import RequestFactory
from django.utils import simplejson as json
from rest_framework import status
from rest_framework.authentication import SessionAuthentication
from django.test.client import RequestFactory
from rest_framework.compat import patterns
from rest_framework.parsers import (
BaseParser,
FormParser,

View File

@ -1,8 +1,5 @@
import unittest
from django.conf.urls.defaults import patterns, url, include
from django.test import TestCase
from rest_framework.compat import patterns, url, include
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status

View File

@ -1,6 +1,6 @@
from django.conf.urls.defaults import patterns, url
from django.test import TestCase
from django.test.client import RequestFactory
from rest_framework.compat import patterns, url
from rest_framework.reverse import reverse
factory = RequestFactory()

View File

@ -2,7 +2,7 @@ import datetime
import pickle
from django.test import TestCase
from rest_framework import serializers
from rest_framework.tests.models import (Album, ActionItem, Anchor, BasicModel,
from rest_framework.tests.models import (HasPositiveIntegerAsChoice, Album, ActionItem, Anchor, BasicModel,
BlankFieldModel, BlogPost, Book, CallableDefaultValueModel, DefaultValueModel,
ManyToManyModel, Person, ReadOnlyManyToManyModel, Photo)
@ -69,6 +69,11 @@ class AlbumsSerializer(serializers.ModelSerializer):
model = Album
fields = ['title'] # lists are also valid options
class PositiveIntegerAsChoiceSerializer(serializers.ModelSerializer):
class Meta:
model = HasPositiveIntegerAsChoice
fields = ['some_integer']
class BasicTests(TestCase):
def setUp(self):
@ -285,6 +290,12 @@ class ValidationTests(TestCase):
self.assertEquals(serializer.errors, {'info': [u'Ensure this value has at most 12 characters (it has 13).']})
class PositiveIntegerAsChoiceTests(TestCase):
def test_positive_integer_in_json_is_correctly_parsed(self):
data = {'some_integer':1}
serializer = PositiveIntegerAsChoiceSerializer(data=data)
self.assertEquals(serializer.is_valid(), True)
class ModelValidationTests(TestCase):
def test_validate_unique(self):
"""
@ -720,6 +731,10 @@ class BlankFieldTests(TestCase):
serializer = self.model_serializer_class(data=self.data)
self.assertEquals(serializer.is_valid(), True)
def test_create_model_null_field(self):
serializer = self.model_serializer_class(data={'title': None})
self.assertEquals(serializer.is_valid(), True)
def test_create_not_blank_field(self):
"""
Test to ensure blank data in a field not marked as blank=True

View File

@ -6,6 +6,7 @@ from django.test import TestCase
NO_SETTING = ('!', None)
class TestSettingsManager(object):
"""
A class which can modify some Django settings temporarily for a
@ -19,7 +20,7 @@ class TestSettingsManager(object):
self._original_settings = {}
def set(self, **kwargs):
for k,v in kwargs.iteritems():
for k, v in kwargs.iteritems():
self._original_settings.setdefault(k, getattr(settings, k,
NO_SETTING))
setattr(settings, k, v)
@ -31,7 +32,7 @@ class TestSettingsManager(object):
call_command('syncdb', verbosity=0)
def revert(self):
for k,v in self._original_settings.iteritems():
for k, v in self._original_settings.iteritems():
if v == NO_SETTING:
delattr(settings, k)
else:
@ -57,6 +58,7 @@ class SettingsTestCase(TestCase):
def tearDown(self):
self.settings_manager.revert()
class TestModelsTestCase(SettingsTestCase):
def setUp(self, *args, **kwargs):
installed_apps = tuple(settings.INSTALLED_APPS) + ('rest_framework.tests',)

View File

@ -12,7 +12,7 @@ your authentication settings include `SessionAuthentication`.
url(r'^auth', include('rest_framework.urls', namespace='rest_framework'))
)
"""
from django.conf.urls.defaults import patterns, url
from rest_framework.compat import patterns, url
template_name = {'template_name': 'rest_framework/login.html'}

View File

@ -12,12 +12,12 @@ deps = https://github.com/django/django/zipball/master
[testenv:py2.7-django1.4]
basepython = python2.7
deps = django==1.4.1
deps = django==1.4.3
django-filter==0.5.4
[testenv:py2.7-django1.3]
basepython = python2.7
deps = django==1.3.3
deps = django==1.3.5
django-filter==0.5.4
[testenv:py2.6-django1.5]
@ -27,10 +27,10 @@ deps = https://github.com/django/django/zipball/master
[testenv:py2.6-django1.4]
basepython = python2.6
deps = django==1.4.1
deps = django==1.4.3
django-filter==0.5.4
[testenv:py2.6-django1.3]
basepython = python2.6
deps = django==1.3.3
deps = django==1.3.5
django-filter==0.5.4