Skip to content

WIP: Remove Django 1.8 and 1.9 compatibility code. #5471

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 12 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
65 changes: 4 additions & 61 deletions rest_framework/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,24 +78,7 @@ def distinct(queryset, base):
return queryset.distinct()


# Obtaining manager instances and names from model options differs after 1.10.
def get_names_and_managers(options):
if django.VERSION >= (1, 10):
# Django 1.10 onwards provides a `.managers` property on the Options.
return [
(manager.name, manager)
for manager
in options.managers
]
# For Django 1.8 and 1.9, use the three-tuple information provided
# by .concrete_managers and .abstract_managers
return [
(manager_info[1], manager_info[2])
for manager_info
in (options.concrete_managers + options.abstract_managers)
]


# TODO: Remove
# field.rel is deprecated from 1.9 onwards
def get_remote_field(field, **kwargs):
if 'default' in kwargs:
Expand Down Expand Up @@ -132,44 +115,6 @@ def _resolve_model(obj):
raise ValueError("{0} is not a Django model".format(obj))


def is_authenticated(user):
if django.VERSION < (1, 10):
return user.is_authenticated()
return user.is_authenticated


def is_anonymous(user):
if django.VERSION < (1, 10):
return user.is_anonymous()
return user.is_anonymous


def get_related_model(field):
if django.VERSION < (1, 9):
return _resolve_model(field.rel.to)
return field.remote_field.model


def value_from_object(field, obj):
if django.VERSION < (1, 9):
return field._get_val_from_obj(obj)
return field.value_from_object(obj)


# contrib.postgres only supported from 1.8 onwards.
try:
from django.contrib.postgres import fields as postgres_fields
except ImportError:
postgres_fields = None


# JSONField is only supported from 1.9 onwards
try:
from django.contrib.postgres.fields import JSONField
except ImportError:
JSONField = None


# coreapi is optional (Note that uritemplate is a dependency of coreapi)
try:
import coreapi
Expand Down Expand Up @@ -325,11 +270,6 @@ def md_filter_add_syntax_highlight(md):
LONG_SEPARATORS = (b', ', b': ')
INDENT_SEPARATORS = (b',', b': ')

try:
# DecimalValidator is unavailable in Django < 1.9
from django.core.validators import DecimalValidator
except ImportError:
DecimalValidator = None

class CustomValidatorMessage(object):
"""
Expand Down Expand Up @@ -371,6 +311,7 @@ def set_rollback():
pass


# TODO: Remove
def template_render(template, context=None, request=None):
"""
Passing Context or RequestContext to Template.render is deprecated in 1.9+,
Expand All @@ -393,6 +334,7 @@ def template_render(template, context=None, request=None):
return template.render(context, request=request)


# TODO: Remove
def set_many(instance, field, value):
if django.VERSION < (1, 10):
setattr(instance, field, value)
Expand All @@ -401,6 +343,7 @@ def set_many(instance, field, value):
field.set(value)


# TODO: Remove
def include(module, namespace=None, app_name=None):
from django.conf.urls import include
if django.VERSION < (1,9):
Expand Down
4 changes: 2 additions & 2 deletions rest_framework/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
from rest_framework.compat import (
InvalidTimeError, MaxLengthValidator, MaxValueValidator,
MinLengthValidator, MinValueValidator, get_remote_field, unicode_repr,
unicode_to_repr, value_from_object
unicode_to_repr
)
from rest_framework.exceptions import ErrorDetail, ValidationError
from rest_framework.settings import api_settings
Expand Down Expand Up @@ -1840,7 +1840,7 @@ def get_attribute(self, obj):
return obj

def to_representation(self, obj):
value = value_from_object(self.model_field, obj)
value = self.model_field.value_from_object(obj)
if is_protected_type(value):
return value
return self.model_field.value_to_string(obj)
7 changes: 3 additions & 4 deletions rest_framework/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from django.http import Http404

from rest_framework import exceptions
from rest_framework.compat import is_authenticated

SAFE_METHODS = ('GET', 'HEAD', 'OPTIONS')

Expand Down Expand Up @@ -47,7 +46,7 @@ class IsAuthenticated(BasePermission):
"""

def has_permission(self, request, view):
return request.user and is_authenticated(request.user)
return request.user and request.user.is_authenticated


class IsAdminUser(BasePermission):
Expand All @@ -68,7 +67,7 @@ def has_permission(self, request, view):
return (
request.method in SAFE_METHODS or
request.user and
is_authenticated(request.user)
request.user.is_authenticated
)


Expand Down Expand Up @@ -136,7 +135,7 @@ def has_permission(self, request, view):
return True

if not request.user or (
not is_authenticated(request.user) and self.authenticated_users_only):
not request.user.is_authenticated and self.authenticated_users_only):
return False

queryset = self._queryset(view)
Expand Down
14 changes: 12 additions & 2 deletions rest_framework/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@
from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _

from rest_framework.compat import JSONField as ModelJSONField
from rest_framework.compat import postgres_fields, set_many, unicode_to_repr
from rest_framework.compat import set_many, unicode_to_repr
from rest_framework.exceptions import ErrorDetail, ValidationError
from rest_framework.fields import get_error_detail, set_value
from rest_framework.settings import api_settings
Expand All @@ -46,6 +45,17 @@
UniqueTogetherValidator
)

try:
from django.contrib.postgres import fields as postgres_fields
except ImportError:
postgres_fields = None

try:
from django.contrib.postgres.fields import JSONField as ModelJSONField
except ImportError:
ModelJSONField = None


# Note: We do the following so that users of the framework can use this style:
#
# example_field = serializers.CharField(...)
Expand Down
7 changes: 3 additions & 4 deletions rest_framework/throttling.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from django.core.cache import cache as default_cache
from django.core.exceptions import ImproperlyConfigured

from rest_framework.compat import is_authenticated
from rest_framework.settings import api_settings


Expand Down Expand Up @@ -174,7 +173,7 @@ class AnonRateThrottle(SimpleRateThrottle):
scope = 'anon'

def get_cache_key(self, request, view):
if is_authenticated(request.user):
if request.user.is_authenticated:
return None # Only throttle unauthenticated requests.

return self.cache_format % {
Expand All @@ -194,7 +193,7 @@ class UserRateThrottle(SimpleRateThrottle):
scope = 'user'

def get_cache_key(self, request, view):
if is_authenticated(request.user):
if request.user.is_authenticated:
ident = request.user.pk
else:
ident = self.get_ident(request)
Expand Down Expand Up @@ -242,7 +241,7 @@ def get_cache_key(self, request, view):
Otherwise generate the unique cache key by concatenating the user id
with the '.throttle_scope` property of the view.
"""
if is_authenticated(request.user):
if request.user.is_authenticated:
ident = request.user.pk
else:
ident = self.get_ident(request)
Expand Down
10 changes: 7 additions & 3 deletions rest_framework/utils/field_mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@
from django.db import models
from django.utils.text import capfirst

from rest_framework.compat import DecimalValidator, JSONField
from rest_framework.validators import UniqueValidator

try:
from django.contrib.postgres.fields import JSONField
except ImportError:
JSONField = None

NUMERIC_FIELD_TYPES = (
models.IntegerField, models.FloatField, models.DecimalField
)
Expand Down Expand Up @@ -182,10 +186,10 @@ def get_field_kwargs(field_name, model_field):
]
# Our decimal validation is handled in the field code, not validator code.
# (In Django 1.9+ this differs from previous style)
if isinstance(model_field, models.DecimalField) and DecimalValidator:
if isinstance(model_field, models.DecimalField):
validator_kwarg = [
validator for validator in validator_kwarg
if not isinstance(validator, DecimalValidator)
if not isinstance(validator, validators.DecimalValidator)
]

# Ensure that max_length is passed explicitly as a keyword arg,
Expand Down
8 changes: 4 additions & 4 deletions rest_framework/utils/model_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"""
from collections import OrderedDict, namedtuple

from rest_framework.compat import get_related_model, get_remote_field
from rest_framework.compat import get_remote_field

FieldInfo = namedtuple('FieldResult', [
'pk', # Model field instance
Expand Down Expand Up @@ -53,7 +53,7 @@ def _get_pk(opts):

while rel and rel.parent_link:
# If model is a child via multi-table inheritance, use parent's pk.
pk = get_related_model(pk)._meta.pk
pk = pk.remote_field.model._meta.pk
rel = get_remote_field(pk)

return pk
Expand All @@ -79,7 +79,7 @@ def _get_forward_relationships(opts):
for field in [field for field in opts.fields if field.serialize and get_remote_field(field)]:
forward_relations[field.name] = RelationInfo(
model_field=field,
related_model=get_related_model(field),
related_model=field.remote_field.model,
to_many=False,
to_field=_get_to_field(field),
has_through_model=False,
Expand All @@ -90,7 +90,7 @@ def _get_forward_relationships(opts):
for field in [field for field in opts.many_to_many if field.serialize]:
forward_relations[field.name] = RelationInfo(
model_field=field,
related_model=get_related_model(field),
related_model=field.remote_field.model,
to_many=True,
# manytomany do not have to_fields
to_field=None,
Expand Down
9 changes: 7 additions & 2 deletions rest_framework/utils/representation.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,18 @@
from django.utils.encoding import force_text
from django.utils.functional import Promise

from rest_framework.compat import get_names_and_managers, unicode_repr
from rest_framework.compat import unicode_repr


def manager_repr(value):
model = value.model
opts = model._meta
for manager_name, manager_instance in get_names_and_managers(opts):
names_and_managers = [
(manager.name, manager)
for manager
in opts.managers
]
for manager_name, manager_instance in names_and_managers:
if manager_instance == value:
return '%s.%s.all()' % (model._meta.object_name, manager_name)
return repr(value)
Expand Down
3 changes: 1 addition & 2 deletions tests/test_authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
TokenAuthentication)
from rest_framework.authtoken.models import Token
from rest_framework.authtoken.views import obtain_auth_token
from rest_framework.compat import is_authenticated
from rest_framework.response import Response
from rest_framework.test import APIClient, APIRequestFactory
from rest_framework.views import APIView
Expand Down Expand Up @@ -450,7 +449,7 @@ class AuthAccessingRenderer(renderers.BaseRenderer):

def render(self, data, media_type=None, renderer_context=None):
request = renderer_context['request']
if is_authenticated(request.user):
if request.user.is_authenticated:
return b'authenticated'
return b'not authenticated'

Expand Down
5 changes: 2 additions & 3 deletions tests/test_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

from rest_framework import status
from rest_framework.authentication import SessionAuthentication
from rest_framework.compat import is_anonymous
from rest_framework.parsers import BaseParser, FormParser, MultiPartParser
from rest_framework.request import Request
from rest_framework.response import Response
Expand Down Expand Up @@ -201,9 +200,9 @@ def test_user_can_login(self):

def test_user_can_logout(self):
self.request.user = self.user
self.assertFalse(is_anonymous(self.request.user))
self.assertFalse(self.request.user.is_anonymous)
logout(self.request)
self.assertTrue(is_anonymous(self.request.user))
self.assertTrue(self.request.user.is_anonymous)

def test_logged_in_user_is_set_on_wrapped_request(self):
login(self.request, self.user)
Expand Down
4 changes: 2 additions & 2 deletions tests/test_requests_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_protect, ensure_csrf_cookie

from rest_framework.compat import is_authenticated, requests
from rest_framework.compat import requests
from rest_framework.response import Response
from rest_framework.test import APITestCase, RequestsClient
from rest_framework.views import APIView
Expand Down Expand Up @@ -72,7 +72,7 @@ def post(self, request):
class AuthView(APIView):
@method_decorator(ensure_csrf_cookie)
def get(self, request):
if is_authenticated(request.user):
if request.user.is_authenticated:
username = request.user.username
else:
username = None
Expand Down