diff --git a/api-guide/exceptions/index.html b/api-guide/exceptions/index.html
index 12933aafa..49cf6ee22 100644
--- a/api-guide/exceptions/index.html
+++ b/api-guide/exceptions/index.html
@@ -541,14 +541,14 @@ for your project.
.detail
- Return the textual description of the error.
.get_codes()
- Return the code identifier of the error.
-.full_details()
- Return both the textual description and the code identifier.
+.get_full_details()
- Return both the textual description and the code identifier.
In most cases the error detail will be a simple item:
>>> print(exc.detail)
You do not have permission to perform this action.
>>> print(exc.get_codes())
permission_denied
->>> print(exc.full_details())
+>>> print(exc.get_full_details())
{'message':'You do not have permission to perform this action.','code':'permission_denied'}
In the case of validation errors the error detail will be either a list or
diff --git a/api-guide/pagination/index.html b/api-guide/pagination/index.html
index 7357e1103..216aa17d8 100644
--- a/api-guide/pagination/index.html
+++ b/api-guide/pagination/index.html
@@ -438,6 +438,10 @@
DRF-extensions
+
+ drf-proxy-pagination
+
+
diff --git a/api-guide/relations/index.html b/api-guide/relations/index.html
index c6d6afa64..73dffb6d8 100644
--- a/api-guide/relations/index.html
+++ b/api-guide/relations/index.html
@@ -527,7 +527,7 @@ AccountSerializer():
artist = models.CharField(max_length=100)
class Track(models.Model):
- album = models.ForeignKey(Album, related_name='tracks')
+ album = models.ForeignKey(Album, related_name='tracks', on_delete=models.CASCADE)
order = models.IntegerField()
title = models.CharField(max_length=100)
duration = models.IntegerField()
@@ -888,7 +888,7 @@ class CustomerHyperlink(serializers.HyperlinkedRelatedField):
You'll normally want to ensure that you've set an appropriate related_name
argument on the relationship, that you can use as the field name. For example:
class Track(models.Model):
- album = models.ForeignKey(Album, related_name='tracks')
+ album = models.ForeignKey(Album, related_name='tracks', on_delete=models.CASCADE)
...
If you have not set a related name for the reverse relationship, you'll need to use the automatically generated related name in the fields
argument. For example:
@@ -907,7 +907,7 @@ class CustomerHyperlink(serializers.HyperlinkedRelatedField):
See: https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/
"""
tag_name = models.SlugField()
- content_type = models.ForeignKey(ContentType)
+ content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
tagged_object = GenericForeignKey('content_type', 'object_id')
diff --git a/mkdocs/search_index.json b/mkdocs/search_index.json
index d3055e001..8e1de3a30 100644
--- a/mkdocs/search_index.json
+++ b/mkdocs/search_index.json
@@ -247,7 +247,7 @@
},
{
"location": "/tutorial/4-authentication-and-permissions/",
- "text": "Tutorial 4: Authentication \n Permissions\n\n\nCurrently our API doesn't have any restrictions on who can edit or delete code snippets. We'd like to have some more advanced behavior in order to make sure that:\n\n\n\n\nCode snippets are always associated with a creator.\n\n\nOnly authenticated users may create snippets.\n\n\nOnly the creator of a snippet may update or delete it.\n\n\nUnauthenticated requests should have full read-only access.\n\n\n\n\nAdding information to our model\n\n\nWe're going to make a couple of changes to our \nSnippet\n model class.\nFirst, let's add a couple of fields. One of those fields will be used to represent the user who created the code snippet. The other field will be used to store the highlighted HTML representation of the code.\n\n\nAdd the following two fields to the \nSnippet\n model in \nmodels.py\n.\n\n\nowner = models.ForeignKey('auth.User', related_name='snippets')\nhighlighted = models.TextField()\n\n\n\nWe'd also need to make sure that when the model is saved, that we populate the highlighted field, using the \npygments\n code highlighting library.\n\n\nWe'll need some extra imports:\n\n\nfrom pygments.lexers import get_lexer_by_name\nfrom pygments.formatters.html import HtmlFormatter\nfrom pygments import highlight\n\n\n\nAnd now we can add a \n.save()\n method to our model class:\n\n\ndef save(self, *args, **kwargs):\n \"\"\"\n Use the `pygments` library to create a highlighted HTML\n representation of the code snippet.\n \"\"\"\n lexer = get_lexer_by_name(self.language)\n linenos = self.linenos and 'table' or False\n options = self.title and {'title': self.title} or {}\n formatter = HtmlFormatter(style=self.style, linenos=linenos,\n full=True, **options)\n self.highlighted = highlight(self.code, lexer, formatter)\n super(Snippet, self).save(*args, **kwargs)\n\n\n\nWhen that's all done we'll need to update our database tables.\nNormally we'd create a database migration in order to do that, but for the purposes of this tutorial, let's just delete the database and start again.\n\n\nrm -f tmp.db db.sqlite3\nrm -r snippets/migrations\npython manage.py makemigrations snippets\npython manage.py migrate\n\n\n\nYou might also want to create a few different users, to use for testing the API. The quickest way to do this will be with the \ncreatesuperuser\n command.\n\n\npython manage.py createsuperuser\n\n\n\nAdding endpoints for our User models\n\n\nNow that we've got some users to work with, we'd better add representations of those users to our API. Creating a new serializer is easy. In \nserializers.py\n add:\n\n\nfrom django.contrib.auth.models import User\n\nclass UserSerializer(serializers.ModelSerializer):\n snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())\n\n class Meta:\n model = User\n fields = ('id', 'username', 'snippets')\n\n\n\nBecause \n'snippets'\n is a \nreverse\n relationship on the User model, it will not be included by default when using the \nModelSerializer\n class, so we needed to add an explicit field for it.\n\n\nWe'll also add a couple of views to \nviews.py\n. We'd like to just use read-only views for the user representations, so we'll use the \nListAPIView\n and \nRetrieveAPIView\n generic class-based views.\n\n\nfrom django.contrib.auth.models import User\n\n\nclass UserList(generics.ListAPIView):\n queryset = User.objects.all()\n serializer_class = UserSerializer\n\n\nclass UserDetail(generics.RetrieveAPIView):\n queryset = User.objects.all()\n serializer_class = UserSerializer\n\n\n\nMake sure to also import the \nUserSerializer\n class\n\n\nfrom snippets.serializers import UserSerializer\n\n\n\nFinally we need to add those views into the API, by referencing them from the URL conf. Add the following to the patterns in \nurls.py\n.\n\n\nurl(r'^users/$', views.UserList.as_view()),\nurl(r'^users/(?P\npk\n[0-9]+)/$', views.UserDetail.as_view()),\n\n\n\nAssociating Snippets with Users\n\n\nRight now, if we created a code snippet, there'd be no way of associating the user that created the snippet, with the snippet instance. The user isn't sent as part of the serialized representation, but is instead a property of the incoming request.\n\n\nThe way we deal with that is by overriding a \n.perform_create()\n method on our snippet views, that allows us to modify how the instance save is managed, and handle any information that is implicit in the incoming request or requested URL.\n\n\nOn the \nSnippetList\n view class, add the following method:\n\n\ndef perform_create(self, serializer):\n serializer.save(owner=self.request.user)\n\n\n\nThe \ncreate()\n method of our serializer will now be passed an additional \n'owner'\n field, along with the validated data from the request.\n\n\nUpdating our serializer\n\n\nNow that snippets are associated with the user that created them, let's update our \nSnippetSerializer\n to reflect that. Add the following field to the serializer definition in \nserializers.py\n:\n\n\nowner = serializers.ReadOnlyField(source='owner.username')\n\n\n\nNote\n: Make sure you also add \n'owner',\n to the list of fields in the inner \nMeta\n class.\n\n\nThis field is doing something quite interesting. The \nsource\n argument controls which attribute is used to populate a field, and can point at any attribute on the serialized instance. It can also take the dotted notation shown above, in which case it will traverse the given attributes, in a similar way as it is used with Django's template language.\n\n\nThe field we've added is the untyped \nReadOnlyField\n class, in contrast to the other typed fields, such as \nCharField\n, \nBooleanField\n etc... The untyped \nReadOnlyField\n is always read-only, and will be used for serialized representations, but will not be used for updating model instances when they are deserialized. We could have also used \nCharField(read_only=True)\n here.\n\n\nAdding required permissions to views\n\n\nNow that code snippets are associated with users, we want to make sure that only authenticated users are able to create, update and delete code snippets.\n\n\nREST framework includes a number of permission classes that we can use to restrict who can access a given view. In this case the one we're looking for is \nIsAuthenticatedOrReadOnly\n, which will ensure that authenticated requests get read-write access, and unauthenticated requests get read-only access.\n\n\nFirst add the following import in the views module\n\n\nfrom rest_framework import permissions\n\n\n\nThen, add the following property to \nboth\n the \nSnippetList\n and \nSnippetDetail\n view classes.\n\n\npermission_classes = (permissions.IsAuthenticatedOrReadOnly,)\n\n\n\nAdding login to the Browsable API\n\n\nIf you open a browser and navigate to the browsable API at the moment, you'll find that you're no longer able to create new code snippets. In order to do so we'd need to be able to login as a user.\n\n\nWe can add a login view for use with the browsable API, by editing the URLconf in our project-level \nurls.py\n file.\n\n\nAdd the following import at the top of the file:\n\n\nfrom django.conf.urls import include\n\n\n\nAnd, at the end of the file, add a pattern to include the login and logout views for the browsable API.\n\n\nurlpatterns += [\n url(r'^api-auth/', include('rest_framework.urls',\n namespace='rest_framework')),\n]\n\n\n\nThe \nr'^api-auth/'\n part of pattern can actually be whatever URL you want to use. The only restriction is that the included urls must use the \n'rest_framework'\n namespace. In Django 1.9+, REST framework will set the namespace, so you may leave it out.\n\n\nNow if you open up the browser again and refresh the page you'll see a 'Login' link in the top right of the page. If you log in as one of the users you created earlier, you'll be able to create code snippets again.\n\n\nOnce you've created a few code snippets, navigate to the '/users/' endpoint, and notice that the representation includes a list of the snippet ids that are associated with each user, in each user's 'snippets' field.\n\n\nObject level permissions\n\n\nReally we'd like all code snippets to be visible to anyone, but also make sure that only the user that created a code snippet is able to update or delete it.\n\n\nTo do that we're going to need to create a custom permission.\n\n\nIn the snippets app, create a new file, \npermissions.py\n\n\nfrom rest_framework import permissions\n\n\nclass IsOwnerOrReadOnly(permissions.BasePermission):\n \"\"\"\n Custom permission to only allow owners of an object to edit it.\n \"\"\"\n\n def has_object_permission(self, request, view, obj):\n # Read permissions are allowed to any request,\n # so we'll always allow GET, HEAD or OPTIONS requests.\n if request.method in permissions.SAFE_METHODS:\n return True\n\n # Write permissions are only allowed to the owner of the snippet.\n return obj.owner == request.user\n\n\n\nNow we can add that custom permission to our snippet instance endpoint, by editing the \npermission_classes\n property on the \nSnippetDetail\n view class:\n\n\npermission_classes = (permissions.IsAuthenticatedOrReadOnly,\n IsOwnerOrReadOnly,)\n\n\n\nMake sure to also import the \nIsOwnerOrReadOnly\n class.\n\n\nfrom snippets.permissions import IsOwnerOrReadOnly\n\n\n\nNow, if you open a browser again, you find that the 'DELETE' and 'PUT' actions only appear on a snippet instance endpoint if you're logged in as the same user that created the code snippet.\n\n\nAuthenticating with the API\n\n\nBecause we now have a set of permissions on the API, we need to authenticate our requests to it if we want to edit any snippets. We haven't set up any \nauthentication classes\n, so the defaults are currently applied, which are \nSessionAuthentication\n and \nBasicAuthentication\n.\n\n\nWhen we interact with the API through the web browser, we can login, and the browser session will then provide the required authentication for the requests.\n\n\nIf we're interacting with the API programmatically we need to explicitly provide the authentication credentials on each request.\n\n\nIf we try to create a snippet without authenticating, we'll get an error:\n\n\nhttp POST http://127.0.0.1:8000/snippets/ code=\"print 123\"\n\n{\n \"detail\": \"Authentication credentials were not provided.\"\n}\n\n\n\nWe can make a successful request by including the username and password of one of the users we created earlier.\n\n\nhttp -a tom:password123 POST http://127.0.0.1:8000/snippets/ code=\"print 789\"\n\n{\n \"id\": 5,\n \"owner\": \"tom\",\n \"title\": \"foo\",\n \"code\": \"print 789\",\n \"linenos\": false,\n \"language\": \"python\",\n \"style\": \"friendly\"\n}\n\n\n\nSummary\n\n\nWe've now got a fairly fine-grained set of permissions on our Web API, and end points for users of the system and for the code snippets that they have created.\n\n\nIn \npart 5\n of the tutorial we'll look at how we can tie everything together by creating an HTML endpoint for our highlighted snippets, and improve the cohesion of our API by using hyperlinking for the relationships within the system.",
+ "text": "Tutorial 4: Authentication \n Permissions\n\n\nCurrently our API doesn't have any restrictions on who can edit or delete code snippets. We'd like to have some more advanced behavior in order to make sure that:\n\n\n\n\nCode snippets are always associated with a creator.\n\n\nOnly authenticated users may create snippets.\n\n\nOnly the creator of a snippet may update or delete it.\n\n\nUnauthenticated requests should have full read-only access.\n\n\n\n\nAdding information to our model\n\n\nWe're going to make a couple of changes to our \nSnippet\n model class.\nFirst, let's add a couple of fields. One of those fields will be used to represent the user who created the code snippet. The other field will be used to store the highlighted HTML representation of the code.\n\n\nAdd the following two fields to the \nSnippet\n model in \nmodels.py\n.\n\n\nowner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)\nhighlighted = models.TextField()\n\n\n\nWe'd also need to make sure that when the model is saved, that we populate the highlighted field, using the \npygments\n code highlighting library.\n\n\nWe'll need some extra imports:\n\n\nfrom pygments.lexers import get_lexer_by_name\nfrom pygments.formatters.html import HtmlFormatter\nfrom pygments import highlight\n\n\n\nAnd now we can add a \n.save()\n method to our model class:\n\n\ndef save(self, *args, **kwargs):\n \"\"\"\n Use the `pygments` library to create a highlighted HTML\n representation of the code snippet.\n \"\"\"\n lexer = get_lexer_by_name(self.language)\n linenos = self.linenos and 'table' or False\n options = self.title and {'title': self.title} or {}\n formatter = HtmlFormatter(style=self.style, linenos=linenos,\n full=True, **options)\n self.highlighted = highlight(self.code, lexer, formatter)\n super(Snippet, self).save(*args, **kwargs)\n\n\n\nWhen that's all done we'll need to update our database tables.\nNormally we'd create a database migration in order to do that, but for the purposes of this tutorial, let's just delete the database and start again.\n\n\nrm -f tmp.db db.sqlite3\nrm -r snippets/migrations\npython manage.py makemigrations snippets\npython manage.py migrate\n\n\n\nYou might also want to create a few different users, to use for testing the API. The quickest way to do this will be with the \ncreatesuperuser\n command.\n\n\npython manage.py createsuperuser\n\n\n\nAdding endpoints for our User models\n\n\nNow that we've got some users to work with, we'd better add representations of those users to our API. Creating a new serializer is easy. In \nserializers.py\n add:\n\n\nfrom django.contrib.auth.models import User\n\nclass UserSerializer(serializers.ModelSerializer):\n snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())\n\n class Meta:\n model = User\n fields = ('id', 'username', 'snippets')\n\n\n\nBecause \n'snippets'\n is a \nreverse\n relationship on the User model, it will not be included by default when using the \nModelSerializer\n class, so we needed to add an explicit field for it.\n\n\nWe'll also add a couple of views to \nviews.py\n. We'd like to just use read-only views for the user representations, so we'll use the \nListAPIView\n and \nRetrieveAPIView\n generic class-based views.\n\n\nfrom django.contrib.auth.models import User\n\n\nclass UserList(generics.ListAPIView):\n queryset = User.objects.all()\n serializer_class = UserSerializer\n\n\nclass UserDetail(generics.RetrieveAPIView):\n queryset = User.objects.all()\n serializer_class = UserSerializer\n\n\n\nMake sure to also import the \nUserSerializer\n class\n\n\nfrom snippets.serializers import UserSerializer\n\n\n\nFinally we need to add those views into the API, by referencing them from the URL conf. Add the following to the patterns in \nurls.py\n.\n\n\nurl(r'^users/$', views.UserList.as_view()),\nurl(r'^users/(?P\npk\n[0-9]+)/$', views.UserDetail.as_view()),\n\n\n\nAssociating Snippets with Users\n\n\nRight now, if we created a code snippet, there'd be no way of associating the user that created the snippet, with the snippet instance. The user isn't sent as part of the serialized representation, but is instead a property of the incoming request.\n\n\nThe way we deal with that is by overriding a \n.perform_create()\n method on our snippet views, that allows us to modify how the instance save is managed, and handle any information that is implicit in the incoming request or requested URL.\n\n\nOn the \nSnippetList\n view class, add the following method:\n\n\ndef perform_create(self, serializer):\n serializer.save(owner=self.request.user)\n\n\n\nThe \ncreate()\n method of our serializer will now be passed an additional \n'owner'\n field, along with the validated data from the request.\n\n\nUpdating our serializer\n\n\nNow that snippets are associated with the user that created them, let's update our \nSnippetSerializer\n to reflect that. Add the following field to the serializer definition in \nserializers.py\n:\n\n\nowner = serializers.ReadOnlyField(source='owner.username')\n\n\n\nNote\n: Make sure you also add \n'owner',\n to the list of fields in the inner \nMeta\n class.\n\n\nThis field is doing something quite interesting. The \nsource\n argument controls which attribute is used to populate a field, and can point at any attribute on the serialized instance. It can also take the dotted notation shown above, in which case it will traverse the given attributes, in a similar way as it is used with Django's template language.\n\n\nThe field we've added is the untyped \nReadOnlyField\n class, in contrast to the other typed fields, such as \nCharField\n, \nBooleanField\n etc... The untyped \nReadOnlyField\n is always read-only, and will be used for serialized representations, but will not be used for updating model instances when they are deserialized. We could have also used \nCharField(read_only=True)\n here.\n\n\nAdding required permissions to views\n\n\nNow that code snippets are associated with users, we want to make sure that only authenticated users are able to create, update and delete code snippets.\n\n\nREST framework includes a number of permission classes that we can use to restrict who can access a given view. In this case the one we're looking for is \nIsAuthenticatedOrReadOnly\n, which will ensure that authenticated requests get read-write access, and unauthenticated requests get read-only access.\n\n\nFirst add the following import in the views module\n\n\nfrom rest_framework import permissions\n\n\n\nThen, add the following property to \nboth\n the \nSnippetList\n and \nSnippetDetail\n view classes.\n\n\npermission_classes = (permissions.IsAuthenticatedOrReadOnly,)\n\n\n\nAdding login to the Browsable API\n\n\nIf you open a browser and navigate to the browsable API at the moment, you'll find that you're no longer able to create new code snippets. In order to do so we'd need to be able to login as a user.\n\n\nWe can add a login view for use with the browsable API, by editing the URLconf in our project-level \nurls.py\n file.\n\n\nAdd the following import at the top of the file:\n\n\nfrom django.conf.urls import include\n\n\n\nAnd, at the end of the file, add a pattern to include the login and logout views for the browsable API.\n\n\nurlpatterns += [\n url(r'^api-auth/', include('rest_framework.urls',\n namespace='rest_framework')),\n]\n\n\n\nThe \nr'^api-auth/'\n part of pattern can actually be whatever URL you want to use. The only restriction is that the included urls must use the \n'rest_framework'\n namespace. In Django 1.9+, REST framework will set the namespace, so you may leave it out.\n\n\nNow if you open up the browser again and refresh the page you'll see a 'Login' link in the top right of the page. If you log in as one of the users you created earlier, you'll be able to create code snippets again.\n\n\nOnce you've created a few code snippets, navigate to the '/users/' endpoint, and notice that the representation includes a list of the snippet ids that are associated with each user, in each user's 'snippets' field.\n\n\nObject level permissions\n\n\nReally we'd like all code snippets to be visible to anyone, but also make sure that only the user that created a code snippet is able to update or delete it.\n\n\nTo do that we're going to need to create a custom permission.\n\n\nIn the snippets app, create a new file, \npermissions.py\n\n\nfrom rest_framework import permissions\n\n\nclass IsOwnerOrReadOnly(permissions.BasePermission):\n \"\"\"\n Custom permission to only allow owners of an object to edit it.\n \"\"\"\n\n def has_object_permission(self, request, view, obj):\n # Read permissions are allowed to any request,\n # so we'll always allow GET, HEAD or OPTIONS requests.\n if request.method in permissions.SAFE_METHODS:\n return True\n\n # Write permissions are only allowed to the owner of the snippet.\n return obj.owner == request.user\n\n\n\nNow we can add that custom permission to our snippet instance endpoint, by editing the \npermission_classes\n property on the \nSnippetDetail\n view class:\n\n\npermission_classes = (permissions.IsAuthenticatedOrReadOnly,\n IsOwnerOrReadOnly,)\n\n\n\nMake sure to also import the \nIsOwnerOrReadOnly\n class.\n\n\nfrom snippets.permissions import IsOwnerOrReadOnly\n\n\n\nNow, if you open a browser again, you find that the 'DELETE' and 'PUT' actions only appear on a snippet instance endpoint if you're logged in as the same user that created the code snippet.\n\n\nAuthenticating with the API\n\n\nBecause we now have a set of permissions on the API, we need to authenticate our requests to it if we want to edit any snippets. We haven't set up any \nauthentication classes\n, so the defaults are currently applied, which are \nSessionAuthentication\n and \nBasicAuthentication\n.\n\n\nWhen we interact with the API through the web browser, we can login, and the browser session will then provide the required authentication for the requests.\n\n\nIf we're interacting with the API programmatically we need to explicitly provide the authentication credentials on each request.\n\n\nIf we try to create a snippet without authenticating, we'll get an error:\n\n\nhttp POST http://127.0.0.1:8000/snippets/ code=\"print 123\"\n\n{\n \"detail\": \"Authentication credentials were not provided.\"\n}\n\n\n\nWe can make a successful request by including the username and password of one of the users we created earlier.\n\n\nhttp -a tom:password123 POST http://127.0.0.1:8000/snippets/ code=\"print 789\"\n\n{\n \"id\": 5,\n \"owner\": \"tom\",\n \"title\": \"foo\",\n \"code\": \"print 789\",\n \"linenos\": false,\n \"language\": \"python\",\n \"style\": \"friendly\"\n}\n\n\n\nSummary\n\n\nWe've now got a fairly fine-grained set of permissions on our Web API, and end points for users of the system and for the code snippets that they have created.\n\n\nIn \npart 5\n of the tutorial we'll look at how we can tie everything together by creating an HTML endpoint for our highlighted snippets, and improve the cohesion of our API by using hyperlinking for the relationships within the system.",
"title": "4 - Authentication and permissions"
},
{
@@ -257,7 +257,7 @@
},
{
"location": "/tutorial/4-authentication-and-permissions/#adding-information-to-our-model",
- "text": "We're going to make a couple of changes to our Snippet model class.\nFirst, let's add a couple of fields. One of those fields will be used to represent the user who created the code snippet. The other field will be used to store the highlighted HTML representation of the code. Add the following two fields to the Snippet model in models.py . owner = models.ForeignKey('auth.User', related_name='snippets')\nhighlighted = models.TextField() We'd also need to make sure that when the model is saved, that we populate the highlighted field, using the pygments code highlighting library. We'll need some extra imports: from pygments.lexers import get_lexer_by_name\nfrom pygments.formatters.html import HtmlFormatter\nfrom pygments import highlight And now we can add a .save() method to our model class: def save(self, *args, **kwargs):\n \"\"\"\n Use the `pygments` library to create a highlighted HTML\n representation of the code snippet.\n \"\"\"\n lexer = get_lexer_by_name(self.language)\n linenos = self.linenos and 'table' or False\n options = self.title and {'title': self.title} or {}\n formatter = HtmlFormatter(style=self.style, linenos=linenos,\n full=True, **options)\n self.highlighted = highlight(self.code, lexer, formatter)\n super(Snippet, self).save(*args, **kwargs) When that's all done we'll need to update our database tables.\nNormally we'd create a database migration in order to do that, but for the purposes of this tutorial, let's just delete the database and start again. rm -f tmp.db db.sqlite3\nrm -r snippets/migrations\npython manage.py makemigrations snippets\npython manage.py migrate You might also want to create a few different users, to use for testing the API. The quickest way to do this will be with the createsuperuser command. python manage.py createsuperuser",
+ "text": "We're going to make a couple of changes to our Snippet model class.\nFirst, let's add a couple of fields. One of those fields will be used to represent the user who created the code snippet. The other field will be used to store the highlighted HTML representation of the code. Add the following two fields to the Snippet model in models.py . owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)\nhighlighted = models.TextField() We'd also need to make sure that when the model is saved, that we populate the highlighted field, using the pygments code highlighting library. We'll need some extra imports: from pygments.lexers import get_lexer_by_name\nfrom pygments.formatters.html import HtmlFormatter\nfrom pygments import highlight And now we can add a .save() method to our model class: def save(self, *args, **kwargs):\n \"\"\"\n Use the `pygments` library to create a highlighted HTML\n representation of the code snippet.\n \"\"\"\n lexer = get_lexer_by_name(self.language)\n linenos = self.linenos and 'table' or False\n options = self.title and {'title': self.title} or {}\n formatter = HtmlFormatter(style=self.style, linenos=linenos,\n full=True, **options)\n self.highlighted = highlight(self.code, lexer, formatter)\n super(Snippet, self).save(*args, **kwargs) When that's all done we'll need to update our database tables.\nNormally we'd create a database migration in order to do that, but for the purposes of this tutorial, let's just delete the database and start again. rm -f tmp.db db.sqlite3\nrm -r snippets/migrations\npython manage.py makemigrations snippets\npython manage.py migrate You might also want to create a few different users, to use for testing the API. The quickest way to do this will be with the createsuperuser command. python manage.py createsuperuser",
"title": "Adding information to our model"
},
{
@@ -372,7 +372,7 @@
},
{
"location": "/tutorial/7-schemas-and-client-libraries/",
- "text": "Tutorial 7: Schemas \n client libraries\n\n\nA schema is a machine-readable document that describes the available API\nendpoints, their URLS, and what operations they support.\n\n\nSchemas can be a useful tool for auto-generated documentation, and can also\nbe used to drive dynamic client libraries that can interact with the API.\n\n\nCore API\n\n\nIn order to provide schema support REST framework uses \nCore API\n.\n\n\nCore API is a document specification for describing APIs. It is used to provide\nan internal representation format of the available endpoints and possible\ninteractions that an API exposes. It can either be used server-side, or\nclient-side.\n\n\nWhen used server-side, Core API allows an API to support rendering to a wide\nrange of schema or hypermedia formats.\n\n\nWhen used client-side, Core API allows for dynamically driven client libraries\nthat can interact with any API that exposes a supported schema or hypermedia\nformat.\n\n\nAdding a schema\n\n\nREST framework supports either explicitly defined schema views, or\nautomatically generated schemas. Since we're using viewsets and routers,\nwe can simply use the automatic schema generation.\n\n\nYou'll need to install the \ncoreapi\n python package in order to include an\nAPI schema.\n\n\n$ pip install coreapi\n\n\n\nWe can now include a schema for our API, by including an autogenerated schema\nview in our URL configuration.\n\n\nfrom rest_framework.schemas import get_schema_view\n\nschema_view = get_schema_view(title='Pastebin API')\n\nurlpatterns = [\n url('^schema/$', schema_view),\n ...\n]\n\n\n\nIf you visit the API root endpoint in a browser you should now see \ncorejson\n\nrepresentation become available as an option.\n\n\n\n\nWe can also request the schema from the command line, by specifying the desired\ncontent type in the \nAccept\n header.\n\n\n$ http http://127.0.0.1:8000/schema/ Accept:application/vnd.coreapi+json\nHTTP/1.0 200 OK\nAllow: GET, HEAD, OPTIONS\nContent-Type: application/vnd.coreapi+json\n\n{\n \"_meta\": {\n \"title\": \"Pastebin API\"\n },\n \"_type\": \"document\",\n ...\n\n\n\nThe default output style is to use the \nCore JSON\n encoding.\n\n\nOther schema formats, such as \nOpen API\n (formerly Swagger) are\nalso supported.\n\n\nUsing a command line client\n\n\nNow that our API is exposing a schema endpoint, we can use a dynamic client\nlibrary to interact with the API. To demonstrate this, let's use the\nCore API command line client.\n\n\nThe command line client is available as the \ncoreapi-cli\n package:\n\n\n$ pip install coreapi-cli\n\n\n\nNow check that it is available on the command line...\n\n\n$ coreapi\nUsage: coreapi [OPTIONS] COMMAND [ARGS]...\n\n Command line client for interacting with CoreAPI services.\n\n Visit http://www.coreapi.org for more information.\n\nOptions:\n --version Display the package version number.\n --help Show this message and exit.\n\nCommands:\n...\n\n\n\nFirst we'll load the API schema using the command line client.\n\n\n$ coreapi get http://127.0.0.1:8000/schema/\n\nPastebin API \"http://127.0.0.1:8000/schema/\"\n\n snippets: {\n highlight(id)\n list()\n read(id)\n }\n users: {\n list()\n read(id)\n }\n\n\n\nWe haven't authenticated yet, so right now we're only able to see the read only\nendpoints, in line with how we've set up the permissions on the API.\n\n\nLet's try listing the existing snippets, using the command line client:\n\n\n$ coreapi action snippets list\n[\n {\n \"url\": \"http://127.0.0.1:8000/snippets/1/\",\n \"id\": 1,\n \"highlight\": \"http://127.0.0.1:8000/snippets/1/highlight/\",\n \"owner\": \"lucy\",\n \"title\": \"Example\",\n \"code\": \"print('hello, world!')\",\n \"linenos\": true,\n \"language\": \"python\",\n \"style\": \"friendly\"\n },\n ...\n\n\n\nSome of the API endpoints require named parameters. For example, to get back\nthe highlight HTML for a particular snippet we need to provide an id.\n\n\n$ coreapi action snippets highlight --param id=1\n\n!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\"\n\n\n\nhtml\n\n\nhead\n\n \ntitle\nExample\n/title\n\n ...\n\n\n\nAuthenticating our client\n\n\nIf we want to be able to create, edit and delete snippets, we'll need to\nauthenticate as a valid user. In this case we'll just use basic auth.\n\n\nMake sure to replace the \nusername\n and \npassword\n below with your\nactual username and password.\n\n\n$ coreapi credentials add 127.0.0.1 \nusername\n:\npassword\n --auth basic\nAdded credentials\n127.0.0.1 \"Basic \n...\n\"\n\n\n\nNow if we fetch the schema again, we should be able to see the full\nset of available interactions.\n\n\n$ coreapi reload\nPastebin API \"http://127.0.0.1:8000/schema/\"\n\n snippets: {\n create(code, [title], [linenos], [language], [style])\n delete(id)\n highlight(id)\n list()\n partial_update(id, [title], [code], [linenos], [language], [style])\n read(id)\n update(id, code, [title], [linenos], [language], [style])\n }\n users: {\n list()\n read(id)\n }\n\n\n\nWe're now able to interact with these endpoints. For example, to create a new\nsnippet:\n\n\n$ coreapi action snippets create --param title=\"Example\" --param code=\"print('hello, world')\"\n{\n \"url\": \"http://127.0.0.1:8000/snippets/7/\",\n \"id\": 7,\n \"highlight\": \"http://127.0.0.1:8000/snippets/7/highlight/\",\n \"owner\": \"lucy\",\n \"title\": \"Example\",\n \"code\": \"print('hello, world')\",\n \"linenos\": false,\n \"language\": \"python\",\n \"style\": \"friendly\"\n}\n\n\n\nAnd to delete a snippet:\n\n\n$ coreapi action snippets delete --param id=7\n\n\n\nAs well as the command line client, developers can also interact with your\nAPI using client libraries. The Python client library is the first of these\nto be available, and a Javascript client library is planned to be released\nsoon.\n\n\nFor more details on customizing schema generation and using Core API\nclient libraries you'll need to refer to the full documentation.\n\n\nReviewing our work\n\n\nWith an incredibly small amount of code, we've now got a complete pastebin Web API, which is fully web browsable, includes a schema-driven client library, and comes complete with authentication, per-object permissions, and multiple renderer formats.\n\n\nWe'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.\n\n\nYou can review the final \ntutorial code\n on GitHub, or try out a live example in \nthe sandbox\n.\n\n\nOnwards and upwards\n\n\nWe've reached the end of our tutorial. If you want to get more involved in the REST framework project, here are a few places you can start:\n\n\n\n\nContribute on \nGitHub\n by reviewing and submitting issues, and making pull requests.\n\n\nJoin the \nREST framework discussion group\n, and help build the community.\n\n\nFollow \nthe author\n on Twitter and say hi.\n\n\n\n\nNow go build awesome things.",
+ "text": "Tutorial 7: Schemas \n client libraries\n\n\nA schema is a machine-readable document that describes the available API\nendpoints, their URLS, and what operations they support.\n\n\nSchemas can be a useful tool for auto-generated documentation, and can also\nbe used to drive dynamic client libraries that can interact with the API.\n\n\nCore API\n\n\nIn order to provide schema support REST framework uses \nCore API\n.\n\n\nCore API is a document specification for describing APIs. It is used to provide\nan internal representation format of the available endpoints and possible\ninteractions that an API exposes. It can either be used server-side, or\nclient-side.\n\n\nWhen used server-side, Core API allows an API to support rendering to a wide\nrange of schema or hypermedia formats.\n\n\nWhen used client-side, Core API allows for dynamically driven client libraries\nthat can interact with any API that exposes a supported schema or hypermedia\nformat.\n\n\nAdding a schema\n\n\nREST framework supports either explicitly defined schema views, or\nautomatically generated schemas. Since we're using viewsets and routers,\nwe can simply use the automatic schema generation.\n\n\nYou'll need to install the \ncoreapi\n python package in order to include an\nAPI schema.\n\n\n$ pip install coreapi\n\n\n\nWe can now include a schema for our API, by including an autogenerated schema\nview in our URL configuration.\n\n\nfrom rest_framework.schemas import get_schema_view\n\nschema_view = get_schema_view(title='Pastebin API')\n\nurlpatterns = [\n url('^schema/$', schema_view),\n ...\n]\n\n\n\nIf you visit the API root endpoint in a browser you should now see \ncorejson\n\nrepresentation become available as an option.\n\n\n\n\nWe can also request the schema from the command line, by specifying the desired\ncontent type in the \nAccept\n header.\n\n\n$ http http://127.0.0.1:8000/schema/ Accept:application/coreapi+json\nHTTP/1.0 200 OK\nAllow: GET, HEAD, OPTIONS\nContent-Type: application/coreapi+json\n\n{\n \"_meta\": {\n \"title\": \"Pastebin API\"\n },\n \"_type\": \"document\",\n ...\n\n\n\nThe default output style is to use the \nCore JSON\n encoding.\n\n\nOther schema formats, such as \nOpen API\n (formerly Swagger) are\nalso supported.\n\n\nUsing a command line client\n\n\nNow that our API is exposing a schema endpoint, we can use a dynamic client\nlibrary to interact with the API. To demonstrate this, let's use the\nCore API command line client.\n\n\nThe command line client is available as the \ncoreapi-cli\n package:\n\n\n$ pip install coreapi-cli\n\n\n\nNow check that it is available on the command line...\n\n\n$ coreapi\nUsage: coreapi [OPTIONS] COMMAND [ARGS]...\n\n Command line client for interacting with CoreAPI services.\n\n Visit http://www.coreapi.org for more information.\n\nOptions:\n --version Display the package version number.\n --help Show this message and exit.\n\nCommands:\n...\n\n\n\nFirst we'll load the API schema using the command line client.\n\n\n$ coreapi get http://127.0.0.1:8000/schema/\n\nPastebin API \"http://127.0.0.1:8000/schema/\"\n\n snippets: {\n highlight(id)\n list()\n read(id)\n }\n users: {\n list()\n read(id)\n }\n\n\n\nWe haven't authenticated yet, so right now we're only able to see the read only\nendpoints, in line with how we've set up the permissions on the API.\n\n\nLet's try listing the existing snippets, using the command line client:\n\n\n$ coreapi action snippets list\n[\n {\n \"url\": \"http://127.0.0.1:8000/snippets/1/\",\n \"id\": 1,\n \"highlight\": \"http://127.0.0.1:8000/snippets/1/highlight/\",\n \"owner\": \"lucy\",\n \"title\": \"Example\",\n \"code\": \"print('hello, world!')\",\n \"linenos\": true,\n \"language\": \"python\",\n \"style\": \"friendly\"\n },\n ...\n\n\n\nSome of the API endpoints require named parameters. For example, to get back\nthe highlight HTML for a particular snippet we need to provide an id.\n\n\n$ coreapi action snippets highlight --param id=1\n\n!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\"\n\n\n\nhtml\n\n\nhead\n\n \ntitle\nExample\n/title\n\n ...\n\n\n\nAuthenticating our client\n\n\nIf we want to be able to create, edit and delete snippets, we'll need to\nauthenticate as a valid user. In this case we'll just use basic auth.\n\n\nMake sure to replace the \nusername\n and \npassword\n below with your\nactual username and password.\n\n\n$ coreapi credentials add 127.0.0.1 \nusername\n:\npassword\n --auth basic\nAdded credentials\n127.0.0.1 \"Basic \n...\n\"\n\n\n\nNow if we fetch the schema again, we should be able to see the full\nset of available interactions.\n\n\n$ coreapi reload\nPastebin API \"http://127.0.0.1:8000/schema/\"\n\n snippets: {\n create(code, [title], [linenos], [language], [style])\n delete(id)\n highlight(id)\n list()\n partial_update(id, [title], [code], [linenos], [language], [style])\n read(id)\n update(id, code, [title], [linenos], [language], [style])\n }\n users: {\n list()\n read(id)\n }\n\n\n\nWe're now able to interact with these endpoints. For example, to create a new\nsnippet:\n\n\n$ coreapi action snippets create --param title=\"Example\" --param code=\"print('hello, world')\"\n{\n \"url\": \"http://127.0.0.1:8000/snippets/7/\",\n \"id\": 7,\n \"highlight\": \"http://127.0.0.1:8000/snippets/7/highlight/\",\n \"owner\": \"lucy\",\n \"title\": \"Example\",\n \"code\": \"print('hello, world')\",\n \"linenos\": false,\n \"language\": \"python\",\n \"style\": \"friendly\"\n}\n\n\n\nAnd to delete a snippet:\n\n\n$ coreapi action snippets delete --param id=7\n\n\n\nAs well as the command line client, developers can also interact with your\nAPI using client libraries. The Python client library is the first of these\nto be available, and a Javascript client library is planned to be released\nsoon.\n\n\nFor more details on customizing schema generation and using Core API\nclient libraries you'll need to refer to the full documentation.\n\n\nReviewing our work\n\n\nWith an incredibly small amount of code, we've now got a complete pastebin Web API, which is fully web browsable, includes a schema-driven client library, and comes complete with authentication, per-object permissions, and multiple renderer formats.\n\n\nWe'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.\n\n\nYou can review the final \ntutorial code\n on GitHub, or try out a live example in \nthe sandbox\n.\n\n\nOnwards and upwards\n\n\nWe've reached the end of our tutorial. If you want to get more involved in the REST framework project, here are a few places you can start:\n\n\n\n\nContribute on \nGitHub\n by reviewing and submitting issues, and making pull requests.\n\n\nJoin the \nREST framework discussion group\n, and help build the community.\n\n\nFollow \nthe author\n on Twitter and say hi.\n\n\n\n\nNow go build awesome things.",
"title": "7 - Schemas and client libraries"
},
{
@@ -387,7 +387,7 @@
},
{
"location": "/tutorial/7-schemas-and-client-libraries/#adding-a-schema",
- "text": "REST framework supports either explicitly defined schema views, or\nautomatically generated schemas. Since we're using viewsets and routers,\nwe can simply use the automatic schema generation. You'll need to install the coreapi python package in order to include an\nAPI schema. $ pip install coreapi We can now include a schema for our API, by including an autogenerated schema\nview in our URL configuration. from rest_framework.schemas import get_schema_view\n\nschema_view = get_schema_view(title='Pastebin API')\n\nurlpatterns = [\n url('^schema/$', schema_view),\n ...\n] If you visit the API root endpoint in a browser you should now see corejson \nrepresentation become available as an option. We can also request the schema from the command line, by specifying the desired\ncontent type in the Accept header. $ http http://127.0.0.1:8000/schema/ Accept:application/vnd.coreapi+json\nHTTP/1.0 200 OK\nAllow: GET, HEAD, OPTIONS\nContent-Type: application/vnd.coreapi+json\n\n{\n \"_meta\": {\n \"title\": \"Pastebin API\"\n },\n \"_type\": \"document\",\n ... The default output style is to use the Core JSON encoding. Other schema formats, such as Open API (formerly Swagger) are\nalso supported.",
+ "text": "REST framework supports either explicitly defined schema views, or\nautomatically generated schemas. Since we're using viewsets and routers,\nwe can simply use the automatic schema generation. You'll need to install the coreapi python package in order to include an\nAPI schema. $ pip install coreapi We can now include a schema for our API, by including an autogenerated schema\nview in our URL configuration. from rest_framework.schemas import get_schema_view\n\nschema_view = get_schema_view(title='Pastebin API')\n\nurlpatterns = [\n url('^schema/$', schema_view),\n ...\n] If you visit the API root endpoint in a browser you should now see corejson \nrepresentation become available as an option. We can also request the schema from the command line, by specifying the desired\ncontent type in the Accept header. $ http http://127.0.0.1:8000/schema/ Accept:application/coreapi+json\nHTTP/1.0 200 OK\nAllow: GET, HEAD, OPTIONS\nContent-Type: application/coreapi+json\n\n{\n \"_meta\": {\n \"title\": \"Pastebin API\"\n },\n \"_type\": \"document\",\n ... The default output style is to use the Core JSON encoding. Other schema formats, such as Open API (formerly Swagger) are\nalso supported.",
"title": "Adding a schema"
},
{
@@ -2037,7 +2037,7 @@
},
{
"location": "/api-guide/relations/",
- "text": "Serializer relations\n\n\n\n\nBad programmers worry about the code.\nGood programmers worry about data structures and their relationships.\n\n\n \nLinus Torvalds\n\n\n\n\nRelational fields are used to represent model relationships. They can be applied to \nForeignKey\n, \nManyToManyField\n and \nOneToOneField\n relationships, as well as to reverse relationships, and custom relationships such as \nGenericForeignKey\n.\n\n\n\n\nNote:\n The relational fields are declared in \nrelations.py\n, but by convention you should import them from the \nserializers\n module, using \nfrom rest_framework import serializers\n and refer to fields as \nserializers.\nFieldName\n.\n\n\n\n\nInspecting relationships.\n\n\nWhen using the \nModelSerializer\n class, serializer fields and relationships will be automatically generated for you. Inspecting these automatically generated fields can be a useful tool for determining how to customize the relationship style.\n\n\nTo do so, open the Django shell, using \npython manage.py shell\n, then import the serializer class, instantiate it, and print the object representation\u2026\n\n\n from myapp.serializers import AccountSerializer\n\n serializer = AccountSerializer()\n\n print repr(serializer) # Or `print(repr(serializer))` in Python 3.x.\nAccountSerializer():\n id = IntegerField(label='ID', read_only=True)\n name = CharField(allow_blank=True, max_length=100, required=False)\n owner = PrimaryKeyRelatedField(queryset=User.objects.all())\n\n\n\nAPI Reference\n\n\nIn order to explain the various types of relational fields, we'll use a couple of simple models for our examples. Our models will be for music albums, and the tracks listed on each album.\n\n\nclass Album(models.Model):\n album_name = models.CharField(max_length=100)\n artist = models.CharField(max_length=100)\n\nclass Track(models.Model):\n album = models.ForeignKey(Album, related_name='tracks')\n order = models.IntegerField()\n title = models.CharField(max_length=100)\n duration = models.IntegerField()\n\n class Meta:\n unique_together = ('album', 'order')\n ordering = ['order']\n\n def __unicode__(self):\n return '%d: %s' % (self.order, self.title)\n\n\n\nStringRelatedField\n\n\nStringRelatedField\n may be used to represent the target of the relationship using its \n__unicode__\n method.\n\n\nFor example, the following serializer.\n\n\nclass AlbumSerializer(serializers.ModelSerializer):\n tracks = serializers.StringRelatedField(many=True)\n\n class Meta:\n model = Album\n fields = ('album_name', 'artist', 'tracks')\n\n\n\nWould serialize to the following representation.\n\n\n{\n 'album_name': 'Things We Lost In The Fire',\n 'artist': 'Low',\n 'tracks': [\n '1: Sunflower',\n '2: Whitetail',\n '3: Dinosaur Act',\n ...\n ]\n}\n\n\n\nThis field is read only.\n\n\nArguments\n:\n\n\n\n\nmany\n - If applied to a to-many relationship, you should set this argument to \nTrue\n.\n\n\n\n\nPrimaryKeyRelatedField\n\n\nPrimaryKeyRelatedField\n may be used to represent the target of the relationship using its primary key.\n\n\nFor example, the following serializer:\n\n\nclass AlbumSerializer(serializers.ModelSerializer):\n tracks = serializers.PrimaryKeyRelatedField(many=True, read_only=True)\n\n class Meta:\n model = Album\n fields = ('album_name', 'artist', 'tracks')\n\n\n\nWould serialize to a representation like this:\n\n\n{\n 'album_name': 'Undun',\n 'artist': 'The Roots',\n 'tracks': [\n 89,\n 90,\n 91,\n ...\n ]\n}\n\n\n\nBy default this field is read-write, although you can change this behavior using the \nread_only\n flag.\n\n\nArguments\n:\n\n\n\n\nqueryset\n - The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set \nread_only=True\n.\n\n\nmany\n - If applied to a to-many relationship, you should set this argument to \nTrue\n.\n\n\nallow_null\n - If set to \nTrue\n, the field will accept values of \nNone\n or the empty string for nullable relationships. Defaults to \nFalse\n.\n\n\npk_field\n - Set to a field to control serialization/deserialization of the primary key's value. For example, \npk_field=UUIDField(format='hex')\n would serialize a UUID primary key into its compact hex representation.\n\n\n\n\nHyperlinkedRelatedField\n\n\nHyperlinkedRelatedField\n may be used to represent the target of the relationship using a hyperlink.\n\n\nFor example, the following serializer:\n\n\nclass AlbumSerializer(serializers.ModelSerializer):\n tracks = serializers.HyperlinkedRelatedField(\n many=True,\n read_only=True,\n view_name='track-detail'\n )\n\n class Meta:\n model = Album\n fields = ('album_name', 'artist', 'tracks')\n\n\n\nWould serialize to a representation like this:\n\n\n{\n 'album_name': 'Graceland',\n 'artist': 'Paul Simon',\n 'tracks': [\n 'http://www.example.com/api/tracks/45/',\n 'http://www.example.com/api/tracks/46/',\n 'http://www.example.com/api/tracks/47/',\n ...\n ]\n}\n\n\n\nBy default this field is read-write, although you can change this behavior using the \nread_only\n flag.\n\n\n\n\nNote\n: This field is designed for objects that map to a URL that accepts a single URL keyword argument, as set using the \nlookup_field\n and \nlookup_url_kwarg\n arguments.\n\n\nThis is suitable for URLs that contain a single primary key or slug argument as part of the URL.\n\n\nIf you require more complex hyperlinked representation you'll need to customize the field, as described in the \ncustom hyperlinked fields\n section, below.\n\n\n\n\nArguments\n:\n\n\n\n\nview_name\n - The view name that should be used as the target of the relationship. If you're using \nthe standard router classes\n this will be a string with the format \nmodelname\n-detail\n. \nrequired\n.\n\n\nqueryset\n - The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set \nread_only=True\n.\n\n\nmany\n - If applied to a to-many relationship, you should set this argument to \nTrue\n.\n\n\nallow_null\n - If set to \nTrue\n, the field will accept values of \nNone\n or the empty string for nullable relationships. Defaults to \nFalse\n.\n\n\nlookup_field\n - The field on the target that should be used for the lookup. Should correspond to a URL keyword argument on the referenced view. Default is \n'pk'\n.\n\n\nlookup_url_kwarg\n - The name of the keyword argument defined in the URL conf that corresponds to the lookup field. Defaults to using the same value as \nlookup_field\n.\n\n\nformat\n - If using format suffixes, hyperlinked fields will use the same format suffix for the target unless overridden by using the \nformat\n argument.\n\n\n\n\nSlugRelatedField\n\n\nSlugRelatedField\n may be used to represent the target of the relationship using a field on the target.\n\n\nFor example, the following serializer:\n\n\nclass AlbumSerializer(serializers.ModelSerializer):\n tracks = serializers.SlugRelatedField(\n many=True,\n read_only=True,\n slug_field='title'\n )\n\n class Meta:\n model = Album\n fields = ('album_name', 'artist', 'tracks')\n\n\n\nWould serialize to a representation like this:\n\n\n{\n 'album_name': 'Dear John',\n 'artist': 'Loney Dear',\n 'tracks': [\n 'Airport Surroundings',\n 'Everything Turns to You',\n 'I Was Only Going Out',\n ...\n ]\n}\n\n\n\nBy default this field is read-write, although you can change this behavior using the \nread_only\n flag.\n\n\nWhen using \nSlugRelatedField\n as a read-write field, you will normally want to ensure that the slug field corresponds to a model field with \nunique=True\n.\n\n\nArguments\n:\n\n\n\n\nslug_field\n - The field on the target that should be used to represent it. This should be a field that uniquely identifies any given instance. For example, \nusername\n. \nrequired\n\n\nqueryset\n - The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set \nread_only=True\n.\n\n\nmany\n - If applied to a to-many relationship, you should set this argument to \nTrue\n.\n\n\nallow_null\n - If set to \nTrue\n, the field will accept values of \nNone\n or the empty string for nullable relationships. Defaults to \nFalse\n.\n\n\n\n\nHyperlinkedIdentityField\n\n\nThis field can be applied as an identity relationship, such as the \n'url'\n field on a HyperlinkedModelSerializer. It can also be used for an attribute on the object. For example, the following serializer:\n\n\nclass AlbumSerializer(serializers.HyperlinkedModelSerializer):\n track_listing = serializers.HyperlinkedIdentityField(view_name='track-list')\n\n class Meta:\n model = Album\n fields = ('album_name', 'artist', 'track_listing')\n\n\n\nWould serialize to a representation like this:\n\n\n{\n 'album_name': 'The Eraser',\n 'artist': 'Thom Yorke',\n 'track_listing': 'http://www.example.com/api/track_list/12/',\n}\n\n\n\nThis field is always read-only.\n\n\nArguments\n:\n\n\n\n\nview_name\n - The view name that should be used as the target of the relationship. If you're using \nthe standard router classes\n this will be a string with the format \nmodel_name\n-detail\n. \nrequired\n.\n\n\nlookup_field\n - The field on the target that should be used for the lookup. Should correspond to a URL keyword argument on the referenced view. Default is \n'pk'\n.\n\n\nlookup_url_kwarg\n - The name of the keyword argument defined in the URL conf that corresponds to the lookup field. Defaults to using the same value as \nlookup_field\n.\n\n\nformat\n - If using format suffixes, hyperlinked fields will use the same format suffix for the target unless overridden by using the \nformat\n argument.\n\n\n\n\n\n\nNested relationships\n\n\nNested relationships can be expressed by using serializers as fields.\n\n\nIf the field is used to represent a to-many relationship, you should add the \nmany=True\n flag to the serializer field.\n\n\nExample\n\n\nFor example, the following serializer:\n\n\nclass TrackSerializer(serializers.ModelSerializer):\n class Meta:\n model = Track\n fields = ('order', 'title', 'duration')\n\nclass AlbumSerializer(serializers.ModelSerializer):\n tracks = TrackSerializer(many=True, read_only=True)\n\n class Meta:\n model = Album\n fields = ('album_name', 'artist', 'tracks')\n\n\n\nWould serialize to a nested representation like this:\n\n\n album = Album.objects.create(album_name=\"The Grey Album\", artist='Danger Mouse')\n\n Track.objects.create(album=album, order=1, title='Public Service Announcement', duration=245)\n\nTrack: Track object\n\n\n Track.objects.create(album=album, order=2, title='What More Can I Say', duration=264)\n\nTrack: Track object\n\n\n Track.objects.create(album=album, order=3, title='Encore', duration=159)\n\nTrack: Track object\n\n\n serializer = AlbumSerializer(instance=album)\n\n serializer.data\n{\n 'album_name': 'The Grey Album',\n 'artist': 'Danger Mouse',\n 'tracks': [\n {'order': 1, 'title': 'Public Service Announcement', 'duration': 245},\n {'order': 2, 'title': 'What More Can I Say', 'duration': 264},\n {'order': 3, 'title': 'Encore', 'duration': 159},\n ...\n ],\n}\n\n\n\nWritable nested serializers\n\n\nBy default nested serializers are read-only. If you want to support write-operations to a nested serializer field you'll need to create \ncreate()\n and/or \nupdate()\n methods in order to explicitly specify how the child relationships should be saved.\n\n\nclass TrackSerializer(serializers.ModelSerializer):\n class Meta:\n model = Track\n fields = ('order', 'title', 'duration')\n\nclass AlbumSerializer(serializers.ModelSerializer):\n tracks = TrackSerializer(many=True)\n\n class Meta:\n model = Album\n fields = ('album_name', 'artist', 'tracks')\n\n def create(self, validated_data):\n tracks_data = validated_data.pop('tracks')\n album = Album.objects.create(**validated_data)\n for track_data in tracks_data:\n Track.objects.create(album=album, **track_data)\n return album\n\n\n data = {\n 'album_name': 'The Grey Album',\n 'artist': 'Danger Mouse',\n 'tracks': [\n {'order': 1, 'title': 'Public Service Announcement', 'duration': 245},\n {'order': 2, 'title': 'What More Can I Say', 'duration': 264},\n {'order': 3, 'title': 'Encore', 'duration': 159},\n ],\n}\n\n serializer = AlbumSerializer(data=data)\n\n serializer.is_valid()\nTrue\n\n serializer.save()\n\nAlbum: Album object\n\n\n\n\n\n\nCustom relational fields\n\n\nIn rare cases where none of the existing relational styles fit the representation you need,\nyou can implement a completely custom relational field, that describes exactly how the\noutput representation should be generated from the model instance.\n\n\nTo implement a custom relational field, you should override \nRelatedField\n, and implement the \n.to_representation(self, value)\n method. This method takes the target of the field as the \nvalue\n argument, and should return the representation that should be used to serialize the target. The \nvalue\n argument will typically be a model instance.\n\n\nIf you want to implement a read-write relational field, you must also implement the \n.to_internal_value(self, data)\n method.\n\n\nTo provide a dynamic queryset based on the \ncontext\n, you can also override \n.get_queryset(self)\n instead of specifying \n.queryset\n on the class or when initializing the field.\n\n\nExample\n\n\nFor example, we could define a relational field to serialize a track to a custom string representation, using its ordering, title, and duration.\n\n\nimport time\n\nclass TrackListingField(serializers.RelatedField):\n def to_representation(self, value):\n duration = time.strftime('%M:%S', time.gmtime(value.duration))\n return 'Track %d: %s (%s)' % (value.order, value.name, duration)\n\nclass AlbumSerializer(serializers.ModelSerializer):\n tracks = TrackListingField(many=True)\n\n class Meta:\n model = Album\n fields = ('album_name', 'artist', 'tracks')\n\n\n\nThis custom field would then serialize to the following representation.\n\n\n{\n 'album_name': 'Sometimes I Wish We Were an Eagle',\n 'artist': 'Bill Callahan',\n 'tracks': [\n 'Track 1: Jim Cain (04:39)',\n 'Track 2: Eid Ma Clack Shaw (04:19)',\n 'Track 3: The Wind and the Dove (04:34)',\n ...\n ]\n}\n\n\n\n\n\nCustom hyperlinked fields\n\n\nIn some cases you may need to customize the behavior of a hyperlinked field, in order to represent URLs that require more than a single lookup field.\n\n\nYou can achieve this by overriding \nHyperlinkedRelatedField\n. There are two methods that may be overridden:\n\n\nget_url(self, obj, view_name, request, format)\n\n\nThe \nget_url\n method is used to map the object instance to its URL representation.\n\n\nMay raise a \nNoReverseMatch\n if the \nview_name\n and \nlookup_field\n\nattributes are not configured to correctly match the URL conf.\n\n\nget_object(self, queryset, view_name, view_args, view_kwargs)\n\n\nIf you want to support a writable hyperlinked field then you'll also want to override \nget_object\n, in order to map incoming URLs back to the object they represent. For read-only hyperlinked fields there is no need to override this method.\n\n\nThe return value of this method should the object that corresponds to the matched URL conf arguments.\n\n\nMay raise an \nObjectDoesNotExist\n exception.\n\n\nExample\n\n\nSay we have a URL for a customer object that takes two keyword arguments, like so:\n\n\n/api/\norganization_slug\n/customers/\ncustomer_pk\n/\n\n\n\nThis cannot be represented with the default implementation, which accepts only a single lookup field.\n\n\nIn this case we'd need to override \nHyperlinkedRelatedField\n to get the behavior we want:\n\n\nfrom rest_framework import serializers\nfrom rest_framework.reverse import reverse\n\nclass CustomerHyperlink(serializers.HyperlinkedRelatedField):\n # We define these as class attributes, so we don't need to pass them as arguments.\n view_name = 'customer-detail'\n queryset = Customer.objects.all()\n\n def get_url(self, obj, view_name, request, format):\n url_kwargs = {\n 'organization_slug': obj.organization.slug,\n 'customer_pk': obj.pk\n }\n return reverse(view_name, kwargs=url_kwargs, request=request, format=format)\n\n def get_object(self, view_name, view_args, view_kwargs):\n lookup_kwargs = {\n 'organization__slug': view_kwargs['organization_slug'],\n 'pk': view_kwargs['customer_pk']\n }\n return self.get_queryset().get(**lookup_kwargs)\n\n\n\nNote that if you wanted to use this style together with the generic views then you'd also need to override \n.get_object\n on the view in order to get the correct lookup behavior.\n\n\nGenerally we recommend a flat style for API representations where possible, but the nested URL style can also be reasonable when used in moderation.\n\n\n\n\nFurther notes\n\n\nThe \nqueryset\n argument\n\n\nThe \nqueryset\n argument is only ever required for \nwritable\n relationship field, in which case it is used for performing the model instance lookup, that maps from the primitive user input, into a model instance.\n\n\nIn version 2.x a serializer class could \nsometimes\n automatically determine the \nqueryset\n argument \nif\n a \nModelSerializer\n class was being used.\n\n\nThis behavior is now replaced with \nalways\n using an explicit \nqueryset\n argument for writable relational fields.\n\n\nDoing so reduces the amount of hidden 'magic' that \nModelSerializer\n provides, makes the behavior of the field more clear, and ensures that it is trivial to move between using the \nModelSerializer\n shortcut, or using fully explicit \nSerializer\n classes.\n\n\nCustomizing the HTML display\n\n\nThe built-in \n__str__\n method of the model will be used to generate string representations of the objects used to populate the \nchoices\n property. These choices are used to populate select HTML inputs in the browsable API.\n\n\nTo provide customized representations for such inputs, override \ndisplay_value()\n of a \nRelatedField\n subclass. This method will receive a model object, and should return a string suitable for representing it. For example:\n\n\nclass TrackPrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):\n def display_value(self, instance):\n return 'Track: %s' % (instance.title)\n\n\n\nSelect field cutoffs\n\n\nWhen rendered in the browsable API relational fields will default to only displaying a maximum of 1000 selectable items. If more items are present then a disabled option with \"More than 1000 items\u2026\" will be displayed.\n\n\nThis behavior is intended to prevent a template from being unable to render in an acceptable timespan due to a very large number of relationships being displayed.\n\n\nThere are two keyword arguments you can use to control this behavior:\n\n\n\n\nhtml_cutoff\n - If set this will be the maximum number of choices that will be displayed by a HTML select drop down. Set to \nNone\n to disable any limiting. Defaults to \n1000\n.\n\n\nhtml_cutoff_text\n - If set this will display a textual indicator if the maximum number of items have been cutoff in an HTML select drop down. Defaults to \n\"More than {count} items\u2026\"\n\n\n\n\nYou can also control these globally using the settings \nHTML_SELECT_CUTOFF\n and \nHTML_SELECT_CUTOFF_TEXT\n.\n\n\nIn cases where the cutoff is being enforced you may want to instead use a plain input field in the HTML form. You can do so using the \nstyle\n keyword argument. For example:\n\n\nassigned_to = serializers.SlugRelatedField(\n queryset=User.objects.all(),\n slug_field='username',\n style={'base_template': 'input.html'}\n)\n\n\n\nReverse relations\n\n\nNote that reverse relationships are not automatically included by the \nModelSerializer\n and \nHyperlinkedModelSerializer\n classes. To include a reverse relationship, you must explicitly add it to the fields list. For example:\n\n\nclass AlbumSerializer(serializers.ModelSerializer):\n class Meta:\n fields = ('tracks', ...)\n\n\n\nYou'll normally want to ensure that you've set an appropriate \nrelated_name\n argument on the relationship, that you can use as the field name. For example:\n\n\nclass Track(models.Model):\n album = models.ForeignKey(Album, related_name='tracks')\n ...\n\n\n\nIf you have not set a related name for the reverse relationship, you'll need to use the automatically generated related name in the \nfields\n argument. For example:\n\n\nclass AlbumSerializer(serializers.ModelSerializer):\n class Meta:\n fields = ('track_set', ...)\n\n\n\nSee the Django documentation on \nreverse relationships\n for more details.\n\n\nGeneric relationships\n\n\nIf you want to serialize a generic foreign key, you need to define a custom field, to determine explicitly how you want to serialize the targets of the relationship.\n\n\nFor example, given the following model for a tag, which has a generic relationship with other arbitrary models:\n\n\nclass TaggedItem(models.Model):\n \"\"\"\n Tags arbitrary model instances using a generic relation.\n\n See: https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/\n \"\"\"\n tag_name = models.SlugField()\n content_type = models.ForeignKey(ContentType)\n object_id = models.PositiveIntegerField()\n tagged_object = GenericForeignKey('content_type', 'object_id')\n\n def __unicode__(self):\n return self.tag_name\n\n\n\nAnd the following two models, which may have associated tags:\n\n\nclass Bookmark(models.Model):\n \"\"\"\n A bookmark consists of a URL, and 0 or more descriptive tags.\n \"\"\"\n url = models.URLField()\n tags = GenericRelation(TaggedItem)\n\n\nclass Note(models.Model):\n \"\"\"\n A note consists of some text, and 0 or more descriptive tags.\n \"\"\"\n text = models.CharField(max_length=1000)\n tags = GenericRelation(TaggedItem)\n\n\n\nWe could define a custom field that could be used to serialize tagged instances, using the type of each instance to determine how it should be serialized.\n\n\nclass TaggedObjectRelatedField(serializers.RelatedField):\n \"\"\"\n A custom field to use for the `tagged_object` generic relationship.\n \"\"\"\n\n def to_representation(self, value):\n \"\"\"\n Serialize tagged objects to a simple textual representation.\n \"\"\"\n if isinstance(value, Bookmark):\n return 'Bookmark: ' + value.url\n elif isinstance(value, Note):\n return 'Note: ' + value.text\n raise Exception('Unexpected type of tagged object')\n\n\n\nIf you need the target of the relationship to have a nested representation, you can use the required serializers inside the \n.to_representation()\n method:\n\n\n def to_representation(self, value):\n \"\"\"\n Serialize bookmark instances using a bookmark serializer,\n and note instances using a note serializer.\n \"\"\"\n if isinstance(value, Bookmark):\n serializer = BookmarkSerializer(value)\n elif isinstance(value, Note):\n serializer = NoteSerializer(value)\n else:\n raise Exception('Unexpected type of tagged object')\n\n return serializer.data\n\n\n\nNote that reverse generic keys, expressed using the \nGenericRelation\n field, can be serialized using the regular relational field types, since the type of the target in the relationship is always known.\n\n\nFor more information see \nthe Django documentation on generic relations\n.\n\n\nManyToManyFields with a Through Model\n\n\nBy default, relational fields that target a \nManyToManyField\n with a\n\nthrough\n model specified are set to read-only.\n\n\nIf you explicitly specify a relational field pointing to a\n\nManyToManyField\n with a through model, be sure to set \nread_only\n\nto \nTrue\n.\n\n\n\n\nThird Party Packages\n\n\nThe following third party packages are also available.\n\n\nDRF Nested Routers\n\n\nThe \ndrf-nested-routers package\n provides routers and relationship fields for working with nested resources.\n\n\nRest Framework Generic Relations\n\n\nThe \nrest-framework-generic-relations\n library provides read/write serialization for generic foreign keys.",
+ "text": "Serializer relations\n\n\n\n\nBad programmers worry about the code.\nGood programmers worry about data structures and their relationships.\n\n\n \nLinus Torvalds\n\n\n\n\nRelational fields are used to represent model relationships. They can be applied to \nForeignKey\n, \nManyToManyField\n and \nOneToOneField\n relationships, as well as to reverse relationships, and custom relationships such as \nGenericForeignKey\n.\n\n\n\n\nNote:\n The relational fields are declared in \nrelations.py\n, but by convention you should import them from the \nserializers\n module, using \nfrom rest_framework import serializers\n and refer to fields as \nserializers.\nFieldName\n.\n\n\n\n\nInspecting relationships.\n\n\nWhen using the \nModelSerializer\n class, serializer fields and relationships will be automatically generated for you. Inspecting these automatically generated fields can be a useful tool for determining how to customize the relationship style.\n\n\nTo do so, open the Django shell, using \npython manage.py shell\n, then import the serializer class, instantiate it, and print the object representation\u2026\n\n\n from myapp.serializers import AccountSerializer\n\n serializer = AccountSerializer()\n\n print repr(serializer) # Or `print(repr(serializer))` in Python 3.x.\nAccountSerializer():\n id = IntegerField(label='ID', read_only=True)\n name = CharField(allow_blank=True, max_length=100, required=False)\n owner = PrimaryKeyRelatedField(queryset=User.objects.all())\n\n\n\nAPI Reference\n\n\nIn order to explain the various types of relational fields, we'll use a couple of simple models for our examples. Our models will be for music albums, and the tracks listed on each album.\n\n\nclass Album(models.Model):\n album_name = models.CharField(max_length=100)\n artist = models.CharField(max_length=100)\n\nclass Track(models.Model):\n album = models.ForeignKey(Album, related_name='tracks', on_delete=models.CASCADE)\n order = models.IntegerField()\n title = models.CharField(max_length=100)\n duration = models.IntegerField()\n\n class Meta:\n unique_together = ('album', 'order')\n ordering = ['order']\n\n def __unicode__(self):\n return '%d: %s' % (self.order, self.title)\n\n\n\nStringRelatedField\n\n\nStringRelatedField\n may be used to represent the target of the relationship using its \n__unicode__\n method.\n\n\nFor example, the following serializer.\n\n\nclass AlbumSerializer(serializers.ModelSerializer):\n tracks = serializers.StringRelatedField(many=True)\n\n class Meta:\n model = Album\n fields = ('album_name', 'artist', 'tracks')\n\n\n\nWould serialize to the following representation.\n\n\n{\n 'album_name': 'Things We Lost In The Fire',\n 'artist': 'Low',\n 'tracks': [\n '1: Sunflower',\n '2: Whitetail',\n '3: Dinosaur Act',\n ...\n ]\n}\n\n\n\nThis field is read only.\n\n\nArguments\n:\n\n\n\n\nmany\n - If applied to a to-many relationship, you should set this argument to \nTrue\n.\n\n\n\n\nPrimaryKeyRelatedField\n\n\nPrimaryKeyRelatedField\n may be used to represent the target of the relationship using its primary key.\n\n\nFor example, the following serializer:\n\n\nclass AlbumSerializer(serializers.ModelSerializer):\n tracks = serializers.PrimaryKeyRelatedField(many=True, read_only=True)\n\n class Meta:\n model = Album\n fields = ('album_name', 'artist', 'tracks')\n\n\n\nWould serialize to a representation like this:\n\n\n{\n 'album_name': 'Undun',\n 'artist': 'The Roots',\n 'tracks': [\n 89,\n 90,\n 91,\n ...\n ]\n}\n\n\n\nBy default this field is read-write, although you can change this behavior using the \nread_only\n flag.\n\n\nArguments\n:\n\n\n\n\nqueryset\n - The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set \nread_only=True\n.\n\n\nmany\n - If applied to a to-many relationship, you should set this argument to \nTrue\n.\n\n\nallow_null\n - If set to \nTrue\n, the field will accept values of \nNone\n or the empty string for nullable relationships. Defaults to \nFalse\n.\n\n\npk_field\n - Set to a field to control serialization/deserialization of the primary key's value. For example, \npk_field=UUIDField(format='hex')\n would serialize a UUID primary key into its compact hex representation.\n\n\n\n\nHyperlinkedRelatedField\n\n\nHyperlinkedRelatedField\n may be used to represent the target of the relationship using a hyperlink.\n\n\nFor example, the following serializer:\n\n\nclass AlbumSerializer(serializers.ModelSerializer):\n tracks = serializers.HyperlinkedRelatedField(\n many=True,\n read_only=True,\n view_name='track-detail'\n )\n\n class Meta:\n model = Album\n fields = ('album_name', 'artist', 'tracks')\n\n\n\nWould serialize to a representation like this:\n\n\n{\n 'album_name': 'Graceland',\n 'artist': 'Paul Simon',\n 'tracks': [\n 'http://www.example.com/api/tracks/45/',\n 'http://www.example.com/api/tracks/46/',\n 'http://www.example.com/api/tracks/47/',\n ...\n ]\n}\n\n\n\nBy default this field is read-write, although you can change this behavior using the \nread_only\n flag.\n\n\n\n\nNote\n: This field is designed for objects that map to a URL that accepts a single URL keyword argument, as set using the \nlookup_field\n and \nlookup_url_kwarg\n arguments.\n\n\nThis is suitable for URLs that contain a single primary key or slug argument as part of the URL.\n\n\nIf you require more complex hyperlinked representation you'll need to customize the field, as described in the \ncustom hyperlinked fields\n section, below.\n\n\n\n\nArguments\n:\n\n\n\n\nview_name\n - The view name that should be used as the target of the relationship. If you're using \nthe standard router classes\n this will be a string with the format \nmodelname\n-detail\n. \nrequired\n.\n\n\nqueryset\n - The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set \nread_only=True\n.\n\n\nmany\n - If applied to a to-many relationship, you should set this argument to \nTrue\n.\n\n\nallow_null\n - If set to \nTrue\n, the field will accept values of \nNone\n or the empty string for nullable relationships. Defaults to \nFalse\n.\n\n\nlookup_field\n - The field on the target that should be used for the lookup. Should correspond to a URL keyword argument on the referenced view. Default is \n'pk'\n.\n\n\nlookup_url_kwarg\n - The name of the keyword argument defined in the URL conf that corresponds to the lookup field. Defaults to using the same value as \nlookup_field\n.\n\n\nformat\n - If using format suffixes, hyperlinked fields will use the same format suffix for the target unless overridden by using the \nformat\n argument.\n\n\n\n\nSlugRelatedField\n\n\nSlugRelatedField\n may be used to represent the target of the relationship using a field on the target.\n\n\nFor example, the following serializer:\n\n\nclass AlbumSerializer(serializers.ModelSerializer):\n tracks = serializers.SlugRelatedField(\n many=True,\n read_only=True,\n slug_field='title'\n )\n\n class Meta:\n model = Album\n fields = ('album_name', 'artist', 'tracks')\n\n\n\nWould serialize to a representation like this:\n\n\n{\n 'album_name': 'Dear John',\n 'artist': 'Loney Dear',\n 'tracks': [\n 'Airport Surroundings',\n 'Everything Turns to You',\n 'I Was Only Going Out',\n ...\n ]\n}\n\n\n\nBy default this field is read-write, although you can change this behavior using the \nread_only\n flag.\n\n\nWhen using \nSlugRelatedField\n as a read-write field, you will normally want to ensure that the slug field corresponds to a model field with \nunique=True\n.\n\n\nArguments\n:\n\n\n\n\nslug_field\n - The field on the target that should be used to represent it. This should be a field that uniquely identifies any given instance. For example, \nusername\n. \nrequired\n\n\nqueryset\n - The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set \nread_only=True\n.\n\n\nmany\n - If applied to a to-many relationship, you should set this argument to \nTrue\n.\n\n\nallow_null\n - If set to \nTrue\n, the field will accept values of \nNone\n or the empty string for nullable relationships. Defaults to \nFalse\n.\n\n\n\n\nHyperlinkedIdentityField\n\n\nThis field can be applied as an identity relationship, such as the \n'url'\n field on a HyperlinkedModelSerializer. It can also be used for an attribute on the object. For example, the following serializer:\n\n\nclass AlbumSerializer(serializers.HyperlinkedModelSerializer):\n track_listing = serializers.HyperlinkedIdentityField(view_name='track-list')\n\n class Meta:\n model = Album\n fields = ('album_name', 'artist', 'track_listing')\n\n\n\nWould serialize to a representation like this:\n\n\n{\n 'album_name': 'The Eraser',\n 'artist': 'Thom Yorke',\n 'track_listing': 'http://www.example.com/api/track_list/12/',\n}\n\n\n\nThis field is always read-only.\n\n\nArguments\n:\n\n\n\n\nview_name\n - The view name that should be used as the target of the relationship. If you're using \nthe standard router classes\n this will be a string with the format \nmodel_name\n-detail\n. \nrequired\n.\n\n\nlookup_field\n - The field on the target that should be used for the lookup. Should correspond to a URL keyword argument on the referenced view. Default is \n'pk'\n.\n\n\nlookup_url_kwarg\n - The name of the keyword argument defined in the URL conf that corresponds to the lookup field. Defaults to using the same value as \nlookup_field\n.\n\n\nformat\n - If using format suffixes, hyperlinked fields will use the same format suffix for the target unless overridden by using the \nformat\n argument.\n\n\n\n\n\n\nNested relationships\n\n\nNested relationships can be expressed by using serializers as fields.\n\n\nIf the field is used to represent a to-many relationship, you should add the \nmany=True\n flag to the serializer field.\n\n\nExample\n\n\nFor example, the following serializer:\n\n\nclass TrackSerializer(serializers.ModelSerializer):\n class Meta:\n model = Track\n fields = ('order', 'title', 'duration')\n\nclass AlbumSerializer(serializers.ModelSerializer):\n tracks = TrackSerializer(many=True, read_only=True)\n\n class Meta:\n model = Album\n fields = ('album_name', 'artist', 'tracks')\n\n\n\nWould serialize to a nested representation like this:\n\n\n album = Album.objects.create(album_name=\"The Grey Album\", artist='Danger Mouse')\n\n Track.objects.create(album=album, order=1, title='Public Service Announcement', duration=245)\n\nTrack: Track object\n\n\n Track.objects.create(album=album, order=2, title='What More Can I Say', duration=264)\n\nTrack: Track object\n\n\n Track.objects.create(album=album, order=3, title='Encore', duration=159)\n\nTrack: Track object\n\n\n serializer = AlbumSerializer(instance=album)\n\n serializer.data\n{\n 'album_name': 'The Grey Album',\n 'artist': 'Danger Mouse',\n 'tracks': [\n {'order': 1, 'title': 'Public Service Announcement', 'duration': 245},\n {'order': 2, 'title': 'What More Can I Say', 'duration': 264},\n {'order': 3, 'title': 'Encore', 'duration': 159},\n ...\n ],\n}\n\n\n\nWritable nested serializers\n\n\nBy default nested serializers are read-only. If you want to support write-operations to a nested serializer field you'll need to create \ncreate()\n and/or \nupdate()\n methods in order to explicitly specify how the child relationships should be saved.\n\n\nclass TrackSerializer(serializers.ModelSerializer):\n class Meta:\n model = Track\n fields = ('order', 'title', 'duration')\n\nclass AlbumSerializer(serializers.ModelSerializer):\n tracks = TrackSerializer(many=True)\n\n class Meta:\n model = Album\n fields = ('album_name', 'artist', 'tracks')\n\n def create(self, validated_data):\n tracks_data = validated_data.pop('tracks')\n album = Album.objects.create(**validated_data)\n for track_data in tracks_data:\n Track.objects.create(album=album, **track_data)\n return album\n\n\n data = {\n 'album_name': 'The Grey Album',\n 'artist': 'Danger Mouse',\n 'tracks': [\n {'order': 1, 'title': 'Public Service Announcement', 'duration': 245},\n {'order': 2, 'title': 'What More Can I Say', 'duration': 264},\n {'order': 3, 'title': 'Encore', 'duration': 159},\n ],\n}\n\n serializer = AlbumSerializer(data=data)\n\n serializer.is_valid()\nTrue\n\n serializer.save()\n\nAlbum: Album object\n\n\n\n\n\n\nCustom relational fields\n\n\nIn rare cases where none of the existing relational styles fit the representation you need,\nyou can implement a completely custom relational field, that describes exactly how the\noutput representation should be generated from the model instance.\n\n\nTo implement a custom relational field, you should override \nRelatedField\n, and implement the \n.to_representation(self, value)\n method. This method takes the target of the field as the \nvalue\n argument, and should return the representation that should be used to serialize the target. The \nvalue\n argument will typically be a model instance.\n\n\nIf you want to implement a read-write relational field, you must also implement the \n.to_internal_value(self, data)\n method.\n\n\nTo provide a dynamic queryset based on the \ncontext\n, you can also override \n.get_queryset(self)\n instead of specifying \n.queryset\n on the class or when initializing the field.\n\n\nExample\n\n\nFor example, we could define a relational field to serialize a track to a custom string representation, using its ordering, title, and duration.\n\n\nimport time\n\nclass TrackListingField(serializers.RelatedField):\n def to_representation(self, value):\n duration = time.strftime('%M:%S', time.gmtime(value.duration))\n return 'Track %d: %s (%s)' % (value.order, value.name, duration)\n\nclass AlbumSerializer(serializers.ModelSerializer):\n tracks = TrackListingField(many=True)\n\n class Meta:\n model = Album\n fields = ('album_name', 'artist', 'tracks')\n\n\n\nThis custom field would then serialize to the following representation.\n\n\n{\n 'album_name': 'Sometimes I Wish We Were an Eagle',\n 'artist': 'Bill Callahan',\n 'tracks': [\n 'Track 1: Jim Cain (04:39)',\n 'Track 2: Eid Ma Clack Shaw (04:19)',\n 'Track 3: The Wind and the Dove (04:34)',\n ...\n ]\n}\n\n\n\n\n\nCustom hyperlinked fields\n\n\nIn some cases you may need to customize the behavior of a hyperlinked field, in order to represent URLs that require more than a single lookup field.\n\n\nYou can achieve this by overriding \nHyperlinkedRelatedField\n. There are two methods that may be overridden:\n\n\nget_url(self, obj, view_name, request, format)\n\n\nThe \nget_url\n method is used to map the object instance to its URL representation.\n\n\nMay raise a \nNoReverseMatch\n if the \nview_name\n and \nlookup_field\n\nattributes are not configured to correctly match the URL conf.\n\n\nget_object(self, queryset, view_name, view_args, view_kwargs)\n\n\nIf you want to support a writable hyperlinked field then you'll also want to override \nget_object\n, in order to map incoming URLs back to the object they represent. For read-only hyperlinked fields there is no need to override this method.\n\n\nThe return value of this method should the object that corresponds to the matched URL conf arguments.\n\n\nMay raise an \nObjectDoesNotExist\n exception.\n\n\nExample\n\n\nSay we have a URL for a customer object that takes two keyword arguments, like so:\n\n\n/api/\norganization_slug\n/customers/\ncustomer_pk\n/\n\n\n\nThis cannot be represented with the default implementation, which accepts only a single lookup field.\n\n\nIn this case we'd need to override \nHyperlinkedRelatedField\n to get the behavior we want:\n\n\nfrom rest_framework import serializers\nfrom rest_framework.reverse import reverse\n\nclass CustomerHyperlink(serializers.HyperlinkedRelatedField):\n # We define these as class attributes, so we don't need to pass them as arguments.\n view_name = 'customer-detail'\n queryset = Customer.objects.all()\n\n def get_url(self, obj, view_name, request, format):\n url_kwargs = {\n 'organization_slug': obj.organization.slug,\n 'customer_pk': obj.pk\n }\n return reverse(view_name, kwargs=url_kwargs, request=request, format=format)\n\n def get_object(self, view_name, view_args, view_kwargs):\n lookup_kwargs = {\n 'organization__slug': view_kwargs['organization_slug'],\n 'pk': view_kwargs['customer_pk']\n }\n return self.get_queryset().get(**lookup_kwargs)\n\n\n\nNote that if you wanted to use this style together with the generic views then you'd also need to override \n.get_object\n on the view in order to get the correct lookup behavior.\n\n\nGenerally we recommend a flat style for API representations where possible, but the nested URL style can also be reasonable when used in moderation.\n\n\n\n\nFurther notes\n\n\nThe \nqueryset\n argument\n\n\nThe \nqueryset\n argument is only ever required for \nwritable\n relationship field, in which case it is used for performing the model instance lookup, that maps from the primitive user input, into a model instance.\n\n\nIn version 2.x a serializer class could \nsometimes\n automatically determine the \nqueryset\n argument \nif\n a \nModelSerializer\n class was being used.\n\n\nThis behavior is now replaced with \nalways\n using an explicit \nqueryset\n argument for writable relational fields.\n\n\nDoing so reduces the amount of hidden 'magic' that \nModelSerializer\n provides, makes the behavior of the field more clear, and ensures that it is trivial to move between using the \nModelSerializer\n shortcut, or using fully explicit \nSerializer\n classes.\n\n\nCustomizing the HTML display\n\n\nThe built-in \n__str__\n method of the model will be used to generate string representations of the objects used to populate the \nchoices\n property. These choices are used to populate select HTML inputs in the browsable API.\n\n\nTo provide customized representations for such inputs, override \ndisplay_value()\n of a \nRelatedField\n subclass. This method will receive a model object, and should return a string suitable for representing it. For example:\n\n\nclass TrackPrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):\n def display_value(self, instance):\n return 'Track: %s' % (instance.title)\n\n\n\nSelect field cutoffs\n\n\nWhen rendered in the browsable API relational fields will default to only displaying a maximum of 1000 selectable items. If more items are present then a disabled option with \"More than 1000 items\u2026\" will be displayed.\n\n\nThis behavior is intended to prevent a template from being unable to render in an acceptable timespan due to a very large number of relationships being displayed.\n\n\nThere are two keyword arguments you can use to control this behavior:\n\n\n\n\nhtml_cutoff\n - If set this will be the maximum number of choices that will be displayed by a HTML select drop down. Set to \nNone\n to disable any limiting. Defaults to \n1000\n.\n\n\nhtml_cutoff_text\n - If set this will display a textual indicator if the maximum number of items have been cutoff in an HTML select drop down. Defaults to \n\"More than {count} items\u2026\"\n\n\n\n\nYou can also control these globally using the settings \nHTML_SELECT_CUTOFF\n and \nHTML_SELECT_CUTOFF_TEXT\n.\n\n\nIn cases where the cutoff is being enforced you may want to instead use a plain input field in the HTML form. You can do so using the \nstyle\n keyword argument. For example:\n\n\nassigned_to = serializers.SlugRelatedField(\n queryset=User.objects.all(),\n slug_field='username',\n style={'base_template': 'input.html'}\n)\n\n\n\nReverse relations\n\n\nNote that reverse relationships are not automatically included by the \nModelSerializer\n and \nHyperlinkedModelSerializer\n classes. To include a reverse relationship, you must explicitly add it to the fields list. For example:\n\n\nclass AlbumSerializer(serializers.ModelSerializer):\n class Meta:\n fields = ('tracks', ...)\n\n\n\nYou'll normally want to ensure that you've set an appropriate \nrelated_name\n argument on the relationship, that you can use as the field name. For example:\n\n\nclass Track(models.Model):\n album = models.ForeignKey(Album, related_name='tracks', on_delete=models.CASCADE)\n ...\n\n\n\nIf you have not set a related name for the reverse relationship, you'll need to use the automatically generated related name in the \nfields\n argument. For example:\n\n\nclass AlbumSerializer(serializers.ModelSerializer):\n class Meta:\n fields = ('track_set', ...)\n\n\n\nSee the Django documentation on \nreverse relationships\n for more details.\n\n\nGeneric relationships\n\n\nIf you want to serialize a generic foreign key, you need to define a custom field, to determine explicitly how you want to serialize the targets of the relationship.\n\n\nFor example, given the following model for a tag, which has a generic relationship with other arbitrary models:\n\n\nclass TaggedItem(models.Model):\n \"\"\"\n Tags arbitrary model instances using a generic relation.\n\n See: https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/\n \"\"\"\n tag_name = models.SlugField()\n content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)\n object_id = models.PositiveIntegerField()\n tagged_object = GenericForeignKey('content_type', 'object_id')\n\n def __unicode__(self):\n return self.tag_name\n\n\n\nAnd the following two models, which may have associated tags:\n\n\nclass Bookmark(models.Model):\n \"\"\"\n A bookmark consists of a URL, and 0 or more descriptive tags.\n \"\"\"\n url = models.URLField()\n tags = GenericRelation(TaggedItem)\n\n\nclass Note(models.Model):\n \"\"\"\n A note consists of some text, and 0 or more descriptive tags.\n \"\"\"\n text = models.CharField(max_length=1000)\n tags = GenericRelation(TaggedItem)\n\n\n\nWe could define a custom field that could be used to serialize tagged instances, using the type of each instance to determine how it should be serialized.\n\n\nclass TaggedObjectRelatedField(serializers.RelatedField):\n \"\"\"\n A custom field to use for the `tagged_object` generic relationship.\n \"\"\"\n\n def to_representation(self, value):\n \"\"\"\n Serialize tagged objects to a simple textual representation.\n \"\"\"\n if isinstance(value, Bookmark):\n return 'Bookmark: ' + value.url\n elif isinstance(value, Note):\n return 'Note: ' + value.text\n raise Exception('Unexpected type of tagged object')\n\n\n\nIf you need the target of the relationship to have a nested representation, you can use the required serializers inside the \n.to_representation()\n method:\n\n\n def to_representation(self, value):\n \"\"\"\n Serialize bookmark instances using a bookmark serializer,\n and note instances using a note serializer.\n \"\"\"\n if isinstance(value, Bookmark):\n serializer = BookmarkSerializer(value)\n elif isinstance(value, Note):\n serializer = NoteSerializer(value)\n else:\n raise Exception('Unexpected type of tagged object')\n\n return serializer.data\n\n\n\nNote that reverse generic keys, expressed using the \nGenericRelation\n field, can be serialized using the regular relational field types, since the type of the target in the relationship is always known.\n\n\nFor more information see \nthe Django documentation on generic relations\n.\n\n\nManyToManyFields with a Through Model\n\n\nBy default, relational fields that target a \nManyToManyField\n with a\n\nthrough\n model specified are set to read-only.\n\n\nIf you explicitly specify a relational field pointing to a\n\nManyToManyField\n with a through model, be sure to set \nread_only\n\nto \nTrue\n.\n\n\n\n\nThird Party Packages\n\n\nThe following third party packages are also available.\n\n\nDRF Nested Routers\n\n\nThe \ndrf-nested-routers package\n provides routers and relationship fields for working with nested resources.\n\n\nRest Framework Generic Relations\n\n\nThe \nrest-framework-generic-relations\n library provides read/write serialization for generic foreign keys.",
"title": "Serializer relations"
},
{
@@ -2052,7 +2052,7 @@
},
{
"location": "/api-guide/relations/#api-reference",
- "text": "In order to explain the various types of relational fields, we'll use a couple of simple models for our examples. Our models will be for music albums, and the tracks listed on each album. class Album(models.Model):\n album_name = models.CharField(max_length=100)\n artist = models.CharField(max_length=100)\n\nclass Track(models.Model):\n album = models.ForeignKey(Album, related_name='tracks')\n order = models.IntegerField()\n title = models.CharField(max_length=100)\n duration = models.IntegerField()\n\n class Meta:\n unique_together = ('album', 'order')\n ordering = ['order']\n\n def __unicode__(self):\n return '%d: %s' % (self.order, self.title)",
+ "text": "In order to explain the various types of relational fields, we'll use a couple of simple models for our examples. Our models will be for music albums, and the tracks listed on each album. class Album(models.Model):\n album_name = models.CharField(max_length=100)\n artist = models.CharField(max_length=100)\n\nclass Track(models.Model):\n album = models.ForeignKey(Album, related_name='tracks', on_delete=models.CASCADE)\n order = models.IntegerField()\n title = models.CharField(max_length=100)\n duration = models.IntegerField()\n\n class Meta:\n unique_together = ('album', 'order')\n ordering = ['order']\n\n def __unicode__(self):\n return '%d: %s' % (self.order, self.title)",
"title": "API Reference"
},
{
@@ -2137,12 +2137,12 @@
},
{
"location": "/api-guide/relations/#reverse-relations",
- "text": "Note that reverse relationships are not automatically included by the ModelSerializer and HyperlinkedModelSerializer classes. To include a reverse relationship, you must explicitly add it to the fields list. For example: class AlbumSerializer(serializers.ModelSerializer):\n class Meta:\n fields = ('tracks', ...) You'll normally want to ensure that you've set an appropriate related_name argument on the relationship, that you can use as the field name. For example: class Track(models.Model):\n album = models.ForeignKey(Album, related_name='tracks')\n ... If you have not set a related name for the reverse relationship, you'll need to use the automatically generated related name in the fields argument. For example: class AlbumSerializer(serializers.ModelSerializer):\n class Meta:\n fields = ('track_set', ...) See the Django documentation on reverse relationships for more details.",
+ "text": "Note that reverse relationships are not automatically included by the ModelSerializer and HyperlinkedModelSerializer classes. To include a reverse relationship, you must explicitly add it to the fields list. For example: class AlbumSerializer(serializers.ModelSerializer):\n class Meta:\n fields = ('tracks', ...) You'll normally want to ensure that you've set an appropriate related_name argument on the relationship, that you can use as the field name. For example: class Track(models.Model):\n album = models.ForeignKey(Album, related_name='tracks', on_delete=models.CASCADE)\n ... If you have not set a related name for the reverse relationship, you'll need to use the automatically generated related name in the fields argument. For example: class AlbumSerializer(serializers.ModelSerializer):\n class Meta:\n fields = ('track_set', ...) See the Django documentation on reverse relationships for more details.",
"title": "Reverse relations"
},
{
"location": "/api-guide/relations/#generic-relationships",
- "text": "If you want to serialize a generic foreign key, you need to define a custom field, to determine explicitly how you want to serialize the targets of the relationship. For example, given the following model for a tag, which has a generic relationship with other arbitrary models: class TaggedItem(models.Model):\n \"\"\"\n Tags arbitrary model instances using a generic relation.\n\n See: https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/\n \"\"\"\n tag_name = models.SlugField()\n content_type = models.ForeignKey(ContentType)\n object_id = models.PositiveIntegerField()\n tagged_object = GenericForeignKey('content_type', 'object_id')\n\n def __unicode__(self):\n return self.tag_name And the following two models, which may have associated tags: class Bookmark(models.Model):\n \"\"\"\n A bookmark consists of a URL, and 0 or more descriptive tags.\n \"\"\"\n url = models.URLField()\n tags = GenericRelation(TaggedItem)\n\n\nclass Note(models.Model):\n \"\"\"\n A note consists of some text, and 0 or more descriptive tags.\n \"\"\"\n text = models.CharField(max_length=1000)\n tags = GenericRelation(TaggedItem) We could define a custom field that could be used to serialize tagged instances, using the type of each instance to determine how it should be serialized. class TaggedObjectRelatedField(serializers.RelatedField):\n \"\"\"\n A custom field to use for the `tagged_object` generic relationship.\n \"\"\"\n\n def to_representation(self, value):\n \"\"\"\n Serialize tagged objects to a simple textual representation.\n \"\"\"\n if isinstance(value, Bookmark):\n return 'Bookmark: ' + value.url\n elif isinstance(value, Note):\n return 'Note: ' + value.text\n raise Exception('Unexpected type of tagged object') If you need the target of the relationship to have a nested representation, you can use the required serializers inside the .to_representation() method: def to_representation(self, value):\n \"\"\"\n Serialize bookmark instances using a bookmark serializer,\n and note instances using a note serializer.\n \"\"\"\n if isinstance(value, Bookmark):\n serializer = BookmarkSerializer(value)\n elif isinstance(value, Note):\n serializer = NoteSerializer(value)\n else:\n raise Exception('Unexpected type of tagged object')\n\n return serializer.data Note that reverse generic keys, expressed using the GenericRelation field, can be serialized using the regular relational field types, since the type of the target in the relationship is always known. For more information see the Django documentation on generic relations .",
+ "text": "If you want to serialize a generic foreign key, you need to define a custom field, to determine explicitly how you want to serialize the targets of the relationship. For example, given the following model for a tag, which has a generic relationship with other arbitrary models: class TaggedItem(models.Model):\n \"\"\"\n Tags arbitrary model instances using a generic relation.\n\n See: https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/\n \"\"\"\n tag_name = models.SlugField()\n content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)\n object_id = models.PositiveIntegerField()\n tagged_object = GenericForeignKey('content_type', 'object_id')\n\n def __unicode__(self):\n return self.tag_name And the following two models, which may have associated tags: class Bookmark(models.Model):\n \"\"\"\n A bookmark consists of a URL, and 0 or more descriptive tags.\n \"\"\"\n url = models.URLField()\n tags = GenericRelation(TaggedItem)\n\n\nclass Note(models.Model):\n \"\"\"\n A note consists of some text, and 0 or more descriptive tags.\n \"\"\"\n text = models.CharField(max_length=1000)\n tags = GenericRelation(TaggedItem) We could define a custom field that could be used to serialize tagged instances, using the type of each instance to determine how it should be serialized. class TaggedObjectRelatedField(serializers.RelatedField):\n \"\"\"\n A custom field to use for the `tagged_object` generic relationship.\n \"\"\"\n\n def to_representation(self, value):\n \"\"\"\n Serialize tagged objects to a simple textual representation.\n \"\"\"\n if isinstance(value, Bookmark):\n return 'Bookmark: ' + value.url\n elif isinstance(value, Note):\n return 'Note: ' + value.text\n raise Exception('Unexpected type of tagged object') If you need the target of the relationship to have a nested representation, you can use the required serializers inside the .to_representation() method: def to_representation(self, value):\n \"\"\"\n Serialize bookmark instances using a bookmark serializer,\n and note instances using a note serializer.\n \"\"\"\n if isinstance(value, Bookmark):\n serializer = BookmarkSerializer(value)\n elif isinstance(value, Note):\n serializer = NoteSerializer(value)\n else:\n raise Exception('Unexpected type of tagged object')\n\n return serializer.data Note that reverse generic keys, expressed using the GenericRelation field, can be serialized using the regular relational field types, since the type of the target in the relationship is always known. For more information see the Django documentation on generic relations .",
"title": "Generic relationships"
},
{
@@ -2737,7 +2737,7 @@
},
{
"location": "/api-guide/pagination/",
- "text": "Pagination\n\n\n\n\nDjango provides a few classes that help you manage paginated data \u2013 that is, data that\u2019s split across several pages, with \u201cPrevious/Next\u201d links.\n\n\n \nDjango documentation\n\n\n\n\nREST framework includes support for customizable pagination styles. This allows you to modify how large result sets are split into individual pages of data.\n\n\nThe pagination API can support either:\n\n\n\n\nPagination links that are provided as part of the content of the response.\n\n\nPagination links that are included in response headers, such as \nContent-Range\n or \nLink\n.\n\n\n\n\nThe built-in styles currently all use links included as part of the content of the response. This style is more accessible when using the browsable API.\n\n\nPagination is only performed automatically if you're using the generic views or viewsets. If you're using a regular \nAPIView\n, you'll need to call into the pagination API yourself to ensure you return a paginated response. See the source code for the \nmixins.ListModelMixin\n and \ngenerics.GenericAPIView\n classes for an example.\n\n\nPagination can be turned off by setting the pagination class to \nNone\n.\n\n\nSetting the pagination style\n\n\nThe default pagination style may be set globally, using the \nDEFAULT_PAGINATION_CLASS\n and \nPAGE_SIZE\n setting keys. For example, to use the built-in limit/offset pagination, you would do something like this:\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',\n 'PAGE_SIZE': 100\n}\n\n\n\nNote that you need to set both the pagination class, and the page size that should be used.\n\n\nYou can also set the pagination class on an individual view by using the \npagination_class\n attribute. Typically you'll want to use the same pagination style throughout your API, although you might want to vary individual aspects of the pagination, such as default or maximum page size, on a per-view basis.\n\n\nModifying the pagination style\n\n\nIf you want to modify particular aspects of the pagination style, you'll want to override one of the pagination classes, and set the attributes that you want to change.\n\n\nclass LargeResultsSetPagination(PageNumberPagination):\n page_size = 1000\n page_size_query_param = 'page_size'\n max_page_size = 10000\n\nclass StandardResultsSetPagination(PageNumberPagination):\n page_size = 100\n page_size_query_param = 'page_size'\n max_page_size = 1000\n\n\n\nYou can then apply your new style to a view using the \n.pagination_class\n attribute:\n\n\nclass BillingRecordsView(generics.ListAPIView):\n queryset = Billing.objects.all()\n serializer_class = BillingRecordsSerializer\n pagination_class = LargeResultsSetPagination\n\n\n\nOr apply the style globally, using the \nDEFAULT_PAGINATION_CLASS\n settings key. For example:\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.StandardResultsSetPagination'\n}\n\n\n\n\n\nAPI Reference\n\n\nPageNumberPagination\n\n\nThis pagination style accepts a single number page number in the request query parameters.\n\n\nRequest\n:\n\n\nGET https://api.example.org/accounts/?page=4\n\n\n\nResponse\n:\n\n\nHTTP 200 OK\n{\n \"count\": 1023\n \"next\": \"https://api.example.org/accounts/?page=5\",\n \"previous\": \"https://api.example.org/accounts/?page=3\",\n \"results\": [\n \u2026\n ]\n}\n\n\n\nSetup\n\n\nTo enable the \nPageNumberPagination\n style globally, use the following configuration, modifying the \nPAGE_SIZE\n as desired:\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',\n 'PAGE_SIZE': 100\n}\n\n\n\nOn \nGenericAPIView\n subclasses you may also set the \npagination_class\n attribute to select \nPageNumberPagination\n on a per-view basis.\n\n\nConfiguration\n\n\nThe \nPageNumberPagination\n class includes a number of attributes that may be overridden to modify the pagination style.\n\n\nTo set these attributes you should override the \nPageNumberPagination\n class, and then enable your custom pagination class as above.\n\n\n\n\ndjango_paginator_class\n - The Django Paginator class to use. Default is \ndjango.core.paginator.Paginator\n, which should be fine for most use cases.\n\n\npage_size\n - A numeric value indicating the page size. If set, this overrides the \nPAGE_SIZE\n setting. Defaults to the same value as the \nPAGE_SIZE\n settings key.\n\n\npage_query_param\n - A string value indicating the name of the query parameter to use for the pagination control.\n\n\npage_size_query_param\n - If set, this is a string value indicating the name of a query parameter that allows the client to set the page size on a per-request basis. Defaults to \nNone\n, indicating that the client may not control the requested page size.\n\n\nmax_page_size\n - If set, this is a numeric value indicating the maximum allowable requested page size. This attribute is only valid if \npage_size_query_param\n is also set.\n\n\nlast_page_strings\n - A list or tuple of string values indicating values that may be used with the \npage_query_param\n to request the final page in the set. Defaults to \n('last',)\n\n\ntemplate\n - The name of a template to use when rendering pagination controls in the browsable API. May be overridden to modify the rendering style, or set to \nNone\n to disable HTML pagination controls completely. Defaults to \n\"rest_framework/pagination/numbers.html\"\n.\n\n\n\n\n\n\nLimitOffsetPagination\n\n\nThis pagination style mirrors the syntax used when looking up multiple database records. The client includes both a \"limit\" and an\n\"offset\" query parameter. The limit indicates the maximum number of items to return, and is equivalent to the \npage_size\n in other styles. The offset indicates the starting position of the query in relation to the complete set of unpaginated items.\n\n\nRequest\n:\n\n\nGET https://api.example.org/accounts/?limit=100\noffset=400\n\n\n\nResponse\n:\n\n\nHTTP 200 OK\n{\n \"count\": 1023\n \"next\": \"https://api.example.org/accounts/?limit=100\noffset=500\",\n \"previous\": \"https://api.example.org/accounts/?limit=100\noffset=300\",\n \"results\": [\n \u2026\n ]\n}\n\n\n\nSetup\n\n\nTo enable the \nLimitOffsetPagination\n style globally, use the following configuration:\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination'\n}\n\n\n\nOptionally, you may also set a \nPAGE_SIZE\n key. If the \nPAGE_SIZE\n parameter is also used then the \nlimit\n query parameter will be optional, and may be omitted by the client.\n\n\nOn \nGenericAPIView\n subclasses you may also set the \npagination_class\n attribute to select \nLimitOffsetPagination\n on a per-view basis.\n\n\nConfiguration\n\n\nThe \nLimitOffsetPagination\n class includes a number of attributes that may be overridden to modify the pagination style.\n\n\nTo set these attributes you should override the \nLimitOffsetPagination\n class, and then enable your custom pagination class as above.\n\n\n\n\ndefault_limit\n - A numeric value indicating the limit to use if one is not provided by the client in a query parameter. Defaults to the same value as the \nPAGE_SIZE\n settings key.\n\n\nlimit_query_param\n - A string value indicating the name of the \"limit\" query parameter. Defaults to \n'limit'\n.\n\n\noffset_query_param\n - A string value indicating the name of the \"offset\" query parameter. Defaults to \n'offset'\n.\n\n\nmax_limit\n - If set this is a numeric value indicating the maximum allowable limit that may be requested by the client. Defaults to \nNone\n.\n\n\ntemplate\n - The name of a template to use when rendering pagination controls in the browsable API. May be overridden to modify the rendering style, or set to \nNone\n to disable HTML pagination controls completely. Defaults to \n\"rest_framework/pagination/numbers.html\"\n.\n\n\n\n\n\n\nCursorPagination\n\n\nThe cursor-based pagination presents an opaque \"cursor\" indicator that the client may use to page through the result set. This pagination style only presents forward and reverse controls, and does not allow the client to navigate to arbitrary positions.\n\n\nCursor based pagination requires that there is a unique, unchanging ordering of items in the result set. This ordering might typically be a creation timestamp on the records, as this presents a consistent ordering to paginate against.\n\n\nCursor based pagination is more complex than other schemes. It also requires that the result set presents a fixed ordering, and does not allow the client to arbitrarily index into the result set. However it does provide the following benefits:\n\n\n\n\nProvides a consistent pagination view. When used properly \nCursorPagination\n ensures that the client will never see the same item twice when paging through records, even when new items are being inserted by other clients during the pagination process.\n\n\nSupports usage with very large datasets. With extremely large datasets pagination using offset-based pagination styles may become inefficient or unusable. Cursor based pagination schemes instead have fixed-time properties, and do not slow down as the dataset size increases.\n\n\n\n\nDetails and limitations\n\n\nProper use of cursor based pagination requires a little attention to detail. You'll need to think about what ordering you want the scheme to be applied against. The default is to order by \n\"-created\"\n. This assumes that \nthere must be a 'created' timestamp field\n on the model instances, and will present a \"timeline\" style paginated view, with the most recently added items first.\n\n\nYou can modify the ordering by overriding the \n'ordering'\n attribute on the pagination class, or by using the \nOrderingFilter\n filter class together with \nCursorPagination\n. When used with \nOrderingFilter\n you should strongly consider restricting the fields that the user may order by.\n\n\nProper usage of cursor pagination should have an ordering field that satisfies the following:\n\n\n\n\nShould be an unchanging value, such as a timestamp, slug, or other field that is only set once, on creation.\n\n\nShould be unique, or nearly unique. Millisecond precision timestamps are a good example. This implementation of cursor pagination uses a smart \"position plus offset\" style that allows it to properly support not-strictly-unique values as the ordering.\n\n\nShould be a non-nullable value that can be coerced to a string.\n\n\nThe field should have a database index.\n\n\n\n\nUsing an ordering field that does not satisfy these constraints will generally still work, but you'll be losing some of the benefits of cursor pagination.\n\n\nFor more technical details on the implementation we use for cursor pagination, the \n\"Building cursors for the Disqus API\"\n blog post gives a good overview of the basic approach.\n\n\nSetup\n\n\nTo enable the \nCursorPagination\n style globally, use the following configuration, modifying the \nPAGE_SIZE\n as desired:\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.CursorPagination',\n 'PAGE_SIZE': 100\n}\n\n\n\nOn \nGenericAPIView\n subclasses you may also set the \npagination_class\n attribute to select \nCursorPagination\n on a per-view basis.\n\n\nConfiguration\n\n\nThe \nCursorPagination\n class includes a number of attributes that may be overridden to modify the pagination style.\n\n\nTo set these attributes you should override the \nCursorPagination\n class, and then enable your custom pagination class as above.\n\n\n\n\npage_size\n = A numeric value indicating the page size. If set, this overrides the \nPAGE_SIZE\n setting. Defaults to the same value as the \nPAGE_SIZE\n settings key.\n\n\ncursor_query_param\n = A string value indicating the name of the \"cursor\" query parameter. Defaults to \n'cursor'\n.\n\n\nordering\n = This should be a string, or list of strings, indicating the field against which the cursor based pagination will be applied. For example: \nordering = 'slug'\n. Defaults to \n-created\n. This value may also be overridden by using \nOrderingFilter\n on the view.\n\n\ntemplate\n = The name of a template to use when rendering pagination controls in the browsable API. May be overridden to modify the rendering style, or set to \nNone\n to disable HTML pagination controls completely. Defaults to \n\"rest_framework/pagination/previous_and_next.html\"\n.\n\n\n\n\n\n\nCustom pagination styles\n\n\nTo create a custom pagination serializer class you should subclass \npagination.BasePagination\n and override the \npaginate_queryset(self, queryset, request, view=None)\n and \nget_paginated_response(self, data)\n methods:\n\n\n\n\nThe \npaginate_queryset\n method is passed the initial queryset and should return an iterable object that contains only the data in the requested page.\n\n\nThe \nget_paginated_response\n method is passed the serialized page data and should return a \nResponse\n instance.\n\n\n\n\nNote that the \npaginate_queryset\n method may set state on the pagination instance, that may later be used by the \nget_paginated_response\n method.\n\n\nExample\n\n\nSuppose we want to replace the default pagination output style with a modified format that includes the next and previous links under in a nested 'links' key. We could specify a custom pagination class like so:\n\n\nclass CustomPagination(pagination.PageNumberPagination):\n def get_paginated_response(self, data):\n return Response({\n 'links': {\n 'next': self.get_next_link(),\n 'previous': self.get_previous_link()\n },\n 'count': self.page.paginator.count,\n 'results': data\n })\n\n\n\nWe'd then need to setup the custom class in our configuration:\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.CustomPagination',\n 'PAGE_SIZE': 100\n}\n\n\n\nNote that if you care about how the ordering of keys is displayed in responses in the browsable API you might choose to use an \nOrderedDict\n when constructing the body of paginated responses, but this is optional.\n\n\nHeader based pagination\n\n\nLet's modify the built-in \nPageNumberPagination\n style, so that instead of include the pagination links in the body of the response, we'll instead include a \nLink\n header, in a \nsimilar style to the GitHub API\n.\n\n\nclass LinkHeaderPagination(pagination.PageNumberPagination):\n def get_paginated_response(self, data):\n next_url = self.get_next_link()\n previous_url = self.get_previous_link()\n\n if next_url is not None and previous_url is not None:\n link = '\n{next_url}\n; rel=\"next\", \n{previous_url}\n; rel=\"prev\"'\n elif next_url is not None:\n link = '\n{next_url}\n; rel=\"next\"'\n elif previous_url is not None:\n link = '\n{previous_url}\n; rel=\"prev\"'\n else:\n link = ''\n\n link = link.format(next_url=next_url, previous_url=previous_url)\n headers = {'Link': link} if link else {}\n\n return Response(data, headers=headers)\n\n\n\nUsing your custom pagination class\n\n\nTo have your custom pagination class be used by default, use the \nDEFAULT_PAGINATION_CLASS\n setting:\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.LinkHeaderPagination',\n 'PAGE_SIZE': 100\n}\n\n\n\nAPI responses for list endpoints will now include a \nLink\n header, instead of including the pagination links as part of the body of the response, for example:\n\n\nPagination \n schemas\n\n\nYou can also make the pagination controls available to the schema autogeneration\nthat REST framework provides, by implementing a \nget_schema_fields()\n method,\nwhich should return a list of \ncoreapi.Field\n instances.\n\n\n\n\n\n\nA custom pagination style, using the 'Link' header'\n\n\n\n\nHTML pagination controls\n\n\nBy default using the pagination classes will cause HTML pagination controls to be displayed in the browsable API. There are two built-in display styles. The \nPageNumberPagination\n and \nLimitOffsetPagination\n classes display a list of page numbers with previous and next controls. The \nCursorPagination\n class displays a simpler style that only displays a previous and next control.\n\n\nCustomizing the controls\n\n\nYou can override the templates that render the HTML pagination controls. The two built-in styles are:\n\n\n\n\nrest_framework/pagination/numbers.html\n\n\nrest_framework/pagination/previous_and_next.html\n\n\n\n\nProviding a template with either of these paths in a global template directory will override the default rendering for the relevant pagination classes.\n\n\nAlternatively you can disable HTML pagination controls completely by subclassing on of the existing classes, setting \ntemplate = None\n as an attribute on the class. You'll then need to configure your \nDEFAULT_PAGINATION_CLASS\n settings key to use your custom class as the default pagination style.\n\n\nLow-level API\n\n\nThe low-level API for determining if a pagination class should display the controls or not is exposed as a \ndisplay_page_controls\n attribute on the pagination instance. Custom pagination classes should be set to \nTrue\n in the \npaginate_queryset\n method if they require the HTML pagination controls to be displayed.\n\n\nThe \n.to_html()\n and \n.get_html_context()\n methods may also be overridden in a custom pagination class in order to further customize how the controls are rendered.\n\n\n\n\nThird party packages\n\n\nThe following third party packages are also available.\n\n\nDRF-extensions\n\n\nThe \nDRF-extensions\n package\n includes a \nPaginateByMaxMixin\n mixin class\n that allows your API clients to specify \n?page_size=max\n to obtain the maximum allowed page size.",
+ "text": "Pagination\n\n\n\n\nDjango provides a few classes that help you manage paginated data \u2013 that is, data that\u2019s split across several pages, with \u201cPrevious/Next\u201d links.\n\n\n \nDjango documentation\n\n\n\n\nREST framework includes support for customizable pagination styles. This allows you to modify how large result sets are split into individual pages of data.\n\n\nThe pagination API can support either:\n\n\n\n\nPagination links that are provided as part of the content of the response.\n\n\nPagination links that are included in response headers, such as \nContent-Range\n or \nLink\n.\n\n\n\n\nThe built-in styles currently all use links included as part of the content of the response. This style is more accessible when using the browsable API.\n\n\nPagination is only performed automatically if you're using the generic views or viewsets. If you're using a regular \nAPIView\n, you'll need to call into the pagination API yourself to ensure you return a paginated response. See the source code for the \nmixins.ListModelMixin\n and \ngenerics.GenericAPIView\n classes for an example.\n\n\nPagination can be turned off by setting the pagination class to \nNone\n.\n\n\nSetting the pagination style\n\n\nThe default pagination style may be set globally, using the \nDEFAULT_PAGINATION_CLASS\n and \nPAGE_SIZE\n setting keys. For example, to use the built-in limit/offset pagination, you would do something like this:\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',\n 'PAGE_SIZE': 100\n}\n\n\n\nNote that you need to set both the pagination class, and the page size that should be used.\n\n\nYou can also set the pagination class on an individual view by using the \npagination_class\n attribute. Typically you'll want to use the same pagination style throughout your API, although you might want to vary individual aspects of the pagination, such as default or maximum page size, on a per-view basis.\n\n\nModifying the pagination style\n\n\nIf you want to modify particular aspects of the pagination style, you'll want to override one of the pagination classes, and set the attributes that you want to change.\n\n\nclass LargeResultsSetPagination(PageNumberPagination):\n page_size = 1000\n page_size_query_param = 'page_size'\n max_page_size = 10000\n\nclass StandardResultsSetPagination(PageNumberPagination):\n page_size = 100\n page_size_query_param = 'page_size'\n max_page_size = 1000\n\n\n\nYou can then apply your new style to a view using the \n.pagination_class\n attribute:\n\n\nclass BillingRecordsView(generics.ListAPIView):\n queryset = Billing.objects.all()\n serializer_class = BillingRecordsSerializer\n pagination_class = LargeResultsSetPagination\n\n\n\nOr apply the style globally, using the \nDEFAULT_PAGINATION_CLASS\n settings key. For example:\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.StandardResultsSetPagination'\n}\n\n\n\n\n\nAPI Reference\n\n\nPageNumberPagination\n\n\nThis pagination style accepts a single number page number in the request query parameters.\n\n\nRequest\n:\n\n\nGET https://api.example.org/accounts/?page=4\n\n\n\nResponse\n:\n\n\nHTTP 200 OK\n{\n \"count\": 1023\n \"next\": \"https://api.example.org/accounts/?page=5\",\n \"previous\": \"https://api.example.org/accounts/?page=3\",\n \"results\": [\n \u2026\n ]\n}\n\n\n\nSetup\n\n\nTo enable the \nPageNumberPagination\n style globally, use the following configuration, modifying the \nPAGE_SIZE\n as desired:\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',\n 'PAGE_SIZE': 100\n}\n\n\n\nOn \nGenericAPIView\n subclasses you may also set the \npagination_class\n attribute to select \nPageNumberPagination\n on a per-view basis.\n\n\nConfiguration\n\n\nThe \nPageNumberPagination\n class includes a number of attributes that may be overridden to modify the pagination style.\n\n\nTo set these attributes you should override the \nPageNumberPagination\n class, and then enable your custom pagination class as above.\n\n\n\n\ndjango_paginator_class\n - The Django Paginator class to use. Default is \ndjango.core.paginator.Paginator\n, which should be fine for most use cases.\n\n\npage_size\n - A numeric value indicating the page size. If set, this overrides the \nPAGE_SIZE\n setting. Defaults to the same value as the \nPAGE_SIZE\n settings key.\n\n\npage_query_param\n - A string value indicating the name of the query parameter to use for the pagination control.\n\n\npage_size_query_param\n - If set, this is a string value indicating the name of a query parameter that allows the client to set the page size on a per-request basis. Defaults to \nNone\n, indicating that the client may not control the requested page size.\n\n\nmax_page_size\n - If set, this is a numeric value indicating the maximum allowable requested page size. This attribute is only valid if \npage_size_query_param\n is also set.\n\n\nlast_page_strings\n - A list or tuple of string values indicating values that may be used with the \npage_query_param\n to request the final page in the set. Defaults to \n('last',)\n\n\ntemplate\n - The name of a template to use when rendering pagination controls in the browsable API. May be overridden to modify the rendering style, or set to \nNone\n to disable HTML pagination controls completely. Defaults to \n\"rest_framework/pagination/numbers.html\"\n.\n\n\n\n\n\n\nLimitOffsetPagination\n\n\nThis pagination style mirrors the syntax used when looking up multiple database records. The client includes both a \"limit\" and an\n\"offset\" query parameter. The limit indicates the maximum number of items to return, and is equivalent to the \npage_size\n in other styles. The offset indicates the starting position of the query in relation to the complete set of unpaginated items.\n\n\nRequest\n:\n\n\nGET https://api.example.org/accounts/?limit=100\noffset=400\n\n\n\nResponse\n:\n\n\nHTTP 200 OK\n{\n \"count\": 1023\n \"next\": \"https://api.example.org/accounts/?limit=100\noffset=500\",\n \"previous\": \"https://api.example.org/accounts/?limit=100\noffset=300\",\n \"results\": [\n \u2026\n ]\n}\n\n\n\nSetup\n\n\nTo enable the \nLimitOffsetPagination\n style globally, use the following configuration:\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination'\n}\n\n\n\nOptionally, you may also set a \nPAGE_SIZE\n key. If the \nPAGE_SIZE\n parameter is also used then the \nlimit\n query parameter will be optional, and may be omitted by the client.\n\n\nOn \nGenericAPIView\n subclasses you may also set the \npagination_class\n attribute to select \nLimitOffsetPagination\n on a per-view basis.\n\n\nConfiguration\n\n\nThe \nLimitOffsetPagination\n class includes a number of attributes that may be overridden to modify the pagination style.\n\n\nTo set these attributes you should override the \nLimitOffsetPagination\n class, and then enable your custom pagination class as above.\n\n\n\n\ndefault_limit\n - A numeric value indicating the limit to use if one is not provided by the client in a query parameter. Defaults to the same value as the \nPAGE_SIZE\n settings key.\n\n\nlimit_query_param\n - A string value indicating the name of the \"limit\" query parameter. Defaults to \n'limit'\n.\n\n\noffset_query_param\n - A string value indicating the name of the \"offset\" query parameter. Defaults to \n'offset'\n.\n\n\nmax_limit\n - If set this is a numeric value indicating the maximum allowable limit that may be requested by the client. Defaults to \nNone\n.\n\n\ntemplate\n - The name of a template to use when rendering pagination controls in the browsable API. May be overridden to modify the rendering style, or set to \nNone\n to disable HTML pagination controls completely. Defaults to \n\"rest_framework/pagination/numbers.html\"\n.\n\n\n\n\n\n\nCursorPagination\n\n\nThe cursor-based pagination presents an opaque \"cursor\" indicator that the client may use to page through the result set. This pagination style only presents forward and reverse controls, and does not allow the client to navigate to arbitrary positions.\n\n\nCursor based pagination requires that there is a unique, unchanging ordering of items in the result set. This ordering might typically be a creation timestamp on the records, as this presents a consistent ordering to paginate against.\n\n\nCursor based pagination is more complex than other schemes. It also requires that the result set presents a fixed ordering, and does not allow the client to arbitrarily index into the result set. However it does provide the following benefits:\n\n\n\n\nProvides a consistent pagination view. When used properly \nCursorPagination\n ensures that the client will never see the same item twice when paging through records, even when new items are being inserted by other clients during the pagination process.\n\n\nSupports usage with very large datasets. With extremely large datasets pagination using offset-based pagination styles may become inefficient or unusable. Cursor based pagination schemes instead have fixed-time properties, and do not slow down as the dataset size increases.\n\n\n\n\nDetails and limitations\n\n\nProper use of cursor based pagination requires a little attention to detail. You'll need to think about what ordering you want the scheme to be applied against. The default is to order by \n\"-created\"\n. This assumes that \nthere must be a 'created' timestamp field\n on the model instances, and will present a \"timeline\" style paginated view, with the most recently added items first.\n\n\nYou can modify the ordering by overriding the \n'ordering'\n attribute on the pagination class, or by using the \nOrderingFilter\n filter class together with \nCursorPagination\n. When used with \nOrderingFilter\n you should strongly consider restricting the fields that the user may order by.\n\n\nProper usage of cursor pagination should have an ordering field that satisfies the following:\n\n\n\n\nShould be an unchanging value, such as a timestamp, slug, or other field that is only set once, on creation.\n\n\nShould be unique, or nearly unique. Millisecond precision timestamps are a good example. This implementation of cursor pagination uses a smart \"position plus offset\" style that allows it to properly support not-strictly-unique values as the ordering.\n\n\nShould be a non-nullable value that can be coerced to a string.\n\n\nThe field should have a database index.\n\n\n\n\nUsing an ordering field that does not satisfy these constraints will generally still work, but you'll be losing some of the benefits of cursor pagination.\n\n\nFor more technical details on the implementation we use for cursor pagination, the \n\"Building cursors for the Disqus API\"\n blog post gives a good overview of the basic approach.\n\n\nSetup\n\n\nTo enable the \nCursorPagination\n style globally, use the following configuration, modifying the \nPAGE_SIZE\n as desired:\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.CursorPagination',\n 'PAGE_SIZE': 100\n}\n\n\n\nOn \nGenericAPIView\n subclasses you may also set the \npagination_class\n attribute to select \nCursorPagination\n on a per-view basis.\n\n\nConfiguration\n\n\nThe \nCursorPagination\n class includes a number of attributes that may be overridden to modify the pagination style.\n\n\nTo set these attributes you should override the \nCursorPagination\n class, and then enable your custom pagination class as above.\n\n\n\n\npage_size\n = A numeric value indicating the page size. If set, this overrides the \nPAGE_SIZE\n setting. Defaults to the same value as the \nPAGE_SIZE\n settings key.\n\n\ncursor_query_param\n = A string value indicating the name of the \"cursor\" query parameter. Defaults to \n'cursor'\n.\n\n\nordering\n = This should be a string, or list of strings, indicating the field against which the cursor based pagination will be applied. For example: \nordering = 'slug'\n. Defaults to \n-created\n. This value may also be overridden by using \nOrderingFilter\n on the view.\n\n\ntemplate\n = The name of a template to use when rendering pagination controls in the browsable API. May be overridden to modify the rendering style, or set to \nNone\n to disable HTML pagination controls completely. Defaults to \n\"rest_framework/pagination/previous_and_next.html\"\n.\n\n\n\n\n\n\nCustom pagination styles\n\n\nTo create a custom pagination serializer class you should subclass \npagination.BasePagination\n and override the \npaginate_queryset(self, queryset, request, view=None)\n and \nget_paginated_response(self, data)\n methods:\n\n\n\n\nThe \npaginate_queryset\n method is passed the initial queryset and should return an iterable object that contains only the data in the requested page.\n\n\nThe \nget_paginated_response\n method is passed the serialized page data and should return a \nResponse\n instance.\n\n\n\n\nNote that the \npaginate_queryset\n method may set state on the pagination instance, that may later be used by the \nget_paginated_response\n method.\n\n\nExample\n\n\nSuppose we want to replace the default pagination output style with a modified format that includes the next and previous links under in a nested 'links' key. We could specify a custom pagination class like so:\n\n\nclass CustomPagination(pagination.PageNumberPagination):\n def get_paginated_response(self, data):\n return Response({\n 'links': {\n 'next': self.get_next_link(),\n 'previous': self.get_previous_link()\n },\n 'count': self.page.paginator.count,\n 'results': data\n })\n\n\n\nWe'd then need to setup the custom class in our configuration:\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.CustomPagination',\n 'PAGE_SIZE': 100\n}\n\n\n\nNote that if you care about how the ordering of keys is displayed in responses in the browsable API you might choose to use an \nOrderedDict\n when constructing the body of paginated responses, but this is optional.\n\n\nHeader based pagination\n\n\nLet's modify the built-in \nPageNumberPagination\n style, so that instead of include the pagination links in the body of the response, we'll instead include a \nLink\n header, in a \nsimilar style to the GitHub API\n.\n\n\nclass LinkHeaderPagination(pagination.PageNumberPagination):\n def get_paginated_response(self, data):\n next_url = self.get_next_link()\n previous_url = self.get_previous_link()\n\n if next_url is not None and previous_url is not None:\n link = '\n{next_url}\n; rel=\"next\", \n{previous_url}\n; rel=\"prev\"'\n elif next_url is not None:\n link = '\n{next_url}\n; rel=\"next\"'\n elif previous_url is not None:\n link = '\n{previous_url}\n; rel=\"prev\"'\n else:\n link = ''\n\n link = link.format(next_url=next_url, previous_url=previous_url)\n headers = {'Link': link} if link else {}\n\n return Response(data, headers=headers)\n\n\n\nUsing your custom pagination class\n\n\nTo have your custom pagination class be used by default, use the \nDEFAULT_PAGINATION_CLASS\n setting:\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.LinkHeaderPagination',\n 'PAGE_SIZE': 100\n}\n\n\n\nAPI responses for list endpoints will now include a \nLink\n header, instead of including the pagination links as part of the body of the response, for example:\n\n\nPagination \n schemas\n\n\nYou can also make the pagination controls available to the schema autogeneration\nthat REST framework provides, by implementing a \nget_schema_fields()\n method,\nwhich should return a list of \ncoreapi.Field\n instances.\n\n\n\n\n\n\nA custom pagination style, using the 'Link' header'\n\n\n\n\nHTML pagination controls\n\n\nBy default using the pagination classes will cause HTML pagination controls to be displayed in the browsable API. There are two built-in display styles. The \nPageNumberPagination\n and \nLimitOffsetPagination\n classes display a list of page numbers with previous and next controls. The \nCursorPagination\n class displays a simpler style that only displays a previous and next control.\n\n\nCustomizing the controls\n\n\nYou can override the templates that render the HTML pagination controls. The two built-in styles are:\n\n\n\n\nrest_framework/pagination/numbers.html\n\n\nrest_framework/pagination/previous_and_next.html\n\n\n\n\nProviding a template with either of these paths in a global template directory will override the default rendering for the relevant pagination classes.\n\n\nAlternatively you can disable HTML pagination controls completely by subclassing on of the existing classes, setting \ntemplate = None\n as an attribute on the class. You'll then need to configure your \nDEFAULT_PAGINATION_CLASS\n settings key to use your custom class as the default pagination style.\n\n\nLow-level API\n\n\nThe low-level API for determining if a pagination class should display the controls or not is exposed as a \ndisplay_page_controls\n attribute on the pagination instance. Custom pagination classes should be set to \nTrue\n in the \npaginate_queryset\n method if they require the HTML pagination controls to be displayed.\n\n\nThe \n.to_html()\n and \n.get_html_context()\n methods may also be overridden in a custom pagination class in order to further customize how the controls are rendered.\n\n\n\n\nThird party packages\n\n\nThe following third party packages are also available.\n\n\nDRF-extensions\n\n\nThe \nDRF-extensions\n package\n includes a \nPaginateByMaxMixin\n mixin class\n that allows your API clients to specify \n?page_size=max\n to obtain the maximum allowed page size.\n\n\ndrf-proxy-pagination\n\n\nThe \ndrf-proxy-pagination\n package\n includes a \nProxyPagination\n class which allows to choose pagination class with a query parameter.",
"title": "Pagination"
},
{
@@ -2860,6 +2860,11 @@
"text": "The DRF-extensions package includes a PaginateByMaxMixin mixin class that allows your API clients to specify ?page_size=max to obtain the maximum allowed page size.",
"title": "DRF-extensions"
},
+ {
+ "location": "/api-guide/pagination/#drf-proxy-pagination",
+ "text": "The drf-proxy-pagination package includes a ProxyPagination class which allows to choose pagination class with a query parameter.",
+ "title": "drf-proxy-pagination"
+ },
{
"location": "/api-guide/versioning/",
"text": "Versioning\n\n\n\n\nVersioning an interface is just a \"polite\" way to kill deployed clients.\n\n\n \nRoy Fielding\n.\n\n\n\n\nAPI versioning allows you to alter behavior between different clients. REST framework provides for a number of different versioning schemes.\n\n\nVersioning is determined by the incoming client request, and may either be based on the request URL, or based on the request headers.\n\n\nThere are a number of valid approaches to approaching versioning. \nNon-versioned systems can also be appropriate\n, particularly if you're engineering for very long-term systems with multiple clients outside of your control.\n\n\nVersioning with REST framework\n\n\nWhen API versioning is enabled, the \nrequest.version\n attribute will contain a string that corresponds to the version requested in the incoming client request.\n\n\nBy default, versioning is not enabled, and \nrequest.version\n will always return \nNone\n.\n\n\nVarying behavior based on the version\n\n\nHow you vary the API behavior is up to you, but one example you might typically want is to switch to a different serialization style in a newer version. For example:\n\n\ndef get_serializer_class(self):\n if self.request.version == 'v1':\n return AccountSerializerVersion1\n return AccountSerializer\n\n\n\nReversing URLs for versioned APIs\n\n\nThe \nreverse\n function included by REST framework ties in with the versioning scheme. You need to make sure to include the current \nrequest\n as a keyword argument, like so.\n\n\nfrom rest_framework.reverse import reverse\n\nreverse('bookings-list', request=request)\n\n\n\nThe above function will apply any URL transformations appropriate to the request version. For example:\n\n\n\n\nIf \nNamespacedVersioning\n was being used, and the API version was 'v1', then the URL lookup used would be \n'v1:bookings-list'\n, which might resolve to a URL like \nhttp://example.org/v1/bookings/\n.\n\n\nIf \nQueryParameterVersioning\n was being used, and the API version was \n1.0\n, then the returned URL might be something like \nhttp://example.org/bookings/?version=1.0\n\n\n\n\nVersioned APIs and hyperlinked serializers\n\n\nWhen using hyperlinked serialization styles together with a URL based versioning scheme make sure to include the request as context to the serializer.\n\n\ndef get(self, request):\n queryset = Booking.objects.all()\n serializer = BookingsSerializer(queryset, many=True, context={'request': request})\n return Response({'all_bookings': serializer.data})\n\n\n\nDoing so will allow any returned URLs to include the appropriate versioning.\n\n\nConfiguring the versioning scheme\n\n\nThe versioning scheme is defined by the \nDEFAULT_VERSIONING_CLASS\n settings key.\n\n\nREST_FRAMEWORK = {\n 'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.NamespaceVersioning'\n}\n\n\n\nUnless it is explicitly set, the value for \nDEFAULT_VERSIONING_CLASS\n will be \nNone\n. In this case the \nrequest.version\n attribute will always return \nNone\n.\n\n\nYou can also set the versioning scheme on an individual view. Typically you won't need to do this, as it makes more sense to have a single versioning scheme used globally. If you do need to do so, use the \nversioning_class\n attribute.\n\n\nclass ProfileList(APIView):\n versioning_class = versioning.QueryParameterVersioning\n\n\n\nOther versioning settings\n\n\nThe following settings keys are also used to control versioning:\n\n\n\n\nDEFAULT_VERSION\n. The value that should be used for \nrequest.version\n when no versioning information is present. Defaults to \nNone\n.\n\n\nALLOWED_VERSIONS\n. If set, this value will restrict the set of versions that may be returned by the versioning scheme, and will raise an error if the provided version is not in this set. Note that the value used for the \nDEFAULT_VERSION\n setting is always considered to be part of the \nALLOWED_VERSIONS\n set (unless it is \nNone\n). Defaults to \nNone\n.\n\n\nVERSION_PARAM\n. The string that should be used for any versioning parameters, such as in the media type or URL query parameters. Defaults to \n'version'\n.\n\n\n\n\nYou can also set your versioning class plus those three values on a per-view or a per-viewset basis by defining your own versioning scheme and using the \ndefault_version\n, \nallowed_versions\n and \nversion_param\n class variables. For example, if you want to use \nURLPathVersioning\n:\n\n\nfrom rest_framework.versioning import URLPathVersioning\nfrom rest_framework.views import APIView\n\nclass ExampleVersioning(URLPathVersioning):\n default_version = ...\n allowed_versions = ...\n version_param = ...\n\nclass ExampleView(APIVIew):\n versioning_class = ExampleVersioning\n\n\n\n\n\nAPI Reference\n\n\nAcceptHeaderVersioning\n\n\nThis scheme requires the client to specify the version as part of the media type in the \nAccept\n header. The version is included as a media type parameter, that supplements the main media type.\n\n\nHere's an example HTTP request using the accept header versioning style.\n\n\nGET /bookings/ HTTP/1.1\nHost: example.com\nAccept: application/json; version=1.0\n\n\n\nIn the example request above \nrequest.version\n attribute would return the string \n'1.0'\n.\n\n\nVersioning based on accept headers is \ngenerally considered\n as \nbest practice\n, although other styles may be suitable depending on your client requirements.\n\n\nUsing accept headers with vendor media types\n\n\nStrictly speaking the \njson\n media type is not specified as \nincluding additional parameters\n. If you are building a well-specified public API you might consider using a \nvendor media type\n. To do so, configure your renderers to use a JSON based renderer with a custom media type:\n\n\nclass BookingsAPIRenderer(JSONRenderer):\n media_type = 'application/vnd.megacorp.bookings+json'\n\n\n\nYour client requests would now look like this:\n\n\nGET /bookings/ HTTP/1.1\nHost: example.com\nAccept: application/vnd.megacorp.bookings+json; version=1.0\n\n\n\nURLPathVersioning\n\n\nThis scheme requires the client to specify the version as part of the URL path.\n\n\nGET /v1/bookings/ HTTP/1.1\nHost: example.com\nAccept: application/json\n\n\n\nYour URL conf must include a pattern that matches the version with a \n'version'\n keyword argument, so that this information is available to the versioning scheme.\n\n\nurlpatterns = [\n url(\n r'^(?P\nversion\n(v1|v2))/bookings/$',\n bookings_list,\n name='bookings-list'\n ),\n url(\n r'^(?P\nversion\n(v1|v2))/bookings/(?P\npk\n[0-9]+)/$',\n bookings_detail,\n name='bookings-detail'\n )\n]\n\n\n\nNamespaceVersioning\n\n\nTo the client, this scheme is the same as \nURLPathVersioning\n. The only difference is how it is configured in your Django application, as it uses URL namespacing, instead of URL keyword arguments.\n\n\nGET /v1/something/ HTTP/1.1\nHost: example.com\nAccept: application/json\n\n\n\nWith this scheme the \nrequest.version\n attribute is determined based on the \nnamespace\n that matches the incoming request path.\n\n\nIn the following example we're giving a set of views two different possible URL prefixes, each under a different namespace:\n\n\n# bookings/urls.py\nurlpatterns = [\n url(r'^$', bookings_list, name='bookings-list'),\n url(r'^(?P\npk\n[0-9]+)/$', bookings_detail, name='bookings-detail')\n]\n\n# urls.py\nurlpatterns = [\n url(r'^v1/bookings/', include('bookings.urls', namespace='v1')),\n url(r'^v2/bookings/', include('bookings.urls', namespace='v2'))\n]\n\n\n\nBoth \nURLPathVersioning\n and \nNamespaceVersioning\n are reasonable if you just need a simple versioning scheme. The \nURLPathVersioning\n approach might be better suitable for small ad-hoc projects, and the \nNamespaceVersioning\n is probably easier to manage for larger projects.\n\n\nHostNameVersioning\n\n\nThe hostname versioning scheme requires the client to specify the requested version as part of the hostname in the URL.\n\n\nFor example the following is an HTTP request to the \nhttp://v1.example.com/bookings/\n URL:\n\n\nGET /bookings/ HTTP/1.1\nHost: v1.example.com\nAccept: application/json\n\n\n\nBy default this implementation expects the hostname to match this simple regular expression:\n\n\n^([a-zA-Z0-9]+)\\.[a-zA-Z0-9]+\\.[a-zA-Z0-9]+$\n\n\n\nNote that the first group is enclosed in brackets, indicating that this is the matched portion of the hostname.\n\n\nThe \nHostNameVersioning\n scheme can be awkward to use in debug mode as you will typically be accessing a raw IP address such as \n127.0.0.1\n. There are various online services which you to \naccess localhost with a custom subdomain\n which you may find helpful in this case.\n\n\nHostname based versioning can be particularly useful if you have requirements to route incoming requests to different servers based on the version, as you can configure different DNS records for different API versions.\n\n\nQueryParameterVersioning\n\n\nThis scheme is a simple style that includes the version as a query parameter in the URL. For example:\n\n\nGET /something/?version=0.1 HTTP/1.1\nHost: example.com\nAccept: application/json\n\n\n\n\n\nCustom versioning schemes\n\n\nTo implement a custom versioning scheme, subclass \nBaseVersioning\n and override the \n.determine_version\n method.\n\n\nExample\n\n\nThe following example uses a custom \nX-API-Version\n header to determine the requested version.\n\n\nclass XAPIVersionScheme(versioning.BaseVersioning):\n def determine_version(self, request, *args, **kwargs):\n return request.META.get('HTTP_X_API_VERSION', None)\n\n\n\nIf your versioning scheme is based on the request URL, you will also want to alter how versioned URLs are determined. In order to do so you should override the \n.reverse()\n method on the class. See the source code for examples.",
@@ -3277,7 +3282,7 @@
},
{
"location": "/api-guide/exceptions/",
- "text": "Exceptions\n\n\n\n\nExceptions\u2026 allow error handling to be organized cleanly in a central or high-level place within the program structure.\n\n\n Doug Hellmann, \nPython Exception Handling Techniques\n\n\n\n\nException handling in REST framework views\n\n\nREST framework's views handle various exceptions, and deal with returning appropriate error responses.\n\n\nThe handled exceptions are:\n\n\n\n\nSubclasses of \nAPIException\n raised inside REST framework.\n\n\nDjango's \nHttp404\n exception.\n\n\nDjango's \nPermissionDenied\n exception.\n\n\n\n\nIn each case, REST framework will return a response with an appropriate status code and content-type. The body of the response will include any additional details regarding the nature of the error.\n\n\nMost error responses will include a key \ndetail\n in the body of the response.\n\n\nFor example, the following request:\n\n\nDELETE http://api.example.com/foo/bar HTTP/1.1\nAccept: application/json\n\n\n\nMight receive an error response indicating that the \nDELETE\n method is not allowed on that resource:\n\n\nHTTP/1.1 405 Method Not Allowed\nContent-Type: application/json\nContent-Length: 42\n\n{\"detail\": \"Method 'DELETE' not allowed.\"}\n\n\n\nValidation errors are handled slightly differently, and will include the field names as the keys in the response. If the validation error was not specific to a particular field then it will use the \"non_field_errors\" key, or whatever string value has been set for the \nNON_FIELD_ERRORS_KEY\n setting.\n\n\nAny example validation error might look like this:\n\n\nHTTP/1.1 400 Bad Request\nContent-Type: application/json\nContent-Length: 94\n\n{\"amount\": [\"A valid integer is required.\"], \"description\": [\"This field may not be blank.\"]}\n\n\n\nCustom exception handling\n\n\nYou can implement custom exception handling by creating a handler function that converts exceptions raised in your API views into response objects. This allows you to control the style of error responses used by your API.\n\n\nThe function must take a pair of arguments, this first is the exception to be handled, and the second is a dictionary containing any extra context such as the view currently being handled. The exception handler function should either return a \nResponse\n object, or return \nNone\n if the exception cannot be handled. If the handler returns \nNone\n then the exception will be re-raised and Django will return a standard HTTP 500 'server error' response.\n\n\nFor example, you might want to ensure that all error responses include the HTTP status code in the body of the response, like so:\n\n\nHTTP/1.1 405 Method Not Allowed\nContent-Type: application/json\nContent-Length: 62\n\n{\"status_code\": 405, \"detail\": \"Method 'DELETE' not allowed.\"}\n\n\n\nIn order to alter the style of the response, you could write the following custom exception handler:\n\n\nfrom rest_framework.views import exception_handler\n\ndef custom_exception_handler(exc, context):\n # Call REST framework's default exception handler first,\n # to get the standard error response.\n response = exception_handler(exc, context)\n\n #\u00a0Now add the HTTP status code to the response.\n if response is not None:\n response.data['status_code'] = response.status_code\n\n return response\n\n\n\nThe context argument is not used by the default handler, but can be useful if the exception handler needs further information such as the view currently being handled, which can be accessed as \ncontext['view']\n.\n\n\nThe exception handler must also be configured in your settings, using the \nEXCEPTION_HANDLER\n setting key. For example:\n\n\nREST_FRAMEWORK = {\n 'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler'\n}\n\n\n\nIf not specified, the \n'EXCEPTION_HANDLER'\n setting defaults to the standard exception handler provided by REST framework:\n\n\nREST_FRAMEWORK = {\n 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'\n}\n\n\n\nNote that the exception handler will only be called for responses generated by raised exceptions. It will not be used for any responses returned directly by the view, such as the \nHTTP_400_BAD_REQUEST\n responses that are returned by the generic views when serializer validation fails.\n\n\n\n\nAPI Reference\n\n\nAPIException\n\n\nSignature:\n \nAPIException()\n\n\nThe \nbase class\n for all exceptions raised inside an \nAPIView\n class or \n@api_view\n.\n\n\nTo provide a custom exception, subclass \nAPIException\n and set the \n.status_code\n, \n.default_detail\n, and \ndefault_code\n attributes on the class.\n\n\nFor example, if your API relies on a third party service that may sometimes be unreachable, you might want to implement an exception for the \"503 Service Unavailable\" HTTP response code. You could do this like so:\n\n\nfrom rest_framework.exceptions import APIException\n\nclass ServiceUnavailable(APIException):\n status_code = 503\n default_detail = 'Service temporarily unavailable, try again later.'\n default_code = 'service_unavailable'\n\n\n\nInspecting API exceptions\n\n\nThere are a number of different properties available for inspecting the status\nof an API exception. You can use these to build custom exception handling\nfor your project.\n\n\nThe available attributes and methods are:\n\n\n\n\n.detail\n - Return the textual description of the error.\n\n\n.get_codes()\n - Return the code identifier of the error.\n\n\n.full_details()\n - Return both the textual description and the code identifier.\n\n\n\n\nIn most cases the error detail will be a simple item:\n\n\n print(exc.detail)\nYou do not have permission to perform this action.\n\n print(exc.get_codes())\npermission_denied\n\n print(exc.full_details())\n{'message':'You do not have permission to perform this action.','code':'permission_denied'}\n\n\n\nIn the case of validation errors the error detail will be either a list or\ndictionary of items:\n\n\n print(exc.detail)\n{\"name\":\"This field is required.\",\"age\":\"A valid integer is required.\"}\n\n print(exc.get_codes())\n{\"name\":\"required\",\"age\":\"invalid\"}\n\n print(exc.get_full_details())\n{\"name\":{\"message\":\"This field is required.\",\"code\":\"required\"},\"age\":{\"message\":\"A valid integer is required.\",\"code\":\"invalid\"}}\n\n\n\nParseError\n\n\nSignature:\n \nParseError(detail=None, code=None)\n\n\nRaised if the request contains malformed data when accessing \nrequest.data\n.\n\n\nBy default this exception results in a response with the HTTP status code \"400 Bad Request\".\n\n\nAuthenticationFailed\n\n\nSignature:\n \nAuthenticationFailed(detail=None, code=None)\n\n\nRaised when an incoming request includes incorrect authentication.\n\n\nBy default this exception results in a response with the HTTP status code \"401 Unauthenticated\", but it may also result in a \"403 Forbidden\" response, depending on the authentication scheme in use. See the \nauthentication documentation\n for more details.\n\n\nNotAuthenticated\n\n\nSignature:\n \nNotAuthenticated(detail=None, code=None)\n\n\nRaised when an unauthenticated request fails the permission checks.\n\n\nBy default this exception results in a response with the HTTP status code \"401 Unauthenticated\", but it may also result in a \"403 Forbidden\" response, depending on the authentication scheme in use. See the \nauthentication documentation\n for more details.\n\n\nPermissionDenied\n\n\nSignature:\n \nPermissionDenied(detail=None, code=None)\n\n\nRaised when an authenticated request fails the permission checks.\n\n\nBy default this exception results in a response with the HTTP status code \"403 Forbidden\".\n\n\nNotFound\n\n\nSignature:\n \nNotFound(detail=None, code=None)\n\n\nRaised when a resource does not exists at the given URL. This exception is equivalent to the standard \nHttp404\n Django exception.\n\n\nBy default this exception results in a response with the HTTP status code \"404 Not Found\".\n\n\nMethodNotAllowed\n\n\nSignature:\n \nMethodNotAllowed(method, detail=None, code=None)\n\n\nRaised when an incoming request occurs that does not map to a handler method on the view.\n\n\nBy default this exception results in a response with the HTTP status code \"405 Method Not Allowed\".\n\n\nNotAcceptable\n\n\nSignature:\n \nNotAcceptable(detail=None, code=None)\n\n\nRaised when an incoming request occurs with an \nAccept\n header that cannot be satisfied by any of the available renderers.\n\n\nBy default this exception results in a response with the HTTP status code \"406 Not Acceptable\".\n\n\nUnsupportedMediaType\n\n\nSignature:\n \nUnsupportedMediaType(media_type, detail=None, code=None)\n\n\nRaised if there are no parsers that can handle the content type of the request data when accessing \nrequest.data\n.\n\n\nBy default this exception results in a response with the HTTP status code \"415 Unsupported Media Type\".\n\n\nThrottled\n\n\nSignature:\n \nThrottled(wait=None, detail=None, code=None)\n\n\nRaised when an incoming request fails the throttling checks.\n\n\nBy default this exception results in a response with the HTTP status code \"429 Too Many Requests\".\n\n\nValidationError\n\n\nSignature:\n \nValidationError(detail, code=None)\n\n\nThe \nValidationError\n exception is slightly different from the other \nAPIException\n classes:\n\n\n\n\nThe \ndetail\n argument is mandatory, not optional.\n\n\nThe \ndetail\n argument may be a list or dictionary of error details, and may also be a nested data structure.\n\n\nBy convention you should import the serializers module and use a fully qualified \nValidationError\n style, in order to differentiate it from Django's built-in validation error. For example. \nraise serializers.ValidationError('This field must be an integer value.')\n\n\n\n\nThe \nValidationError\n class should be used for serializer and field validation, and by validator classes. It is also raised when calling \nserializer.is_valid\n with the \nraise_exception\n keyword argument:\n\n\nserializer.is_valid(raise_exception=True)\n\n\n\nThe generic views use the \nraise_exception=True\n flag, which means that you can override the style of validation error responses globally in your API. To do so, use a custom exception handler, as described above.\n\n\nBy default this exception results in a response with the HTTP status code \"400 Bad Request\".",
+ "text": "Exceptions\n\n\n\n\nExceptions\u2026 allow error handling to be organized cleanly in a central or high-level place within the program structure.\n\n\n Doug Hellmann, \nPython Exception Handling Techniques\n\n\n\n\nException handling in REST framework views\n\n\nREST framework's views handle various exceptions, and deal with returning appropriate error responses.\n\n\nThe handled exceptions are:\n\n\n\n\nSubclasses of \nAPIException\n raised inside REST framework.\n\n\nDjango's \nHttp404\n exception.\n\n\nDjango's \nPermissionDenied\n exception.\n\n\n\n\nIn each case, REST framework will return a response with an appropriate status code and content-type. The body of the response will include any additional details regarding the nature of the error.\n\n\nMost error responses will include a key \ndetail\n in the body of the response.\n\n\nFor example, the following request:\n\n\nDELETE http://api.example.com/foo/bar HTTP/1.1\nAccept: application/json\n\n\n\nMight receive an error response indicating that the \nDELETE\n method is not allowed on that resource:\n\n\nHTTP/1.1 405 Method Not Allowed\nContent-Type: application/json\nContent-Length: 42\n\n{\"detail\": \"Method 'DELETE' not allowed.\"}\n\n\n\nValidation errors are handled slightly differently, and will include the field names as the keys in the response. If the validation error was not specific to a particular field then it will use the \"non_field_errors\" key, or whatever string value has been set for the \nNON_FIELD_ERRORS_KEY\n setting.\n\n\nAny example validation error might look like this:\n\n\nHTTP/1.1 400 Bad Request\nContent-Type: application/json\nContent-Length: 94\n\n{\"amount\": [\"A valid integer is required.\"], \"description\": [\"This field may not be blank.\"]}\n\n\n\nCustom exception handling\n\n\nYou can implement custom exception handling by creating a handler function that converts exceptions raised in your API views into response objects. This allows you to control the style of error responses used by your API.\n\n\nThe function must take a pair of arguments, this first is the exception to be handled, and the second is a dictionary containing any extra context such as the view currently being handled. The exception handler function should either return a \nResponse\n object, or return \nNone\n if the exception cannot be handled. If the handler returns \nNone\n then the exception will be re-raised and Django will return a standard HTTP 500 'server error' response.\n\n\nFor example, you might want to ensure that all error responses include the HTTP status code in the body of the response, like so:\n\n\nHTTP/1.1 405 Method Not Allowed\nContent-Type: application/json\nContent-Length: 62\n\n{\"status_code\": 405, \"detail\": \"Method 'DELETE' not allowed.\"}\n\n\n\nIn order to alter the style of the response, you could write the following custom exception handler:\n\n\nfrom rest_framework.views import exception_handler\n\ndef custom_exception_handler(exc, context):\n # Call REST framework's default exception handler first,\n # to get the standard error response.\n response = exception_handler(exc, context)\n\n #\u00a0Now add the HTTP status code to the response.\n if response is not None:\n response.data['status_code'] = response.status_code\n\n return response\n\n\n\nThe context argument is not used by the default handler, but can be useful if the exception handler needs further information such as the view currently being handled, which can be accessed as \ncontext['view']\n.\n\n\nThe exception handler must also be configured in your settings, using the \nEXCEPTION_HANDLER\n setting key. For example:\n\n\nREST_FRAMEWORK = {\n 'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler'\n}\n\n\n\nIf not specified, the \n'EXCEPTION_HANDLER'\n setting defaults to the standard exception handler provided by REST framework:\n\n\nREST_FRAMEWORK = {\n 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'\n}\n\n\n\nNote that the exception handler will only be called for responses generated by raised exceptions. It will not be used for any responses returned directly by the view, such as the \nHTTP_400_BAD_REQUEST\n responses that are returned by the generic views when serializer validation fails.\n\n\n\n\nAPI Reference\n\n\nAPIException\n\n\nSignature:\n \nAPIException()\n\n\nThe \nbase class\n for all exceptions raised inside an \nAPIView\n class or \n@api_view\n.\n\n\nTo provide a custom exception, subclass \nAPIException\n and set the \n.status_code\n, \n.default_detail\n, and \ndefault_code\n attributes on the class.\n\n\nFor example, if your API relies on a third party service that may sometimes be unreachable, you might want to implement an exception for the \"503 Service Unavailable\" HTTP response code. You could do this like so:\n\n\nfrom rest_framework.exceptions import APIException\n\nclass ServiceUnavailable(APIException):\n status_code = 503\n default_detail = 'Service temporarily unavailable, try again later.'\n default_code = 'service_unavailable'\n\n\n\nInspecting API exceptions\n\n\nThere are a number of different properties available for inspecting the status\nof an API exception. You can use these to build custom exception handling\nfor your project.\n\n\nThe available attributes and methods are:\n\n\n\n\n.detail\n - Return the textual description of the error.\n\n\n.get_codes()\n - Return the code identifier of the error.\n\n\n.get_full_details()\n - Return both the textual description and the code identifier.\n\n\n\n\nIn most cases the error detail will be a simple item:\n\n\n print(exc.detail)\nYou do not have permission to perform this action.\n\n print(exc.get_codes())\npermission_denied\n\n print(exc.get_full_details())\n{'message':'You do not have permission to perform this action.','code':'permission_denied'}\n\n\n\nIn the case of validation errors the error detail will be either a list or\ndictionary of items:\n\n\n print(exc.detail)\n{\"name\":\"This field is required.\",\"age\":\"A valid integer is required.\"}\n\n print(exc.get_codes())\n{\"name\":\"required\",\"age\":\"invalid\"}\n\n print(exc.get_full_details())\n{\"name\":{\"message\":\"This field is required.\",\"code\":\"required\"},\"age\":{\"message\":\"A valid integer is required.\",\"code\":\"invalid\"}}\n\n\n\nParseError\n\n\nSignature:\n \nParseError(detail=None, code=None)\n\n\nRaised if the request contains malformed data when accessing \nrequest.data\n.\n\n\nBy default this exception results in a response with the HTTP status code \"400 Bad Request\".\n\n\nAuthenticationFailed\n\n\nSignature:\n \nAuthenticationFailed(detail=None, code=None)\n\n\nRaised when an incoming request includes incorrect authentication.\n\n\nBy default this exception results in a response with the HTTP status code \"401 Unauthenticated\", but it may also result in a \"403 Forbidden\" response, depending on the authentication scheme in use. See the \nauthentication documentation\n for more details.\n\n\nNotAuthenticated\n\n\nSignature:\n \nNotAuthenticated(detail=None, code=None)\n\n\nRaised when an unauthenticated request fails the permission checks.\n\n\nBy default this exception results in a response with the HTTP status code \"401 Unauthenticated\", but it may also result in a \"403 Forbidden\" response, depending on the authentication scheme in use. See the \nauthentication documentation\n for more details.\n\n\nPermissionDenied\n\n\nSignature:\n \nPermissionDenied(detail=None, code=None)\n\n\nRaised when an authenticated request fails the permission checks.\n\n\nBy default this exception results in a response with the HTTP status code \"403 Forbidden\".\n\n\nNotFound\n\n\nSignature:\n \nNotFound(detail=None, code=None)\n\n\nRaised when a resource does not exists at the given URL. This exception is equivalent to the standard \nHttp404\n Django exception.\n\n\nBy default this exception results in a response with the HTTP status code \"404 Not Found\".\n\n\nMethodNotAllowed\n\n\nSignature:\n \nMethodNotAllowed(method, detail=None, code=None)\n\n\nRaised when an incoming request occurs that does not map to a handler method on the view.\n\n\nBy default this exception results in a response with the HTTP status code \"405 Method Not Allowed\".\n\n\nNotAcceptable\n\n\nSignature:\n \nNotAcceptable(detail=None, code=None)\n\n\nRaised when an incoming request occurs with an \nAccept\n header that cannot be satisfied by any of the available renderers.\n\n\nBy default this exception results in a response with the HTTP status code \"406 Not Acceptable\".\n\n\nUnsupportedMediaType\n\n\nSignature:\n \nUnsupportedMediaType(media_type, detail=None, code=None)\n\n\nRaised if there are no parsers that can handle the content type of the request data when accessing \nrequest.data\n.\n\n\nBy default this exception results in a response with the HTTP status code \"415 Unsupported Media Type\".\n\n\nThrottled\n\n\nSignature:\n \nThrottled(wait=None, detail=None, code=None)\n\n\nRaised when an incoming request fails the throttling checks.\n\n\nBy default this exception results in a response with the HTTP status code \"429 Too Many Requests\".\n\n\nValidationError\n\n\nSignature:\n \nValidationError(detail, code=None)\n\n\nThe \nValidationError\n exception is slightly different from the other \nAPIException\n classes:\n\n\n\n\nThe \ndetail\n argument is mandatory, not optional.\n\n\nThe \ndetail\n argument may be a list or dictionary of error details, and may also be a nested data structure.\n\n\nBy convention you should import the serializers module and use a fully qualified \nValidationError\n style, in order to differentiate it from Django's built-in validation error. For example. \nraise serializers.ValidationError('This field must be an integer value.')\n\n\n\n\nThe \nValidationError\n class should be used for serializer and field validation, and by validator classes. It is also raised when calling \nserializer.is_valid\n with the \nraise_exception\n keyword argument:\n\n\nserializer.is_valid(raise_exception=True)\n\n\n\nThe generic views use the \nraise_exception=True\n flag, which means that you can override the style of validation error responses globally in your API. To do so, use a custom exception handler, as described above.\n\n\nBy default this exception results in a response with the HTTP status code \"400 Bad Request\".",
"title": "Exceptions"
},
{
@@ -3307,7 +3312,7 @@
},
{
"location": "/api-guide/exceptions/#inspecting-api-exceptions",
- "text": "There are a number of different properties available for inspecting the status\nof an API exception. You can use these to build custom exception handling\nfor your project. The available attributes and methods are: .detail - Return the textual description of the error. .get_codes() - Return the code identifier of the error. .full_details() - Return both the textual description and the code identifier. In most cases the error detail will be a simple item: print(exc.detail)\nYou do not have permission to perform this action. print(exc.get_codes())\npermission_denied print(exc.full_details())\n{'message':'You do not have permission to perform this action.','code':'permission_denied'} In the case of validation errors the error detail will be either a list or\ndictionary of items: print(exc.detail)\n{\"name\":\"This field is required.\",\"age\":\"A valid integer is required.\"} print(exc.get_codes())\n{\"name\":\"required\",\"age\":\"invalid\"} print(exc.get_full_details())\n{\"name\":{\"message\":\"This field is required.\",\"code\":\"required\"},\"age\":{\"message\":\"A valid integer is required.\",\"code\":\"invalid\"}}",
+ "text": "There are a number of different properties available for inspecting the status\nof an API exception. You can use these to build custom exception handling\nfor your project. The available attributes and methods are: .detail - Return the textual description of the error. .get_codes() - Return the code identifier of the error. .get_full_details() - Return both the textual description and the code identifier. In most cases the error detail will be a simple item: print(exc.detail)\nYou do not have permission to perform this action. print(exc.get_codes())\npermission_denied print(exc.get_full_details())\n{'message':'You do not have permission to perform this action.','code':'permission_denied'} In the case of validation errors the error detail will be either a list or\ndictionary of items: print(exc.detail)\n{\"name\":\"This field is required.\",\"age\":\"A valid integer is required.\"} print(exc.get_codes())\n{\"name\":\"required\",\"age\":\"invalid\"} print(exc.get_full_details())\n{\"name\":{\"message\":\"This field is required.\",\"code\":\"required\"},\"age\":{\"message\":\"A valid integer is required.\",\"code\":\"invalid\"}}",
"title": "Inspecting API exceptions"
},
{
@@ -5227,7 +5232,7 @@
},
{
"location": "/topics/release-notes/",
- "text": "Release Notes\n\n\n\n\nRelease Early, Release Often\n\n\n Eric S. Raymond, \nThe Cathedral and the Bazaar\n.\n\n\n\n\nVersioning\n\n\nMinor version numbers (0.0.x) are used for changes that are API compatible. You should be able to upgrade between minor point releases without any other code changes.\n\n\nMedium version numbers (0.x.0) may include API changes, in line with the \ndeprecation policy\n. You should read the release notes carefully before upgrading between medium point releases.\n\n\nMajor version numbers (x.0.0) are reserved for substantial project milestones.\n\n\nDeprecation policy\n\n\nREST framework releases follow a formal deprecation policy, which is in line with \nDjango's deprecation policy\n.\n\n\nThe timeline for deprecation of a feature present in version 1.0 would work as follows:\n\n\n\n\n\n\nVersion 1.1 would remain \nfully backwards compatible\n with 1.0, but would raise \nPendingDeprecationWarning\n warnings if you use the feature that are due to be deprecated. These warnings are \nsilent by default\n, but can be explicitly enabled when you're ready to start migrating any required changes. For example if you start running your tests using \npython -Wd manage.py test\n, you'll be warned of any API changes you need to make.\n\n\n\n\n\n\nVersion 1.2 would escalate these warnings to \nDeprecationWarning\n, which is loud by default.\n\n\n\n\n\n\nVersion 1.3 would remove the deprecated bits of API entirely.\n\n\n\n\n\n\nNote that in line with Django's policy, any parts of the framework not mentioned in the documentation should generally be considered private API, and may be subject to change.\n\n\nUpgrading\n\n\nTo upgrade Django REST framework to the latest version, use pip:\n\n\npip install -U djangorestframework\n\n\n\nYou can determine your currently installed version using \npip freeze\n:\n\n\npip freeze | grep djangorestframework\n\n\n\n\n\n3.5.x series\n\n\n3.5.0\n\n\nDate\n: \n20th October 2016\n\n\n\n\n3.4.x series\n\n\n3.4.7\n\n\nDate\n: \n21st September 2016\n\n\n\n\nFallback behavior for request parsing when request.POST already accessed. (\n#3951\n, \n#4500\n)\n\n\nFix regression of \nRegexField\n. (\n#4489\n, \n#4490\n, \n#2617\n)\n\n\nMissing comma in \nadmin.html\n causing CSRF error. (\n#4472\n, \n#4473\n)\n\n\nFix response rendering with empty context. (\n#4495\n)\n\n\nFix indentation regression in API listing. (\n#4493\n)\n\n\nFixed an issue where the incorrect value is set to \nResolverMatch.func_name\n of api_view decorated view. (\n#4465\n, \n#4462\n)\n\n\nFix \nAPIClient.get()\n when path contains unicode arguments (\n#4458\n)\n\n\n\n\n3.4.6\n\n\nDate\n: \n23rd August 2016\n\n\n\n\nFix malformed Javascript in browsable API. (\n#4435\n)\n\n\nSkip HiddenField from Schema fields. (\n#4425\n, \n#4429\n)\n\n\nImprove Create to show the original exception traceback. (\n#3508\n)\n\n\nFix \nAdminRenderer\n display of PK only related fields. (\n#4419\n, \n#4423\n)\n\n\n\n\n3.4.5\n\n\nDate\n: \n19th August 2016\n\n\n\n\nImprove debug error handling. (\n#4416\n, \n#4409\n)\n\n\nAllow custom CSRF_HEADER_NAME setting. (\n#4415\n, \n#4410\n)\n\n\nInclude .action attribute on viewsets when generating schemas. (\n#4408\n, \n#4398\n)\n\n\nDo not include request.FILES items in request.POST. (\n#4407\n)\n\n\nFix rendering of checkbox multiple. (\n#4403\n)\n\n\nFix docstring of Field.get_default. (\n#4404\n)\n\n\nReplace utf8 character with its ascii counterpart in README. (\n#4412\n)\n\n\n\n\n3.4.4\n\n\nDate\n: \n12th August 2016\n\n\n\n\nEnsure views are fully initialized when generating schemas. (\n#4373\n, \n#4382\n, \n#4383\n, \n#4279\n, \n#4278\n)\n\n\nAdd form field descriptions to schemas. (\n#4387\n)\n\n\nFix category generation for schema endpoints. (\n#4391\n, \n#4394\n, \n#4390\n, \n#4386\n, \n#4376\n, \n#4329\n)\n\n\nDon't strip empty query params when paginating. (\n#4392\n, \n#4393\n, \n#4260\n)\n\n\nDo not re-run query for empty results with LimitOffsetPagination. (\n#4201\n, \n#4388\n)\n\n\nStricter type validation for CharField. (\n#4380\n, \n#3394\n)\n\n\nRelatedField.choices should preserve non-string values. (\n#4111\n, \n#4379\n, \n#3365\n)\n\n\nTest case for rendering checkboxes in vertical form style. (\n#4378\n, \n#3868\n, \n#3868\n)\n\n\nShow error traceback HTML in browsable API (\n#4042\n, \n#4172\n)\n\n\nFix handling of ALLOWED_VERSIONS and no DEFAULT_VERSION. \n#4370\n\n\nAllow \nmax_digits=None\n on DecimalField. (\n#4377\n, \n#4372\n)\n\n\nLimit queryset when rendering relational choices. (\n#4375\n, \n#4122\n, \n#3329\n, \n#3330\n, \n#3877\n)\n\n\nResolve form display with ChoiceField, MultipleChoiceField and non-string choices. (\n#4374\n, \n#4119\n, \n#4121\n, \n#4137\n, \n#4120\n)\n\n\nFix call to TemplateHTMLRenderer.resolve_context() fallback method. (\n#4371\n)\n\n\n\n\n3.4.3\n\n\nDate\n: \n5th August 2016\n\n\n\n\nInclude fallaback for users of older TemplateHTMLRenderer internal API. (\n#4361\n)\n\n\n\n\n3.4.2\n\n\nDate\n: \n5th August 2016\n\n\n\n\nInclude kwargs passed to 'as_view' when generating schemas. (\n#4359\n, \n#4330\n, \n#4331\n)\n\n\nAccess \nrequest.user.is_authenticated\n as property not method, under Django 1.10+ (\n#4358\n, \n#4354\n)\n\n\nFilter HEAD out from schemas. (\n#4357\n)\n\n\nextra_kwargs takes precedence over uniqueness kwargs. (\n#4198\n, \n#4199\n, \n#4349\n)\n\n\nCorrect descriptions when tabs are used in code indentation. (\n#4345\n, \n#4347\n)*\n\n\nChange template context generation in TemplateHTMLRenderer. (\n#4236\n)\n\n\nSerializer defaults should not be included in partial updates. (\n#4346\n, \n#3565\n)\n\n\nConsistent behavior \n descriptive error from FileUploadParser when filename not included. (\n#4340\n, \n#3610\n, \n#4292\n, \n#4296\n)\n\n\nDecimalField quantizes incoming digitals. (\n#4339\n, \n#4318\n)\n\n\nHandle non-string input for IP fields. (\n#4335\n, \n#4336\n, \n#4338\n)\n\n\nFix leading slash handling when Schema generation includes a root URL. (\n#4332\n)\n\n\nTest cases for DictField with allow_null options. (\n#4348\n)\n\n\nUpdate tests from Django 1.10 beta to Django 1.10. (\n#4344\n)\n\n\n\n\n3.4.1\n\n\nDate\n: \n28th July 2016\n\n\n\n\nAdded \nroot_renderers\n argument to \nDefaultRouter\n. (\n#4323\n, \n#4268\n)\n\n\nAdded \nurl\n and \nschema_url\n arguments. (\n#4321\n, \n#4308\n, \n#4305\n)\n\n\nUnique together checks should apply to read-only fields which have a default. (\n#4316\n, \n#4294\n)\n\n\nSet view.format_kwarg in schema generator. (\n#4293\n, \n#4315\n)\n\n\nFix schema generator for views with \npagination_class = None\n. (\n#4314\n, \n#4289\n)\n\n\nFix schema generator for views with no \nget_serializer_class\n. (\n#4265\n, \n#4285\n)\n\n\nFixes for media type parameters in \nAccept\n and \nContent-Type\n headers. (\n#4287\n, \n#4313\n, \n#4281\n)\n\n\nUse verbose_name instead of object_name in error messages. (\n#4299\n)\n\n\nMinor version update to Twitter Bootstrap. (\n#4307\n)\n\n\nSearchFilter raises error when using with related field. (\n#4302\n, \n#4303\n, \n#4298\n)\n\n\nAdding support for RFC 4918 status codes. (\n#4291\n)\n\n\nAdd LICENSE.md to the built wheel. (\n#4270\n)\n\n\nSerializing \"complex\" field returns None instead of the value since 3.4 (\n#4272\n, \n#4273\n, \n#4288\n)\n\n\n\n\n3.4.0\n\n\nDate\n: \n14th July 2016\n\n\n\n\nDon't strip microseconds in JSON output. (\n#4256\n)\n\n\nTwo slightly different iso 8601 datetime serialization. (\n#4255\n)\n\n\nResolve incorrect inclusion of media type parameters. (\n#4254\n)\n\n\nResponse Content-Type potentially malformed. (\n#4253\n)\n\n\nFix setup.py error on some platforms. (\n#4246\n)\n\n\nMove alternate formats in coreapi into separate packages. (\n#4244\n)\n\n\nAdd localize keyword argument to \nDecimalField\n. (\n#4233\n)\n\n\nFix issues with routers for custom list-route and detail-routes. (\n#4229\n)\n\n\nNamespace versioning with nested namespaces. (\n#4219\n)\n\n\nRobust uniqueness checks. (\n#4217\n)\n\n\nMinor refactoring of \nmust_call_distinct\n. (\n#4215\n)\n\n\nOverridable offset cutoff in CursorPagination. (\n#4212\n)\n\n\nPass through strings as-in with date/time fields. (\n#4196\n)\n\n\nAdd test confirming that required=False is valid on a relational field. (\n#4195\n)\n\n\nIn LimitOffsetPagination \nlimit=0\n should revert to default limit. (\n#4194\n)\n\n\nExclude read_only=True fields from unique_together validation \n add docs. (\n#4192\n)\n\n\nHandle bytestrings in JSON. (\n#4191\n)\n\n\nJSONField(binary=True) represents using binary strings, which JSONRenderer does not support. (\n#4187\n)\n\n\nJSONField(binary=True) represents using binary strings, which JSONRenderer does not support. (\n#4185\n)\n\n\nMore robust form rendering in the browsable API. (\n#4181\n)\n\n\nEmpty cases of \n.validated_data\n and \n.errors\n as lists not dicts for ListSerializer. (\n#4180\n)\n\n\nSchemas \n client libraries. (\n#4179\n)\n\n\nRemoved \nAUTH_USER_MODEL\n compat property. (\n#4176\n)\n\n\nClean up existing deprecation warnings. (\n#4166\n)\n\n\nDjango 1.10 support. (\n#4158\n)\n\n\nUpdated jQuery version to 1.12.4. (\n#4157\n)\n\n\nMore robust default behavior on OrderingFilter. (\n#4156\n)\n\n\ndescription.py codes and tests removal. (\n#4153\n)\n\n\nWrap guardian.VERSION in tuple. (\n#4149\n)\n\n\nRefine validator for fields with \n kwargs. (\n#4146\n)\n\n\nFix None values representation in childs of ListField, DictField. (\n#4118\n)\n\n\nResolve TimeField representation for midnight value. (\n#4107\n)\n\n\nSet proper status code in AdminRenderer for the redirection after POST/DELETE requests. (\n#4106\n)\n\n\nTimeField render returns None instead of 00:00:00. (\n#4105\n)\n\n\nFix incorrectly named zh-hans and zh-hant locale path. (\n#4103\n)\n\n\nPrevent raising exception when limit is 0. (\n#4098\n)\n\n\nTokenAuthentication: Allow custom keyword in the header. (\n#4097\n)\n\n\nHandle incorrectly padded HTTP basic auth header. (\n#4090\n)\n\n\nLimitOffset pagination crashes Browseable API when limit=0. (\n#4079\n)\n\n\nFixed DecimalField arbitrary precision support. (\n#4075\n)\n\n\nAdded support for custom CSRF cookie names. (\n#4049\n)\n\n\nFix regression introduced by #4035. (\n#4041\n)\n\n\nNo auth view failing permission should raise 403. (\n#4040\n)\n\n\nFix string_types / text_types confusion. (\n#4025\n)\n\n\nDo not list related field choices in OPTIONS requests. (\n#4021\n)\n\n\nFix typo. (\n#4008\n)\n\n\nReorder initializing the view. (\n#4006\n)\n\n\nType error in DjangoObjectPermissionsFilter on Python 3.4. (\n#4005\n)\n\n\nFixed use of deprecated Query.aggregates. (\n#4003\n)\n\n\nFix blank lines around docstrings. (\n#4002\n)\n\n\nFixed admin pagination when limit is 0. (\n#3990\n)\n\n\nOrderingFilter adjustements. (\n#3983\n)\n\n\nNon-required serializer related fields. (\n#3976\n)\n\n\nUsing safer calling way of \"@api_view\" in tutorial. (\n#3971\n)\n\n\nListSerializer doesn't handle unique_together constraints. (\n#3970\n)\n\n\nAdd missing migration file. (\n#3968\n)\n\n\nOrderingFilter\n should call \nget_serializer_class()\n to determine default fields. (\n#3964\n)\n\n\nRemove old django checks from tests and compat. (\n#3953\n)\n\n\nSupport callable as the value of \ninitial\n for any \nserializer.Field\n. (\n#3943\n)\n\n\nPrevented unnecessary distinct() call in SearchFilter. (\n#3938\n)\n\n\nFix None UUID ForeignKey serialization. (\n#3936\n)\n\n\nDrop EOL Django 1.7. (\n#3933\n)\n\n\nAdd missing space in serializer error message. (\n#3926\n)\n\n\nFixed _force_text_recursive typo. (\n#3908\n)\n\n\nAttempt to address Django 2.0 deprecate warnings related to \nfield.rel\n. (\n#3906\n)\n\n\nFix parsing multipart data using a nested serializer with list. (\n#3820\n)\n\n\nResolving APIs URL to different namespaces. (\n#3816\n)\n\n\nDo not HTML-escape \nhelp_text\n in Browsable API forms. (\n#3812\n)\n\n\nOPTIONS fetches and shows all possible foreign keys in choices field. (\n#3751\n)\n\n\nDjango 1.9 deprecation warnings (\n#3729\n)\n\n\nTest case for #3598 (\n#3710\n)\n\n\nAdding support for multiple values for search filter. (\n#3541\n)\n\n\nUse get_serializer_class in ordering filter. (\n#3487\n)\n\n\nSerializers with many=True should return empty list rather than empty dict. (\n#3476\n)\n\n\nLimitOffsetPagination limit=0 fix. (\n#3444\n)\n\n\nEnable Validators to defer string evaluation and handle new string format. (\n#3438\n)\n\n\nUnique validator is executed and breaks if field is invalid. (\n#3381\n)\n\n\nDo not ignore overridden View.get_view_name() in breadcrumbs. (\n#3273\n)\n\n\nRetry form rendering when rendering with serializer fails. (\n#3164\n)\n\n\nUnique constraint prevents nested serializers from updating. (\n#2996\n)\n\n\nUniqueness validators should not be run for excluded (read_only) fields. (\n#2848\n)\n\n\nUniqueValidator raises exception for nested objects. (\n#2403\n)\n\n\nlookup_type\n is deprecated in favor of \nlookup_expr\n. (\n#4259\n)\n\n\n\n\n\n\n3.3.x series\n\n\n3.3.3\n\n\nDate\n: \n14th March 2016\n.\n\n\n\n\nRemove version string from templates. Thanks to @blag for the report and fixes. (\n#3878\n, \n#3913\n, \n#3912\n)\n\n\nFixes vertical html layout for \nBooleanField\n. Thanks to Mikalai Radchuk for the fix. (\n#3910\n)\n\n\nSilenced deprecation warnings on Django 1.8. Thanks to Simon Charette for the fix. (\n#3903\n)\n\n\nInternationalization for authtoken. Thanks to Michael Nacharov for the fix. (\n#3887\n, \n#3968\n)\n\n\nFix \nToken\n model as \nabstract\n when the authtoken application isn't declared. Thanks to Adam Thomas for the report. (\n#3860\n, \n#3858\n)\n\n\nImprove Markdown version compatibility. Thanks to Michael J. Schultz for the fix. (\n#3604\n, \n#3842\n)\n\n\nQueryParameterVersioning\n does not use \nDEFAULT_VERSION\n setting. Thanks to Brad Montgomery for the fix. (\n#3833\n)\n\n\nAdd an explicit \non_delete\n on the models. Thanks to Mads Jensen for the fix. (\n#3832\n)\n\n\nFix \nDateField.to_representation\n to work with Python 2 unicode. Thanks to Mikalai Radchuk for the fix. (\n#3819\n)\n\n\nFixed \nTimeField\n not handling string times. Thanks to Areski Belaid for the fix. (\n#3809\n)\n\n\nAvoid updates of \nMeta.extra_kwargs\n. Thanks to Kevin Massey for the report and fix. (\n#3805\n, \n#3804\n)\n\n\nFix nested validation error being rendered incorrectly. Thanks to Craig de Stigter for the fix. (\n#3801\n)\n\n\nDocument how to avoid CSRF and missing button issues with \ndjango-crispy-forms\n. Thanks to Emmanuelle Delescolle, Jos\u00e9 Padilla and Luis San Pablo for the report, analysis and fix. (\n#3787\n, \n#3636\n, \n#3637\n)\n\n\nImprove Rest Framework Settings file setup time. Thanks to Miles Hutson for the report and Mads Jensen for the fix. (\n#3786\n, \n#3815\n)\n\n\nImprove authtoken compatibility with Django 1.9. Thanks to S. Andrew Sheppard for the fix. (\n#3785\n)\n\n\nFix \nMin/MaxValueValidator\n transfer from a model's \nDecimalField\n. Thanks to Kevin Brown for the fix. (\n#3774\n)\n\n\nImprove HTML title in the Browsable API. Thanks to Mike Lissner for the report and fix. (\n#3769\n)\n\n\nFix \nAutoFilterSet\n to inherit from \ndefault_filter_set\n. Thanks to Tom Linford for the fix. (\n#3753\n)\n\n\nFix transifex config to handle the new Chinese language codes. Thanks to @nypisces for the report and fix. (\n#3739\n)\n\n\nDateTimeField\n does not handle empty values correctly. Thanks to Mick Parker for the report and fix. (\n#3731\n, \n#3726\n)\n\n\nRaise error when setting a removed rest_framework setting. Thanks to Luis San Pablo for the fix. (\n#3715\n)\n\n\nAdd missing csrf_token in AdminRenderer post form. Thanks to Piotr \u015aniegowski for the fix. (\n#3703\n)\n\n\nRefactored \n_get_reverse_relationships()\n to use correct \nto_field\n. Thanks to Benjamin Phillips for the fix. (\n#3696\n)\n\n\nDocument the use of \nget_queryset\n for \nRelatedField\n. Thanks to Ryan Hiebert for the fix. (\n#3605\n)\n\n\nFix empty pk detection in HyperlinkRelatedField.get_url. Thanks to @jslang for the fix (\n#3962\n)\n\n\n\n\n3.3.2\n\n\nDate\n: \n14th December 2015\n.\n\n\n\n\nListField\n enforces input is a list. (\n#3513\n)\n\n\nFix regression hiding raw data form. (\n#3600\n, \n#3578\n)\n\n\nFix Python 3.5 compatibility. (\n#3534\n, \n#3626\n)\n\n\nAllow setting a custom Django Paginator in \npagination.PageNumberPagination\n. (\n#3631\n, \n#3684\n)\n\n\nFix relational fields without \nto_fields\n attribute. (\n#3635\n, \n#3634\n)\n\n\nFix \ntemplate.render\n deprecation warnings for Django 1.9. (\n#3654\n)\n\n\nSort response headers in browsable API renderer. (\n#3655\n)\n\n\nUse related_objects api for Django 1.9+. (\n#3656\n, \n#3252\n)\n\n\nAdd confirm modal when deleting. (\n#3228\n, \n#3662\n)\n\n\nReveal previously hidden AttributeErrors and TypeErrors while calling has_[object_]permissions. (\n#3668\n)\n\n\nMake DRF compatible with multi template engine in Django 1.8. (\n#3672\n)\n\n\nUpdate \nNestedBoundField\n to also handle empty string when rendering its form. (\n#3677\n)\n\n\nFix UUID validation to properly catch invalid input types. (\n#3687\n, \n#3679\n)\n\n\nFix caching issues. (\n#3628\n, \n#3701\n)\n\n\nFix Admin and API browser for views without a filter_class. (\n#3705\n, \n#3596\n, \n#3597\n)\n\n\nAdd app_name to rest_framework.urls. (\n#3714\n)\n\n\nImprove authtoken's views to support url versioning. (\n#3718\n, \n#3723\n)\n\n\n\n\n3.3.1\n\n\nDate\n: \n4th November 2015\n.\n\n\n\n\nResolve parsing bug when accessing \nrequest.POST\n (\n#3592\n)\n\n\nCorrectly deal with \nto_field\n referring to primary key. (\n#3593\n)\n\n\nAllow filter HTML to render when no \nfilter_class\n is defined. (\n#3560\n)\n\n\nFix admin rendering issues. (\n#3564\n, \n#3556\n)\n\n\nFix issue with DecimalValidator. (\n#3568\n)\n\n\n\n\n3.3.0\n\n\nDate\n: \n28th October 2015\n.\n\n\n\n\nHTML controls for filters. (\n#3315\n)\n\n\nForms API. (\n#3475\n)\n\n\nAJAX browsable API. (\n#3410\n)\n\n\nAdded JSONField. (\n#3454\n)\n\n\nCorrectly map \nto_field\n when creating \nModelSerializer\n relational fields. (\n#3526\n)\n\n\nInclude keyword arguments when mapping \nFilePathField\n to a serializer field. (\n#3536\n)\n\n\nMap appropriate model \nerror_messages\n on \nModelSerializer\n uniqueness constraints. (\n#3435\n)\n\n\nInclude \nmax_length\n constraint for \nModelSerializer\n fields mapped from TextField. (\n#3509\n)\n\n\nAdded support for Django 1.9. (\n#3450\n, \n#3525\n)\n\n\nRemoved support for Django 1.5 \n 1.6. (\n#3421\n, \n#3429\n)\n\n\nRemoved 'south' migrations. (\n#3495\n)\n\n\n\n\n\n\n3.2.x series\n\n\n3.2.5\n\n\nDate\n: \n27th October 2015\n.\n\n\n\n\nEscape \nusername\n in optional logout tag. (\n#3550\n)\n\n\n\n\n3.2.4\n\n\nDate\n: \n21th September 2015\n.\n\n\n\n\nDon't error on missing \nViewSet.search_fields\n attribute. (\n#3324\n, \n#3323\n)\n\n\nFix \nallow_empty\n not working on serializers with \nmany=True\n. (\n#3361\n, \n#3364\n)\n\n\nLet \nDurationField\n accepts integers. (\n#3359\n)\n\n\nMulti-level dictionaries not supported in multipart requests. (\n#3314\n)\n\n\nFix \nListField\n truncation on HTTP PATCH (\n#3415\n, \n#2761\n)\n\n\n\n\n3.2.3\n\n\nDate\n: \n24th August 2015\n.\n\n\n\n\nAdded \nhtml_cutoff\n and \nhtml_cutoff_text\n for limiting select dropdowns. (\n#3313\n)\n\n\nAdded regex style to \nSearchFilter\n. (\n#3316\n)\n\n\nResolve issues with setting blank HTML fields. (\n#3318\n) (\n#3321\n)\n\n\nCorrectly display existing 'select multiple' values in browsable API forms. (\n#3290\n)\n\n\nResolve duplicated validation message for \nIPAddressField\n. ([#3249[gh3249]) (\n#3250\n)\n\n\nFix to ensure admin renderer continues to work when pagination is disabled. (\n#3275\n)\n\n\nResolve error with \nLimitOffsetPagination\n when count=0, offset=0. (\n#3303\n)\n\n\n\n\n3.2.2\n\n\nDate\n: \n13th August 2015\n.\n\n\n\n\nAdd \ndisplay_value()\n method for use when displaying relational field select inputs. (\n#3254\n)\n\n\nFix issue with \nBooleanField\n checkboxes incorrectly displaying as checked. (\n#3258\n)\n\n\nEnsure empty checkboxes properly set \nBooleanField\n to \nFalse\n in all cases. (\n#2776\n)\n\n\nAllow \nWSGIRequest.FILES\n property without raising incorrect deprecated error. (\n#3261\n)\n\n\nResolve issue with rendering nested serializers in forms. (\n#3260\n)\n\n\nRaise an error if user accidentally pass a serializer instance to a response, rather than data. (\n#3241\n)\n\n\n\n\n3.2.1\n\n\nDate\n: \n7th August 2015\n.\n\n\n\n\nFix for relational select widgets rendering without any choices. (\n#3237\n)\n\n\nFix for \n1\n, \n0\n rendering as \ntrue\n, \nfalse\n in the admin interface. \n#3227\n)\n\n\nFix for ListFields with single value in HTML form input. (\n#3238\n)\n\n\nAllow \nrequest.FILES\n for compat with Django's \nHTTPRequest\n class. (\n#3239\n)\n\n\n\n\n3.2.0\n\n\nDate\n: \n6th August 2015\n.\n\n\n\n\nAdd \nAdminRenderer\n. (\n#2926\n)\n\n\nAdd \nFilePathField\n. (\n#1854\n)\n\n\nAdd \nallow_empty\n to \nListField\n. (\n#2250\n)\n\n\nSupport django-guardian 1.3. (\n#3165\n)\n\n\nSupport grouped choices. (\n#3225\n)\n\n\nSupport error forms in browsable API. (\n#3024\n)\n\n\nAllow permission classes to customize the error message. (\n#2539\n)\n\n\nSupport \nsource=\nmethod\n on hyperlinked fields. (\n#2690\n)\n\n\nListField(allow_null=True)\n now allows null as the list value, not null items in the list. (\n#2766\n)\n\n\nManyToMany()\n maps to \nallow_empty=False\n, \nManyToMany(blank=True)\n maps to \nallow_empty=True\n. (\n#2804\n)\n\n\nSupport custom serialization styles for primary key fields. (\n#2789\n)\n\n\nOPTIONS\n requests support nested representations. (\n#2915\n)\n\n\nSet \nview.action == \"metadata\"\n for viewsets with \nOPTIONS\n requests. (\n#3115\n)\n\n\nSupport \nallow_blank\n on \nUUIDField\n. ([#3130][gh#3130])\n\n\nDo not display view docstrings with 401 or 403 response codes. (\n#3216\n)\n\n\nResolve Django 1.8 deprecation warnings. (\n#2886\n)\n\n\nFix for \nDecimalField\n validation. (\n#3139\n)\n\n\nFix behavior of \nallow_blank=False\n when used with \ntrim_whitespace=True\n. (\n#2712\n)\n\n\nFix issue with some field combinations incorrectly mapping to an invalid \nallow_blank\n argument. (\n#3011\n)\n\n\nFix for output representations with prefetches and modified querysets. (\n#2704\n, \n#2727\n)\n\n\nFix assertion error when CursorPagination is provided with certains invalid query parameters. (#2920)\ngh2920\n.\n\n\nFix \nUnicodeDecodeError\n when invalid characters included in header with \nTokenAuthentication\n. (\n#2928\n)\n\n\nFix transaction rollbacks with \n@non_atomic_requests\n decorator. (\n#3016\n)\n\n\nFix duplicate results issue with Oracle databases using \nSearchFilter\n. (\n#2935\n)\n\n\nFix checkbox alignment and rendering in browsable API forms. (\n#2783\n)\n\n\nFix for unsaved file objects which should use \n\"url\": null\n in the representation. (\n#2759\n)\n\n\nFix field value rendering in browsable API. (\n#2416\n)\n\n\nFix \nHStoreField\n to include \nallow_blank=True\n in \nDictField\n mapping. (\n#2659\n)\n\n\nNumerous other cleanups, improvements to error messaging, private API \n minor fixes.\n\n\n\n\n\n\n3.1.x series\n\n\n3.1.3\n\n\nDate\n: \n4th June 2015\n.\n\n\n\n\nAdd \nDurationField\n. (\n#2481\n, \n#2989\n)\n\n\nAdd \nformat\n argument to \nUUIDField\n. (\n#2788\n, \n#3000\n)\n\n\nMultipleChoiceField\n empties incorrectly on a partial update using multipart/form-data (\n#2993\n, \n#2894\n)\n\n\nFix a bug in options related to read-only \nRelatedField\n. (\n#2981\n, \n#2811\n)\n\n\nFix nested serializers with \nunique_together\n relations. (\n#2975\n)\n\n\nAllow unexpected values for \nChoiceField\n/\nMultipleChoiceField\n representations. (\n#2839\n, \n#2940\n)\n\n\nRollback the transaction on error if \nATOMIC_REQUESTS\n is set. (\n#2887\n, \n#2034\n)\n\n\nSet the action on a view when override_method regardless of its None-ness. (\n#2933\n)\n\n\nDecimalField\n accepts \n2E+2\n as 200 and validates decimal place correctly. (\n#2948\n, \n#2947\n)\n\n\nSupport basic authentication with custom \nUserModel\n that change \nusername\n. (\n#2952\n)\n\n\nIPAddressField\n improvements. (\n#2747\n, \n#2618\n, \n#3008\n)\n\n\nImprove \nDecimalField\n for easier subclassing. (\n#2695\n)\n\n\n\n\n3.1.2\n\n\nDate\n: \n13rd May 2015\n.\n\n\n\n\nDateField.to_representation\n can handle str and empty values. (\n#2656\n, \n#2687\n, \n#2869\n)\n\n\nUse default reason phrases from HTTP standard. (\n#2764\n, \n#2763\n)\n\n\nRaise error when \nModelSerializer\n used with abstract model. (\n#2757\n, \n#2630\n)\n\n\nHandle reversal of non-API view_name in \nHyperLinkedRelatedField\n (\n#2724\n, \n#2711\n)\n\n\nDont require pk strictly for related fields. (\n#2745\n, \n#2754\n)\n\n\nMetadata detects null boolean field type. (\n#2762\n)\n\n\nProper handling of depth in nested serializers. (\n#2798\n)\n\n\nDisplay viewset without paginator. (\n#2807\n)\n\n\nDon't check for deprecated \n.model\n attribute in permissions (\n#2818\n)\n\n\nRestrict integer field to integers and strings. (\n#2835\n, \n#2836\n)\n\n\nImprove \nIntegerField\n to use compiled decimal regex. (\n#2853\n)\n\n\nPrevent empty \nqueryset\n to raise AssertionError. (\n#2862\n)\n\n\nDjangoModelPermissions\n rely on \nget_queryset\n. (\n#2863\n)\n\n\nCheck \nAcceptHeaderVersioning\n with content negotiation in place. (\n#2868\n)\n\n\nAllow \nDjangoObjectPermissions\n to use views that define \nget_queryset\n. (\n#2905\n)\n\n\n\n\n3.1.1\n\n\nDate\n: \n23rd March 2015\n.\n\n\n\n\nSecurity fix\n: Escape tab switching cookie name in browsable API.\n\n\nDisplay input forms in browsable API if \nserializer_class\n is used, even when \nget_serializer\n method does not exist on the view. (\n#2743\n)\n\n\nUse a password input for the AuthTokenSerializer. (\n#2741\n)\n\n\nFix missing anchor closing tag after next button. (\n#2691\n)\n\n\nFix \nlookup_url_kwarg\n handling in viewsets. (\n#2685\n, \n#2591\n)\n\n\nFix problem with importing \nrest_framework.views\n in \napps.py\n (\n#2678\n)\n\n\nLimitOffsetPagination raises \nTypeError\n if PAGE_SIZE not set (\n#2667\n, \n#2700\n)\n\n\nGerman translation for \nmin_value\n field error message references \nmax_value\n. (\n#2645\n)\n\n\nRemove \nMergeDict\n. (\n#2640\n)\n\n\nSupport serializing unsaved models with related fields. (\n#2637\n, \n#2641\n)\n\n\nAllow blank/null on radio.html choices. (\n#2631\n)\n\n\n\n\n3.1.0\n\n\nDate\n: \n5th March 2015\n.\n\n\nFor full details see the \n3.1 release announcement\n.\n\n\n\n\n3.0.x series\n\n\n3.0.5\n\n\nDate\n: \n10th February 2015\n.\n\n\n\n\nFix a bug where \n_closable_objects\n breaks pickling. (\n#1850\n, \n#2492\n)\n\n\nAllow non-standard \nUser\n models with \nThrottling\n. (\n#2524\n)\n\n\nSupport custom \nUser.db_table\n in TokenAuthentication migration. (\n#2479\n)\n\n\nFix misleading \nAttributeError\n tracebacks on \nRequest\n objects. (\n#2530\n, \n#2108\n)\n\n\nManyRelatedField.get_value\n clearing field on partial update. (\n#2475\n)\n\n\nRemoved '.model' shortcut from code. (\n#2486\n)\n\n\nFix \ndetail_route\n and \nlist_route\n mutable argument. (\n#2518\n)\n\n\nPrefetching the user object when getting the token in \nTokenAuthentication\n. (\n#2519\n)\n\n\n\n\n3.0.4\n\n\nDate\n: \n28th January 2015\n.\n\n\n\n\nDjango 1.8a1 support. (\n#2425\n, \n#2446\n, \n#2441\n)\n\n\nAdd \nDictField\n and support Django 1.8 \nHStoreField\n. (\n#2451\n, \n#2106\n)\n\n\nAdd \nUUIDField\n and support Django 1.8 \nUUIDField\n. (\n#2448\n, \n#2433\n, \n#2432\n)\n\n\nBaseRenderer.render\n now raises \nNotImplementedError\n. (\n#2434\n)\n\n\nFix timedelta JSON serialization on Python 2.6. (\n#2430\n)\n\n\nResultDict\n and \nResultList\n now appear as standard dict/list. (\n#2421\n)\n\n\nFix visible \nHiddenField\n in the HTML form of the web browsable API page. (\n#2410\n)\n\n\nUse \nOrderedDict\n for \nRelatedField.choices\n. (\n#2408\n)\n\n\nFix ident format when using \nHTTP_X_FORWARDED_FOR\n. (\n#2401\n)\n\n\nFix invalid key with memcached while using throttling. (\n#2400\n)\n\n\nFix \nFileUploadParser\n with version 3.x. (\n#2399\n)\n\n\nFix the serializer inheritance. (\n#2388\n)\n\n\nFix caching issues with \nReturnDict\n. (\n#2360\n)\n\n\n\n\n3.0.3\n\n\nDate\n: \n8th January 2015\n.\n\n\n\n\nFix \nMinValueValidator\n on \nmodels.DateField\n. (\n#2369\n)\n\n\nFix serializer missing context when pagination is used. (\n#2355\n)\n\n\nNamespaced router URLs are now supported by the \nDefaultRouter\n. (\n#2351\n)\n\n\nrequired=False\n allows omission of value for output. (\n#2342\n)\n\n\nUse textarea input for \nmodels.TextField\n. (\n#2340\n)\n\n\nUse custom \nListSerializer\n for pagination if required. (\n#2331\n, \n#2327\n)\n\n\nBetter behavior with null and '' for blank HTML fields. (\n#2330\n)\n\n\nEnsure fields in \nexclude\n are model fields. (\n#2319\n)\n\n\nFix \nIntegerField\n and \nmax_length\n argument incompatibility. (\n#2317\n)\n\n\nFix the YAML encoder for 3.0 serializers. (\n#2315\n, \n#2283\n)\n\n\nFix the behavior of empty HTML fields. (\n#2311\n, \n#1101\n)\n\n\nFix Metaclass attribute depth ignoring fields attribute. (\n#2287\n)\n\n\nFix \nformat_suffix_patterns\n to work with Django's \ni18n_patterns\n. (\n#2278\n)\n\n\nAbility to customize router URLs for custom actions, using \nurl_path\n. (\n#2010\n)\n\n\nDon't install Django REST Framework as egg. (\n#2386\n)\n\n\n\n\n3.0.2\n\n\nDate\n: \n17th December 2014\n.\n\n\n\n\nEnsure \nrequest.user\n is made available to response middleware. (\n#2155\n)\n\n\nClient.logout()\n also cancels any existing \nforce_authenticate\n. (\n#2218\n, \n#2259\n)\n\n\nExtra assertions and better checks to preventing incorrect serializer API use. (\n#2228\n, \n#2234\n, \n#2262\n, \n#2263\n, \n#2266\n, \n#2267\n, \n#2289\n, \n#2291\n)\n\n\nFixed \nmin_length\n message for \nCharField\n. (\n#2255\n)\n\n\nFix \nUnicodeDecodeError\n, which can occur on serializer \nrepr\n. (\n#2270\n, \n#2279\n)\n\n\nFix empty HTML values when a default is provided. (\n#2280\n, \n#2294\n)\n\n\nFix \nSlugRelatedField\n raising \nUnicodeEncodeError\n when used as a multiple choice input. (\n#2290\n)\n\n\n\n\n3.0.1\n\n\nDate\n: \n11th December 2014\n.\n\n\n\n\nMore helpful error message when the default Serializer \ncreate()\n fails. (\n#2013\n)\n\n\nRaise error when attempting to save serializer if data is not valid. (\n#2098\n)\n\n\nFix \nFileUploadParser\n breaks with empty file names and multiple upload handlers. (\n#2109\n)\n\n\nImprove \nBindingDict\n to support standard dict-functions. (\n#2135\n, \n#2163\n)\n\n\nAdd \nvalidate()\n to \nListSerializer\n. (\n#2168\n, \n#2225\n, \n#2232\n)\n\n\nFix JSONP renderer failing to escape some characters. (\n#2169\n, \n#2195\n)\n\n\nAdd missing default style for \nFileField\n. (\n#2172\n)\n\n\nActions are required when calling \nViewSet.as_view()\n. (\n#2175\n)\n\n\nAdd \nallow_blank\n to \nChoiceField\n. (\n#2184\n, \n#2239\n)\n\n\nCosmetic fixes in the HTML renderer. (\n#2187\n)\n\n\nRaise error if \nfields\n on serializer is not a list of strings. (\n#2193\n, \n#2213\n)\n\n\nImprove checks for nested creates and updates. (\n#2194\n, \n#2196\n)\n\n\nvalidated_attrs\n argument renamed to \nvalidated_data\n in \nSerializer\n \ncreate()\n/\nupdate()\n. (\n#2197\n)\n\n\nRemove deprecated code to reflect the dropped Django versions. (\n#2200\n)\n\n\nBetter serializer errors for nested writes. (\n#2202\n, \n#2215\n)\n\n\nFix pagination and custom permissions incompatibility. (\n#2205\n)\n\n\nRaise error if \nfields\n on serializer is not a list of strings. (\n#2213\n)\n\n\nAdd missing translation markers for relational fields. (\n#2231\n)\n\n\nImprove field lookup behavior for dicts/mappings. (\n#2244\n, \n#2243\n)\n\n\nOptimized hyperlinked PK. (\n#2242\n)\n\n\n\n\n3.0.0\n\n\nDate\n: 1st December 2014\n\n\nFor full details see the \n3.0 release announcement\n.\n\n\n\n\nFor older release notes, \nplease see the version 2.x documentation\n.",
+ "text": "Release Notes\n\n\n\n\nRelease Early, Release Often\n\n\n Eric S. Raymond, \nThe Cathedral and the Bazaar\n.\n\n\n\n\nVersioning\n\n\nMinor version numbers (0.0.x) are used for changes that are API compatible. You should be able to upgrade between minor point releases without any other code changes.\n\n\nMedium version numbers (0.x.0) may include API changes, in line with the \ndeprecation policy\n. You should read the release notes carefully before upgrading between medium point releases.\n\n\nMajor version numbers (x.0.0) are reserved for substantial project milestones.\n\n\nDeprecation policy\n\n\nREST framework releases follow a formal deprecation policy, which is in line with \nDjango's deprecation policy\n.\n\n\nThe timeline for deprecation of a feature present in version 1.0 would work as follows:\n\n\n\n\n\n\nVersion 1.1 would remain \nfully backwards compatible\n with 1.0, but would raise \nPendingDeprecationWarning\n warnings if you use the feature that are due to be deprecated. These warnings are \nsilent by default\n, but can be explicitly enabled when you're ready to start migrating any required changes. For example if you start running your tests using \npython -Wd manage.py test\n, you'll be warned of any API changes you need to make.\n\n\n\n\n\n\nVersion 1.2 would escalate these warnings to \nDeprecationWarning\n, which is loud by default.\n\n\n\n\n\n\nVersion 1.3 would remove the deprecated bits of API entirely.\n\n\n\n\n\n\nNote that in line with Django's policy, any parts of the framework not mentioned in the documentation should generally be considered private API, and may be subject to change.\n\n\nUpgrading\n\n\nTo upgrade Django REST framework to the latest version, use pip:\n\n\npip install -U djangorestframework\n\n\n\nYou can determine your currently installed version using \npip freeze\n:\n\n\npip freeze | grep djangorestframework\n\n\n\n\n\n3.5.x series\n\n\n3.5.2\n\n\nDate\n: \n1st November 2016\n\n\n\n\nRestore exception tracebacks in Python 2.7. (\n#4631\n, \n#4638\n)\n\n\nProperly display dicts in the admin console. (\n#4532\n, \n#4636\n)\n\n\nFix is_simple_callable with variable args, kwargs. (\n#4622\n, \n#4602\n)\n\n\nSupport 'on'/'off' literals with BooleanField. (\n#4640\n, \n#4624\n)\n\n\nEnable cursor pagination of value querysets. (\n#4569\n)\n\n\nFix support of get_full_details() for Throttled exceptions. (\n#4627\n)\n\n\nFix FilterSet proxy. (\n#4620\n)\n\n\nMake serializer fields import explicit. (\n#4628\n)\n\n\nDrop redundant requests adapter. (\n#4639\n)\n\n\n\n\n3.5.1\n\n\nDate\n: \n21st October 2016\n\n\n\n\nMake \nrest_framework/compat.py\n imports. (\n#4612\n, \n#4608\n, \n#4601\n)\n\n\nFix bug in schema base path generation. (\n#4611\n, \n#4605\n)\n\n\nFix broken case of ListSerializer with single item. (\n#4609\n, \n#4606\n)\n\n\nRemove bare \nraise\n for Python 3.5 compat. (\n#4600\n)\n\n\n\n\n3.5.0\n\n\nDate\n: \n20th October 2016\n\n\n\n\n3.4.x series\n\n\n3.4.7\n\n\nDate\n: \n21st September 2016\n\n\n\n\nFallback behavior for request parsing when request.POST already accessed. (\n#3951\n, \n#4500\n)\n\n\nFix regression of \nRegexField\n. (\n#4489\n, \n#4490\n, \n#2617\n)\n\n\nMissing comma in \nadmin.html\n causing CSRF error. (\n#4472\n, \n#4473\n)\n\n\nFix response rendering with empty context. (\n#4495\n)\n\n\nFix indentation regression in API listing. (\n#4493\n)\n\n\nFixed an issue where the incorrect value is set to \nResolverMatch.func_name\n of api_view decorated view. (\n#4465\n, \n#4462\n)\n\n\nFix \nAPIClient.get()\n when path contains unicode arguments (\n#4458\n)\n\n\n\n\n3.4.6\n\n\nDate\n: \n23rd August 2016\n\n\n\n\nFix malformed Javascript in browsable API. (\n#4435\n)\n\n\nSkip HiddenField from Schema fields. (\n#4425\n, \n#4429\n)\n\n\nImprove Create to show the original exception traceback. (\n#3508\n)\n\n\nFix \nAdminRenderer\n display of PK only related fields. (\n#4419\n, \n#4423\n)\n\n\n\n\n3.4.5\n\n\nDate\n: \n19th August 2016\n\n\n\n\nImprove debug error handling. (\n#4416\n, \n#4409\n)\n\n\nAllow custom CSRF_HEADER_NAME setting. (\n#4415\n, \n#4410\n)\n\n\nInclude .action attribute on viewsets when generating schemas. (\n#4408\n, \n#4398\n)\n\n\nDo not include request.FILES items in request.POST. (\n#4407\n)\n\n\nFix rendering of checkbox multiple. (\n#4403\n)\n\n\nFix docstring of Field.get_default. (\n#4404\n)\n\n\nReplace utf8 character with its ascii counterpart in README. (\n#4412\n)\n\n\n\n\n3.4.4\n\n\nDate\n: \n12th August 2016\n\n\n\n\nEnsure views are fully initialized when generating schemas. (\n#4373\n, \n#4382\n, \n#4383\n, \n#4279\n, \n#4278\n)\n\n\nAdd form field descriptions to schemas. (\n#4387\n)\n\n\nFix category generation for schema endpoints. (\n#4391\n, \n#4394\n, \n#4390\n, \n#4386\n, \n#4376\n, \n#4329\n)\n\n\nDon't strip empty query params when paginating. (\n#4392\n, \n#4393\n, \n#4260\n)\n\n\nDo not re-run query for empty results with LimitOffsetPagination. (\n#4201\n, \n#4388\n)\n\n\nStricter type validation for CharField. (\n#4380\n, \n#3394\n)\n\n\nRelatedField.choices should preserve non-string values. (\n#4111\n, \n#4379\n, \n#3365\n)\n\n\nTest case for rendering checkboxes in vertical form style. (\n#4378\n, \n#3868\n, \n#3868\n)\n\n\nShow error traceback HTML in browsable API (\n#4042\n, \n#4172\n)\n\n\nFix handling of ALLOWED_VERSIONS and no DEFAULT_VERSION. \n#4370\n\n\nAllow \nmax_digits=None\n on DecimalField. (\n#4377\n, \n#4372\n)\n\n\nLimit queryset when rendering relational choices. (\n#4375\n, \n#4122\n, \n#3329\n, \n#3330\n, \n#3877\n)\n\n\nResolve form display with ChoiceField, MultipleChoiceField and non-string choices. (\n#4374\n, \n#4119\n, \n#4121\n, \n#4137\n, \n#4120\n)\n\n\nFix call to TemplateHTMLRenderer.resolve_context() fallback method. (\n#4371\n)\n\n\n\n\n3.4.3\n\n\nDate\n: \n5th August 2016\n\n\n\n\nInclude fallaback for users of older TemplateHTMLRenderer internal API. (\n#4361\n)\n\n\n\n\n3.4.2\n\n\nDate\n: \n5th August 2016\n\n\n\n\nInclude kwargs passed to 'as_view' when generating schemas. (\n#4359\n, \n#4330\n, \n#4331\n)\n\n\nAccess \nrequest.user.is_authenticated\n as property not method, under Django 1.10+ (\n#4358\n, \n#4354\n)\n\n\nFilter HEAD out from schemas. (\n#4357\n)\n\n\nextra_kwargs takes precedence over uniqueness kwargs. (\n#4198\n, \n#4199\n, \n#4349\n)\n\n\nCorrect descriptions when tabs are used in code indentation. (\n#4345\n, \n#4347\n)*\n\n\nChange template context generation in TemplateHTMLRenderer. (\n#4236\n)\n\n\nSerializer defaults should not be included in partial updates. (\n#4346\n, \n#3565\n)\n\n\nConsistent behavior \n descriptive error from FileUploadParser when filename not included. (\n#4340\n, \n#3610\n, \n#4292\n, \n#4296\n)\n\n\nDecimalField quantizes incoming digitals. (\n#4339\n, \n#4318\n)\n\n\nHandle non-string input for IP fields. (\n#4335\n, \n#4336\n, \n#4338\n)\n\n\nFix leading slash handling when Schema generation includes a root URL. (\n#4332\n)\n\n\nTest cases for DictField with allow_null options. (\n#4348\n)\n\n\nUpdate tests from Django 1.10 beta to Django 1.10. (\n#4344\n)\n\n\n\n\n3.4.1\n\n\nDate\n: \n28th July 2016\n\n\n\n\nAdded \nroot_renderers\n argument to \nDefaultRouter\n. (\n#4323\n, \n#4268\n)\n\n\nAdded \nurl\n and \nschema_url\n arguments. (\n#4321\n, \n#4308\n, \n#4305\n)\n\n\nUnique together checks should apply to read-only fields which have a default. (\n#4316\n, \n#4294\n)\n\n\nSet view.format_kwarg in schema generator. (\n#4293\n, \n#4315\n)\n\n\nFix schema generator for views with \npagination_class = None\n. (\n#4314\n, \n#4289\n)\n\n\nFix schema generator for views with no \nget_serializer_class\n. (\n#4265\n, \n#4285\n)\n\n\nFixes for media type parameters in \nAccept\n and \nContent-Type\n headers. (\n#4287\n, \n#4313\n, \n#4281\n)\n\n\nUse verbose_name instead of object_name in error messages. (\n#4299\n)\n\n\nMinor version update to Twitter Bootstrap. (\n#4307\n)\n\n\nSearchFilter raises error when using with related field. (\n#4302\n, \n#4303\n, \n#4298\n)\n\n\nAdding support for RFC 4918 status codes. (\n#4291\n)\n\n\nAdd LICENSE.md to the built wheel. (\n#4270\n)\n\n\nSerializing \"complex\" field returns None instead of the value since 3.4 (\n#4272\n, \n#4273\n, \n#4288\n)\n\n\n\n\n3.4.0\n\n\nDate\n: \n14th July 2016\n\n\n\n\nDon't strip microseconds in JSON output. (\n#4256\n)\n\n\nTwo slightly different iso 8601 datetime serialization. (\n#4255\n)\n\n\nResolve incorrect inclusion of media type parameters. (\n#4254\n)\n\n\nResponse Content-Type potentially malformed. (\n#4253\n)\n\n\nFix setup.py error on some platforms. (\n#4246\n)\n\n\nMove alternate formats in coreapi into separate packages. (\n#4244\n)\n\n\nAdd localize keyword argument to \nDecimalField\n. (\n#4233\n)\n\n\nFix issues with routers for custom list-route and detail-routes. (\n#4229\n)\n\n\nNamespace versioning with nested namespaces. (\n#4219\n)\n\n\nRobust uniqueness checks. (\n#4217\n)\n\n\nMinor refactoring of \nmust_call_distinct\n. (\n#4215\n)\n\n\nOverridable offset cutoff in CursorPagination. (\n#4212\n)\n\n\nPass through strings as-in with date/time fields. (\n#4196\n)\n\n\nAdd test confirming that required=False is valid on a relational field. (\n#4195\n)\n\n\nIn LimitOffsetPagination \nlimit=0\n should revert to default limit. (\n#4194\n)\n\n\nExclude read_only=True fields from unique_together validation \n add docs. (\n#4192\n)\n\n\nHandle bytestrings in JSON. (\n#4191\n)\n\n\nJSONField(binary=True) represents using binary strings, which JSONRenderer does not support. (\n#4187\n)\n\n\nJSONField(binary=True) represents using binary strings, which JSONRenderer does not support. (\n#4185\n)\n\n\nMore robust form rendering in the browsable API. (\n#4181\n)\n\n\nEmpty cases of \n.validated_data\n and \n.errors\n as lists not dicts for ListSerializer. (\n#4180\n)\n\n\nSchemas \n client libraries. (\n#4179\n)\n\n\nRemoved \nAUTH_USER_MODEL\n compat property. (\n#4176\n)\n\n\nClean up existing deprecation warnings. (\n#4166\n)\n\n\nDjango 1.10 support. (\n#4158\n)\n\n\nUpdated jQuery version to 1.12.4. (\n#4157\n)\n\n\nMore robust default behavior on OrderingFilter. (\n#4156\n)\n\n\ndescription.py codes and tests removal. (\n#4153\n)\n\n\nWrap guardian.VERSION in tuple. (\n#4149\n)\n\n\nRefine validator for fields with \n kwargs. (\n#4146\n)\n\n\nFix None values representation in childs of ListField, DictField. (\n#4118\n)\n\n\nResolve TimeField representation for midnight value. (\n#4107\n)\n\n\nSet proper status code in AdminRenderer for the redirection after POST/DELETE requests. (\n#4106\n)\n\n\nTimeField render returns None instead of 00:00:00. (\n#4105\n)\n\n\nFix incorrectly named zh-hans and zh-hant locale path. (\n#4103\n)\n\n\nPrevent raising exception when limit is 0. (\n#4098\n)\n\n\nTokenAuthentication: Allow custom keyword in the header. (\n#4097\n)\n\n\nHandle incorrectly padded HTTP basic auth header. (\n#4090\n)\n\n\nLimitOffset pagination crashes Browseable API when limit=0. (\n#4079\n)\n\n\nFixed DecimalField arbitrary precision support. (\n#4075\n)\n\n\nAdded support for custom CSRF cookie names. (\n#4049\n)\n\n\nFix regression introduced by #4035. (\n#4041\n)\n\n\nNo auth view failing permission should raise 403. (\n#4040\n)\n\n\nFix string_types / text_types confusion. (\n#4025\n)\n\n\nDo not list related field choices in OPTIONS requests. (\n#4021\n)\n\n\nFix typo. (\n#4008\n)\n\n\nReorder initializing the view. (\n#4006\n)\n\n\nType error in DjangoObjectPermissionsFilter on Python 3.4. (\n#4005\n)\n\n\nFixed use of deprecated Query.aggregates. (\n#4003\n)\n\n\nFix blank lines around docstrings. (\n#4002\n)\n\n\nFixed admin pagination when limit is 0. (\n#3990\n)\n\n\nOrderingFilter adjustements. (\n#3983\n)\n\n\nNon-required serializer related fields. (\n#3976\n)\n\n\nUsing safer calling way of \"@api_view\" in tutorial. (\n#3971\n)\n\n\nListSerializer doesn't handle unique_together constraints. (\n#3970\n)\n\n\nAdd missing migration file. (\n#3968\n)\n\n\nOrderingFilter\n should call \nget_serializer_class()\n to determine default fields. (\n#3964\n)\n\n\nRemove old django checks from tests and compat. (\n#3953\n)\n\n\nSupport callable as the value of \ninitial\n for any \nserializer.Field\n. (\n#3943\n)\n\n\nPrevented unnecessary distinct() call in SearchFilter. (\n#3938\n)\n\n\nFix None UUID ForeignKey serialization. (\n#3936\n)\n\n\nDrop EOL Django 1.7. (\n#3933\n)\n\n\nAdd missing space in serializer error message. (\n#3926\n)\n\n\nFixed _force_text_recursive typo. (\n#3908\n)\n\n\nAttempt to address Django 2.0 deprecate warnings related to \nfield.rel\n. (\n#3906\n)\n\n\nFix parsing multipart data using a nested serializer with list. (\n#3820\n)\n\n\nResolving APIs URL to different namespaces. (\n#3816\n)\n\n\nDo not HTML-escape \nhelp_text\n in Browsable API forms. (\n#3812\n)\n\n\nOPTIONS fetches and shows all possible foreign keys in choices field. (\n#3751\n)\n\n\nDjango 1.9 deprecation warnings (\n#3729\n)\n\n\nTest case for #3598 (\n#3710\n)\n\n\nAdding support for multiple values for search filter. (\n#3541\n)\n\n\nUse get_serializer_class in ordering filter. (\n#3487\n)\n\n\nSerializers with many=True should return empty list rather than empty dict. (\n#3476\n)\n\n\nLimitOffsetPagination limit=0 fix. (\n#3444\n)\n\n\nEnable Validators to defer string evaluation and handle new string format. (\n#3438\n)\n\n\nUnique validator is executed and breaks if field is invalid. (\n#3381\n)\n\n\nDo not ignore overridden View.get_view_name() in breadcrumbs. (\n#3273\n)\n\n\nRetry form rendering when rendering with serializer fails. (\n#3164\n)\n\n\nUnique constraint prevents nested serializers from updating. (\n#2996\n)\n\n\nUniqueness validators should not be run for excluded (read_only) fields. (\n#2848\n)\n\n\nUniqueValidator raises exception for nested objects. (\n#2403\n)\n\n\nlookup_type\n is deprecated in favor of \nlookup_expr\n. (\n#4259\n)\n\n\n\n\n\n\n3.3.x series\n\n\n3.3.3\n\n\nDate\n: \n14th March 2016\n.\n\n\n\n\nRemove version string from templates. Thanks to @blag for the report and fixes. (\n#3878\n, \n#3913\n, \n#3912\n)\n\n\nFixes vertical html layout for \nBooleanField\n. Thanks to Mikalai Radchuk for the fix. (\n#3910\n)\n\n\nSilenced deprecation warnings on Django 1.8. Thanks to Simon Charette for the fix. (\n#3903\n)\n\n\nInternationalization for authtoken. Thanks to Michael Nacharov for the fix. (\n#3887\n, \n#3968\n)\n\n\nFix \nToken\n model as \nabstract\n when the authtoken application isn't declared. Thanks to Adam Thomas for the report. (\n#3860\n, \n#3858\n)\n\n\nImprove Markdown version compatibility. Thanks to Michael J. Schultz for the fix. (\n#3604\n, \n#3842\n)\n\n\nQueryParameterVersioning\n does not use \nDEFAULT_VERSION\n setting. Thanks to Brad Montgomery for the fix. (\n#3833\n)\n\n\nAdd an explicit \non_delete\n on the models. Thanks to Mads Jensen for the fix. (\n#3832\n)\n\n\nFix \nDateField.to_representation\n to work with Python 2 unicode. Thanks to Mikalai Radchuk for the fix. (\n#3819\n)\n\n\nFixed \nTimeField\n not handling string times. Thanks to Areski Belaid for the fix. (\n#3809\n)\n\n\nAvoid updates of \nMeta.extra_kwargs\n. Thanks to Kevin Massey for the report and fix. (\n#3805\n, \n#3804\n)\n\n\nFix nested validation error being rendered incorrectly. Thanks to Craig de Stigter for the fix. (\n#3801\n)\n\n\nDocument how to avoid CSRF and missing button issues with \ndjango-crispy-forms\n. Thanks to Emmanuelle Delescolle, Jos\u00e9 Padilla and Luis San Pablo for the report, analysis and fix. (\n#3787\n, \n#3636\n, \n#3637\n)\n\n\nImprove Rest Framework Settings file setup time. Thanks to Miles Hutson for the report and Mads Jensen for the fix. (\n#3786\n, \n#3815\n)\n\n\nImprove authtoken compatibility with Django 1.9. Thanks to S. Andrew Sheppard for the fix. (\n#3785\n)\n\n\nFix \nMin/MaxValueValidator\n transfer from a model's \nDecimalField\n. Thanks to Kevin Brown for the fix. (\n#3774\n)\n\n\nImprove HTML title in the Browsable API. Thanks to Mike Lissner for the report and fix. (\n#3769\n)\n\n\nFix \nAutoFilterSet\n to inherit from \ndefault_filter_set\n. Thanks to Tom Linford for the fix. (\n#3753\n)\n\n\nFix transifex config to handle the new Chinese language codes. Thanks to @nypisces for the report and fix. (\n#3739\n)\n\n\nDateTimeField\n does not handle empty values correctly. Thanks to Mick Parker for the report and fix. (\n#3731\n, \n#3726\n)\n\n\nRaise error when setting a removed rest_framework setting. Thanks to Luis San Pablo for the fix. (\n#3715\n)\n\n\nAdd missing csrf_token in AdminRenderer post form. Thanks to Piotr \u015aniegowski for the fix. (\n#3703\n)\n\n\nRefactored \n_get_reverse_relationships()\n to use correct \nto_field\n. Thanks to Benjamin Phillips for the fix. (\n#3696\n)\n\n\nDocument the use of \nget_queryset\n for \nRelatedField\n. Thanks to Ryan Hiebert for the fix. (\n#3605\n)\n\n\nFix empty pk detection in HyperlinkRelatedField.get_url. Thanks to @jslang for the fix (\n#3962\n)\n\n\n\n\n3.3.2\n\n\nDate\n: \n14th December 2015\n.\n\n\n\n\nListField\n enforces input is a list. (\n#3513\n)\n\n\nFix regression hiding raw data form. (\n#3600\n, \n#3578\n)\n\n\nFix Python 3.5 compatibility. (\n#3534\n, \n#3626\n)\n\n\nAllow setting a custom Django Paginator in \npagination.PageNumberPagination\n. (\n#3631\n, \n#3684\n)\n\n\nFix relational fields without \nto_fields\n attribute. (\n#3635\n, \n#3634\n)\n\n\nFix \ntemplate.render\n deprecation warnings for Django 1.9. (\n#3654\n)\n\n\nSort response headers in browsable API renderer. (\n#3655\n)\n\n\nUse related_objects api for Django 1.9+. (\n#3656\n, \n#3252\n)\n\n\nAdd confirm modal when deleting. (\n#3228\n, \n#3662\n)\n\n\nReveal previously hidden AttributeErrors and TypeErrors while calling has_[object_]permissions. (\n#3668\n)\n\n\nMake DRF compatible with multi template engine in Django 1.8. (\n#3672\n)\n\n\nUpdate \nNestedBoundField\n to also handle empty string when rendering its form. (\n#3677\n)\n\n\nFix UUID validation to properly catch invalid input types. (\n#3687\n, \n#3679\n)\n\n\nFix caching issues. (\n#3628\n, \n#3701\n)\n\n\nFix Admin and API browser for views without a filter_class. (\n#3705\n, \n#3596\n, \n#3597\n)\n\n\nAdd app_name to rest_framework.urls. (\n#3714\n)\n\n\nImprove authtoken's views to support url versioning. (\n#3718\n, \n#3723\n)\n\n\n\n\n3.3.1\n\n\nDate\n: \n4th November 2015\n.\n\n\n\n\nResolve parsing bug when accessing \nrequest.POST\n (\n#3592\n)\n\n\nCorrectly deal with \nto_field\n referring to primary key. (\n#3593\n)\n\n\nAllow filter HTML to render when no \nfilter_class\n is defined. (\n#3560\n)\n\n\nFix admin rendering issues. (\n#3564\n, \n#3556\n)\n\n\nFix issue with DecimalValidator. (\n#3568\n)\n\n\n\n\n3.3.0\n\n\nDate\n: \n28th October 2015\n.\n\n\n\n\nHTML controls for filters. (\n#3315\n)\n\n\nForms API. (\n#3475\n)\n\n\nAJAX browsable API. (\n#3410\n)\n\n\nAdded JSONField. (\n#3454\n)\n\n\nCorrectly map \nto_field\n when creating \nModelSerializer\n relational fields. (\n#3526\n)\n\n\nInclude keyword arguments when mapping \nFilePathField\n to a serializer field. (\n#3536\n)\n\n\nMap appropriate model \nerror_messages\n on \nModelSerializer\n uniqueness constraints. (\n#3435\n)\n\n\nInclude \nmax_length\n constraint for \nModelSerializer\n fields mapped from TextField. (\n#3509\n)\n\n\nAdded support for Django 1.9. (\n#3450\n, \n#3525\n)\n\n\nRemoved support for Django 1.5 \n 1.6. (\n#3421\n, \n#3429\n)\n\n\nRemoved 'south' migrations. (\n#3495\n)\n\n\n\n\n\n\n3.2.x series\n\n\n3.2.5\n\n\nDate\n: \n27th October 2015\n.\n\n\n\n\nEscape \nusername\n in optional logout tag. (\n#3550\n)\n\n\n\n\n3.2.4\n\n\nDate\n: \n21th September 2015\n.\n\n\n\n\nDon't error on missing \nViewSet.search_fields\n attribute. (\n#3324\n, \n#3323\n)\n\n\nFix \nallow_empty\n not working on serializers with \nmany=True\n. (\n#3361\n, \n#3364\n)\n\n\nLet \nDurationField\n accepts integers. (\n#3359\n)\n\n\nMulti-level dictionaries not supported in multipart requests. (\n#3314\n)\n\n\nFix \nListField\n truncation on HTTP PATCH (\n#3415\n, \n#2761\n)\n\n\n\n\n3.2.3\n\n\nDate\n: \n24th August 2015\n.\n\n\n\n\nAdded \nhtml_cutoff\n and \nhtml_cutoff_text\n for limiting select dropdowns. (\n#3313\n)\n\n\nAdded regex style to \nSearchFilter\n. (\n#3316\n)\n\n\nResolve issues with setting blank HTML fields. (\n#3318\n) (\n#3321\n)\n\n\nCorrectly display existing 'select multiple' values in browsable API forms. (\n#3290\n)\n\n\nResolve duplicated validation message for \nIPAddressField\n. ([#3249[gh3249]) (\n#3250\n)\n\n\nFix to ensure admin renderer continues to work when pagination is disabled. (\n#3275\n)\n\n\nResolve error with \nLimitOffsetPagination\n when count=0, offset=0. (\n#3303\n)\n\n\n\n\n3.2.2\n\n\nDate\n: \n13th August 2015\n.\n\n\n\n\nAdd \ndisplay_value()\n method for use when displaying relational field select inputs. (\n#3254\n)\n\n\nFix issue with \nBooleanField\n checkboxes incorrectly displaying as checked. (\n#3258\n)\n\n\nEnsure empty checkboxes properly set \nBooleanField\n to \nFalse\n in all cases. (\n#2776\n)\n\n\nAllow \nWSGIRequest.FILES\n property without raising incorrect deprecated error. (\n#3261\n)\n\n\nResolve issue with rendering nested serializers in forms. (\n#3260\n)\n\n\nRaise an error if user accidentally pass a serializer instance to a response, rather than data. (\n#3241\n)\n\n\n\n\n3.2.1\n\n\nDate\n: \n7th August 2015\n.\n\n\n\n\nFix for relational select widgets rendering without any choices. (\n#3237\n)\n\n\nFix for \n1\n, \n0\n rendering as \ntrue\n, \nfalse\n in the admin interface. \n#3227\n)\n\n\nFix for ListFields with single value in HTML form input. (\n#3238\n)\n\n\nAllow \nrequest.FILES\n for compat with Django's \nHTTPRequest\n class. (\n#3239\n)\n\n\n\n\n3.2.0\n\n\nDate\n: \n6th August 2015\n.\n\n\n\n\nAdd \nAdminRenderer\n. (\n#2926\n)\n\n\nAdd \nFilePathField\n. (\n#1854\n)\n\n\nAdd \nallow_empty\n to \nListField\n. (\n#2250\n)\n\n\nSupport django-guardian 1.3. (\n#3165\n)\n\n\nSupport grouped choices. (\n#3225\n)\n\n\nSupport error forms in browsable API. (\n#3024\n)\n\n\nAllow permission classes to customize the error message. (\n#2539\n)\n\n\nSupport \nsource=\nmethod\n on hyperlinked fields. (\n#2690\n)\n\n\nListField(allow_null=True)\n now allows null as the list value, not null items in the list. (\n#2766\n)\n\n\nManyToMany()\n maps to \nallow_empty=False\n, \nManyToMany(blank=True)\n maps to \nallow_empty=True\n. (\n#2804\n)\n\n\nSupport custom serialization styles for primary key fields. (\n#2789\n)\n\n\nOPTIONS\n requests support nested representations. (\n#2915\n)\n\n\nSet \nview.action == \"metadata\"\n for viewsets with \nOPTIONS\n requests. (\n#3115\n)\n\n\nSupport \nallow_blank\n on \nUUIDField\n. ([#3130][gh#3130])\n\n\nDo not display view docstrings with 401 or 403 response codes. (\n#3216\n)\n\n\nResolve Django 1.8 deprecation warnings. (\n#2886\n)\n\n\nFix for \nDecimalField\n validation. (\n#3139\n)\n\n\nFix behavior of \nallow_blank=False\n when used with \ntrim_whitespace=True\n. (\n#2712\n)\n\n\nFix issue with some field combinations incorrectly mapping to an invalid \nallow_blank\n argument. (\n#3011\n)\n\n\nFix for output representations with prefetches and modified querysets. (\n#2704\n, \n#2727\n)\n\n\nFix assertion error when CursorPagination is provided with certains invalid query parameters. (#2920)\ngh2920\n.\n\n\nFix \nUnicodeDecodeError\n when invalid characters included in header with \nTokenAuthentication\n. (\n#2928\n)\n\n\nFix transaction rollbacks with \n@non_atomic_requests\n decorator. (\n#3016\n)\n\n\nFix duplicate results issue with Oracle databases using \nSearchFilter\n. (\n#2935\n)\n\n\nFix checkbox alignment and rendering in browsable API forms. (\n#2783\n)\n\n\nFix for unsaved file objects which should use \n\"url\": null\n in the representation. (\n#2759\n)\n\n\nFix field value rendering in browsable API. (\n#2416\n)\n\n\nFix \nHStoreField\n to include \nallow_blank=True\n in \nDictField\n mapping. (\n#2659\n)\n\n\nNumerous other cleanups, improvements to error messaging, private API \n minor fixes.\n\n\n\n\n\n\n3.1.x series\n\n\n3.1.3\n\n\nDate\n: \n4th June 2015\n.\n\n\n\n\nAdd \nDurationField\n. (\n#2481\n, \n#2989\n)\n\n\nAdd \nformat\n argument to \nUUIDField\n. (\n#2788\n, \n#3000\n)\n\n\nMultipleChoiceField\n empties incorrectly on a partial update using multipart/form-data (\n#2993\n, \n#2894\n)\n\n\nFix a bug in options related to read-only \nRelatedField\n. (\n#2981\n, \n#2811\n)\n\n\nFix nested serializers with \nunique_together\n relations. (\n#2975\n)\n\n\nAllow unexpected values for \nChoiceField\n/\nMultipleChoiceField\n representations. (\n#2839\n, \n#2940\n)\n\n\nRollback the transaction on error if \nATOMIC_REQUESTS\n is set. (\n#2887\n, \n#2034\n)\n\n\nSet the action on a view when override_method regardless of its None-ness. (\n#2933\n)\n\n\nDecimalField\n accepts \n2E+2\n as 200 and validates decimal place correctly. (\n#2948\n, \n#2947\n)\n\n\nSupport basic authentication with custom \nUserModel\n that change \nusername\n. (\n#2952\n)\n\n\nIPAddressField\n improvements. (\n#2747\n, \n#2618\n, \n#3008\n)\n\n\nImprove \nDecimalField\n for easier subclassing. (\n#2695\n)\n\n\n\n\n3.1.2\n\n\nDate\n: \n13rd May 2015\n.\n\n\n\n\nDateField.to_representation\n can handle str and empty values. (\n#2656\n, \n#2687\n, \n#2869\n)\n\n\nUse default reason phrases from HTTP standard. (\n#2764\n, \n#2763\n)\n\n\nRaise error when \nModelSerializer\n used with abstract model. (\n#2757\n, \n#2630\n)\n\n\nHandle reversal of non-API view_name in \nHyperLinkedRelatedField\n (\n#2724\n, \n#2711\n)\n\n\nDont require pk strictly for related fields. (\n#2745\n, \n#2754\n)\n\n\nMetadata detects null boolean field type. (\n#2762\n)\n\n\nProper handling of depth in nested serializers. (\n#2798\n)\n\n\nDisplay viewset without paginator. (\n#2807\n)\n\n\nDon't check for deprecated \n.model\n attribute in permissions (\n#2818\n)\n\n\nRestrict integer field to integers and strings. (\n#2835\n, \n#2836\n)\n\n\nImprove \nIntegerField\n to use compiled decimal regex. (\n#2853\n)\n\n\nPrevent empty \nqueryset\n to raise AssertionError. (\n#2862\n)\n\n\nDjangoModelPermissions\n rely on \nget_queryset\n. (\n#2863\n)\n\n\nCheck \nAcceptHeaderVersioning\n with content negotiation in place. (\n#2868\n)\n\n\nAllow \nDjangoObjectPermissions\n to use views that define \nget_queryset\n. (\n#2905\n)\n\n\n\n\n3.1.1\n\n\nDate\n: \n23rd March 2015\n.\n\n\n\n\nSecurity fix\n: Escape tab switching cookie name in browsable API.\n\n\nDisplay input forms in browsable API if \nserializer_class\n is used, even when \nget_serializer\n method does not exist on the view. (\n#2743\n)\n\n\nUse a password input for the AuthTokenSerializer. (\n#2741\n)\n\n\nFix missing anchor closing tag after next button. (\n#2691\n)\n\n\nFix \nlookup_url_kwarg\n handling in viewsets. (\n#2685\n, \n#2591\n)\n\n\nFix problem with importing \nrest_framework.views\n in \napps.py\n (\n#2678\n)\n\n\nLimitOffsetPagination raises \nTypeError\n if PAGE_SIZE not set (\n#2667\n, \n#2700\n)\n\n\nGerman translation for \nmin_value\n field error message references \nmax_value\n. (\n#2645\n)\n\n\nRemove \nMergeDict\n. (\n#2640\n)\n\n\nSupport serializing unsaved models with related fields. (\n#2637\n, \n#2641\n)\n\n\nAllow blank/null on radio.html choices. (\n#2631\n)\n\n\n\n\n3.1.0\n\n\nDate\n: \n5th March 2015\n.\n\n\nFor full details see the \n3.1 release announcement\n.\n\n\n\n\n3.0.x series\n\n\n3.0.5\n\n\nDate\n: \n10th February 2015\n.\n\n\n\n\nFix a bug where \n_closable_objects\n breaks pickling. (\n#1850\n, \n#2492\n)\n\n\nAllow non-standard \nUser\n models with \nThrottling\n. (\n#2524\n)\n\n\nSupport custom \nUser.db_table\n in TokenAuthentication migration. (\n#2479\n)\n\n\nFix misleading \nAttributeError\n tracebacks on \nRequest\n objects. (\n#2530\n, \n#2108\n)\n\n\nManyRelatedField.get_value\n clearing field on partial update. (\n#2475\n)\n\n\nRemoved '.model' shortcut from code. (\n#2486\n)\n\n\nFix \ndetail_route\n and \nlist_route\n mutable argument. (\n#2518\n)\n\n\nPrefetching the user object when getting the token in \nTokenAuthentication\n. (\n#2519\n)\n\n\n\n\n3.0.4\n\n\nDate\n: \n28th January 2015\n.\n\n\n\n\nDjango 1.8a1 support. (\n#2425\n, \n#2446\n, \n#2441\n)\n\n\nAdd \nDictField\n and support Django 1.8 \nHStoreField\n. (\n#2451\n, \n#2106\n)\n\n\nAdd \nUUIDField\n and support Django 1.8 \nUUIDField\n. (\n#2448\n, \n#2433\n, \n#2432\n)\n\n\nBaseRenderer.render\n now raises \nNotImplementedError\n. (\n#2434\n)\n\n\nFix timedelta JSON serialization on Python 2.6. (\n#2430\n)\n\n\nResultDict\n and \nResultList\n now appear as standard dict/list. (\n#2421\n)\n\n\nFix visible \nHiddenField\n in the HTML form of the web browsable API page. (\n#2410\n)\n\n\nUse \nOrderedDict\n for \nRelatedField.choices\n. (\n#2408\n)\n\n\nFix ident format when using \nHTTP_X_FORWARDED_FOR\n. (\n#2401\n)\n\n\nFix invalid key with memcached while using throttling. (\n#2400\n)\n\n\nFix \nFileUploadParser\n with version 3.x. (\n#2399\n)\n\n\nFix the serializer inheritance. (\n#2388\n)\n\n\nFix caching issues with \nReturnDict\n. (\n#2360\n)\n\n\n\n\n3.0.3\n\n\nDate\n: \n8th January 2015\n.\n\n\n\n\nFix \nMinValueValidator\n on \nmodels.DateField\n. (\n#2369\n)\n\n\nFix serializer missing context when pagination is used. (\n#2355\n)\n\n\nNamespaced router URLs are now supported by the \nDefaultRouter\n. (\n#2351\n)\n\n\nrequired=False\n allows omission of value for output. (\n#2342\n)\n\n\nUse textarea input for \nmodels.TextField\n. (\n#2340\n)\n\n\nUse custom \nListSerializer\n for pagination if required. (\n#2331\n, \n#2327\n)\n\n\nBetter behavior with null and '' for blank HTML fields. (\n#2330\n)\n\n\nEnsure fields in \nexclude\n are model fields. (\n#2319\n)\n\n\nFix \nIntegerField\n and \nmax_length\n argument incompatibility. (\n#2317\n)\n\n\nFix the YAML encoder for 3.0 serializers. (\n#2315\n, \n#2283\n)\n\n\nFix the behavior of empty HTML fields. (\n#2311\n, \n#1101\n)\n\n\nFix Metaclass attribute depth ignoring fields attribute. (\n#2287\n)\n\n\nFix \nformat_suffix_patterns\n to work with Django's \ni18n_patterns\n. (\n#2278\n)\n\n\nAbility to customize router URLs for custom actions, using \nurl_path\n. (\n#2010\n)\n\n\nDon't install Django REST Framework as egg. (\n#2386\n)\n\n\n\n\n3.0.2\n\n\nDate\n: \n17th December 2014\n.\n\n\n\n\nEnsure \nrequest.user\n is made available to response middleware. (\n#2155\n)\n\n\nClient.logout()\n also cancels any existing \nforce_authenticate\n. (\n#2218\n, \n#2259\n)\n\n\nExtra assertions and better checks to preventing incorrect serializer API use. (\n#2228\n, \n#2234\n, \n#2262\n, \n#2263\n, \n#2266\n, \n#2267\n, \n#2289\n, \n#2291\n)\n\n\nFixed \nmin_length\n message for \nCharField\n. (\n#2255\n)\n\n\nFix \nUnicodeDecodeError\n, which can occur on serializer \nrepr\n. (\n#2270\n, \n#2279\n)\n\n\nFix empty HTML values when a default is provided. (\n#2280\n, \n#2294\n)\n\n\nFix \nSlugRelatedField\n raising \nUnicodeEncodeError\n when used as a multiple choice input. (\n#2290\n)\n\n\n\n\n3.0.1\n\n\nDate\n: \n11th December 2014\n.\n\n\n\n\nMore helpful error message when the default Serializer \ncreate()\n fails. (\n#2013\n)\n\n\nRaise error when attempting to save serializer if data is not valid. (\n#2098\n)\n\n\nFix \nFileUploadParser\n breaks with empty file names and multiple upload handlers. (\n#2109\n)\n\n\nImprove \nBindingDict\n to support standard dict-functions. (\n#2135\n, \n#2163\n)\n\n\nAdd \nvalidate()\n to \nListSerializer\n. (\n#2168\n, \n#2225\n, \n#2232\n)\n\n\nFix JSONP renderer failing to escape some characters. (\n#2169\n, \n#2195\n)\n\n\nAdd missing default style for \nFileField\n. (\n#2172\n)\n\n\nActions are required when calling \nViewSet.as_view()\n. (\n#2175\n)\n\n\nAdd \nallow_blank\n to \nChoiceField\n. (\n#2184\n, \n#2239\n)\n\n\nCosmetic fixes in the HTML renderer. (\n#2187\n)\n\n\nRaise error if \nfields\n on serializer is not a list of strings. (\n#2193\n, \n#2213\n)\n\n\nImprove checks for nested creates and updates. (\n#2194\n, \n#2196\n)\n\n\nvalidated_attrs\n argument renamed to \nvalidated_data\n in \nSerializer\n \ncreate()\n/\nupdate()\n. (\n#2197\n)\n\n\nRemove deprecated code to reflect the dropped Django versions. (\n#2200\n)\n\n\nBetter serializer errors for nested writes. (\n#2202\n, \n#2215\n)\n\n\nFix pagination and custom permissions incompatibility. (\n#2205\n)\n\n\nRaise error if \nfields\n on serializer is not a list of strings. (\n#2213\n)\n\n\nAdd missing translation markers for relational fields. (\n#2231\n)\n\n\nImprove field lookup behavior for dicts/mappings. (\n#2244\n, \n#2243\n)\n\n\nOptimized hyperlinked PK. (\n#2242\n)\n\n\n\n\n3.0.0\n\n\nDate\n: 1st December 2014\n\n\nFor full details see the \n3.0 release announcement\n.\n\n\n\n\nFor older release notes, \nplease see the version 2.x documentation\n.",
"title": "Release Notes"
},
{
@@ -5255,6 +5260,16 @@
"text": "",
"title": "3.5.x series"
},
+ {
+ "location": "/topics/release-notes/#352",
+ "text": "Date : 1st November 2016 Restore exception tracebacks in Python 2.7. ( #4631 , #4638 ) Properly display dicts in the admin console. ( #4532 , #4636 ) Fix is_simple_callable with variable args, kwargs. ( #4622 , #4602 ) Support 'on'/'off' literals with BooleanField. ( #4640 , #4624 ) Enable cursor pagination of value querysets. ( #4569 ) Fix support of get_full_details() for Throttled exceptions. ( #4627 ) Fix FilterSet proxy. ( #4620 ) Make serializer fields import explicit. ( #4628 ) Drop redundant requests adapter. ( #4639 )",
+ "title": "3.5.2"
+ },
+ {
+ "location": "/topics/release-notes/#351",
+ "text": "Date : 21st October 2016 Make rest_framework/compat.py imports. ( #4612 , #4608 , #4601 ) Fix bug in schema base path generation. ( #4611 , #4605 ) Fix broken case of ListSerializer with single item. ( #4609 , #4606 ) Remove bare raise for Python 3.5 compat. ( #4600 )",
+ "title": "3.5.1"
+ },
{
"location": "/topics/release-notes/#350",
"text": "Date : 20th October 2016",
diff --git a/sitemap.xml b/sitemap.xml
index 36617e375..bb298c522 100644
--- a/sitemap.xml
+++ b/sitemap.xml
@@ -4,7 +4,7 @@
http://www.django-rest-framework.org//
- 2016-10-20
+ 2016-11-01
daily
@@ -13,49 +13,49 @@
http://www.django-rest-framework.org//tutorial/quickstart/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//tutorial/1-serialization/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//tutorial/2-requests-and-responses/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//tutorial/3-class-based-views/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//tutorial/4-authentication-and-permissions/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//tutorial/5-relationships-and-hyperlinked-apis/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//tutorial/6-viewsets-and-routers/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//tutorial/7-schemas-and-client-libraries/
- 2016-10-20
+ 2016-11-01
daily
@@ -65,163 +65,163 @@
http://www.django-rest-framework.org//api-guide/requests/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/responses/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/views/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/generic-views/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/viewsets/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/routers/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/parsers/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/renderers/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/serializers/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/fields/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/relations/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/validators/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/authentication/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/permissions/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/throttling/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/filtering/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/pagination/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/versioning/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/content-negotiation/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/metadata/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/schemas/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/format-suffixes/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/reverse/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/exceptions/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/status-codes/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/testing/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//api-guide/settings/
- 2016-10-20
+ 2016-11-01
daily
@@ -231,127 +231,127 @@
http://www.django-rest-framework.org//topics/documenting-your-api/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//topics/api-clients/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//topics/internationalization/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//topics/ajax-csrf-cors/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//topics/html-and-forms/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//topics/browser-enhancements/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//topics/browsable-api/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//topics/rest-hypermedia-hateoas/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//topics/third-party-resources/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//topics/contributing/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//topics/project-management/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//topics/3.0-announcement/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//topics/3.1-announcement/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//topics/3.2-announcement/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//topics/3.3-announcement/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//topics/3.4-announcement/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//topics/3.5-announcement/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//topics/kickstarter-announcement/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//topics/mozilla-grant/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//topics/funding/
- 2016-10-20
+ 2016-11-01
daily
http://www.django-rest-framework.org//topics/release-notes/
- 2016-10-20
+ 2016-11-01
daily
diff --git a/topics/release-notes/index.html b/topics/release-notes/index.html
index 1cbea69ee..3366728df 100644
--- a/topics/release-notes/index.html
+++ b/topics/release-notes/index.html
@@ -454,6 +454,27 @@
+
+Date: 1st November 2016
+
+- Restore exception tracebacks in Python 2.7. (#4631, #4638)
+- Properly display dicts in the admin console. (#4532, #4636)
+- Fix is_simple_callable with variable args, kwargs. (#4622, #4602)
+- Support 'on'/'off' literals with BooleanField. (#4640, #4624)
+- Enable cursor pagination of value querysets. (#4569)
+- Fix support of get_full_details() for Throttled exceptions. (#4627)
+- Fix FilterSet proxy. (#4620)
+- Make serializer fields import explicit. (#4628)
+- Drop redundant requests adapter. (#4639)
+
+
+Date: 21st October 2016
+
+- Make
rest_framework/compat.py
imports. (#4612, #4608, #4601)
+- Fix bug in schema base path generation. (#4611, #4605)
+- Fix broken case of ListSerializer with single item. (#4609, #4606)
+- Remove bare
raise
for Python 3.5 compat. (#4600)
+
Date: 20th October 2016
@@ -975,6 +996,10 @@
+
+
+
+
diff --git a/tutorial/4-authentication-and-permissions/index.html b/tutorial/4-authentication-and-permissions/index.html
index a948460a0..d932ce373 100644
--- a/tutorial/4-authentication-and-permissions/index.html
+++ b/tutorial/4-authentication-and-permissions/index.html
@@ -433,7 +433,7 @@
We're going to make a couple of changes to our Snippet
model class.
First, let's add a couple of fields. One of those fields will be used to represent the user who created the code snippet. The other field will be used to store the highlighted HTML representation of the code.
Add the following two fields to the Snippet
model in models.py
.
-owner = models.ForeignKey('auth.User', related_name='snippets')
+owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)
highlighted = models.TextField()
We'd also need to make sure that when the model is saved, that we populate the highlighted field, using the pygments
code highlighting library.
diff --git a/tutorial/7-schemas-and-client-libraries/index.html b/tutorial/7-schemas-and-client-libraries/index.html
index 6c8529bcf..6a694a86f 100644
--- a/tutorial/7-schemas-and-client-libraries/index.html
+++ b/tutorial/7-schemas-and-client-libraries/index.html
@@ -449,10 +449,10 @@ representation become available as an option.
We can also request the schema from the command line, by specifying the desired
content type in the Accept
header.
-$ http http://127.0.0.1:8000/schema/ Accept:application/vnd.coreapi+json
+$ http http://127.0.0.1:8000/schema/ Accept:application/coreapi+json
HTTP/1.0 200 OK
Allow: GET, HEAD, OPTIONS
-Content-Type: application/vnd.coreapi+json
+Content-Type: application/coreapi+json
{
"_meta": {