Remove references to unsupported Django versions in docs and code (#5602)

Per the trove classifiers, DRF only supports Django versions 1.10+. Can
drop documentation, code comments, and workarounds for older Django
versions.
This commit is contained in:
Jon Dufresne 2017-11-20 00:35:54 -08:00 committed by Carlton Gibson
parent 9c11077cf6
commit ff556a91fd
11 changed files with 16 additions and 42 deletions

View File

@ -356,8 +356,6 @@ Corresponds to `django.db.models.fields.DurationField`
The `validated_data` for these fields will contain a `datetime.timedelta` instance. The `validated_data` for these fields will contain a `datetime.timedelta` instance.
The representation is a string following this format `'[DD] [HH:[MM:]]ss[.uuuuuu]'`. The representation is a string following this format `'[DD] [HH:[MM:]]ss[.uuuuuu]'`.
**Note:** This field is only available with Django versions >= 1.8.
**Signature:** `DurationField()` **Signature:** `DurationField()`
--- ---

View File

@ -120,10 +120,10 @@ If you're intending to use the browsable API you'll probably also want to add RE
urlpatterns = [ urlpatterns = [
... ...
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')) url(r'^api-auth/', include('rest_framework.urls'))
] ]
Note that the URL path can be whatever you want, but you must include `'rest_framework.urls'` with the `'rest_framework'` namespace. You may leave out the namespace in Django 1.9+, and REST framework will set it for you. Note that the URL path can be whatever you want.
## Example ## Example

View File

@ -48,8 +48,6 @@ We'll need to add our new `snippets` app and the `rest_framework` app to `INSTAL
'snippets.apps.SnippetsConfig', 'snippets.apps.SnippetsConfig',
) )
Please note that if you're using Django <1.9, you need to replace `snippets.apps.SnippetsConfig` with `snippets`.
Okay, we're ready to roll. Okay, we're ready to roll.
## Creating a model to work with ## Creating a model to work with

View File

@ -142,11 +142,10 @@ Add the following import at the top of the file:
And, at the end of the file, add a pattern to include the login and logout views for the browsable API. And, at the end of the file, add a pattern to include the login and logout views for the browsable API.
urlpatterns += [ urlpatterns += [
url(r'^api-auth/', include('rest_framework.urls', url(r'^api-auth/', include('rest_framework.urls'),
namespace='rest_framework')),
] ]
The `r'^api-auth/'` part of pattern can actually be whatever URL you want to use. The only restriction is that the included urls must use the `'rest_framework'` namespace. In Django 1.9+, REST framework will set the namespace, so you may leave it out. The `r'^api-auth/'` part of pattern can actually be whatever URL you want to use.
Now 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. Now 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.

View File

@ -20,14 +20,10 @@ class AuthTokenSerializer(serializers.Serializer):
user = authenticate(request=self.context.get('request'), user = authenticate(request=self.context.get('request'),
username=username, password=password) username=username, password=password)
if user: # The authenticate call simply returns None for is_active=False
# From Django 1.10 onwards the `authenticate` call simply # users. (Assuming the default ModelBackend authentication
# returns `None` for is_active=False users. # backend.)
# (Assuming the default `ModelBackend` authentication backend.) if not user:
if not user.is_active:
msg = _('User account is disabled.')
raise serializers.ValidationError(msg, code='authorization')
else:
msg = _('Unable to log in with provided credentials.') msg = _('Unable to log in with provided credentials.')
raise serializers.ValidationError(msg, code='authorization') raise serializers.ValidationError(msg, code='authorization')
else: else:

View File

@ -666,7 +666,7 @@ class BrowsableAPIRenderer(BaseRenderer):
paginator = None paginator = None
csrf_cookie_name = settings.CSRF_COOKIE_NAME csrf_cookie_name = settings.CSRF_COOKIE_NAME
csrf_header_name = getattr(settings, 'CSRF_HEADER_NAME', 'HTTP_X_CSRFToken') # Fallback for Django 1.8 csrf_header_name = settings.CSRF_HEADER_NAME
if csrf_header_name.startswith('HTTP_'): if csrf_header_name.startswith('HTTP_'):
csrf_header_name = csrf_header_name[5:] csrf_header_name = csrf_header_name[5:]
csrf_header_name = csrf_header_name.replace('_', '-') csrf_header_name = csrf_header_name.replace('_', '-')

View File

@ -6,11 +6,10 @@ your API requires authentication:
urlpatterns = [ urlpatterns = [
... ...
url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')) url(r'^auth/', include('rest_framework.urls'))
] ]
In Django versions older than 1.9, the urls must be namespaced as 'rest_framework', You should make sure your authentication settings include `SessionAuthentication`.
and you should make sure your authentication settings include `SessionAuthentication`.
""" """
from __future__ import unicode_literals from __future__ import unicode_literals

View File

@ -105,18 +105,13 @@ def _get_reverse_relationships(opts):
""" """
Returns an `OrderedDict` of field names to `RelationInfo`. Returns an `OrderedDict` of field names to `RelationInfo`.
""" """
# Note that we have a hack here to handle internal API differences for
# this internal API across Django 1.7 -> Django 1.8.
# See: https://code.djangoproject.com/ticket/24208
reverse_relations = OrderedDict() reverse_relations = OrderedDict()
all_related_objects = [r for r in opts.related_objects if not r.field.many_to_many] all_related_objects = [r for r in opts.related_objects if not r.field.many_to_many]
for relation in all_related_objects: for relation in all_related_objects:
accessor_name = relation.get_accessor_name() accessor_name = relation.get_accessor_name()
related = getattr(relation, 'related_model', relation.model)
reverse_relations[accessor_name] = RelationInfo( reverse_relations[accessor_name] = RelationInfo(
model_field=None, model_field=None,
related_model=related, related_model=relation.related_model,
to_many=relation.field.remote_field.multiple, to_many=relation.field.remote_field.multiple,
to_field=_get_to_field(relation.field), to_field=_get_to_field(relation.field),
has_through_model=False, has_through_model=False,
@ -127,10 +122,9 @@ def _get_reverse_relationships(opts):
all_related_many_to_many_objects = [r for r in opts.related_objects if r.field.many_to_many] all_related_many_to_many_objects = [r for r in opts.related_objects if r.field.many_to_many]
for relation in all_related_many_to_many_objects: for relation in all_related_many_to_many_objects:
accessor_name = relation.get_accessor_name() accessor_name = relation.get_accessor_name()
related = getattr(relation, 'related_model', relation.model)
reverse_relations[accessor_name] = RelationInfo( reverse_relations[accessor_name] = RelationInfo(
model_field=None, model_field=None,
related_model=related, related_model=relation.related_model,
to_many=True, to_many=True,
# manytomany do not have to_fields # manytomany do not have to_fields
to_field=None, to_field=None,

View File

@ -120,13 +120,12 @@ class DBTransactionAPIExceptionTests(TestCase):
Transaction is rollbacked by our transaction atomic block. Transaction is rollbacked by our transaction atomic block.
""" """
request = factory.post('/') request = factory.post('/')
num_queries = (4 if getattr(connection.features, num_queries = 4 if connection.features.can_release_savepoints else 3
'can_release_savepoints', False) else 3)
with self.assertNumQueries(num_queries): with self.assertNumQueries(num_queries):
# 1 - begin savepoint # 1 - begin savepoint
# 2 - insert # 2 - insert
# 3 - rollback savepoint # 3 - rollback savepoint
# 4 - release savepoint (django>=1.8 only) # 4 - release savepoint
with transaction.atomic(): with transaction.atomic():
response = self.view(request) response = self.view(request)
assert transaction.get_rollback() assert transaction.get_rollback()

View File

@ -5,7 +5,6 @@ import unittest
import uuid import uuid
from decimal import ROUND_DOWN, ROUND_UP, Decimal from decimal import ROUND_DOWN, ROUND_UP, Decimal
import django
import pytest import pytest
from django.http import QueryDict from django.http import QueryDict
from django.test import TestCase, override_settings from django.test import TestCase, override_settings
@ -1197,11 +1196,6 @@ class TestDateTimeField(FieldValues):
field = serializers.DateTimeField(default_timezone=utc) field = serializers.DateTimeField(default_timezone=utc)
if django.VERSION[:2] <= (1, 8):
# Doesn't raise an error on earlier versions of Django
TestDateTimeField.invalid_inputs.pop('2018-08-16 22:00-24:00')
class TestCustomInputFormatDateTimeField(FieldValues): class TestCustomInputFormatDateTimeField(FieldValues):
""" """
Valid and invalid values for `DateTimeField` with a custom input format. Valid and invalid values for `DateTimeField` with a custom input format.

View File

@ -1,9 +1,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import datetime import datetime
import unittest
import django
import pytest import pytest
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.db import models from django.db import models
@ -291,7 +289,6 @@ class SearchFilterToManyTests(TestCase):
Entry.objects.create(blog=b2, headline='Something unrelated', pub_date=datetime.date(1979, 1, 1)) Entry.objects.create(blog=b2, headline='Something unrelated', pub_date=datetime.date(1979, 1, 1))
Entry.objects.create(blog=b2, headline='Retrospective on Lennon', pub_date=datetime.date(1990, 6, 1)) Entry.objects.create(blog=b2, headline='Retrospective on Lennon', pub_date=datetime.date(1990, 6, 1))
@unittest.skipIf(django.VERSION < (1, 9), "Django 1.8 does not support transforms")
def test_multiple_filter_conditions(self): def test_multiple_filter_conditions(self):
class SearchListView(generics.ListAPIView): class SearchListView(generics.ListAPIView):
queryset = Blog.objects.all() queryset = Blog.objects.all()