Skip to content

Commit

Permalink
Merge pull request #375 from carltongibson/develop
Browse files Browse the repository at this point in the history
0.13 Release
  • Loading branch information
Carlton Gibson committed Mar 11, 2016
2 parents d2bda5a + ba92f71 commit 44af395
Show file tree
Hide file tree
Showing 32 changed files with 2,070 additions and 443 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.12.0
current_version = 0.13.0
commit = False
tag = False
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<release>[a-z]+))?
Expand Down
14 changes: 14 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
Version 0.13.0 (2016-03-11)
---------------------------

* Add support for filtering by CSV #363

* Add DateTimeFromToRangeFilter #376

* Add Chinese translation #359

* Lots of fixes.


Version 0.12.0 (2016-01-07)
---------------------------

* Raised minimum Django version to 1.8.x

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

* FEATURE: Add JavaScript friendly BooleanWidget #270
Expand Down
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ recursive-include docs *
recursive-include requirements *
recursive-include tests *
recursive-include django_filters/locale *
prune docs/_build
8 changes: 4 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ querysets dynamically.

Full documentation on `read the docs`_.

.. image:: https://secure.travis-ci.org/alex/django-filter.png?branch=master
:target: http://travis-ci.org/alex/django-filter
.. image:: https://travis-ci.org/carltongibson/django-filter.svg?branch=master
:target: https://travis-ci.org/carltongibson/django-filter

Requirements
------------
Expand All @@ -24,7 +24,7 @@ Install using pip::

Or clone the repo and add to your PYTHONPATH::

git clone git@github.com:alex/django-filter.git
git clone git@github.com:carltongibson/django-filter.git

Usage
-----
Expand All @@ -46,7 +46,7 @@ And then in your view you could do::

def product_list(request):
filter = ProductFilter(request.GET, queryset=Product.objects.all())
return render_to_response('my_app/template.html', {'filter': filter})
return render(request, 'my_app/template.html', {'filter': filter})

Django-filters additionally supports specifying FilterSet fields using a
dictionary to specify filters with lookup types::
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.12.0'
__version__ = '0.13.0'


def parse_version(version):
Expand Down
17 changes: 17 additions & 0 deletions django_filters/compat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

import django


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
72 changes: 57 additions & 15 deletions django_filters/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
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

from django.utils.encoding import force_str
from django.utils.translation import ugettext_lazy as _

from .widgets import RangeWidget, LookupTypeWidget
from .utils import handle_timezone
from .widgets import RangeWidget, LookupTypeWidget, CSVWidget


class RangeField(forms.MultiValueField):
Expand Down Expand Up @@ -42,13 +42,24 @@ def compress(self, data_list):
if data_list:
start_date, stop_date = data_list
if start_date:
start_date = datetime.combine(start_date, time.min)
start_date = handle_timezone(
datetime.combine(start_date, time.min))
if stop_date:
stop_date = datetime.combine(stop_date, time.max)
stop_date = handle_timezone(
datetime.combine(stop_date, time.max))
return slice(start_date, stop_date)
return None


class DateTimeRangeField(RangeField):

def __init__(self, *args, **kwargs):
fields = (
forms.DateTimeField(),
forms.DateTimeField())
super(DateTimeRangeField, self).__init__(fields, *args, **kwargs)


class TimeRangeField(RangeField):

def __init__(self, *args, **kwargs):
Expand All @@ -58,7 +69,12 @@ def __init__(self, *args, **kwargs):
super(TimeRangeField, self).__init__(fields, *args, **kwargs)


Lookup = namedtuple('Lookup', ('value', 'lookup_type'))
class Lookup(namedtuple('Lookup', ('value', 'lookup_type'))):
# python nature is test __len__ on tuple types for boolean check
def __len__(self):
if not self.value:
return 0
return 2


class LookupTypeField(forms.MultiValueField):
Expand Down Expand Up @@ -91,7 +107,6 @@ 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):
value = force_str(value)
Expand All @@ -100,12 +115,39 @@ def strptime(self, value, format):
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 handle_timezone(parsed)
return super(IsoDateTimeField, self).strptime(value, format)


class BaseCSVField(forms.Field):
"""
Base field for validating CSV types. Value validation is performed by
secondary base classes.
ex::
class IntegerCSVField(BaseCSVField, filters.IntegerField):
pass
"""
widget = CSVWidget

def clean(self, value):
if value is None:
return None
return [super(BaseCSVField, self).clean(v) for v in value]


class BaseRangeField(BaseCSVField):
default_error_messages = {
'invalid_values': _('Range query expects two values.')
}

def clean(self, value):
value = super(BaseRangeField, self).clean(value)

if value is not None and len(value) != 2:
raise forms.ValidationError(
self.error_messages['invalid_values'],
code='invalid_values')

return value

0 comments on commit 44af395

Please sign in to comment.