Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
08c7853
Start test case
lovelydinosaur Aug 1, 2016
5abac93
Merge branch 'master' into requests-client
lovelydinosaur Aug 12, 2016
3d1fff3
Added 'requests' test client
lovelydinosaur Aug 15, 2016
e76ca6e
Address typos
lovelydinosaur Aug 15, 2016
6ede654
Graceful fallback if requests is not installed.
lovelydinosaur Aug 17, 2016
049a39e
Add cookie support
lovelydinosaur Aug 17, 2016
64e19c7
Tests for auth and CSRF
lovelydinosaur Aug 17, 2016
da47c34
Py3 compat
lovelydinosaur Aug 17, 2016
5311769
py3 compat
lovelydinosaur Aug 17, 2016
0b3db02
py3 compat
lovelydinosaur Aug 17, 2016
0cc3f50
Add get_requests_client
lovelydinosaur Aug 18, 2016
e4f6928
Added SchemaGenerator.should_include_link
lovelydinosaur Sep 2, 2016
46b9e4e
add settings for html cutoff on related fields
Aug 22, 2016
a556b9c
Router doesn't work if prefix is blank, though project urls.py handle…
c17r Sep 14, 2016
8609c9c
Fix Django 1.10 to-many deprecation
Sep 15, 2016
197b63a
Add django.core.urlresolvers compatibility
Sep 15, 2016
bb37cb7
Update django-filter & django-guardian
Sep 15, 2016
a372a8e
Check for empty router prefix; adjust URL accordingly
c17r Sep 15, 2016
a084924
Fix misc django deprecations
Sep 15, 2016
3bfb0b7
Use TOC extension instead of header
Sep 15, 2016
3bdb0e9
Fix deprecations for py3k
Sep 16, 2016
a0a8b98
Add py3k compatibility to is_simple_callable
Sep 22, 2016
adcf653
Add is_simple_callable tests
Sep 22, 2016
b3afcb2
Drop python 3.2 support (EOL, Dropped by Django)
Sep 22, 2016
b516712
schema_renderers= should *set* the renderers, not append to them.
lovelydinosaur Sep 28, 2016
37b3475
API client (#4424)
lovelydinosaur Sep 29, 2016
c2cec78
Merge master
lovelydinosaur Sep 29, 2016
a60ef8c
Merge branch 'schema-renderers-only-for-root-view' into version-3-5
lovelydinosaur Sep 29, 2016
61b1189
Fix release notes
lovelydinosaur Sep 29, 2016
bc9b522
Merge branch 'rpkilby-fix-simple-callable' into version-3-5
lovelydinosaur Sep 29, 2016
9a4ed1b
Merge branch 'should_include_link' into version-3-5
lovelydinosaur Sep 29, 2016
24bf382
Merge branch 'html_cutoff_settings' of https://github.com/MobileWorks…
lovelydinosaur Sep 29, 2016
f455c67
Merge branch 'MobileWorks-html_cutoff_settings' into version-3-5
lovelydinosaur Sep 29, 2016
b689a3b
Add note about 'User account is disabled.' vs 'Unable to log in'
lovelydinosaur Sep 29, 2016
818ab45
Merge branch 'fix-deprecations' of https://github.com/rpkilby/django-…
lovelydinosaur Sep 29, 2016
ee2b165
Merge branch 'rpkilby-fix-deprecations' into version-3-5
lovelydinosaur Sep 29, 2016
c427144
Merge branch 'router-empty-prefix' of https://github.com/c17r/django-…
lovelydinosaur Sep 29, 2016
49ce3d6
Merge branch 'c17r-router-empty-prefix' into version-3-5
lovelydinosaur Sep 29, 2016
c3a9538
Clean up schema generation (#4527)
lovelydinosaur Sep 30, 2016
4ad5256
Handle multiple methods on custom action (#4529)
lovelydinosaur Sep 30, 2016
8044d38
RequestsClient, CoreAPIClient
lovelydinosaur Oct 4, 2016
a8501f7
exclude_from_schema
lovelydinosaur Oct 5, 2016
cd826ce
Added 'get_schema_view()' shortcut
lovelydinosaur Oct 5, 2016
7e3a3a4
Added schema descriptions
lovelydinosaur Oct 5, 2016
1084dca
Better descriptions for schemas
lovelydinosaur Oct 5, 2016
7edee80
Add type annotation to schema generation
lovelydinosaur Oct 6, 2016
b44ab76
Coerce schema 'pk' in path to actual field name
lovelydinosaur Oct 6, 2016
0724420
Deprecations move into assertion errors
lovelydinosaur Oct 6, 2016
3eb7fe6
Use get_schema_view in tests
lovelydinosaur Oct 7, 2016
5858168
Updte CoreJSON media type
lovelydinosaur Oct 7, 2016
69b4acd
Handle schema structure correctly when path prefixs exist. Closes #4401
lovelydinosaur Oct 7, 2016
fcf932f
Add PendingDeprecation to Router schema generation.
lovelydinosaur Oct 7, 2016
18aebbb
Added SCHEMA_COERCE_PATH_PK and SCHEMA_COERCE_METHOD_NAMES
lovelydinosaur Oct 10, 2016
3f3213b
Renamed and documented 'get_schema_fields' interface.
lovelydinosaur Oct 10, 2016
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
API client (#4424)
  • Loading branch information
lovelydinosaur authored Sep 29, 2016
commit 37b3475e5d048f7f7e751dee6bdb23695fe484bd
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ You may also want to [follow the author on Twitter][twitter].

# Security

If you believe youve 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 [[email protected]][security-mail]. The project maintainers will then work with you to resolve any issues where required, prior to any public disclosure.

Expand Down
7 changes: 6 additions & 1 deletion docs/api-guide/permissions.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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
Expand All @@ -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
25 changes: 25 additions & 0 deletions docs/topics/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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

<!-- 3.0.1 -->
[gh2013]: https://github.com/tomchristie/django-rest-framework/issues/2013
Expand Down Expand Up @@ -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

<!-- 3.4.5 -->
[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
2 changes: 1 addition & 1 deletion requirements/requirements-optionals.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion rest_framework/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
2 changes: 1 addition & 1 deletion rest_framework/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
6 changes: 5 additions & 1 deletion rest_framework/relations.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 _

Expand Down Expand Up @@ -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
Expand All @@ -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.
Expand Down
9 changes: 8 additions & 1 deletion rest_framework/renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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

Expand Down
5 changes: 5 additions & 0 deletions rest_framework/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
7 changes: 7 additions & 0 deletions rest_framework/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
8 changes: 5 additions & 3 deletions rest_framework/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"""
from __future__ import unicode_literals

import traceback
import warnings

from django.db import models
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion rest_framework/static/rest_framework/js/csrf.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
});
1 change: 1 addition & 0 deletions rest_framework/templates/rest_framework/admin.html
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ <h4 class="modal-title" id="myModalLabel">{{ error_title }}</h4>
{% block script %}
<script>
window.drf = {
csrfHeaderName: "{{ csrf_header_name|default:'X-CSRFToken' }}"
csrfCookieName: "{{ csrf_cookie_name|default:'csrftoken' }}"
};
</script>
Expand Down
1 change: 1 addition & 0 deletions rest_framework/templates/rest_framework/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ <h1>{{ name }}</h1>
{% block script %}
<script>
window.drf = {
csrfHeaderName: "{{ csrf_header_name|default:'X-CSRFToken' }}"
csrfCookieName: "{{ csrf_cookie_name|default:'csrftoken' }}"
};
</script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<div>
{% for key, text in field.choices.items %}
<label class="checkbox-inline">
<input type="checkbox" name="{{ field.name }}" value="{{ key }}" {% if key|as_string in field.value|as_list_of_stringsg %}checked{% endif %}>
<input type="checkbox" name="{{ field.name }}" value="{{ key }}" {% if key|as_string in field.value|as_list_of_strings %}checked{% endif %}>
{{ text }}
</label>
{% endfor %}
Expand All @@ -18,7 +18,7 @@
{% for key, text in field.choices.items %}
<div class="checkbox">
<label>
<input type="checkbox" name="{{ field.name }}" value="{{ key }}" {% if key|as_string in field.value|as_list_of_stringsg %}checked{% endif %}>
<input type="checkbox" name="{{ field.name }}" value="{{ key }}" {% if key|as_string in field.value|as_list_of_strings %}checked{% endif %}>
{{ text }}
</label>
</div>
Expand Down
15 changes: 13 additions & 2 deletions rest_framework/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from django.utils.encoding import force_bytes
from django.utils.http import urlencode

from rest_framework.compat import requests
from rest_framework.compat import coreapi, requests
from rest_framework.settings import api_settings


Expand Down Expand Up @@ -60,7 +60,10 @@ def get_environ(self, request):

# Set request content, if any exists.
if request.body is not None:
kwargs['data'] = request.body
if hasattr(request.body, 'read'):
kwargs['data'] = request.body.read()
else:
kwargs['data'] = request.body
if 'content-type' in request.headers:
kwargs['content_type'] = request.headers['content-type']

Expand Down Expand Up @@ -126,6 +129,14 @@ def get_requests_client():
return DjangoTestSession()


def get_api_client():
assert coreapi is not None, 'coreapi must be installed'
session = get_requests_client()
return coreapi.Client(transports=[
coreapi.transports.HTTPTransport(session=session)
])


class APIRequestFactory(DjangoRequestFactory):
renderer_classes_list = api_settings.TEST_REQUEST_RENDERER_CLASSES
default_format = api_settings.TEST_REQUEST_DEFAULT_FORMAT
Expand Down
20 changes: 10 additions & 10 deletions rest_framework/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,14 @@
"""
from __future__ import unicode_literals

import sys

from django.conf import settings
from django.core.exceptions import PermissionDenied
from django.db import models
from django.http import Http404
from django.http.response import HttpResponse, HttpResponseBase
from django.http.response import HttpResponseBase
from django.utils import six
from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _
from django.views import debug
from django.views.decorators.csrf import csrf_exempt
from django.views.generic import View

Expand Down Expand Up @@ -95,11 +92,6 @@ def exception_handler(exc, context):
set_rollback()
return Response(data, status=status.HTTP_403_FORBIDDEN)

# throw django's error page if debug is True
if settings.DEBUG:
exception_reporter = debug.ExceptionReporter(context.get('request'), *sys.exc_info())
return HttpResponse(exception_reporter.get_traceback_html(), status=500)

return None


Expand Down Expand Up @@ -439,11 +431,19 @@ def handle_exception(self, exc):
response = exception_handler(exc, context)

if response is None:
raise
self.raise_uncaught_exception(exc)

response.exception = True
return response

def raise_uncaught_exception(self, exc):
if settings.DEBUG:
request = self.request
renderer_format = getattr(request.accepted_renderer, 'format')
use_plaintext_traceback = renderer_format not in ('html', 'api', 'admin')
request.force_plaintext_errors(use_plaintext_traceback)
raise

# Note: Views are made CSRF exempt from within `as_view` as to prevent
# accidental removal of this exemption in cases where `dispatch` needs to
# be overridden.
Expand Down
Loading