Skip to content

Commit

Permalink
Merge pull request #303 from alex/develop
Browse files Browse the repository at this point in the history
Version 0.12.0 Release
  • Loading branch information
Carlton Gibson committed Jan 7, 2016
2 parents feff453 + e1f40b0 commit d2bda5a
Show file tree
Hide file tree
Showing 33 changed files with 593 additions and 258 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.11.0
current_version = 0.12.0
commit = False
tag = False
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<release>[a-z]+))?
Expand Down
29 changes: 9 additions & 20 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
language: python

sudo: false

python:
- "2.6"
- "2.7"
- "3.2"
- "3.3"
- "3.4"
#- "pypy"
#- "pypy3"
- "3.5"

env:
- DJANGO='https://github.com/django/django/archive/master.tar.gz'
- DJANGO='django>=1.9.0,<1.10.0'
- DJANGO='django>=1.8.0,<1.9.0'
- DJANGO='django>=1.7.0,<1.8.0'
- DJANGO='django>=1.6.0,<1.7.0'
- DJANGO='django>=1.5.0,<1.6.0'
- DJANGO='django>=1.4.0,<1.5.0'

install:
- travis_retry pip install $DJANGO
Expand All @@ -31,21 +28,13 @@ notifications:
matrix:
exclude:
- python: "3.2"
env: DJANGO='django>=1.4.0,<1.5.0'
env: DJANGO='https://github.com/django/django/archive/master.tar.gz'
- python: "3.2"
env: DJANGO='django>=1.9.0,<1.10.0'
- python: "3.3"
env: DJANGO='django>=1.4.0,<1.5.0'
- python: "3.4"
env: DJANGO='django>=1.4.0,<1.5.0'
#- python: "pypy"
# env: DJANGO='django>=1.4.0,<1.5.0'
#- python: "pypy3"
# env: DJANGO='django>=1.4.0,<1.5.0'
- python: "2.6"
env: DJANGO='django>=1.7.0,<1.8.0'
- python: "2.6"
env: DJANGO='django>=1.8.0,<1.9.0'
- python: "2.6"
env: DJANGO='https://github.com/django/django/archive/master.tar.gz'
- python: "3.3"
env: DJANGO='django>=1.9.0,<1.10.0'
allow_failures:
- env: DJANGO='https://github.com/django/django/archive/master.tar.gz'
fast_finish: true
Expand Down
26 changes: 26 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,29 @@
Version 0.12.0 (2016-01-07)
---------------------------

* FEATURE: Add support for custom ORM lookup types #221

* FEATURE: Add JavaScript friendly BooleanWidget #270

* FIXED: (More) Compatability with Django 1.8 and Django 1.9+

* BREAKING CHANGE: custom filter names are now also be used for ordering #230

If you use ordering on a field you defined as custom filter with custom
name, you should now use the filter name as ordering key as well.

Eg. For a filter like :

class F(FilterSet):
account = CharFilter(name='username')
class Meta:
model = User
fields = ['account', 'status']
order_by = True

Before, ordering was like `?o=username`. Since 0.12.0 it's `o=account`.


Version 0.11.0 (2015-08-14)
---------------------------

Expand Down
6 changes: 3 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ Full documentation on `read the docs`_.
Requirements
------------

* Python 2.6+
* Django 1.4.5+
* Python 2.7, 3.2, 3.3, 3.4, 3.5
* Django 1.8, 1.9

Installation
------------
Expand Down Expand Up @@ -50,7 +50,7 @@ And then in your view you could do::

Django-filters additionally supports specifying FilterSet fields using a
dictionary to specify filters with lookup types::

import django_filters

class ProductFilter(django_filters.FilterSet):
Expand Down
2 changes: 1 addition & 1 deletion django_filters/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from .filterset import FilterSet
from .filters import *

__version__ = '0.11.0'
__version__ = '0.12.0'


def parse_version(version):
Expand Down
24 changes: 15 additions & 9 deletions django_filters/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@
from collections import namedtuple

from django import forms
from django.conf import settings
from django.utils.dateparse import parse_datetime
from django.utils import timezone

# TODO: Remove this once Django 1.4 is EOL.
try:
from django.utils.encoding import force_str
except ImportError:
force_str = None
from django.utils.encoding import force_str

from .widgets import RangeWidget, LookupTypeWidget

Expand Down Expand Up @@ -61,6 +59,8 @@ def __init__(self, *args, **kwargs):


Lookup = namedtuple('Lookup', ('value', 'lookup_type'))


class LookupTypeField(forms.MultiValueField):
def __init__(self, field, lookup_choices, *args, **kwargs):
fields = (
Expand All @@ -75,7 +75,7 @@ def __init__(self, field, lookup_choices, *args, **kwargs):
super(LookupTypeField, self).__init__(fields, *args, **kwargs)

def compress(self, data_list):
if len(data_list)==2:
if len(data_list) == 2:
return Lookup(value=data_list[0], lookup_type=data_list[1] or 'exact')
return Lookup(value=None, lookup_type='exact')

Expand All @@ -91,15 +91,21 @@ class IsoDateTimeField(forms.DateTimeField):
"""
ISO_8601 = 'iso-8601'
input_formats = [ISO_8601]
default_timezone = timezone.get_default_timezone() if settings.USE_TZ else None

def strptime(self, value, format):
# TODO: Remove this once Django 1.4 is EOL.
if force_str is not None:
value = force_str(value)
value = force_str(value)

if format == self.ISO_8601:
parsed = parse_datetime(value)
if parsed is None: # Continue with other formats if doesn't match
raise ValueError

# Handle timezone awareness. Copied from:
# https://github.com/tomchristie/django-rest-framework/blob/3.2.0/rest_framework/fields.py#L965-L969
if settings.USE_TZ and not timezone.is_aware(parsed):
return timezone.make_aware(parsed, self.default_timezone)
elif not settings.USE_TZ and timezone.is_aware(parsed):
return timezone.make_naive(parsed, timezone.UTC())
return parsed
return super(IsoDateTimeField, self).strptime(value, format)
65 changes: 39 additions & 26 deletions django_filters/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class Filter(object):
field_class = forms.Field

def __init__(self, name=None, label=None, widget=None, action=None,
lookup_type='exact', required=False, distinct=False, exclude=False, **kwargs):
lookup_type='exact', required=False, distinct=False, exclude=False, **kwargs):
self.name = name
self.label = label
if action:
Expand Down Expand Up @@ -62,18 +62,27 @@ def field(self):
help_text = _('This is an exclusion filter') if self.exclude else _('Filter')
if (self.lookup_type is None or
isinstance(self.lookup_type, (list, tuple))):
if self.lookup_type is None:
lookup = [(x, x) for x in LOOKUP_TYPES]
else:
lookup = [
(x, x) for x in LOOKUP_TYPES if x in self.lookup_type]

lookup = []

for x in LOOKUP_TYPES:
if isinstance(x, (list, tuple)) and len(x) == 2:
choice = (x[0], x[1])
else:
choice = (x, x)

if self.lookup_type is None:
lookup.append(choice)
elif x in self.lookup_type:
lookup.append(choice)

self._field = LookupTypeField(self.field_class(
required=self.required, widget=self.widget, **self.extra),
lookup, required=self.required, label=self.label, help_text=help_text)
else:
self._field = self.field_class(required=self.required,
label=self.label, widget=self.widget,
help_text=help_text, **self.extra)
label=self.label, widget=self.widget,
help_text=help_text, **self.extra)
return self._field

def filter(self, qs, value):
Expand All @@ -84,9 +93,9 @@ def filter(self, qs, value):
lookup = self.lookup_type
if value in ([], (), {}, None, ''):
return qs
qs = self.get_method(qs)(**{'%s__%s' % (self.name, lookup): value})
if self.distinct:
qs = qs.distinct()
qs = self.get_method(qs)(**{'%s__%s' % (self.name, lookup): value})
return qs


Expand All @@ -97,11 +106,6 @@ class CharFilter(Filter):
class BooleanFilter(Filter):
field_class = forms.NullBooleanField

def filter(self, qs, value):
if value is not None:
return self.get_method(qs)(**{self.name: value})
return qs


class ChoiceFilter(Filter):
field_class = forms.ChoiceField
Expand All @@ -111,6 +115,10 @@ class TypedChoiceFilter(Filter):
field_class = forms.TypedChoiceField


class UUIDFilter(Filter):
field_class = forms.UUIDField


class MultipleChoiceFilter(Filter):
"""
This filter preforms OR(by default) or AND(using conjoined=True) query
Expand Down Expand Up @@ -156,7 +164,7 @@ def is_noop(self, qs, value):
return False

def filter(self, qs, value):
value = value or () # Make sure we have an iterable
value = value or () # Make sure we have an iterable

if self.is_noop(qs, value):
return qs
Expand Down Expand Up @@ -185,6 +193,7 @@ class DateFilter(Filter):
class DateTimeFilter(Filter):
field_class = forms.DateTimeField


class IsoDateTimeFilter(DateTimeFilter):
"""
Uses IsoDateTimeField to support filtering on ISO 8601 formated datetimes.
Expand All @@ -197,6 +206,7 @@ class IsoDateTimeFilter(DateTimeFilter):
"""
field_class = IsoDateTimeField


class TimeFilter(Filter):
field_class = forms.TimeField

Expand Down Expand Up @@ -234,19 +244,19 @@ class RangeFilter(Filter):

def filter(self, qs, value):
if value:
if value.start is not None and value.stop is not None:
lookup = '%s__range' % self.name
return self.get_method(qs)(**{lookup: (value.start, value.stop)})
else:

if value.start is not None:
qs = self.get_method(qs)(**{'%s__gte'%self.name:value.start})
if value.stop is not None:
qs = self.get_method(qs)(**{'%s__lte'%self.name:value.stop})
if value.start is not None and value.stop is not None:
lookup = '%s__range' % self.name
return self.get_method(qs)(**{lookup: (value.start, value.stop)})
else:
if value.start is not None:
qs = self.get_method(qs)(**{'%s__gte' % self.name: value.start})
if value.stop is not None:
qs = self.get_method(qs)(**{'%s__lte' % self.name: value.stop})
return qs


_truncate = lambda dt: dt.replace(hour=0, minute=0, second=0)
def _truncate(dt):
return dt.replace(hour=0, minute=0, second=0)


class DateRangeFilter(ChoiceFilter):
Expand Down Expand Up @@ -285,7 +295,10 @@ def filter(self, qs, value):
value = int(value)
except (ValueError, TypeError):
value = ''
return self.options[value][1](qs, self.name)
qs = self.options[value][1](qs, self.name)
if self.distinct:
qs = qs.distinct()
return qs


class DateFromToRangeFilter(RangeFilter):
Expand Down

0 comments on commit d2bda5a

Please sign in to comment.