Skip to content
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

Drop python 2, Django<1.11 support #797

Merged
merged 7 commits into from
Oct 24, 2017
Merged
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
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ sudo: false

language: python
python:
- "2.7"
- "3.4"
- "3.5"
- "3.6"
Expand Down
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 0 additions & 2 deletions django_filters/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# flake8: noqa
from __future__ import absolute_import

import pkgutil

from .constants import STRICTNESS
Expand Down
46 changes: 0 additions & 46 deletions django_filters/compat.py
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -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)
3 changes: 0 additions & 3 deletions django_filters/conf.py
Original file line number Diff line number Diff line change
@@ -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 _
Expand Down
12 changes: 1 addition & 11 deletions django_filters/fields.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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)
Expand Down
13 changes: 5 additions & 8 deletions django_filters/filters.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
from __future__ import absolute_import, unicode_literals

from collections import OrderedDict
from datetime import timedelta

from django import forms
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 (
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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):
Expand Down
23 changes: 13 additions & 10 deletions django_filters/filterset.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
from __future__ import absolute_import, unicode_literals

import copy
from collections import OrderedDict

from django import forms
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 (
Expand All @@ -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)
Expand Down Expand Up @@ -113,15 +116,15 @@ 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,
}
},
models.ForeignKey: {
'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,
}
},
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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


Expand Down
1 change: 0 additions & 1 deletion django_filters/rest_framework/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# flake8: noqa
from __future__ import absolute_import
from .backends import DjangoFilterBackend
from .filterset import FilterSet
from .filters import *
6 changes: 1 addition & 5 deletions django_filters/rest_framework/backends.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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):
Expand Down
3 changes: 0 additions & 3 deletions django_filters/rest_framework/filterset.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@

from __future__ import absolute_import

from copy import deepcopy

from django import forms
Expand Down
13 changes: 6 additions & 7 deletions django_filters/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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))
]


Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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]
Expand Down
2 changes: 0 additions & 2 deletions django_filters/views.py
Original file line number Diff line number Diff line change
@@ -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 (
Expand Down
Loading