diff --git a/README.md b/README.md
index 179f2891a8..e1e2526091 100644
--- a/README.md
+++ b/README.md
@@ -169,7 +169,7 @@ You may also want to [follow the author on Twitter][twitter].
# Security
-If you believe you’ve found something in Django REST framework which has security implications, please **do not raise the issue in a public forum**.
+If you believe you've found something in Django REST framework which has security implications, please **do not raise the issue in a public forum**.
Send a description of the issue via email to [rest-framework-security@googlegroups.com][security-mail]. The project maintainers will then work with you to resolve any issues where required, prior to any public disclosure.
diff --git a/docs/api-guide/permissions.md b/docs/api-guide/permissions.md
index e0838e94a9..7cdb595313 100644
--- a/docs/api-guide/permissions.md
+++ b/docs/api-guide/permissions.md
@@ -92,7 +92,7 @@ Or, if you're using the `@api_view` decorator with function based views.
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
- @api_view('GET')
+ @api_view(['GET'])
@permission_classes((IsAuthenticated, ))
def example_view(request, format=None):
content = {
@@ -261,6 +261,10 @@ The [REST Condition][rest-condition] package is another extension for building c
The [DRY Rest Permissions][dry-rest-permissions] package provides the ability to define different permissions for individual default and custom actions. This package is made for apps with permissions that are derived from relationships defined in the app's data model. It also supports permission checks being returned to a client app through the API's serializer. Additionally it supports adding permissions to the default and custom list actions to restrict the data they retrive per user.
+## Django Rest Framework Roles
+
+The [Django Rest Framework Roles][django-rest-framework-roles] package makes it easier to parameterize your API over multiple types of users.
+
[cite]: https://developer.apple.com/library/mac/#documentation/security/Conceptual/AuthenticationAndAuthorizationGuide/Authorization/Authorization.html
[authentication]: authentication.md
[throttling]: throttling.md
@@ -275,3 +279,4 @@ The [DRY Rest Permissions][dry-rest-permissions] package provides the ability to
[composed-permissions]: https://github.com/niwibe/djangorestframework-composed-permissions
[rest-condition]: https://github.com/caxap/rest_condition
[dry-rest-permissions]: https://github.com/Helioscene/dry-rest-permissions
+[django-rest-framework-roles]: https://github.com/computer-lab/django-rest-framework-roles
diff --git a/docs/topics/release-notes.md b/docs/topics/release-notes.md
index 78a5a8ba90..24728a252e 100644
--- a/docs/topics/release-notes.md
+++ b/docs/topics/release-notes.md
@@ -40,6 +40,18 @@ You can determine your currently installed version using `pip freeze`:
## 3.4.x series
+### 3.4.5
+
+**Date**: [19th August 2016][3.4.5-milestone]
+
+* Improve debug error handling. ([#4416][gh4416], [#4409][gh4409])
+* Allow custom CSRF_HEADER_NAME setting. ([#4415][gh4415], [#4410][gh4410])
+* Include .action attribute on viewsets when generating schemas. ([#4408][gh4408], [#4398][gh4398])
+* Do not include request.FILES items in request.POST. ([#4407][gh4407])
+* Fix rendering of checkbox multiple. ([#4403][gh4403])
+* Fix docstring of Field.get_default. ([#4404][gh4404])
+* Replace utf8 character with its ascii counterpart in README. ([#4412][gh4412])
+
### 3.4.4
**Date**: [12th August 2016][3.4.4-milestone]
@@ -560,6 +572,7 @@ For older release notes, [please see the version 2.x documentation][old-release-
[3.4.2-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.4.2+Release%22
[3.4.3-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.4.3+Release%22
[3.4.4-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.4.4+Release%22
+[3.4.5-milestone]: https://github.com/tomchristie/django-rest-framework/issues?q=milestone%3A%223.4.5+Release%22
[gh2013]: https://github.com/tomchristie/django-rest-framework/issues/2013
@@ -1065,3 +1078,15 @@ For older release notes, [please see the version 2.x documentation][old-release-
[gh4392]: https://github.com/tomchristie/django-rest-framework/issues/4392
[gh4393]: https://github.com/tomchristie/django-rest-framework/issues/4393
[gh4394]: https://github.com/tomchristie/django-rest-framework/issues/4394
+
+
+[gh4416]: https://github.com/tomchristie/django-rest-framework/issues/4416
+[gh4409]: https://github.com/tomchristie/django-rest-framework/issues/4409
+[gh4415]: https://github.com/tomchristie/django-rest-framework/issues/4415
+[gh4410]: https://github.com/tomchristie/django-rest-framework/issues/4410
+[gh4408]: https://github.com/tomchristie/django-rest-framework/issues/4408
+[gh4398]: https://github.com/tomchristie/django-rest-framework/issues/4398
+[gh4407]: https://github.com/tomchristie/django-rest-framework/issues/4407
+[gh4403]: https://github.com/tomchristie/django-rest-framework/issues/4403
+[gh4404]: https://github.com/tomchristie/django-rest-framework/issues/4404
+[gh4412]: https://github.com/tomchristie/django-rest-framework/issues/4412
diff --git a/requirements/requirements-optionals.txt b/requirements/requirements-optionals.txt
index 20436e6b4c..afade0aa0c 100644
--- a/requirements/requirements-optionals.txt
+++ b/requirements/requirements-optionals.txt
@@ -2,4 +2,4 @@
markdown==2.6.4
django-guardian==1.4.3
django-filter==0.13.0
-coreapi==1.32.0
+coreapi==2.0.0
diff --git a/rest_framework/__init__.py b/rest_framework/__init__.py
index 999c5de315..3f8736c258 100644
--- a/rest_framework/__init__.py
+++ b/rest_framework/__init__.py
@@ -8,7 +8,7 @@
"""
__title__ = 'Django REST framework'
-__version__ = '3.4.4'
+__version__ = '3.4.5'
__author__ = 'Tom Christie'
__license__ = 'BSD 2-Clause'
__copyright__ = 'Copyright 2011-2016 Tom Christie'
diff --git a/rest_framework/fields.py b/rest_framework/fields.py
index 8f12b2df48..f76e4e8011 100644
--- a/rest_framework/fields.py
+++ b/rest_framework/fields.py
@@ -432,7 +432,7 @@ def get_default(self):
is provided for this field.
If a default has not been set for this field then this will simply
- return `empty`, indicating that no value should be set in the
+ raise `SkipField`, indicating that no value should be set in the
validated data for this field.
"""
if self.default is empty or getattr(self.root, 'partial', False):
diff --git a/rest_framework/relations.py b/rest_framework/relations.py
index 4b6b3bea45..65c4c03187 100644
--- a/rest_framework/relations.py
+++ b/rest_framework/relations.py
@@ -10,7 +10,7 @@
from django.db.models import Manager
from django.db.models.query import QuerySet
from django.utils import six
-from django.utils.encoding import smart_text
+from django.utils.encoding import python_2_unicode_compatible, smart_text
from django.utils.six.moves.urllib import parse as urlparse
from django.utils.translation import ugettext_lazy as _
@@ -47,6 +47,7 @@ def __getnewargs__(self):
is_hyperlink = True
+@python_2_unicode_compatible
class PKOnlyObject(object):
"""
This is a mock object, used for when we only need the pk of the object
@@ -56,6 +57,9 @@ class PKOnlyObject(object):
def __init__(self, pk):
self.pk = pk
+ def __str__(self):
+ return "%s" % self.pk
+
# We assume that 'validators' are intended for the child serializer,
# rather than the parent serializer.
diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py
index 371cd6ec77..11e9fb9607 100644
--- a/rest_framework/renderers.py
+++ b/rest_framework/renderers.py
@@ -645,6 +645,12 @@ def get_context(self, data, accepted_media_type, renderer_context):
else:
paginator = None
+ csrf_cookie_name = settings.CSRF_COOKIE_NAME
+ csrf_header_name = getattr(settings, 'CSRF_HEADER_NAME', 'HTTP_X_CSRFToken') # Fallback for Django 1.8
+ if csrf_header_name.startswith('HTTP_'):
+ csrf_header_name = csrf_header_name[5:]
+ csrf_header_name = csrf_header_name.replace('_', '-')
+
context = {
'content': self.get_content(renderer, data, accepted_media_type, renderer_context),
'view': view,
@@ -675,7 +681,8 @@ def get_context(self, data, accepted_media_type, renderer_context):
'display_edit_forms': bool(response.status_code != 403),
'api_settings': api_settings,
- 'csrf_cookie_name': settings.CSRF_COOKIE_NAME,
+ 'csrf_cookie_name': csrf_cookie_name,
+ 'csrf_header_name': csrf_header_name
}
return context
diff --git a/rest_framework/request.py b/rest_framework/request.py
index f5738bfd50..355cccad77 100644
--- a/rest_framework/request.py
+++ b/rest_framework/request.py
@@ -391,3 +391,8 @@ def QUERY_PARAMS(self):
'`request.QUERY_PARAMS` has been deprecated in favor of `request.query_params` '
'since version 3.0, and has been fully removed as of version 3.2.'
)
+
+ def force_plaintext_errors(self, value):
+ # Hack to allow our exception handler to force choice of
+ # plaintext or html error responses.
+ self._request.is_ajax = lambda: value
diff --git a/rest_framework/schemas.py b/rest_framework/schemas.py
index 0618e94fd2..c9834c64d0 100644
--- a/rest_framework/schemas.py
+++ b/rest_framework/schemas.py
@@ -79,6 +79,13 @@ def get_schema(self, request=None):
view.kwargs = {}
view.format_kwarg = None
+ actions = getattr(callback, 'actions', None)
+ if actions is not None:
+ if method == 'OPTIONS':
+ view.action = 'metadata'
+ else:
+ view.action = actions.get(method.lower())
+
if request is not None:
view.request = clone_request(request, method)
try:
diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py
index 41412af8ad..4d1ed63aef 100644
--- a/rest_framework/serializers.py
+++ b/rest_framework/serializers.py
@@ -12,6 +12,7 @@
"""
from __future__ import unicode_literals
+import traceback
import warnings
from django.db import models
@@ -870,19 +871,20 @@ def create(self, validated_data):
try:
instance = ModelClass.objects.create(**validated_data)
- except TypeError as exc:
+ except TypeError:
+ tb = traceback.format_exc()
msg = (
'Got a `TypeError` when calling `%s.objects.create()`. '
'This may be because you have a writable field on the '
'serializer class that is not a valid argument to '
'`%s.objects.create()`. You may need to make the field '
'read-only, or override the %s.create() method to handle '
- 'this correctly.\nOriginal exception text was: %s.' %
+ 'this correctly.\nOriginal exception was:\n %s' %
(
ModelClass.__name__,
ModelClass.__name__,
self.__class__.__name__,
- exc
+ tb
)
)
raise TypeError(msg)
diff --git a/rest_framework/static/rest_framework/js/csrf.js b/rest_framework/static/rest_framework/js/csrf.js
index f8ab4428cb..97c8d01242 100644
--- a/rest_framework/static/rest_framework/js/csrf.js
+++ b/rest_framework/static/rest_framework/js/csrf.js
@@ -46,7 +46,7 @@ $.ajaxSetup({
// Send the token to same-origin, relative URLs only.
// Send the token only if the method warrants CSRF protection
// Using the CSRFToken value acquired earlier
- xhr.setRequestHeader("X-CSRFToken", csrftoken);
+ xhr.setRequestHeader(window.drf.csrfHeaderName, csrftoken);
}
}
});
diff --git a/rest_framework/templates/rest_framework/admin.html b/rest_framework/templates/rest_framework/admin.html
index 89af81ef74..eb2b8f1c7e 100644
--- a/rest_framework/templates/rest_framework/admin.html
+++ b/rest_framework/templates/rest_framework/admin.html
@@ -232,6 +232,7 @@