diff --git a/.travis.yml b/.travis.yml
index d68c4c679..2bd24b566 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,7 +2,6 @@ sudo: false
language: python
python:
- - "2.7"
- "3.4"
- "3.5"
- "3.6"
diff --git a/README.rst b/README.rst
index 772babe44..251470fcc 100644
--- a/README.rst
+++ b/README.rst
@@ -19,8 +19,8 @@ Full documentation on `read the docs`_.
Requirements
------------
-* **Python**: 2.7, 3.4, 3.5, 3.6
-* **Django**: 1.8, 1.10, 1.11
+* **Python**: 3.4, 3.5, 3.6
+* **Django**: 1.11, 2.0b
* **DRF**: 3.7
Installation
diff --git a/django_filters/__init__.py b/django_filters/__init__.py
index 77f911904..d552d509a 100644
--- a/django_filters/__init__.py
+++ b/django_filters/__init__.py
@@ -1,6 +1,4 @@
# flake8: noqa
-from __future__ import absolute_import
-
import pkgutil
from .constants import STRICTNESS
diff --git a/django_filters/compat.py b/django_filters/compat.py
index 69945c404..fcaa9e9b4 100644
--- a/django_filters/compat.py
+++ b/django_filters/compat.py
@@ -1,14 +1,4 @@
-
-from __future__ import absolute_import
-
-import django
from django.conf import settings
-from django.utils.timezone import make_aware as make_aware_orig
-
-try:
- from django.forms.utils import pretty_name
-except ImportError: # Django 1.8
- from django.forms.forms import pretty_name
# django-crispy-forms is optional
try:
@@ -33,39 +23,3 @@ def is_crispy():
import coreschema
except ImportError:
coreschema = None
-
-def remote_field(field):
- """
- https://docs.djangoproject.com/en/1.9/releases/1.9/#field-rel-changes
- """
- if django.VERSION >= (1, 9):
- return field.remote_field
- return field.rel
-
-
-def remote_model(field):
- if django.VERSION >= (1, 9):
- return remote_field(field).model
- return remote_field(field).to
-
-
-def remote_queryset(field):
- model = remote_model(field)
- limit_choices_to = field.get_limit_choices_to()
-
- return model._default_manager.complex_filter(limit_choices_to)
-
-
-def format_value(widget, value):
- if django.VERSION >= (1, 10):
- return widget.format_value(value)
- return widget._format_value(value)
-
-
-
-def make_aware(value, timezone, is_dst):
- """is_dst was added for 1.9"""
- if django.VERSION >= (1, 9):
- return make_aware_orig(value, timezone, is_dst)
- else:
- return make_aware_orig(value, timezone)
diff --git a/django_filters/conf.py b/django_filters/conf.py
index b0a102767..cf8a4599f 100644
--- a/django_filters/conf.py
+++ b/django_filters/conf.py
@@ -1,6 +1,3 @@
-
-from __future__ import absolute_import
-
from django.conf import settings as dj_settings
from django.core.signals import setting_changed
from django.utils.translation import ugettext_lazy as _
diff --git a/django_filters/fields.py b/django_filters/fields.py
index 99a107651..3150fa469 100644
--- a/django_filters/fields.py
+++ b/django_filters/fields.py
@@ -1,9 +1,6 @@
-from __future__ import absolute_import, unicode_literals
-
from collections import namedtuple
from datetime import datetime, time
-import django
from django import forms
from django.utils.dateparse import parse_datetime
from django.utils.encoding import force_str
@@ -237,14 +234,7 @@ def __init__(self, *args, **kwargs):
super(ChoiceIteratorMixin, self).__init__(*args, **kwargs)
def _get_choices(self):
- if django.VERSION >= (1, 11):
- return super(ChoiceIteratorMixin, self)._get_choices()
-
- # HACK: Django < 1.11 does not allow a custom iterator to be provided.
- # This code only executes for Model*ChoiceFields.
- if hasattr(self, '_choices'):
- return self._choices
- return self.iterator(self)
+ return super(ChoiceIteratorMixin, self)._get_choices()
def _set_choices(self, value):
super(ChoiceIteratorMixin, self)._set_choices(value)
diff --git a/django_filters/filters.py b/django_filters/filters.py
index 90701a27d..e64fd100a 100644
--- a/django_filters/filters.py
+++ b/django_filters/filters.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import, unicode_literals
-
from collections import OrderedDict
from datetime import timedelta
@@ -7,12 +5,11 @@
from django.db.models import Q
from django.db.models.constants import LOOKUP_SEP
from django.db.models.sql.constants import QUERY_TERMS
-from django.utils import six
+from django.forms.utils import pretty_name
from django.utils.itercompat import is_iterable
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
-from .compat import pretty_name
from .conf import settings
from .constants import EMPTY_VALUES
from .fields import (
@@ -186,7 +183,7 @@ def field(self):
def filter(self, qs, value):
if isinstance(value, Lookup):
- lookup = six.text_type(value.lookup_type)
+ lookup = str(value.lookup_type)
value = value.value
else:
lookup = self.lookup_expr
@@ -475,7 +472,7 @@ class DateRangeFilter(ChoiceFilter):
def __init__(self, *args, **kwargs):
kwargs['choices'] = [
- (key, value[0]) for key, value in six.iteritems(self.options)]
+ (key, value[0]) for key, value in self.options.items()]
# empty/null choices not relevant
kwargs.setdefault('empty_label', None)
@@ -660,13 +657,13 @@ def normalize_fields(cls, fields):
"'fields' must be an iterable (e.g., a list, tuple, or mapping)."
# fields is an iterable of field names
- assert all(isinstance(field, six.string_types) or
+ assert all(isinstance(field, str) or
is_iterable(field) and len(field) == 2 # may need to be wrapped in parens
for field in fields), \
"'fields' must contain strings or (field name, param name) pairs."
return OrderedDict([
- (f, f) if isinstance(f, six.string_types) else f for f in fields
+ (f, f) if isinstance(f, str) else f for f in fields
])
def build_choices(self, fields, labels):
diff --git a/django_filters/filterset.py b/django_filters/filterset.py
index da100952e..a33540ff3 100644
--- a/django_filters/filterset.py
+++ b/django_filters/filterset.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import, unicode_literals
-
import copy
from collections import OrderedDict
@@ -7,9 +5,7 @@
from django.db import models
from django.db.models.constants import LOOKUP_SEP
from django.db.models.fields.related import ForeignObjectRel
-from django.utils import six
-from .compat import remote_field, remote_queryset
from .conf import settings
from .constants import ALL_FIELDS, STRICTNESS
from .filters import (
@@ -36,6 +32,13 @@
)
+def remote_queryset(field):
+ model = field.remote_field.model
+ limit_choices_to = field.get_limit_choices_to()
+
+ return model._default_manager.complex_filter(limit_choices_to)
+
+
class FilterSetOptions(object):
def __init__(self, options=None):
self.model = getattr(options, 'model', None)
@@ -113,7 +116,7 @@ def get_declared_filters(cls, bases, attrs):
'filter_class': ModelChoiceFilter,
'extra': lambda f: {
'queryset': remote_queryset(f),
- 'to_field_name': remote_field(f).field_name,
+ 'to_field_name': f.remote_field.field_name,
'null_label': settings.NULL_CHOICE_LABEL if f.null else None,
}
},
@@ -121,7 +124,7 @@ def get_declared_filters(cls, bases, attrs):
'filter_class': ModelChoiceFilter,
'extra': lambda f: {
'queryset': remote_queryset(f),
- 'to_field_name': remote_field(f).field_name,
+ 'to_field_name': f.remote_field.field_name,
'null_label': settings.NULL_CHOICE_LABEL if f.null else None,
}
},
@@ -181,7 +184,7 @@ def qs(self):
# start with all the results and filter from there
qs = self.queryset.all()
- for name, filter_ in six.iteritems(self.filters):
+ for name, filter_ in self.filters.items():
value = self.form.cleaned_data.get(name)
if value is not None: # valid & clean data
@@ -196,7 +199,7 @@ def form(self):
if not hasattr(self, '_form'):
fields = OrderedDict([
(name, filter_.field)
- for name, filter_ in six.iteritems(self.filters)])
+ for name, filter_ in self.filters.items()])
Form = type(str('%sForm' % self.__class__.__name__),
(self._meta.form,), fields)
@@ -328,7 +331,7 @@ def filter_for_field(cls, f, field_name, lookup_expr='exact'):
@classmethod
def filter_for_reverse_field(cls, f, field_name):
- rel = remote_field(f.field)
+ rel = f.field.remote_field
queryset = f.field.model._default_manager.all()
default = {
'field_name': field_name,
@@ -410,7 +413,7 @@ def _csv_filter_class_name(cls, filter_class, lookup_type):
return str('%s%sFilter' % (type_name, lookup_name))
-class FilterSet(six.with_metaclass(FilterSetMetaclass, BaseFilterSet)):
+class FilterSet(BaseFilterSet, metaclass=FilterSetMetaclass):
pass
diff --git a/django_filters/rest_framework/__init__.py b/django_filters/rest_framework/__init__.py
index 11af6d59e..55025e705 100644
--- a/django_filters/rest_framework/__init__.py
+++ b/django_filters/rest_framework/__init__.py
@@ -1,5 +1,4 @@
# flake8: noqa
-from __future__ import absolute_import
from .backends import DjangoFilterBackend
from .filterset import FilterSet
from .filters import *
diff --git a/django_filters/rest_framework/backends.py b/django_filters/rest_framework/backends.py
index a837324cf..eeba17361 100644
--- a/django_filters/rest_framework/backends.py
+++ b/django_filters/rest_framework/backends.py
@@ -1,10 +1,6 @@
-
-from __future__ import absolute_import
-
import warnings
from django.template import loader
-from django.utils import six
from . import filters, filterset
from .. import compat
@@ -74,7 +70,7 @@ def get_coreschema_field(self, field):
else:
field_cls = compat.coreschema.String
return field_cls(
- description=six.text_type(field.extra.get('help_text', ''))
+ description=str(field.extra.get('help_text', ''))
)
def get_schema_fields(self, view):
diff --git a/django_filters/rest_framework/filterset.py b/django_filters/rest_framework/filterset.py
index 9a984f25f..48d2d66c3 100644
--- a/django_filters/rest_framework/filterset.py
+++ b/django_filters/rest_framework/filterset.py
@@ -1,6 +1,3 @@
-
-from __future__ import absolute_import
-
from copy import deepcopy
from django import forms
diff --git a/django_filters/utils.py b/django_filters/utils.py
index 1531fadb9..f94c3aa50 100644
--- a/django_filters/utils.py
+++ b/django_filters/utils.py
@@ -9,12 +9,11 @@
from django.db.models.fields import FieldDoesNotExist
from django.db.models.fields.related import ForeignObjectRel, RelatedField
from django.forms import ValidationError
-from django.utils import six, timezone
+from django.utils import timezone
from django.utils.encoding import force_text
from django.utils.text import capfirst
from django.utils.translation import ugettext as _
-from .compat import make_aware, remote_field, remote_model
from .exceptions import FieldLookupError
@@ -50,7 +49,7 @@ def get_all_model_fields(model):
return [
f.name for f in sorted(opts.fields + opts.many_to_many)
if not isinstance(f, models.AutoField) and
- not (getattr(remote_field(f), 'parent_link', False))
+ not (getattr(f.remote_field, 'parent_link', False))
]
@@ -93,7 +92,7 @@ def get_field_parts(model, field_name):
fields.append(field)
if isinstance(field, RelatedField):
- opts = remote_model(field)._meta
+ opts = field.remote_field.model._meta
elif isinstance(field, ForeignObjectRel):
opts = field.related_model._meta
@@ -141,12 +140,12 @@ def resolve_field(model_field, lookup_expr):
lhs = query.try_transform(*args)
lookups = lookups[1:]
except FieldError as e:
- six.raise_from(FieldLookupError(model_field, lookup_expr), e)
+ raise FieldLookupError(model_field, lookup_expr) from e
def handle_timezone(value, is_dst=None):
if settings.USE_TZ and timezone.is_naive(value):
- return make_aware(value, timezone.get_current_timezone(), is_dst)
+ return timezone.make_aware(value, timezone.get_current_timezone(), is_dst)
elif not settings.USE_TZ and timezone.is_aware(value):
return timezone.make_naive(value, timezone.utc)
return value
@@ -225,7 +224,7 @@ def label_for_filter(model, field_name, lookup_expr, exclude=False):
verbose_expression = [_('exclude'), name] if exclude else [name]
# iterable lookups indicate a LookupTypeField, which should not be verbose
- if isinstance(lookup_expr, six.string_types):
+ if isinstance(lookup_expr, str):
verbose_expression += [verbose_lookup_expr(lookup_expr)]
verbose_expression = [force_text(part) for part in verbose_expression if part]
diff --git a/django_filters/views.py b/django_filters/views.py
index 8000548f7..2303ed9df 100644
--- a/django_filters/views.py
+++ b/django_filters/views.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import, unicode_literals
-
from django.core.exceptions import ImproperlyConfigured
from django.views.generic import View
from django.views.generic.list import (
diff --git a/django_filters/widgets.py b/django_filters/widgets.py
index 572ee8507..ba1d2c16c 100644
--- a/django_filters/widgets.py
+++ b/django_filters/widgets.py
@@ -1,10 +1,7 @@
-from __future__ import absolute_import, unicode_literals
-
from collections import Iterable
from itertools import chain
from re import search, sub
-import django
from django import forms
from django.db.models.fields import BLANK_CHOICE_DASH
from django.forms.utils import flatatt
@@ -12,11 +9,8 @@
from django.utils.encoding import force_text
from django.utils.http import urlencode
from django.utils.safestring import mark_safe
-from django.utils.six import string_types
from django.utils.translation import ugettext as _
-from .compat import format_value
-
class LinkWidget(forms.Widget):
def __init__(self, attrs=None, choices=()):
@@ -34,10 +28,7 @@ def render(self, name, value, attrs=None, choices=()):
self.data = {}
if value is None:
value = ''
- if django.VERSION < (1, 11):
- final_attrs = self.build_attrs(attrs)
- else:
- final_attrs = self.build_attrs(self.attrs, extra_attrs=attrs)
+ final_attrs = self.build_attrs(self.attrs, extra_attrs=attrs)
output = ['
' % flatatt(final_attrs)]
options = self.render_options(choices, [value], name)
if options:
@@ -118,14 +109,6 @@ def value_omitted_from_data(self, data, files, name):
for widget, suffix in zip(self.widgets, self.suffixes)
)
- # Django < 1.11 compat
- def format_output(self, rendered_widgets):
- rendered_widgets = [
- self.replace_name(output, i)
- for i, output in enumerate(rendered_widgets)
- ]
- return '\n'.join(rendered_widgets)
-
def replace_name(self, output, index):
result = search(r'name="(?P.*)_%d"' % index, output)
name = result.group('name')
@@ -147,10 +130,6 @@ def __init__(self, attrs=None):
widgets = (forms.TextInput, forms.TextInput)
super(RangeWidget, self).__init__(widgets, attrs)
- def format_output(self, rendered_widgets):
- # Method was removed in Django 1.11.
- return '-'.join(rendered_widgets)
-
def decompress(self, value):
if value:
return [value.start, value.stop]
@@ -189,7 +168,7 @@ def render(self, name, value, attrs=None):
def value_from_datadict(self, data, files, name):
value = data.get(name, None)
- if isinstance(value, string_types):
+ if isinstance(value, str):
value = value.lower()
return {
@@ -204,7 +183,7 @@ def value_from_datadict(self, data, files, name):
class BaseCSVWidget(forms.Widget):
def _isiterable(self, value):
- return isinstance(value, Iterable) and not isinstance(value, string_types)
+ return isinstance(value, Iterable) and not isinstance(value, str)
def value_from_datadict(self, data, files, name):
value = super(BaseCSVWidget, self).value_from_datadict(data, files, name)
@@ -227,7 +206,7 @@ def render(self, name, value, attrs=None):
# if we have multiple values, we need to force render as a text input
# (otherwise, the additional values are lost)
surrogate = forms.TextInput()
- value = [force_text(format_value(surrogate, v)) for v in value]
+ value = [force_text(surrogate.format_value(v)) for v in value]
value = ','.join(list(value))
return surrogate.render(name, value, attrs)
@@ -252,7 +231,7 @@ def value_from_datadict(self, data, files, name):
if not isinstance(data, MultiValueDict):
for key, value in data.items():
# treat value as csv string: ?foo=1,2
- if isinstance(value, string_types):
+ if isinstance(value, str):
data[key] = [x.strip() for x in value.rstrip(',').split(',') if x]
data = MultiValueDict(data)
diff --git a/docs/guide/install.txt b/docs/guide/install.txt
index 8572ab881..c494cd06f 100644
--- a/docs/guide/install.txt
+++ b/docs/guide/install.txt
@@ -29,6 +29,6 @@ __ http://www.django-rest-framework.org/
-* **Python**: 2.7, 3.4, 3.5, 3.6
-* **Django**: 1.10, 1.11
+* **Python**: 3.4, 3.5, 3.6
+* **Django**: 1.11, 2.0b
* **DRF**: 3.7
diff --git a/setup.py b/setup.py
index 02e1c9253..d939cdfa2 100644
--- a/setup.py
+++ b/setup.py
@@ -43,14 +43,9 @@
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Framework :: Django',
- 'Framework :: Django :: 1.8',
- 'Framework :: Django :: 1.10',
'Framework :: Django :: 1.11',
'Programming Language :: Python',
- 'Programming Language :: Python :: 2',
- 'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
diff --git a/tests/models.py b/tests/models.py
index 848e7f36e..aadd4f3e6 100644
--- a/tests/models.py
+++ b/tests/models.py
@@ -1,8 +1,5 @@
-from __future__ import absolute_import, unicode_literals
-
from django import forms
from django.db import models
-from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
REGULAR = 0
@@ -42,7 +39,6 @@ def formfield(self, **kwargs):
return super(SubnetMaskField, self).formfield(**defaults)
-@python_2_unicode_compatible
class User(models.Model):
username = models.CharField(_('username'), max_length=255)
first_name = SubCharField(max_length=100)
@@ -58,7 +54,6 @@ def __str__(self):
return self.username
-@python_2_unicode_compatible
class ManagerGroup(models.Model):
users = models.ManyToManyField(User,
limit_choices_to={'is_active': True},
@@ -72,7 +67,6 @@ def __str__(self):
return self.manager.name + ' group'
-@python_2_unicode_compatible
class AdminUser(User):
class Meta:
proxy = True
@@ -81,7 +75,6 @@ def __str__(self):
return "%s (ADMIN)" % self.username
-@python_2_unicode_compatible
class Comment(models.Model):
text = models.TextField()
author = models.ForeignKey(User, related_name='comments', on_delete=models.CASCADE)
@@ -104,7 +97,6 @@ def __str__(self):
return "Anonymous on %s" % self.published
-@python_2_unicode_compatible
class Book(models.Model):
title = models.CharField(max_length=100)
price = models.DecimalField(max_digits=6, decimal_places=2)
@@ -132,7 +124,6 @@ class NetworkSetting(models.Model):
cidr = models.CharField(max_length=18, blank=True, verbose_name="CIDR")
-@python_2_unicode_compatible
class Company(models.Model):
name = models.CharField(max_length=100)
@@ -143,7 +134,6 @@ class Meta:
ordering = ['name']
-@python_2_unicode_compatible
class Location(models.Model):
company = models.ForeignKey(Company, related_name='locations', on_delete=models.CASCADE)
name = models.CharField(max_length=100)
diff --git a/tests/rest_framework/test_backends.py b/tests/rest_framework/test_backends.py
index c5671cd05..b17cf72f3 100644
--- a/tests/rest_framework/test_backends.py
+++ b/tests/rest_framework/test_backends.py
@@ -1,8 +1,4 @@
-from __future__ import unicode_literals
-
-import datetime
import warnings
-from decimal import Decimal
from unittest import skipIf
from django.db.models import BooleanField
diff --git a/tests/rest_framework/test_integration.py b/tests/rest_framework/test_integration.py
index eee716736..c5bb2998d 100644
--- a/tests/rest_framework/test_integration.py
+++ b/tests/rest_framework/test_integration.py
@@ -1,11 +1,10 @@
-from __future__ import unicode_literals
-
import datetime
from decimal import Decimal
from django.conf.urls import url
from django.test import TestCase
from django.test.utils import override_settings
+from django.urls import reverse
from django.utils.dateparse import parse_date
from rest_framework import generics, serializers, status
from rest_framework.test import APIRequestFactory
@@ -20,15 +19,6 @@
FilterableItem
)
-try:
- from django.urls import reverse
-except ImportError:
- # Django < 1.10 compatibility
- from django.core.urlresolvers import reverse
-
-
-
-
factory = APIRequestFactory()
diff --git a/tests/test_fields.py b/tests/test_fields.py
index 21c68d166..dd36c5399 100644
--- a/tests/test_fields.py
+++ b/tests/test_fields.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import, unicode_literals
-
import decimal
from datetime import datetime, time, timedelta, tzinfo
diff --git a/tests/test_filtering.py b/tests/test_filtering.py
index c5225ba53..eb8cd5f5a 100644
--- a/tests/test_filtering.py
+++ b/tests/test_filtering.py
@@ -1,13 +1,10 @@
-from __future__ import absolute_import, unicode_literals
-
import datetime
import mock
import unittest
-import django
from django import forms
from django.test import TestCase, override_settings
-from django.utils import six, timezone
+from django.utils import timezone
from django.utils.timezone import now
from django_filters.exceptions import FieldLookupError
@@ -301,7 +298,6 @@ def test_filtering(self):
User.objects.create(username='aaron', status=2)
User.objects.create(username='carl', status=0)
-
class F(FilterSet):
status = TypedMultipleChoiceFilter(choices=STATUS_CHOICES, coerce=lambda x: x[0:2])
@@ -334,7 +330,7 @@ def test_filtering(self):
today = now().date()
timestamp = now().time().replace(microsecond=0)
last_week = today - datetime.timedelta(days=7)
- check_date = six.text_type(last_week)
+ check_date = str(last_week)
u = User.objects.create(username='alex')
Comment.objects.create(author=u, time=timestamp, date=today)
Comment.objects.create(author=u, time=timestamp, date=last_week)
@@ -358,7 +354,7 @@ def test_filtering(self):
now_time = now().time().replace(microsecond=0)
ten_min_ago = (now() - datetime.timedelta(minutes=10))
fixed_time = ten_min_ago.time().replace(microsecond=0)
- check_time = six.text_type(fixed_time)
+ check_time = str(fixed_time)
u = User.objects.create(username='alex')
Comment.objects.create(author=u, time=now_time, date=today)
Comment.objects.create(author=u, time=fixed_time, date=today)
@@ -389,7 +385,7 @@ def test_filtering(self):
tz = timezone.get_current_timezone()
# make naive, like a browser would send
local_ten_min_ago = timezone.make_naive(ten_min_ago, tz)
- check_dt = six.text_type(local_ten_min_ago)
+ check_dt = str(local_ten_min_ago)
class F(FilterSet):
class Meta:
@@ -941,7 +937,6 @@ class Meta:
'published_1': '2016-01-03'})
self.assertEqual(len(results.qs), 3)
- @unittest.skipIf(django.VERSION < (1, 9), 'version doesnt supports is_dst parameter for make_aware')
@override_settings(TIME_ZONE='America/Sao_Paulo')
def test_filtering_dst_start_midnight(self):
tz = timezone.get_default_timezone()
@@ -962,7 +957,6 @@ class Meta:
'published_1': '2017-10-15'})
self.assertEqual(len(results.qs), 2)
- @unittest.skipIf(django.VERSION < (1, 9), 'version doesnt supports is_dst parameter for make_aware')
@override_settings(TIME_ZONE='America/Sao_Paulo')
def test_filtering_dst_ends_midnight(self):
tz = timezone.get_default_timezone()
@@ -983,7 +977,6 @@ class Meta:
'published_1': '2017-02-18'})
self.assertEqual(len(results.qs), 2)
- @unittest.skipIf(django.VERSION < (1, 9), 'version doesnt supports is_dst parameter for make_aware')
@override_settings(TIME_ZONE='Europe/Paris')
def test_filtering_dst_start(self):
tz = timezone.get_default_timezone()
@@ -1005,7 +998,6 @@ class Meta:
'published_1': '2017-3-26'})
self.assertEqual(len(results.qs), 3)
- @unittest.skipIf(django.VERSION < (1, 9), 'version doesnt supports is_dst parameter for make_aware')
@override_settings(TIME_ZONE='Europe/Paris')
def test_filtering_dst_end(self):
tz = timezone.get_default_timezone()
@@ -1667,7 +1659,6 @@ class Meta:
# use naive datetimes, as pytz is required to perform
# date lookups when timezones are involved.
@override_settings(USE_TZ=False)
-@unittest.skipIf(django.VERSION < (1, 9), "version does not support transformed lookup expressions")
class TransformedQueryExpressionFilterTests(TestCase):
def test_filtering(self):
diff --git a/tests/test_filters.py b/tests/test_filters.py
index 713230a80..d3a16517a 100644
--- a/tests/test_filters.py
+++ b/tests/test_filters.py
@@ -1,6 +1,4 @@
# -*- coding: utf-8 -*-
-from __future__ import absolute_import, unicode_literals
-
import inspect
import mock
from collections import OrderedDict
diff --git a/tests/test_filterset.py b/tests/test_filterset.py
index 976a205a9..0c5ba7cca 100644
--- a/tests/test_filterset.py
+++ b/tests/test_filterset.py
@@ -1,9 +1,6 @@
-from __future__ import absolute_import, unicode_literals
-
import mock
import unittest
-import django
from django.core.exceptions import ValidationError
from django.db import models
from django.test import TestCase, override_settings
@@ -195,7 +192,6 @@ def test_m2m_field_with_through_model(self):
self.assertIsNotNone(result.extra['queryset'])
self.assertEqual(result.extra['queryset'].model, Worker)
- @unittest.skipIf(django.VERSION < (1, 9), "version does not support transformed lookup expressions")
def test_transformed_lookup_expr(self):
f = Comment._meta.get_field('date')
result = FilterSet.filter_for_field(f, 'date', 'year__gte')
diff --git a/tests/test_forms.py b/tests/test_forms.py
index 0932f35e6..8b1dfbe22 100644
--- a/tests/test_forms.py
+++ b/tests/test_forms.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import, unicode_literals
-
from django import forms
from django.test import TestCase, override_settings
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 138ef654f..dd7c6438d 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -1,7 +1,5 @@
import datetime
-import unittest
-import django
from django.db import models
from django.db.models.constants import LOOKUP_SEP
from django.db.models.fields.related import ForeignObjectRel
@@ -24,7 +22,6 @@
)
from .models import (
- Account,
Article,
Book,
Business,
@@ -112,7 +109,6 @@ def test_resolve_forward_related_lookups(self):
self.assertIsInstance(field, models.ManyToManyField)
self.assertEqual(lookup, term)
- @unittest.skipIf(django.VERSION < (1, 9), "version does not reverse lookups")
def test_resolve_reverse_related_lookups(self):
"""
Check that lookups can be resolved for related fields
@@ -134,7 +130,6 @@ def test_resolve_reverse_related_lookups(self):
self.assertIsInstance(field, models.ManyToManyRel)
self.assertEqual(lookup, term)
- @unittest.skipIf(django.VERSION < (1, 9), "version does not support transformed lookup expressions")
def test_resolve_transformed_lookups(self):
"""
Check that chained field transforms are correctly resolved.
@@ -186,7 +181,6 @@ def test_resolve_transformed_lookups(self):
self.assertIsInstance(field, models.IntegerField)
self.assertEqual(resolved_lookup, lookup)
- @unittest.skipIf(django.VERSION < (1, 9), "version does not support transformed lookup expressions")
def test_resolve_implicit_exact_lookup(self):
# Use a DateTimeField, so we can check multiple transforms.
# eg, date__year__gte
@@ -335,14 +329,12 @@ def test_field_all_caps(self):
class HandleTimezone(TestCase):
- @unittest.skipIf(django.VERSION < (1, 9), 'version doesnt supports is_dst parameter for make_aware')
@override_settings(TIME_ZONE='America/Sao_Paulo')
def test_handle_dst_ending(self):
dst_ending_date = datetime.datetime(2017, 2, 18, 23, 59, 59, 999999)
handled = handle_timezone(dst_ending_date, False)
self.assertEqual(handled, get_default_timezone().localize(dst_ending_date, False))
- @unittest.skipIf(django.VERSION < (1, 9), 'version doesnt supports is_dst parameter for make_aware')
@override_settings(TIME_ZONE='America/Sao_Paulo')
def test_handle_dst_starting(self):
dst_starting_date = datetime.datetime(2017, 10, 15, 0, 0, 0, 0)
diff --git a/tests/test_views.py b/tests/test_views.py
index e8fdbc718..9204e9a33 100644
--- a/tests/test_views.py
+++ b/tests/test_views.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import, unicode_literals
-
from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase, override_settings
from django.test.client import RequestFactory
diff --git a/tests/test_widgets.py b/tests/test_widgets.py
index 78ff92d30..e170d2c58 100644
--- a/tests/test_widgets.py
+++ b/tests/test_widgets.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import, unicode_literals
-
from django.forms import Select, TextInput
from django.test import TestCase
diff --git a/tests/urls.py b/tests/urls.py
index 64a0c0600..8a7da0627 100644
--- a/tests/urls.py
+++ b/tests/urls.py
@@ -1,5 +1,3 @@
-from __future__ import absolute_import, unicode_literals
-
from django.conf.urls import url
from django_filters.views import FilterView, object_filter
diff --git a/tox.ini b/tox.ini
index 70cabd959..dc54f9e2b 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,7 +1,7 @@
[tox]
envlist =
- {py27,py34,py35}-django110,
- {py27,py35,py36}-django111,
+ {py27,py34,py35,py36}-django111,
+ {py34,py35,py36}-django20,
{py35,py36}-latest,
isort, warnings,
@@ -17,8 +17,8 @@ ignore_outcome =
setenv =
PYTHONDONTWRITEBYTECODE=1
deps =
- django110: django>=1.10.0,<1.11.0
django111: django>=1.11.0,<2.0
+ django20: django>=2.0b1,<2.1
djangorestframework>=3.7,<3.8
latest: {[latest]deps}
-rrequirements/test-ci.txt