mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-30 05:24:00 +03:00
Merge pull request #2161 from NextHub/master
Move models to respective test modules
This commit is contained in:
commit
d847e336c5
|
@ -3,7 +3,7 @@
|
||||||
[![build-status-image]][travis]
|
[![build-status-image]][travis]
|
||||||
[![pypi-version]][pypi]
|
[![pypi-version]][pypi]
|
||||||
|
|
||||||
**Awesome web-browseable Web APIs.**
|
**Awesome web-browsable Web APIs.**
|
||||||
|
|
||||||
Full documentation for the project is available at [http://www.django-rest-framework.org][docs].
|
Full documentation for the project is available at [http://www.django-rest-framework.org][docs].
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ Django REST framework is a powerful and flexible toolkit for building Web APIs.
|
||||||
|
|
||||||
Some reasons you might want to use REST framework:
|
Some reasons you might want to use REST framework:
|
||||||
|
|
||||||
* The [Web browseable API][sandbox] is a huge useability win for your developers.
|
* The [Web browsable API][sandbox] is a huge usability win for your developers.
|
||||||
* [Authentication policies][authentication] including [OAuth1a][oauth1-section] and [OAuth2][oauth2-section] out of the box.
|
* [Authentication policies][authentication] including [OAuth1a][oauth1-section] and [OAuth2][oauth2-section] out of the box.
|
||||||
* [Serialization][serializers] that supports both [ORM][modelserializer-section] and [non-ORM][serializer-section] data sources.
|
* [Serialization][serializers] that supports both [ORM][modelserializer-section] and [non-ORM][serializer-section] data sources.
|
||||||
* Customizable all the way down - just use [regular function-based views][functionview-section] if you don't need the [more][generic-views] [powerful][viewsets] [features][routers].
|
* Customizable all the way down - just use [regular function-based views][functionview-section] if you don't need the [more][generic-views] [powerful][viewsets] [features][routers].
|
||||||
|
@ -27,7 +27,7 @@ Some reasons you might want to use REST framework:
|
||||||
|
|
||||||
There is a live example API for testing purposes, [available here][sandbox].
|
There is a live example API for testing purposes, [available here][sandbox].
|
||||||
|
|
||||||
**Below**: *Screenshot from the browseable API*
|
**Below**: *Screenshot from the browsable API*
|
||||||
|
|
||||||
![Screenshot][image]
|
![Screenshot][image]
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ router.register(r'users', UserViewSet)
|
||||||
|
|
||||||
|
|
||||||
# Wire up our API using automatic URL routing.
|
# Wire up our API using automatic URL routing.
|
||||||
# Additionally, we include login URLs for the browseable API.
|
# Additionally, we include login URLs for the browsable API.
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^', include(router.urls)),
|
url(r'^', include(router.urls)),
|
||||||
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
||||||
|
|
|
@ -33,7 +33,7 @@ Django REST framework is a powerful and flexible toolkit that makes it easy to b
|
||||||
|
|
||||||
Some reasons you might want to use REST framework:
|
Some reasons you might want to use REST framework:
|
||||||
|
|
||||||
* The [Web browseable API][sandbox] is a huge usability win for your developers.
|
* The [Web browsable API][sandbox] is a huge usability win for your developers.
|
||||||
* [Authentication policies][authentication] including [OAuth1a][oauth1-section] and [OAuth2][oauth2-section] out of the box.
|
* [Authentication policies][authentication] including [OAuth1a][oauth1-section] and [OAuth2][oauth2-section] out of the box.
|
||||||
* [Serialization][serializers] that supports both [ORM][modelserializer-section] and [non-ORM][serializer-section] data sources.
|
* [Serialization][serializers] that supports both [ORM][modelserializer-section] and [non-ORM][serializer-section] data sources.
|
||||||
* Customizable all the way down - just use [regular function-based views][functionview-section] if you don't need the [more][generic-views] [powerful][viewsets] [features][routers].
|
* Customizable all the way down - just use [regular function-based views][functionview-section] if you don't need the [more][generic-views] [powerful][viewsets] [features][routers].
|
||||||
|
@ -134,7 +134,7 @@ Here's our project's root `urls.py` module:
|
||||||
router.register(r'users', UserViewSet)
|
router.register(r'users', UserViewSet)
|
||||||
|
|
||||||
# Wire up our API using automatic URL routing.
|
# Wire up our API using automatic URL routing.
|
||||||
# Additionally, we include login URLs for the browseable API.
|
# Additionally, we include login URLs for the browsable API.
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^', include(router.urls)),
|
url(r'^', include(router.urls)),
|
||||||
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
||||||
|
|
|
@ -35,7 +35,7 @@ As an example of just how simple REST framework APIs can now be, here's an API w
|
||||||
|
|
||||||
|
|
||||||
# Wire up our API using automatic URL routing.
|
# Wire up our API using automatic URL routing.
|
||||||
# Additionally, we include login URLs for the browseable API.
|
# Additionally, we include login URLs for the browsable API.
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^', include(router.urls)),
|
url(r'^', include(router.urls)),
|
||||||
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
||||||
|
@ -207,9 +207,9 @@ The old-style signature will continue to function but will raise a `PendingDepre
|
||||||
|
|
||||||
## View names and descriptions
|
## View names and descriptions
|
||||||
|
|
||||||
The mechanics of how the names and descriptions used in the browseable API are generated has been modified and cleaned up somewhat.
|
The mechanics of how the names and descriptions used in the browsable API are generated has been modified and cleaned up somewhat.
|
||||||
|
|
||||||
If you've been customizing this behavior, for example perhaps to use `rst` markup for the browseable API, then you'll need to take a look at the implementation to see what updates you need to make.
|
If you've been customizing this behavior, for example perhaps to use `rst` markup for the browsable API, then you'll need to take a look at the implementation to see what updates you need to make.
|
||||||
|
|
||||||
Note that the relevant methods have always been private APIs, and the docstrings called them out as intended to be deprecated.
|
Note that the relevant methods have always been private APIs, and the docstrings called them out as intended to be deprecated.
|
||||||
|
|
||||||
|
|
|
@ -121,7 +121,7 @@ You can determine your currently installed version using `pip freeze`:
|
||||||
* Add `UnicodeYAMLRenderer` that extends `YAMLRenderer` with unicode.
|
* Add `UnicodeYAMLRenderer` that extends `YAMLRenderer` with unicode.
|
||||||
* Fix `parse_header` argument convertion.
|
* Fix `parse_header` argument convertion.
|
||||||
* Fix mediatype detection under Python 3.
|
* Fix mediatype detection under Python 3.
|
||||||
* Web browseable API now offers blank option on dropdown when the field is not required.
|
* Web browsable API now offers blank option on dropdown when the field is not required.
|
||||||
* `APIException` representation improved for logging purposes.
|
* `APIException` representation improved for logging purposes.
|
||||||
* Allow source="*" within nested serializers.
|
* Allow source="*" within nested serializers.
|
||||||
* Better support for custom oauth2 provider backends.
|
* Better support for custom oauth2 provider backends.
|
||||||
|
@ -200,7 +200,7 @@ You can determine your currently installed version using `pip freeze`:
|
||||||
* Added `MAX_PAGINATE_BY` setting and `max_paginate_by` generic view attribute.
|
* Added `MAX_PAGINATE_BY` setting and `max_paginate_by` generic view attribute.
|
||||||
* Added `cache` attribute to throttles to allow overriding of default cache.
|
* Added `cache` attribute to throttles to allow overriding of default cache.
|
||||||
* 'Raw data' tab in browsable API now contains pre-populated data.
|
* 'Raw data' tab in browsable API now contains pre-populated data.
|
||||||
* 'Raw data' and 'HTML form' tab preference in browseable API now saved between page views.
|
* 'Raw data' and 'HTML form' tab preference in browsable API now saved between page views.
|
||||||
* Bugfix: `required=True` argument fixed for boolean serializer fields.
|
* Bugfix: `required=True` argument fixed for boolean serializer fields.
|
||||||
* Bugfix: `client.force_authenticate(None)` should also clear session info if it exists.
|
* Bugfix: `client.force_authenticate(None)` should also clear session info if it exists.
|
||||||
* Bugfix: Client sending empty string instead of file now clears `FileField`.
|
* Bugfix: Client sending empty string instead of file now clears `FileField`.
|
||||||
|
|
|
@ -112,7 +112,7 @@ Here's our re-wired `urls.py` file.
|
||||||
router.register(r'users', views.UserViewSet)
|
router.register(r'users', views.UserViewSet)
|
||||||
|
|
||||||
# The API URLs are now determined automatically by the router.
|
# The API URLs are now determined automatically by the router.
|
||||||
# Additionally, we include the login URLs for the browseable API.
|
# Additionally, we include the login URLs for the browsable API.
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^', include(router.urls)),
|
url(r'^', include(router.urls)),
|
||||||
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
||||||
|
@ -130,7 +130,7 @@ That doesn't mean it's always the right approach to take. There's a similar set
|
||||||
|
|
||||||
## Reviewing our work
|
## Reviewing our work
|
||||||
|
|
||||||
With an incredibly small amount of code, we've now got a complete pastebin Web API, which is fully web browseable, and comes complete with authentication, per-object permissions, and multiple renderer formats.
|
With an incredibly small amount of code, we've now got a complete pastebin Web API, which is fully web browsable, and comes complete with authentication, per-object permissions, and multiple renderer formats.
|
||||||
|
|
||||||
We've walked through each step of the design process, and seen how if we need to customize anything we can gradually work our way down to simply using regular Django views.
|
We've walked through each step of the design process, and seen how if we need to customize anything we can gradually work our way down to simply using regular Django views.
|
||||||
|
|
||||||
|
|
|
@ -100,7 +100,7 @@ Okay, now let's wire up the API URLs. On to `tutorial/urls.py`...
|
||||||
router.register(r'groups', views.GroupViewSet)
|
router.register(r'groups', views.GroupViewSet)
|
||||||
|
|
||||||
# Wire up our API using automatic URL routing.
|
# Wire up our API using automatic URL routing.
|
||||||
# Additionally, we include login URLs for the browseable API.
|
# Additionally, we include login URLs for the browsable API.
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^', include(router.urls)),
|
url(r'^', include(router.urls)),
|
||||||
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
||||||
|
|
111
tests/models.py
111
tests/models.py
|
@ -3,62 +3,20 @@ from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
def foobar():
|
|
||||||
return 'foobar'
|
|
||||||
|
|
||||||
|
|
||||||
class CustomField(models.CharField):
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
kwargs['max_length'] = 12
|
|
||||||
super(CustomField, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class RESTFrameworkModel(models.Model):
|
class RESTFrameworkModel(models.Model):
|
||||||
"""
|
"""
|
||||||
Base for test models that sets app_label, so they play nicely.
|
Base for test models that sets app_label, so they play nicely.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'tests'
|
app_label = 'tests'
|
||||||
abstract = True
|
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')
|
|
||||||
|
|
||||||
|
|
||||||
class BasicModel(RESTFrameworkModel):
|
class BasicModel(RESTFrameworkModel):
|
||||||
text = models.CharField(max_length=100, verbose_name=_("Text comes here"), help_text=_("Text description."))
|
text = models.CharField(max_length=100, verbose_name=_("Text comes here"), help_text=_("Text description."))
|
||||||
|
|
||||||
|
|
||||||
class SlugBasedModel(RESTFrameworkModel):
|
|
||||||
text = models.CharField(max_length=100)
|
|
||||||
slug = models.SlugField(max_length=32)
|
|
||||||
|
|
||||||
|
|
||||||
class DefaultValueModel(RESTFrameworkModel):
|
|
||||||
text = models.CharField(default='foobar', max_length=100)
|
|
||||||
extra = models.CharField(blank=True, null=True, max_length=100)
|
|
||||||
|
|
||||||
|
|
||||||
class CallableDefaultValueModel(RESTFrameworkModel):
|
|
||||||
text = models.CharField(default=foobar, max_length=100)
|
|
||||||
|
|
||||||
|
|
||||||
class ManyToManyModel(RESTFrameworkModel):
|
|
||||||
rel = models.ManyToManyField(Anchor, help_text='Some help text.')
|
|
||||||
|
|
||||||
|
|
||||||
class ReadOnlyManyToManyModel(RESTFrameworkModel):
|
|
||||||
text = models.CharField(max_length=100, default='anchor')
|
|
||||||
rel = models.ManyToManyField(Anchor)
|
|
||||||
|
|
||||||
|
|
||||||
class BaseFilterableItem(RESTFrameworkModel):
|
class BaseFilterableItem(RESTFrameworkModel):
|
||||||
text = models.CharField(max_length=100)
|
text = models.CharField(max_length=100)
|
||||||
|
|
||||||
|
@ -71,73 +29,6 @@ class FilterableItem(BaseFilterableItem):
|
||||||
date = models.DateField()
|
date = models.DateField()
|
||||||
|
|
||||||
|
|
||||||
# Model for regression test for #285
|
|
||||||
|
|
||||||
class Comment(RESTFrameworkModel):
|
|
||||||
email = models.EmailField()
|
|
||||||
content = models.CharField(max_length=200)
|
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
|
||||||
|
|
||||||
|
|
||||||
class ActionItem(RESTFrameworkModel):
|
|
||||||
title = models.CharField(max_length=200)
|
|
||||||
started = models.NullBooleanField(default=False)
|
|
||||||
done = models.BooleanField(default=False)
|
|
||||||
info = CustomField(default='---', max_length=12)
|
|
||||||
|
|
||||||
|
|
||||||
# Models for reverse relations
|
|
||||||
class Person(RESTFrameworkModel):
|
|
||||||
name = models.CharField(max_length=10)
|
|
||||||
age = models.IntegerField(null=True, blank=True)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def info(self):
|
|
||||||
return {
|
|
||||||
'name': self.name,
|
|
||||||
'age': self.age,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class BlogPost(RESTFrameworkModel):
|
|
||||||
title = models.CharField(max_length=100)
|
|
||||||
writer = models.ForeignKey(Person, null=True, blank=True)
|
|
||||||
|
|
||||||
def get_first_comment(self):
|
|
||||||
return self.blogpostcomment_set.all()[0]
|
|
||||||
|
|
||||||
|
|
||||||
class BlogPostComment(RESTFrameworkModel):
|
|
||||||
text = models.TextField()
|
|
||||||
blog_post = models.ForeignKey(BlogPost)
|
|
||||||
|
|
||||||
|
|
||||||
class Album(RESTFrameworkModel):
|
|
||||||
title = models.CharField(max_length=100, unique=True)
|
|
||||||
ref = models.CharField(max_length=10, unique=True, null=True, blank=True)
|
|
||||||
|
|
||||||
|
|
||||||
class Photo(RESTFrameworkModel):
|
|
||||||
description = models.TextField()
|
|
||||||
album = models.ForeignKey(Album)
|
|
||||||
|
|
||||||
|
|
||||||
# Model for issue #324
|
|
||||||
class BlankFieldModel(RESTFrameworkModel):
|
|
||||||
title = models.CharField(max_length=100, blank=True, null=False,
|
|
||||||
default="title")
|
|
||||||
|
|
||||||
|
|
||||||
# Model for issue #380
|
|
||||||
class OptionalRelationModel(RESTFrameworkModel):
|
|
||||||
other = models.ForeignKey('OptionalRelationModel', blank=True, null=True)
|
|
||||||
|
|
||||||
|
|
||||||
# Model for RegexField
|
|
||||||
class Book(RESTFrameworkModel):
|
|
||||||
isbn = models.CharField(max_length=13)
|
|
||||||
|
|
||||||
|
|
||||||
# Models for relations tests
|
# Models for relations tests
|
||||||
# ManyToMany
|
# ManyToMany
|
||||||
class ManyToManyTarget(RESTFrameworkModel):
|
class ManyToManyTarget(RESTFrameworkModel):
|
||||||
|
|
|
@ -6,12 +6,26 @@ from django.test import TestCase
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from rest_framework import generics, renderers, serializers, status
|
from rest_framework import generics, renderers, serializers, status
|
||||||
from rest_framework.test import APIRequestFactory
|
from rest_framework.test import APIRequestFactory
|
||||||
from tests.models import BasicModel, Comment, SlugBasedModel
|
from tests.models import BasicModel, RESTFrameworkModel
|
||||||
from tests.models import ForeignKeySource, ForeignKeyTarget
|
from tests.models import ForeignKeySource, ForeignKeyTarget
|
||||||
|
|
||||||
factory = APIRequestFactory()
|
factory = APIRequestFactory()
|
||||||
|
|
||||||
|
|
||||||
|
# Models
|
||||||
|
class SlugBasedModel(RESTFrameworkModel):
|
||||||
|
text = models.CharField(max_length=100)
|
||||||
|
slug = models.SlugField(max_length=32)
|
||||||
|
|
||||||
|
|
||||||
|
# Model for regression test for #285
|
||||||
|
class Comment(RESTFrameworkModel):
|
||||||
|
email = models.EmailField()
|
||||||
|
content = models.CharField(max_length=200)
|
||||||
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
|
|
||||||
|
# Serializers
|
||||||
class BasicSerializer(serializers.ModelSerializer):
|
class BasicSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = BasicModel
|
model = BasicModel
|
||||||
|
@ -22,6 +36,15 @@ class ForeignKeySerializer(serializers.ModelSerializer):
|
||||||
model = ForeignKeySource
|
model = ForeignKeySource
|
||||||
|
|
||||||
|
|
||||||
|
class SlugSerializer(serializers.ModelSerializer):
|
||||||
|
slug = serializers.ReadOnlyField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = SlugBasedModel
|
||||||
|
fields = ('text', 'slug')
|
||||||
|
|
||||||
|
|
||||||
|
# Views
|
||||||
class RootView(generics.ListCreateAPIView):
|
class RootView(generics.ListCreateAPIView):
|
||||||
queryset = BasicModel.objects.all()
|
queryset = BasicModel.objects.all()
|
||||||
serializer_class = BasicSerializer
|
serializer_class = BasicSerializer
|
||||||
|
@ -37,14 +60,6 @@ class FKInstanceView(generics.RetrieveUpdateDestroyAPIView):
|
||||||
serializer_class = ForeignKeySerializer
|
serializer_class = ForeignKeySerializer
|
||||||
|
|
||||||
|
|
||||||
class SlugSerializer(serializers.ModelSerializer):
|
|
||||||
slug = serializers.ReadOnlyField()
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = SlugBasedModel
|
|
||||||
fields = ('text', 'slug')
|
|
||||||
|
|
||||||
|
|
||||||
class SlugBasedInstanceView(InstanceView):
|
class SlugBasedInstanceView(InstanceView):
|
||||||
"""
|
"""
|
||||||
A model with a slug-field.
|
A model with a slug-field.
|
||||||
|
@ -54,6 +69,7 @@ class SlugBasedInstanceView(InstanceView):
|
||||||
lookup_field = 'slug'
|
lookup_field = 'slug'
|
||||||
|
|
||||||
|
|
||||||
|
# Tests
|
||||||
class TestRootView(TestCase):
|
class TestRootView(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""
|
"""
|
||||||
|
@ -127,13 +143,13 @@ class TestRootView(TestCase):
|
||||||
self.assertEqual(created.text, 'foobar')
|
self.assertEqual(created.text, 'foobar')
|
||||||
|
|
||||||
|
|
||||||
EXPECTED_QUERYS_FOR_PUT = 3 if django.VERSION < (1, 6) else 2
|
EXPECTED_QUERIES_FOR_PUT = 3 if django.VERSION < (1, 6) else 2
|
||||||
|
|
||||||
|
|
||||||
class TestInstanceView(TestCase):
|
class TestInstanceView(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""
|
"""
|
||||||
Create 3 BasicModel intances.
|
Create 3 BasicModel instances.
|
||||||
"""
|
"""
|
||||||
items = ['foo', 'bar', 'baz', 'filtered out']
|
items = ['foo', 'bar', 'baz', 'filtered out']
|
||||||
for item in items:
|
for item in items:
|
||||||
|
@ -173,7 +189,7 @@ class TestInstanceView(TestCase):
|
||||||
"""
|
"""
|
||||||
data = {'text': 'foobar'}
|
data = {'text': 'foobar'}
|
||||||
request = factory.put('/1', data, format='json')
|
request = factory.put('/1', data, format='json')
|
||||||
with self.assertNumQueries(EXPECTED_QUERYS_FOR_PUT):
|
with self.assertNumQueries(EXPECTED_QUERIES_FOR_PUT):
|
||||||
response = self.view(request, pk='1').render()
|
response = self.view(request, pk='1').render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertEqual(dict(response.data), {'id': 1, 'text': 'foobar'})
|
self.assertEqual(dict(response.data), {'id': 1, 'text': 'foobar'})
|
||||||
|
@ -187,7 +203,7 @@ class TestInstanceView(TestCase):
|
||||||
data = {'text': 'foobar'}
|
data = {'text': 'foobar'}
|
||||||
request = factory.patch('/1', data, format='json')
|
request = factory.patch('/1', data, format='json')
|
||||||
|
|
||||||
with self.assertNumQueries(EXPECTED_QUERYS_FOR_PUT):
|
with self.assertNumQueries(EXPECTED_QUERIES_FOR_PUT):
|
||||||
response = self.view(request, pk=1).render()
|
response = self.view(request, pk=1).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertEqual(response.data, {'id': 1, 'text': 'foobar'})
|
self.assertEqual(response.data, {'id': 1, 'text': 'foobar'})
|
||||||
|
@ -222,7 +238,7 @@ class TestInstanceView(TestCase):
|
||||||
"""
|
"""
|
||||||
data = {'id': 999, 'text': 'foobar'}
|
data = {'id': 999, 'text': 'foobar'}
|
||||||
request = factory.put('/1', data, format='json')
|
request = factory.put('/1', data, format='json')
|
||||||
with self.assertNumQueries(EXPECTED_QUERYS_FOR_PUT):
|
with self.assertNumQueries(EXPECTED_QUERIES_FOR_PUT):
|
||||||
response = self.view(request, pk=1).render()
|
response = self.view(request, pk=1).render()
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertEqual(response.data, {'id': 1, 'text': 'foobar'})
|
self.assertEqual(response.data, {'id': 1, 'text': 'foobar'})
|
||||||
|
@ -288,9 +304,10 @@ class TestOverriddenGetObject(TestCase):
|
||||||
Test cases for a RetrieveUpdateDestroyAPIView that does NOT use the
|
Test cases for a RetrieveUpdateDestroyAPIView that does NOT use the
|
||||||
queryset/model mechanism but instead overrides get_object()
|
queryset/model mechanism but instead overrides get_object()
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""
|
"""
|
||||||
Create 3 BasicModel intances.
|
Create 3 BasicModel instances.
|
||||||
"""
|
"""
|
||||||
items = ['foo', 'bar', 'baz']
|
items = ['foo', 'bar', 'baz']
|
||||||
for item in items:
|
for item in items:
|
||||||
|
@ -363,11 +380,11 @@ class ClassB(models.Model):
|
||||||
|
|
||||||
class ClassA(models.Model):
|
class ClassA(models.Model):
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
childs = models.ManyToManyField(ClassB, blank=True, null=True)
|
children = models.ManyToManyField(ClassB, blank=True, null=True)
|
||||||
|
|
||||||
|
|
||||||
class ClassASerializer(serializers.ModelSerializer):
|
class ClassASerializer(serializers.ModelSerializer):
|
||||||
childs = serializers.PrimaryKeyRelatedField(
|
children = serializers.PrimaryKeyRelatedField(
|
||||||
many=True, queryset=ClassB.objects.all()
|
many=True, queryset=ClassB.objects.all()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -380,8 +397,8 @@ class ExampleView(generics.ListCreateAPIView):
|
||||||
queryset = ClassA.objects.all()
|
queryset = ClassA.objects.all()
|
||||||
|
|
||||||
|
|
||||||
class TestM2MBrowseableAPI(TestCase):
|
class TestM2MBrowsableAPI(TestCase):
|
||||||
def test_m2m_in_browseable_api(self):
|
def test_m2m_in_browsable_api(self):
|
||||||
"""
|
"""
|
||||||
Test for particularly ugly regression with m2m in browsable API
|
Test for particularly ugly regression with m2m in browsable API
|
||||||
"""
|
"""
|
||||||
|
@ -424,7 +441,6 @@ class DynamicSerializerView(generics.ListCreateAPIView):
|
||||||
|
|
||||||
|
|
||||||
class TestFilterBackendAppliedToViews(TestCase):
|
class TestFilterBackendAppliedToViews(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""
|
"""
|
||||||
Create 3 BasicModel instances to filter on.
|
Create 3 BasicModel instances to filter on.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user