Giter Club home page Giter Club logo

django-filter's Introduction

Django Filter

Django-filter is a reusable Django application allowing users to declaratively add dynamic QuerySet filtering from URL parameters.

Full documentation on read the docs.

Versioning and stability policy

Django-Filter is a mature and stable package. It uses a two-part CalVer versioning scheme, such as 21.1. The first number is the year. The second is the release number within that year.

On an on-going basis, Django-Filter aims to support all current Django versions, the matching current Python versions, and the latest version of Django REST Framework.

Please see:

Support for Python and Django versions will be dropped when they reach end-of-life. Support for Python versions will be dropped when they reach end-of-life, even when still supported by a current version of Django.

Other breaking changes are rare. Where required, every effort will be made to apply a "Year plus two" deprecation period. For example, a change initially introduced in 23.x would offer a fallback where feasible and finally be removed in 25.1. Where fallbacks are not feasible, breaking changes without deprecation will be called out in the release notes.

Installation

Install using pip:

pip install django-filter

Then add 'django_filters' to your INSTALLED_APPS.

INSTALLED_APPS = [
    ...
    'django_filters',
]

Usage

Django-filter can be used for generating interfaces similar to the Django admin's list_filter interface. It has an API very similar to Django's ModelForms. For example, if you had a Product model you could have a filterset for it with the code:

import django_filters

class ProductFilter(django_filters.FilterSet):
    class Meta:
        model = Product
        fields = ['name', 'price', 'manufacturer']

And then in your view you could do:

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

Usage with Django REST Framework

Django-filter provides a custom FilterSet and filter backend for use with Django REST Framework.

To use this adjust your import to use django_filters.rest_framework.FilterSet.

from django_filters import rest_framework as filters

class ProductFilter(filters.FilterSet):
    class Meta:
        model = Product
        fields = ('category', 'in_stock')

For more details see the DRF integration docs.

Support

If you need help you can start a discussion. For commercial support, please contact Carlton Gibson via his website.

django-filter's People

Contributors

ad-m avatar alasdairnicol avatar alej0varas avatar alex avatar apollo13 avatar askeyt avatar benkonrath avatar blueyed avatar bogdal avatar carltongibson avatar dependabot[bot] avatar felixxm avatar michael-k avatar nicholasserra avatar nkryptic avatar patriotyk avatar pysilver avatar qrilka avatar rpkilby avatar smithdc1 avatar thedrow avatar thenewguy avatar ticosax avatar tomchristie avatar vladimirbright avatar weblate avatar whitews avatar willemarcel avatar xordoquy avatar zoidyzoidzoid avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-filter's Issues

MultipleChoiceFilter does not use lookup_type

MultipleChoiceFilter.filter() should be updated to include something along these lines:

def filter(self, qs, value):
    (...)
    lookup = self.lookup_type or 'exact'
    for v in value:
        q |= Q(**{'%s__%s' % (self.name, self.lookup_type): v})
    (...)

I haven't really taken a good look at any of the code, so this is just my initial solution.

test models in package

I think it's a good idea to move models.py to another directory, for example "tests"

Every time, when I update my db-scheme, system ask me to make tables from "django-filter/models.py" file. I don't need these test tables, but I don't think that's right to remove this file from external package.

Must pass request.GET or None to construct filter correctly.

The docs show that you need to construct a FilterSet like this:

filterset = ProductFilterSet(request.GET or None)

Shouldn't this be done in the constructor instead of the calling code? It is easy to accidentally pass just the request.GET, which prevents initial values from being used.

Make lookup type a class attribute on the Filter

To make overriding of lookup types easier

class Filter(object):
    creation_counter = 0
    field_class = forms.Field
    lookup_type = 'exact'

    def __init__(self, name=None, label=None, widget=None, action=None,
        lookup_type=None, required=False, **kwargs):
        self.name = name
        self.label = label
        if action:
            self.filter = action
        self.lookup_type = lookup_type or self.lookup_type
        self.widget = widget
        self.required = required
        self.extra = kwargs

Support for displaying related object fields

There is currently nothing in place on the display side that will respect any querying done against related fields.

Let's take this basic relationship:

class Company(models.Model):
   name = models.CharField()
   address = models.ManyToManyField('below.Address')

class Address(models.Model):
    zip = models.CharField()
    telephone = models.CharField()

With related fields, I could grab all companies within a particular zip code, however, I'm still stuck displaying information strictly on the primary model of a FilterSet. If I wanted to grab all telephone numbers with the zip code, I would have to a) re-execute my querying somewhere after django-filter is done and grab the zips myself b) reorient my whole approach and create a filter against the Address model (but now I'm stuck with the same problem on a different model).

I've already got this working (albeit, outside of django-filter). Right now it works like:

(Deprecated, See comment below)

  1. User submits a form much like that which django-filters provides
  2. The querying is done internally, and records are matched. At this step, django-filter current work is done.
  3. Check for related objects in my "display_fields" (i imagine it would be a item in Meta)
  4. If I find them, I group them into "bundles"
  5. I organize my initial querying into similar bundles
  6. I loop through the original queryset
  7. For each item, I check the relations against the display field, if I find one, I grab the related objects. If I find a querying bundle, I respect whatever that query was as I do this
  8. I throw the result into a tuple, the first item of which is my original model.
  9. If my querying turned up a set of objects, the values_list is then dumped in instead of the object value (maybe two telephone numbers were matched). Alternately, you could create another tuple for the same object and add them both.

I'm looking for direction on whether this is a goal of django-filters. Alternatives I see are:

  1. return a subclass of a QuerySet which has these field values
  2. return a list of tuples that contains each record, and any additional valuse tacked-on

LinkWidget.render_options fails on unicode data

Solution: Encode data as UTF-8 before passing to urlencode.

Here's the patch for widgets.py:

2a3
> import types
52a54,56
>    
>         # Make sure that data is utf-8 encoded before being passed to urlencode.
>         data = dict([(k,v.encode('utf-8') if type(v) is types.UnicodeType else v) for (k,v) in data.items()])

How to let user specify filtering behavior?

Hi Alex, Your filter app looks great and I'd like to use it. But I'm trying to figure out if it is possible to let the user specify ranges. I see code like this in filters.py:

def filter(self, qs, value):
    if value:
        if isinstance(value, (list, tuple)):
            lookup = str(value[1])
            value = value[0]
        else:
            lookup = self.lookup_type
        return qs.filter(**{'%s__%s' % (self.name, lookup): value})
    return qs

So I see that in my Filter class I can specify any field lookup (ie __regex, __contains, __lt, etc), as my lookup type, like this:

class TaskFilter(filtler.FilterSet):
name = filter.CharFIlter(lookup_type='regex')

But what if I want the user to be able to specify the lookup type. Say I want them to be able to put in a name and then let them choose whether to have queryset filtered for an exact match or a regex. Or for a date, I'd like them to put in a date and then choose lt, lte, (and in a perfect world, do ands and ors, ie "lt 5/20/09 & gt 5/5/09".)

In the filter() code above, I have the feeling that I can provide a way to let the user input text into their form such that the value that comes into filter() contains both the filter string and the lookup type. Is this the intention and can you give me some hints on how to let the user input this lookup type info? It would be very cool if the user had the abiity to put in complex lookups similar to what we can do with the Q object in code. For example, it would be cool if in my filter class I could specify one or more Q objects and then render each as a drop down in the user's form. Then the user would input some text to query for and choose the type of lookup.

Anyway, don't mean to bombard you - am actually just trying to figure out if any of this functionality is there and if not, what approach you recommend for what I am trying to do. Perhaps the intention is I (as developer) create a Filter class on the fly, dynamically, based on user input from a form? However, if that is the intention, it doesn't seem to me that you have support for Q lookups - true?

Thanks very much for contributing this. I learned a lot just from reading through the code and am very appreciative of your work!

Margie

Add "Any" filter to ChoicesField

The ChoicesField currently doesn't provide an "Any" or "Unknown" filter entry, so as soon as a ChoiceField is added to a search form, the user has to always select an entry.

I currently workaround this by adding an empty filter in the Filter's constructor, but it would be great if there could be an easier way to achieve this:

class NicerFilterSet(django_filters.FilterSet):

def __init__(self, *args, **kwargs):
    super(NicerFilterSet, self).__init__(*args, **kwargs)

    for name, field in self.filters.iteritems():
        if isinstance(field, ChoiceFilter):
            # Add "Any" entry to choice fields.
            field.extra['choices'] = tuple([("", "Any"), ] + list(field.extra['choices']))`

What is the documentation format?

A very simple issue... :-)
As per title - I wanted to add to the documentation as per issue #13, but what format is it in? I thought of Sphinx, markdown... but it's neither of them. So what is it?

tests fail with new pinax tests/runner.py

File "/home/skyl/Desktop/code/pinax/pinax-dev/lib/python2.6/site-packages/django_filters/tests/init.py", line ?, in django_filters.tests.test.filter_tests
Failed example:
print F().form
Exception raised:
Traceback (most recent call last):
File "/home/skyl/Desktop/code/pinax/pinax-dev/lib/python2.6/site-packages/django/test/_doctest.py", line 1267, in __run
compileflags, 1) in test.globs
File "<doctest django_filters.tests.test.filter_tests[114]>", line 1, in
print F().form
File "/home/skyl/Desktop/code/pinax/pinax-dev/lib/python2.6/site-packages/django_filters/filterset.py", line 184, in init
self.filters = deepcopy(self.base_filters)
File "/usr/lib/python2.6/copy.py", line 173, in deepcopy
y = copier(memo)
File "/home/skyl/Desktop/code/pinax/pinax-dev/lib/python2.6/site-packages/django/utils/datastructures.py", line 77, in deepcopy
for key, value in self.iteritems()])
File "/usr/lib/python2.6/copy.py", line 189, in deepcopy
y = _reconstruct(x, rv, 1, memo)
File "/usr/lib/python2.6/copy.py", line 338, in _reconstruct
state = deepcopy(state, memo)
File "/usr/lib/python2.6/copy.py", line 162, in deepcopy
y = copier(x, memo)
File "/usr/lib/python2.6/copy.py", line 255, in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
File "/usr/lib/python2.6/copy.py", line 162, in deepcopy
y = copier(x, memo)
File "/usr/lib/python2.6/copy.py", line 255, in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
File "/usr/lib/python2.6/copy.py", line 181, in deepcopy
rv = reductor(2)
File "/home/skyl/Desktop/code/pinax/pinax-dev/lib/python2.6/site-packages/django/db/models/query.py", line 153, in getstate
len(self)
File "/home/skyl/Desktop/code/pinax/pinax-dev/lib/python2.6/site-packages/django/db/models/query.py", line 173, in len
self._result_cache = list(self.iterator())
File "/home/skyl/Desktop/code/pinax/pinax-dev/lib/python2.6/site-packages/django/db/models/query.py", line 288, in iterator
for row in self.query.results_iter():
File "/home/skyl/Desktop/code/pinax/pinax-dev/lib/python2.6/site-packages/django/db/models/sql/query.py", line 205, in results_iter
for rows in self.execute_sql(MULTI):
File "/home/skyl/Desktop/code/pinax/pinax-dev/lib/python2.6/site-packages/django/db/models/sql/query.py", line 1820, in execute_sql
cursor.execute(sql, params)
File "/home/skyl/Desktop/code/pinax/pinax-dev/lib/python2.6/site-packages/django/db/backends/sqlite3/base.py", line 170, in execute
return Database.Cursor.execute(self, query, params)
OperationalError: no such table: tests_user
a few like this, tests_book.

Using a foreign key with "to_field" option

Django-filters fails on these fields. I have to use a legacy primary key system, in which the foreign keys between the filtered model and a list is made like this :

place = models.ForeignKey(Place, blank=True, null=True, to_field='code')

Where 'code' is always a 3 or 4 letter code
The search returns nothing, but it works with other fields types (integer, charfield or fk without the to_field option)
If I try to define this field as CharFilter (instead of the default ModelChoiceFilter)
and just input the pk char code, it works . If I turn it to a ModelChoice, there's no options at all

Passing in None/list for lookup type isn't creating a dropdown properly.

According to the docs, I can pass None or a list to lookup_type and let the user choose...doing this blows up:
File "/env/d/lib/python2.5/site-packages/filter/filterset.py", line 186, in iter
for obj in self.qs:
File "/env/d/lib/python2.5/site-packages/filter/filterset.py", line 196, in qs
qs = filter_.filter(qs, val)
File "/env/d/lib/python2.5/site-packages/filter/filters.py", line 56, in filter
lookup = str(value[1])
IndexError: list index out of range

django-tagging integration

hi alex, great project!
i've been trying various things for a while, but i can't seem to find a decent solution to filter tags from django-tagging with django-filter.
have you considered this? could you point me in the right direction, code-wise?

Bootstrap compliant form output

Hey,

How do I get django-filter to output Bootstrap compliant tags?

Is there any way to overwrite the django-filter html output?

Problem with using standart django widgets

Filtering doesn't work, when I add standart widgets:

class MovieFilter(FilterSet):
    genres = ModelMultipleChoiceFilter(queryset=Genre.objects.all(), widget=django.forms.widgets.Select())
    countries = ModelMultipleChoiceFilter(queryset=Country.objects.all(), widget=django.forms.widgets.Select())
    year = ChoiceFilter(choices=Movie._meta.get_field('year').choices, widget=django.forms.widgets.Select())

Problems with ModelMultipleChoiceFilter and simple ChoiceFilter too. After removing everything works ok.

Tests failing on 0.5.2

Looks like it's something related to testing under different databases, and having results in different orders. Enforce ordering on models and tests, or make test assertions ignore the order.

The output:

........................................F.E..........F....F.............................

FAIL: Doctest: django_filters.tests.test.filter_tests

Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/Django-1.1.1-py2.6.egg/django/test/_doctest.py", line 2180, in runTest
raise self.failureException(self.format_failure(new.getvalue()))
AssertionError: Failed doctest test for django_filters.tests.test.filter_tests
File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django_filter-0.5.2-py2.6.egg/django_filters/tests/init.py", line unknown line number, in filter_tests


File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django_filter-0.5.2-py2.6.egg/django_filters/tests/init.py", line ?, in django_filters.tests.test.filter_tests
Failed example:
f.qs
Expected:
[<User: alex>, <User: aaron>, <User: jacob>]
Got:

[<User: aaron>, <User: alex>, <User: jacob>]

File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django_filter-0.5.2-py2.6.egg/django_filters/tests/init.py", line ?, in django_filters.tests.test.filter_tests
Failed example:
f.qs
Expected:
[<User: alex>, <User: aaron>, <User: jacob>]
Got:

[<User: aaron>, <User: alex>, <User: jacob>]

File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django_filter-0.5.2-py2.6.egg/django_filters/tests/init.py", line ?, in django_filters.tests.test.filter_tests
Failed example:
f.qs
Expected:
[<User: alex>, <User: aaron>]
Got:

[<User: aaron>, <User: alex>]

File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django_filter-0.5.2-py2.6.egg/django_filters/tests/init.py", line ?, in django_filters.tests.test.filter_tests
Failed example:
f.qs
Expected:
[<User: alex>, <User: aaron>]
Got:

[<User: aaron>, <User: alex>]

File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/django_filter-0.5.2-py2.6.egg/django_filters/tests/init.py", line ?, in django_filters.tests.test.filter_tests
Failed example:
f.qs
Expected:
[<User: alex>, <User: aaron>, <User: jacob>]
Got:
[<User: aaron>, <User: alex>, <User: jacob>]


Ran 88 tests in 3.208s

FAILED (failures=3, errors=1)

AllValuesFilter does not have an empty value

When I use AllValuesFilter, I can't choose value that does not affect (filter) result list. I can only choose one of the model objects.

This is how I resolved this issue:

def __init__(self, *args, **kwargs):
    super(ApplicationFilter, self).__init__(*args, **kwargs)
    self.filters['a_filter_field'].field.choices.insert(0, ('', u'---------'))

Filterset doesn't know fields of abstracted models

A Filterset only knows the fields of it's direct Model, not the abstracted ones. Example:

class Foo(models.Model):
    date = models.DateField()
    class Meta:
       abstract = True

class Bar(Foo):
    text = models.TextField()

class FiltyFilter(filter.FilterSet):
    class Meta:
        model = Bar
        fields = ['text', 'date']

The abstracted field "date" results in:

Meta.fields contains a field that isn't defined on this FilterSet

But it works if you declare the field specifically:

class FiltyFilter(filter.FilterSet):
    date = filter.DateRangeFilter()
    class Meta:
        model = Bar
        fields = ['text', 'date']

So I'm not sure if it's a bug or it only should been mentioned in the docs.

if lookup_type is tuple/list, filtering occurs even if filter value is empty

Hey Alex,

This was one of my three questions in http://github.com/alex/django-filter/issues/closed#issue/3. I see that you fixed question 3, but I don't think addressed this one, so am going to post it standalone so it doesn't get lost.

If the lookup_type is set to a tuple or list, ie:

name = filter.CharFilter(lookup_type=['exact', 'regex'])

then when the user does not provide a value for this filter, the filter is applied using the empty string as the value in the Filter::filter() function. This results in the filter returning no objects, which seems incorrect and is inconsistent with the behavior I'd get if I declared my filter like this:

name = filter.CharFilter(lookup_type='exact')

In this case, if the user does not provide a value, the filter is ignored, and that seems like the behavior we'd want in the case where the lookup_type is a tuple/list.

Margie

Enhancement: chain filters across submits

Seems like their it would be possible to enhance this tool to allow for the chaining of filters to allow the results to be refined/constrained. This might be done by serializing the form data from one submit, and passing it as a hidden field back in the next form. The presence of this previous form could be used to create a filtered queryset before then filtering again with the current form's contents?

What do you think? I'm still learning at this level, but I could fork and try to implement if you think its a worthwhile addition.

django-filter and django-refinery

@apollo13,

It's great to see some activity on django-filter after so much time. I had previously attempted to contact Alex about making changes/releasing a new version of the package, but never got a response. I ended up forking the project to get the changes I needed, eventually releasing it as django-refinery after adding more changes, figuring others would like not having to create their own fork to get those features.

You can see the list of changes from django-filter 0.5.3 and also see why I changed the names of things. Most of the work was incorporating features/updates from the issues and pull requests that had been sitting for a year or two in the django-filter issues list.

With django-filter development (and releases) finally getting started again, it raises the question as to whether continuing with django-refinery makes sense. I think the largest difference between the two, at this point, is that django-refinery uses Q objects instead of chaining filter calls -- which came out of an issue or two for django-filter and django-qfilters coming about. You can also see the ideas I had for moving forward. If we're going in the same direction, I think it best for the community at large to only have a single project with this feature set.

I'd appreciate your thoughts on how to proceed from here.

filter returns multiple results

Hello,

With django-filter, it is possible to setup filters on related tables (very good!). Unfortunately, in some situations, this means the same result is returned many times, e.g. when following a one-to-many relationship in the reverse direction.

I propose the following patch to solve this:

=== cut ===
diff --git a/filter/filterset.py b/filter/filterset.py
index 5a2cb1b..ef06c55 100644
--- a/filter/filterset.py
+++ b/filter/filterset.py
@@ -205,7 +205,7 @@ class BaseFilterSet(object):
except forms.ValidationError:
pass
self._qs = qs

  •    return self._qs
    
  •    return self._qs.distinct()
    

    @Property
    def form(self):
    === cut ===

Brian May

Leaving 'o' key unset when creating a Filter whose class has order_by set generates an error

Adding this to tests.py will show the error:

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

f = F(queryset=User.objects.all())
f.qs
Traceback (most recent call last):
File "", line 1, in
File "/home/mlevine/django/chipvision40/chip_vision_2/apps/filter/filterset.py", line 174, in qs
File "/tools/aticad/1.0/external/python-2.5.1/lib/python2.5/site-packages/django/db/models/query.py", line 614, in order_by
obj.query.add_ordering(*field_names)
File "/tools/aticad/1.0/external/python-2.5.1/lib/python2.5/site-packages/django/db/models/sql/query.py", line 1794, in add_ordering
raise FieldError('Invalid order_by arguments: %s' % errors)
FieldError: Invalid order_by arguments: [u'']

I noticed this when working via rendered views, because when you first render the filter's form the ordering is available to the user, but not yet set, which results in this error.

Just to clarify - I don't mean to be annoying or demanding in any way with these posts. I am fine with fixing any of these in my own area and working with your code exactly as is. So please view my posts as my attempt to help out, not as requests or complaints. Feel free to be too busy to work on this. I'm sure you are volunteering your code, and actually in its current state exactly as is, I can make good progress with it. I can also pass on my fixes to you at some point if you want them.

Margie

Import Error with multiple lookup types with no GET params

Filter.filter() expects 2 items in a list, if value is a list. However, the clean method of django.forms.MultiValueField will return an empty list when the input is None for both field (as is the case when the form is accessed without any GET parameters).

This is probably best fixed in Filter.filter, by returning the whole queryset immediatly when the passed value not results in a True boolean.

Allow 'fields' to be passed into a filterset as an arg

I've got a use-case where I create a report form based on the results of a 'pre_form'. Some models have upwards of 50 fields that could be of interest to report on, but it doesn't necessarily mean the user wants to be confronted with all of those fields every time.

This is also connected to the other issue related to 'display_fields'. If it becomes possible to instantiate a filterset with arbitrary fields and display_fields, you've got an incredibly customizable reporting scope that's very code-light.

Filtering 'bundles'

There is no way currently to evaluate two filters together (AND vs OR on the relations queried):0

Given

class Organization(models.Model):
    name = models.CharField(..)

class Location(models.Model):
    organization = models.ForeignKey(Organization)
    zip_code = models.PositiveIntegerfield(...)
    open_saturday = models.BooleanField(...)

A django filter oriented around Organization but with fields for 'zip_code' and 'open_saturday' cannot give you all organization within a particular zip code who are also open saturday.

One possible approach would be to create a filter_together option for Meta, which would be a list of tuples of field name bundles. If there is a way to garner a Q object from a queryset, one could loop through these bundles compiling Q objects and then filter them together. If not, perhaps an as_q() method could be added to a filter which returns a Q object instead.

Like my other Issue in this realm, I really don't mind submitting code if a design decision favors things like this.

Document how django-filter works with django-pagination

They both work well together, it took me a while to fiddle it out. Based on the example in the docs:

{% block content %}
    <form action="" method="get">
        {{ f.form.as_p }}
        <input type="submit" />
    </form>

    {% autopaginate f.qs 40 as filter_list %}

    {% for obj in filter_list %}
        {{ obj.name }} - ${{ obj.price }}<br />
    {% endfor %}

    {% paginate %}
{% endblock %}

The key is that you have to use pagination's as argument.

The DateRangeFilter don't displays todays entries if set to "past 7 days"

When DateRangeFilter is applied on a DateTimeField and it's filtered with "Show past 7 days" it will show not the today's results.

That's because the Starting date is treated as "2009-06-04 00:00:00". I've tested that only on MySQL. My quick, ugly fix is:

--- a/filter/filters.py
+++ b/filter/filters.py
@@ -123,7 +123,7 @@ class DateRangeFilter(ChoiceFilter):
         })),
         2: (_('Past 7 days'), lambda qs, name: qs.filter(**{
             '%s__gte' % name: (datetime.today() - timedelta(days=7)).strftime('%Y-%m-%d'),
-            '%s__lte' % name: datetime.today().strftime('%Y-%m-%d'),
+            '%s__lte' % name: datetime.today().strftime('%Y-%m-%d 23:59:59'),
         })),
         3: (_('This month'), lambda qs, name: qs.filter(**{
             '%s__year' % name: datetime.today().year,

Which works for me but I guess it's not working on a Datefield.

Hide filter items that produce zero results

Hi Alex,
Thank you very much for this project, it is great!
I'm using the LinkWidget on a ModelChoiceFilter, my only issue is how to hide the items that will produce zero results. I think that there is a simple method to do this, but idk how.
I use the ModelChoiceFilter in this way:
provider = django_filters.ModelChoiceFilter(queryset=Provider.objects.all(), widget=django_filters.widgets.LinkWidget)
What I need to do is filter the queryset and select only the Provider that will produce at least one result, and exclude the others.
There is a way to do that?

form validation

hello,

I have got a complicated bug using django-filter and a specific filter:

Here is my specific filter class :

class LocationFilter(Filter):
field_class = floppyforms.gis.PolygonField

def __init__(self, *args, **kwargs):
    super(LocationFilter, self).__init__(*args, **kwargs)

def filter(self, qs, value):
    lookup = 'within'
    if not value:
        return qs
    if value:
        value = fromstr(value)
        return qs.filter(**{'%s__%s' % (self.name, lookup): value})

I have also standard filters in my filter form.

The thing is:

  • when I don't have a value for my LocationFilter, if I set some values for other fields, I get a error message for the field I set, "This value must be an integer" (or other specifiq type value field error), even if value well setted (in this case, I have filled the form with an integer). In this case, even if there is 'an error', django-filter works, and gives me the right results.
  • when I specify a value for my locationfilter, the error related to other fields disappear.

Any workaround ?

Thx

Error with ChoiceFiter and ManyToOneRel

Hi,

while trying to use django-filter in a project of mine I got stuck when I wanted to customize a FilterSet (i.e. provide a lookup type). Once I define a custom filter it loses the choices.

I tried to figure it out by myself, but unfortunately the metaprogramming prevented me from doing so.

This works:

    class FooFilter(django_filters.FilterSet):
        class Meta:
            model=Foo
            fields=('foofield','bar__language')

This doesn't (The language choices aren't displayed):

    class FooFilter(django_filters.FilterSet):
        bar__language=django_filters.ChoiceFilter() # <- look ma, no choices 
        class Meta:
            model=Foo
            fields=('foofield','bar__language')

Using ModelChoiceFilter doesn't (seem to) work either - it complains about
missing keyword somewhere.

Relevant parts of the test application:

    #models.py
    from django.db import models

    class Foo(models.Model):
        foofield=models.CharField(blank=True, max_length=100)

        def __unicode__(self):
            return self.foofield

    class Bar(models.Model):
        LANGUAGES=(('en','english'),
                   ('de','german'))
        foo=models.ForeignKey(Foo)
        language=models.CharField(max_length=2,choices=LANGUAGES)
        barfield = models.CharField(blank=True, max_length=100)

        def __unicode__(self):
            return self.barfield

        #class Meta:
        #    unique_together=(('foo','language'))

    #filters.py
    from models import *
    import django_filters

    class FooFilter(django_filters.FilterSet):
        bar__language=django_filters.ChoiceFilter()
        class Meta:
            model=Foo
            fields=('foofield','bar__language')

    class BarFilter(django_filters.FilterSet):
        class Meta:
            model=Bar
            fields=('foo__foofield',)

    #views.py
    from django.shortcuts import render_to_response
    from models import *
    from filters import *

    def index(request):
        f = FooFilter(request.GET, queryset=Foo.objects.all())
        return render_to_response('index.html',{'f':f})

Using initial value parameter with a Filter results in a different query set being returned .

Hi Alex,

Using the ChoiceFilter below without the initial parameter and selecting "Any" on the form results in all entries being returned (as expected)

If i set the initial parameter to '0' for example, selecting "Any" on the form results in a different queryset result:

qs.filter(addressed__exact='0')

Note that the addressed field is a BooleanField in the model.


ADDRESSED_CHOICES = (

    ('0','Not Addressed'),
    ('','Any'),
    ('1','Addressed'),
)

class FeedbackFilter(django_filters.FilterSet):
  """ filter for feedback entries """
  creation_date = django_filters.DateRangeFilter(lookup_type='lte',label='date')
  addressed =  django_filters.ChoiceFilter(choices=ADDRESSED_CHOICES,label='Status',initial='0')

  class Meta:
    model = Feedback
    fields = ['creation_date','addressed']


Looking at the filter method of Filter i can see that when initial is set and value is "" then a filter will be applied as oppossed to returning the entire queryset which occurs when initial is None and value is ""



   def filter(self, qs, value):
    .
    .

        if value or self.initial:
            return qs.filter(**{'%s__%s' % (self.name, lookup): value or self.initial})
        return qs

Should initial be being used in this way? i noticed this in the django docs:

Form.initial
.
.
Use initial to declare the initial value of form fields at runtime. For example, you might want to fill in a username field with the username of the current session
These values are only displayed for unbound forms, and they're not used as fallback values if a particular value isn't provided.

http://docs.djangoproject.com/en/dev/ref/forms/api/#ref-forms-api

I guess the way I use the ChoiceFilter with a BooleanField may be non standard, so any suggestions on acheiving the same result by modifying my code would be appreciated.

For now i have made a simple change to your filter method which won't use the initial value
Thanks
Anthony

Add a QuerySafeChoiceField

I run into situations often where users see a multi-select box as a chance to select all options within that box. This wouldn't be a problem, except SQL IN(...) can be rather heinous in some database (slow query log one time reported 77k+ rows were affected by a queryset that only got about 2k queries)

http://dpaste.com/hold/120201/

Obviously, some other result might be preferable than the above paste.. Perhaps replacing queries executed that way with the less abbraisive is_null=False?

Filters based on initial queryset

I want to changed some filter's querysets/choices based on initial queryset passed to FilterSet. What would be the best way to do that, override everything in init?

USStateField

Hi,
Thanks for this great django contribution!

I ran into one minor problem. It seems that FilterSet does not find USStateFields. When I add the model field as a class variable to FilterSet, it appears, but is out of order - it appears after the fields it can find.

Thanks

Add conf.py for docs

It seems that the docs are done in sphinx however the conf.py is not provided in order to be easily compile them.

empty_label not implemented

The documentation says:

class ProductFilterSet(django_filters.FilterSet):
    class Meta:
        model = Product
        fields = ['manufacturer']

    def __init__(self, *args, **kwargs):
        super(ProductFilterSet, self).__init__(*args, **kwargs)
        self.filters['manufacturer'].extra.update(
            {'empty_label': u'All Manufacturers'})

When using empty_label this error is thrown:

File "/Users/pauld/.buildout/eggs/django_filter-0.5.3-py2.6.egg/django_filters/filterset.py" in qs
225.                         data = self.form[name].data
File "/Users/pauld/.buildout/eggs/django_filter-0.5.3-py2.6.egg/django_filters/filterset.py" in form
245.             fields = SortedDict([(name, filter_.field) for name, filter_ in self.filters.iteritems()])
File "/Users/pauld/.buildout/eggs/django_filter-0.5.3-py2.6.egg/django_filters/filters.py" in field
50.                     label=self.label, widget=self.widget, **self.extra)
File "/Users/pauld/proj/ownix/parts/django/django/forms/fields.py" in __init__
583.                                         initial=initial, help_text=help_text, *args, **kwargs)

Exception Type: TypeError at /inventory/servers/
Exception Value: __init__() got an unexpected keyword argument 'empty_label'

Save query to DB

Wondering what the best way would be to save the query to the DB? TIA

Way to define Media for Filters?

Analogous to class Media: for forms. I couldn't find anything in the code but it's possible I missed it. If it's not there, feature request?

I'm not likely to have time to work on a pull request in the near future, but if I come across some time I'll try to add it, if you like the idea.

choices for BooleanFilter fields

Hi Alex,

I am trying to assign custom choices to a BooleanNullFilter, by default the options displayed on the form field are Yes,No and Unknown however this doesn't suit my application.

Heres my model and filter:

Model


class Feedback(models.Model):
  
  feedback = models.TextField(blank=True)
  addressed = models.BooleanField(default=False)

Filter


# uses the BooleanNullFilter by default 

class FeedbackFilter(filter.FilterSet):
  
  class Meta:
    model = Feedback
    fields = ['addressed']

I tried changing the widget to one that would allow me to specify choices , this displays fine but doesn't perform the filtering :


ADDRESSED_CHOICES = (
    (True,'Adressed'),
    (False,'Not Addressed'),
    (None,'Any'),
)

class FeedbackFilter(filter.FilterSet):
  
  addressed =  filter.ChoiceFilter(choices=ADDRESSED_CHOICES,label='Status')

  class Meta:
    model = Feedback
    fields = ['addressed']

I also tried using a different widget, however this throws an exception:


class FeedbackFilter(filter.FilterSet):
  
  addressed = filter.BooleanFilter(widget=forms.Select,choices=ADDRESSED_CHOICES,label='Status')
.
.

Result:


Traceback:
File "/home/anthony/lib/python2.5/django/core/handlers/base.py" in get_response
  92.                 response = callback(request, *callback_args, **callback_kwargs)
File "/home/anthony/src/ams/trunk/src/ams/browse/views.py" in common_detail
  23.     feedback_list = feedback_set.qs
File "/home/anthony/src/django-filter/filter/filterset.py" in qs
  196.                     val = self.form.fields[name].clean(self.form[name].data)
File "/home/anthony/src/django-filter/filter/filterset.py" in form
  213.             fields = SortedDict([(name, filter_.field) for name, filter_ in self.filters.iteritems()])
File "/home/anthony/src/django-filter/filter/filters.py" in field
  50.                     widget=self.widget, **self.extra)

Exception Type: TypeError at /browse/shots/1/
Exception Value: __init__() got an unexpected keyword argument 'choices'

I expected this to work since the Select widget requires a choices argument.

I was wondering if you could offer any advice on how to get this behaviour to work without having to change my model.

Thanks
Anthony

Repeated results when using pagination

Hi,

I have this weird pagination bug in Django with django-filter: using object_list as a return of a view, but passing a "paginate_by" argument to it, it's repeating some of the results; Otherwise, if I remove the argument or set as "paginate_by=None", the results are correct.
If using pagination, the quantity of results is maintained at a total, so, because there are repeated results, the last results are left out of the list, so they don't appear in the template.

This is the part of my code that is hit by the problem:
http://pastebin.com/b4zinh27

One thing I noted is that the number of repetitions in the object listing is the same as the number of relations between the target model and the ManyToManyField being filtered (for example, if Company has 4 Categories, it shows 4 times in the listing)

Any ideas of what might be happening?

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.