aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xdocs/api-guide/generic-views.md3
-rw-r--r--docs/topics/credits.md2
-rw-r--r--docs/topics/release-notes.md2
-rw-r--r--rest_framework/authentication.py9
-rw-r--r--rest_framework/authtoken/models.py4
-rw-r--r--rest_framework/compat.py20
-rw-r--r--rest_framework/runtests/settings.py2
-rw-r--r--rest_framework/serializers.py5
-rw-r--r--rest_framework/tests/test_description.py33
-rw-r--r--rest_framework/utils/formatting.py4
10 files changed, 59 insertions, 25 deletions
diff --git a/docs/api-guide/generic-views.md b/docs/api-guide/generic-views.md
index cd1bc7a1..67853ed0 100755
--- a/docs/api-guide/generic-views.md
+++ b/docs/api-guide/generic-views.md
@@ -92,7 +92,8 @@ May be overridden to provide dynamic behavior such as returning a queryset that
For example:
def get_queryset(self):
- return self.user.accounts.all()
+ user = self.request.user
+ return user.accounts.all()
#### `get_object(self)`
diff --git a/docs/topics/credits.md b/docs/topics/credits.md
index a7c09b5b..94760c74 100644
--- a/docs/topics/credits.md
+++ b/docs/topics/credits.md
@@ -143,6 +143,7 @@ The following people have helped make REST framework great.
* Ethan Freman - [mindlace]
* David Sanders - [davesque]
* Philip Douglas - [freakydug]
+* Igor Kalat - [trwired]
Many thanks to everyone who's contributed to the project.
@@ -322,3 +323,4 @@ You can also contact [@_tomchristie][twitter] directly on twitter.
[mindlace]: https://github.com/mindlace
[davesque]: https://github.com/davesque
[freakydug]: https://github.com/freakydug
+[trwired]: https://github.com/trwired
diff --git a/docs/topics/release-notes.md b/docs/topics/release-notes.md
index b08ac058..4fecbf1f 100644
--- a/docs/topics/release-notes.md
+++ b/docs/topics/release-notes.md
@@ -45,6 +45,8 @@ You can determine your currently installed version using `pip freeze`:
* Added `trailing_slash` option to routers.
* Include support for `HttpStreamingResponse`.
* Support wider range of default serializer validation when used with custom model fields.
+* UTF-8 Support for browsable API descriptions.
+* OAuth2 provider usez timezone aware datetimes when supported.
* Bugfix: Return error correctly when OAuth non-existent consumer occurs.
* Bugfix: Allow `FileUploadParser` to correctly filename if provided as URL kwarg.
* Bugfix: Fix `ScopedRateThrottle`.
diff --git a/rest_framework/authentication.py b/rest_framework/authentication.py
index f659a172..10298027 100644
--- a/rest_framework/authentication.py
+++ b/rest_framework/authentication.py
@@ -3,14 +3,13 @@ Provides various authentication policies.
"""
from __future__ import unicode_literals
import base64
-from datetime import datetime
from django.contrib.auth import authenticate
from django.core.exceptions import ImproperlyConfigured
from rest_framework import exceptions, HTTP_HEADER_ENCODING
from rest_framework.compat import CsrfViewMiddleware
from rest_framework.compat import oauth, oauth_provider, oauth_provider_store
-from rest_framework.compat import oauth2_provider
+from rest_framework.compat import oauth2_provider, provider_now
from rest_framework.authtoken.models import Token
@@ -320,9 +319,9 @@ class OAuth2Authentication(BaseAuthentication):
try:
token = oauth2_provider.models.AccessToken.objects.select_related('user')
- # TODO: Change to timezone aware datetime when oauth2_provider add
- # support to it.
- token = token.get(token=access_token, expires__gt=datetime.now())
+ # provider_now switches to timezone aware datetime when
+ # the oauth2_provider version supports to it.
+ token = token.get(token=access_token, expires__gt=provider_now())
except oauth2_provider.models.AccessToken.DoesNotExist:
raise exceptions.AuthenticationFailed('Invalid token')
diff --git a/rest_framework/authtoken/models.py b/rest_framework/authtoken/models.py
index 52c45ad1..7601f5b7 100644
--- a/rest_framework/authtoken/models.py
+++ b/rest_framework/authtoken/models.py
@@ -1,7 +1,7 @@
import uuid
import hmac
from hashlib import sha1
-from rest_framework.compat import User
+from rest_framework.compat import AUTH_USER_MODEL
from django.conf import settings
from django.db import models
@@ -11,7 +11,7 @@ class Token(models.Model):
The default authorization token model.
"""
key = models.CharField(max_length=40, primary_key=True)
- user = models.OneToOneField(User, related_name='auth_token')
+ user = models.OneToOneField(AUTH_USER_MODEL, related_name='auth_token')
created = models.DateTimeField(auto_now_add=True)
class Meta:
diff --git a/rest_framework/compat.py b/rest_framework/compat.py
index a19bd778..b748dcc5 100644
--- a/rest_framework/compat.py
+++ b/rest_framework/compat.py
@@ -2,6 +2,7 @@
The `compat` module provides support for backwards compatibility with older
versions of django/python, and compatibility wrappers around optional packages.
"""
+
# flake8: noqa
from __future__ import unicode_literals
@@ -83,15 +84,9 @@ def get_concrete_model(model_cls):
# Django 1.5 add support for custom auth user model
if django.VERSION >= (1, 5):
from django.conf import settings
- if hasattr(settings, 'AUTH_USER_MODEL'):
- User = settings.AUTH_USER_MODEL
- else:
- from django.contrib.auth.models import User
+ AUTH_USER_MODEL = settings.AUTH_USER_MODEL
else:
- try:
- from django.contrib.auth.models import User
- except ImportError:
- raise ImportError("User model is not to be found.")
+ AUTH_USER_MODEL = 'auth.User'
if django.VERSION >= (1, 5):
@@ -495,12 +490,21 @@ try:
from provider.oauth2 import forms as oauth2_provider_forms
from provider import scope as oauth2_provider_scope
from provider import constants as oauth2_constants
+ from provider import __version__ as provider_version
+ if provider_version in ('0.2.3', '0.2.4'):
+ # 0.2.3 and 0.2.4 are supported version that do not support
+ # timezone aware datetimes
+ from datetime.datetime import now as provider_now
+ else:
+ # Any other supported version does use timezone aware datetimes
+ from django.utils.timezone import now as provider_now
except ImportError:
oauth2_provider = None
oauth2_provider_models = None
oauth2_provider_forms = None
oauth2_provider_scope = None
oauth2_constants = None
+ provider_now = None
# Handle lazy strings
from django.utils.functional import Promise
diff --git a/rest_framework/runtests/settings.py b/rest_framework/runtests/settings.py
index 9dd7b545..b3702d0b 100644
--- a/rest_framework/runtests/settings.py
+++ b/rest_framework/runtests/settings.py
@@ -134,6 +134,8 @@ PASSWORD_HASHERS = (
'django.contrib.auth.hashers.CryptPasswordHasher',
)
+AUTH_USER_MODEL = 'auth.User'
+
import django
if django.VERSION < (1, 3):
diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py
index 5a8fd89f..023f7ccf 100644
--- a/rest_framework/serializers.py
+++ b/rest_framework/serializers.py
@@ -915,7 +915,10 @@ class HyperlinkedModelSerializer(ModelSerializer):
view_name=self.opts.view_name,
lookup_field=self.opts.lookup_field
)
- fields.insert(0, 'url', url_field)
+ ret = self._dict_class()
+ ret['url'] = url_field
+ ret.update(fields)
+ fields = ret
return fields
diff --git a/rest_framework/tests/test_description.py b/rest_framework/tests/test_description.py
index 52c1a34c..ea4b2c3a 100644
--- a/rest_framework/tests/test_description.py
+++ b/rest_framework/tests/test_description.py
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
from django.test import TestCase
from rest_framework.views import APIView
-from rest_framework.compat import apply_markdown
+from rest_framework.compat import apply_markdown, smart_text
from rest_framework.utils.formatting import get_view_name, get_view_description
# We check that docstrings get nicely un-indented.
@@ -49,6 +49,28 @@ MARKED_DOWN_gte_21 = """<h2 id="an-example-docstring">an example docstring</h2>
<h2 id="hash-style-header">hash style header</h2>"""
+# test strings snatched from http://www.columbia.edu/~fdc/utf8/,
+# http://winrus.com/utf8-jap.htm and memory
+UTF8_TEST_DOCSTRING = (
+ 'zażółć gęślą jaźń'
+ 'Sîne klâwen durh die wolken sint geslagen'
+ 'Τη γλώσσα μου έδωσαν ελληνική'
+ 'யாமறிந்த மொழிகளிலே தமிழ்மொழி'
+ 'На берегу пустынных волн'
+ 'てすと'
+ 'アイウエオカキクケコサシスセソタチツテ'
+)
+
+
+# Apparently there is an issue where docstrings of imported view classes
+# do not retain their encoding information even if a module has a proper
+# encoding declaration at the top of its source file. Therefore for tests
+# to catch unicode related errors, a mock view has to be declared in a separate
+# module.
+class ViewWithNonASCIICharactersInDocstring(APIView):
+ __doc__ = UTF8_TEST_DOCSTRING
+
+
class TestViewNamesAndDescriptions(TestCase):
def test_view_name_uses_class_name(self):
"""
@@ -83,11 +105,10 @@ class TestViewNamesAndDescriptions(TestCase):
Unicode in docstrings should be respected.
"""
- class MockView(APIView):
- """Проверка"""
- pass
-
- self.assertEqual(get_view_description(MockView), "Проверка")
+ self.assertEqual(
+ get_view_description(ViewWithNonASCIICharactersInDocstring),
+ smart_text(UTF8_TEST_DOCSTRING)
+ )
def test_view_description_can_be_empty(self):
"""
diff --git a/rest_framework/utils/formatting.py b/rest_framework/utils/formatting.py
index ebadb3a6..4bec8387 100644
--- a/rest_framework/utils/formatting.py
+++ b/rest_framework/utils/formatting.py
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
from django.utils.html import escape
from django.utils.safestring import mark_safe
-from rest_framework.compat import apply_markdown
+from rest_framework.compat import apply_markdown, smart_text
import re
@@ -63,7 +63,7 @@ def get_view_description(cls, html=False):
Return a description for an `APIView` class or `@api_view` function.
"""
description = cls.__doc__ or ''
- description = _remove_leading_indent(description)
+ description = _remove_leading_indent(smart_text(description))
if html:
return markup_description(description)
return description