Code Monkey home page Code Monkey logo

django-url-filter's People

Contributors

anatolyivanov avatar cresg820 avatar danousna avatar davidthewatson avatar haakenlid avatar jostcrow avatar manelclos avatar miki725 avatar minitech avatar netjinho avatar pctestjfarz avatar simone-divitel 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

django-url-filter's Issues

change enum34 dependency to enum-compat

I'm using python 3.6 and after installing django-url-filter my test runner is broken. Turns out that it's caused by the enum34 package which is not compatible with the standard library enum, which is used by other standard library modules such as re.

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "<string>", line 3, in <module>
  File "/usr/local/lib/python3.6/site-packages/execnet/gateway_base.py", line 18, in <module>
    import traceback
  File "/usr/local/lib/python3.6/traceback.py", line 5, in <module>
    import linecache
  File "/usr/local/lib/python3.6/linecache.py", line 11, in <module>
    import tokenize
  File "/usr/local/lib/python3.6/tokenize.py", line 33, in <module>
    import re
  File "/usr/local/lib/python3.6/re.py", line 142, in <module>
    class RegexFlag(enum.IntFlag):
AttributeError: module 'enum' has no attribute 'IntFlag'

It seems that there is a package that solves this. It will install enum34 only on versions < 3.4, to avoid messing with the standard library enum in current versions of python 3.

https://pypi.python.org/pypi/enum-compat

Cannot filter on jsonfields (django)

I'm trying to filter on a jsonfield in django named data_filters. However it seems like this is not working when I'm not specifying any filters. And when i try to spesify filters it crashes because the same fields are not present everywhere.

Is there a way to not validate filters? So that i can just pass along any filter value? for example ?data_filters__region__id=01,02

Edit: Can i use the plain filter to acchieve this?

Also it seems like the pip install version of this gem (0.2.0) does not include the plain version of the filter, it seems like i have to request the master branch to get this.

strict_mode not working for me, is it problem at my end only?

Hi Team,

using below
Django 2.0
DRF 3.7

Below is my filterClass and I made changes to strict_mode still I do not get validation error.

I entered the below url on browser
http://127.0.0.1:8000/api/listmydata/?nonexistcolumn=123

I was expecting a validation error, but I get the result set which is the default behavior of strict_mode. How do I override to fail?

Am I making a mistake here in over riding in my filter Class?

from url_filter.filtersets import ModelFilterSet, StrictMode

class myCustomFilterSet(ModelFilterSet):
    strict_mode = StrictMode.fail
    #strict_mode = 'fail'   #I tried this as well

    class Meta(object):
        model = myModel
class MyDataList(generics.ListAPIView):
    queryset = MyModel.objects.all()
    serializer_class = mySerializer
    filter_class = myCustomFilterSet

Thanks

Sorting support

Having form validate all of the query data, might as well add ordering support.

QUESTION: How to filter a list of dictionaries and *not* from a queryset/Model.

I have a case where I have a list of dictionaries containing my data and I want to be able to filter this via a URL query. There are no models involved here because the data is processed and manipulated in memory so I cannot specify anything for the queryset parameter unless this can be set to a list of objects.
I need something like this from your example here

fs = UserFilterSet(data=query, quertset=[
  {'id': 1, 'name':'hello'},
  {'id': 2, 'name':'world'},
])

Is this possible with django-url-filter?

Returning all values if invalid filter value (string)

I don't know if this is an issue or a feature :) But when the filter value does not exist all the results are returned, for example:

/?state=done
# (Returns only the results where the field state is equal to 'done')
/?state=xpto
# (Returns all the results instead of none) (I think this is **not** the expected behaviour)

Note:
This behaviour does not apply if the field is int, for example id=33 (If 33 does not exist it returns empty).

Generate filter form for Django integration

I imagine most native Django integration will attempt to use a form for the filtering on the list pages. Therefore it probably makes sense to provide a way to create a form dynamically with the form fields from the filterset filters from their default lookups. For example:

class MyFilterSet(FilterSet):
    foo = Filter(form_field=forms.CharField(max_length=50))
    bar = Filter(form_field=forms.IntegerFIeld(max_value=100), default_lookup='in')

# generated form will be something like:
class MyFilterForm(forms.Form):
    foo = forms.CharField(max_length=50)
    bar = MultipleValuesField(child=forms.IntegerFIeld(max_value=100))

using that form you can easily add filtering to the template either via vanilla django forms rendering or customize layout via crispy forms.

The challenge here is how do you enable the url-filter functionality within that form? If the above form would be auto generated its all very nice but not very useful. The whole point of this lib was to allow to filter with multiple lookups on the same field dynamically. How do you do that in django form though? Adding a form field for each lookup is ugly and user will see too many form fields so filter form experience would be terrible:

class MyFilterForm(forms.Form):
    foo = forms.CharField(max_length=50)
    foo__exact = forms.CharField(max_length=50)
    foo__contains = forms.CharField(max_length=50)
    ...

The best I came up with so far is to be able to specify for which lookups to create the form with. A form will be limited to a single lookup for each field but at least which lookup is used will be customizable.

Maybe something like this will work:

class MyFilterForm(FilterForm):
    class Meta(object):
        filterset = MyFilterSet
        lookups = {  # if not provided will use default lookups from each filter
            'bar': 'range',
        }

Support for fields = '__all__'

I couldn't find an indication on Github, ReadtheDocs or in the code that suggests that there is support for this.

Basically, in the Meta class of a serializer, you can specify fields = 'all' to indicate that the serializer should represent all fields in its return.

Similarly, I'm keen to see if we can currently use something like filter_fields = '__all__' in the view/viewset definition.

The behaviour will then essentially automatically allow filtering on all model fields for that viewset.

Thoughts?

URL filter negative lookup logic is counterintuitive / faulty

With current library, it is possible to have negative lookups, like this:
title__contains!=WIP will yield all the entries not containing "WIP", which works well.

Now, let's suppose we want to have all entries not containing WIP which are authored by 'admin'. No problem, we just add another clause here: title__contains!=WIP&author=admin.

But what if we also want filter this set down by adding a condition of entry not having 'draft' status? Logic tells us to add another negative condition: title__contains!=WIP&author=admin&status!=draft.

Unfortunately, with current implementation, it'll result to the following SQL: select * from entry_entries where author = 'admin' and not (title like '%WIP%' and status='draft') which seems a bit illogical. Correct (IMO) behavior would translate this filter URL to select * from entry_entries where author = 'admin' and not title like '%WIP%' and not status = 'draft'.

The reason is that implementation of filtering tries to deal with multiple positive and negative filters similarly:
include = {self._prepare_spec(i): i.value for i in self.includes}
exclude = {self._prepare_spec(i): i.value for i in self.excludes}

    if include:
        queryset = queryset.filter(**include)
    if exclude:
        queryset = queryset.exclude(**exclude)

However, .exclude() logic with multiple kwargs differs from .filter(). Django doc suggests to use chained .exclude() instead to achieve similarity to .filter()

That's why I suggest to fix this logical issue by changing implementation.

How get URL from Query Set?

Hello!

# Need:
some_method(SomeModel.objects.filter(some_field='some_value'))
# returns '?some_field__exact=some_value'

Is there such a function?

Django<1.8 Support

Currently only 1.8 is supported. We should support at least 1.7 and maybe even 1.4 since its still LTS and I imagine many people are still using it.

Using `__in` returns entire queryset

Based on the documentation, it seems I should just be able to configure my viewset as follows and automatically get filtering. However, certain URL filtering seems to be ignored completed.

from django_filters.rest_framework import DjangoFilterBackend

class UsersViewSet(ModelViewSet):
    queryset = MyModel.objects.all()
    serializer_class = MyModelSerializer
    filter_backends = [DjangoFilterBackend]
    filter_fields = ['id']

Assuming that viewset maps to an endpoint like /users/, I should be able to use a query like /users?id__in=1,2,3,4,5 and only see results where the ID is either 1, 2, 3, 4 or 5.

However, that's not the case. Using that minimal setup, I can only use a filter like /users/?id=1. As soon as I use id__in=1,2,3,4,5, I get my entire queryset back - all 20 users.

Am I missing a setup step?

Question on your usage?

I really like what you're doing here & will probably be rolling this into a production app but I'm curious to know what your support situation is for this project. Do you currently use it in any production apps? Do you still consider yourself as actively maintaining this project? Do you follow along with latest deprecations of django & DRF & update this project & do you plan on continuing to do so?

I'm not asking because I expect you to do any of the above lol (you've already built something really nice & are generous enough to release it) but just curious where you stand. Thanks & feel free to close immediately.

How to specify a url filter for related models with multiple levels ?

Hi, I can use the url-filter manually for related models multiple levels deep like this:

from django.http import QueryDict
from url_filter.filtersets import ModelFilterSet
class FilterSet(ModelFilterSet):
     class Meta(object):
         model = TransferRequest

>>> q = QueryDict('transfer_job__transfer_session__priority=1')
>>> fs = FilterSet(data=q, queryset=TransferRequest.objects.all())
>>> fs.filter()
<QuerySet [<TransferRequest: ffdf29cb-1de7-4553-9c8b-b476a0d9d9f0>, ...

but if I have a model view set like this:

class TransferRequestViewSet(QueryOrderableViewSetMixin, viewsets.ModelViewSet):
    queryset = TransferRequest.objects.all()
    serializer_class = TransferRequestSerializer
    filter_backends = [DjangoFilterBackend]
    filter_fields = ['source_studio', 'destination_studio', 'requester_studio', 'user', 'created',
                     'priority', 'options', 'status', 'paths', 'guid',
                     # relation names
                     "transfer_job", "transfer_job__transfer_session"]

and I enter a URL like this:

http://localhost/api/requests/?transfer_job__transfer_session__priority=1

I get the following error:

2018-06-07T00:16:21.404012283Z KeyError: 'transfer_job__transfer_session'
2018-06-07T00:16:21.404015892Z 
2018-06-07T00:16:21.404019373Z During handling of the above exception, another exception occurred:
2018-06-07T00:16:21.404022912Z 
2018-06-07T00:16:21.404026226Z Traceback (most recent call last):
2018-06-07T00:16:21.404029726Z   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
2018-06-07T00:16:21.404033418Z     response = get_response(request)
2018-06-07T00:16:21.404048822Z   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 187, in _get_response
2018-06-07T00:16:21.404052804Z     response = self.process_exception_by_middleware(e, request)
2018-06-07T00:16:21.404055994Z   File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 185, in _get_response
2018-06-07T00:16:21.404059390Z     response = wrapped_callback(request, *callback_args, **callback_kwargs)
2018-06-07T00:16:21.404062545Z   File "/usr/local/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
2018-06-07T00:16:21.404065945Z     return view_func(*args, **kwargs)
2018-06-07T00:16:21.404068985Z   File "/usr/local/lib/python3.6/site-packages/rest_framework/viewsets.py", line 103, in view
2018-06-07T00:16:21.404072336Z     return self.dispatch(request, *args, **kwargs)
2018-06-07T00:16:21.404075373Z   File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py", line 483, in dispatch
2018-06-07T00:16:21.404078630Z     response = self.handle_exception(exc)
2018-06-07T00:16:21.404081677Z   File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py", line 443, in handle_exception
2018-06-07T00:16:21.404085025Z     self.raise_uncaught_exception(exc)
2018-06-07T00:16:21.404088460Z   File "/usr/local/lib/python3.6/site-packages/rest_framework/views.py", line 480, in dispatch
2018-06-07T00:16:21.404091759Z     response = handler(request, *args, **kwargs)
2018-06-07T00:16:21.404094827Z   File "/usr/local/lib/python3.6/site-packages/rest_framework/mixins.py", line 40, in list
2018-06-07T00:16:21.404098214Z     queryset = self.filter_queryset(self.get_queryset())
2018-06-07T00:16:21.404101283Z   File "/usr/local/lib/python3.6/site-packages/rest_framework/generics.py", line 152, in filter_queryset
2018-06-07T00:16:21.404104530Z     queryset = backend().filter_queryset(self.request, queryset, self)
2018-06-07T00:16:21.404108429Z   File "/usr/local/lib/python3.6/site-packages/url_filter/integrations/drf.py", line 160, in filter_queryset
2018-06-07T00:16:21.404111880Z     return _filter.filter()
2018-06-07T00:16:21.404115061Z   File "/usr/local/lib/python3.6/site-packages/url_filter/filtersets/base.py", line 324, in filter
2018-06-07T00:16:21.404118401Z     specs = self.get_specs()
2018-06-07T00:16:21.404121429Z   File "/usr/local/lib/python3.6/site-packages/url_filter/filtersets/base.py", line 358, in get_specs
2018-06-07T00:16:21.404124811Z     specs.append(self.get_spec(data))
2018-06-07T00:16:21.404127821Z   File "/usr/local/lib/python3.6/site-packages/url_filter/filtersets/base.py", line 400, in get_spec
2018-06-07T00:16:21.404131037Z     if name not in self.filters:
2018-06-07T00:16:21.404134085Z   File "/usr/local/lib/python3.6/site-packages/cached_property.py", line 35, in __get__
2018-06-07T00:16:21.404138102Z     value = obj.__dict__[self.func.__name__] = self.func(obj)
2018-06-07T00:16:21.404141194Z   File "/usr/local/lib/python3.6/site-packages/url_filter/filtersets/base.py", line 224, in filters
2018-06-07T00:16:21.404147396Z     filters = self.get_filters()
2018-06-07T00:16:21.404150516Z   File "/usr/local/lib/python3.6/site-packages/url_filter/filtersets/base.py", line 487, in get_filters
2018-06-07T00:16:21.404153786Z     _filter = self._build_filter(name, state)
2018-06-07T00:16:21.404156840Z   File "/usr/local/lib/python3.6/site-packages/url_filter/filtersets/django.py", line 93, in _build_filter
2018-06-07T00:16:21.404160186Z     field = self.Meta.model._meta.get_field(name)
2018-06-07T00:16:21.404163206Z   File "/usr/local/lib/python3.6/site-packages/django/db/models/options.py", line 619, in get_field
2018-06-07T00:16:21.404166434Z     raise FieldDoesNotExist("%s has no field named '%s'" % (self.object_name, field_name))
2018-06-07T00:16:21.404169750Z django.core.exceptions.FieldDoesNotExist: TransferRequest has no field named 'transfer_job__transfer_session'

Is there a special syntax for entering such filters ?

Thanks
-Selim

Documentation examples don't include imports

Having the imports in the examples would be really useful, especially since you have two different DjangoFilterBackend classes (thankfully they take different numbers of __init__ arguments, otherwise I would have been extremely confused).

Installation does not install all files

pip install django-url-filter only the files in the root without the sub-directories.

This package seems great and I would like to try work with it! :-)

-thanks, Eli.

Method to pretty print the filter

I'm using this to filter ListViews beautifully now. Thanks. Love it.

I find myself wanting at the top of the list view to summarise the filter in use. Alas no quick easy way to format it seems available.

self.request.GET of course contains the GET parameters. and FilsterSet.get_specs() also provides a parsed view I guess of those GET parameters that made it into the filter. But I see now easy way to print either as a nice HTML list of the filter criteria.

I may write one yet, but first a check to see if there is a way I'm missing, and second a check to see if I write one if it would be a welcome pull request into this package?

Fallback behavior for the callable filter

Hi I have a callable filter that handles a custom lookup that I implemented:

class StatusFilter(CallableFilter):
    @form_field_for_filter(forms.CharField())
    def filter_has_any_keys_for_django(self, queryset, spec):
        value = spec.value.split(',')
        if spec.is_negated:
            return queryset.exclude(status__has_any_keys=value)
        else:
            return queryset.filter(status__has_any_keys=value)

    @form_field_for_filter(forms.CharField())
    def filter_contains_for_django(self, queryset, spec):
        if spec.is_negated:
            return queryset.exclude(status__contains=spec.value)
        else:
            return queryset.filter(status__contains=spec.value)

And it works great. The issue is that if the callable filter doesn't support other types of lookups, I want it to fall back to the default way of handling the filters, so for example if I try to specify a query parameter like ".../?status=["complete","succeeded"] then I get an error:

AssertionError: StatusFilter was not provided form_field parameter in initialization (e.g. StatusFilter(form_field=CharField)) and form_field was not provided for the lookup. If the lookup is a custom filter callable you should provide form_field by using @form_field_for_filter decorator. If the lookup is a normal lookup, then please either provide form_field parameter or overwrite get_form_field().

Is there a mechanism for this?

Thanks
-Selim

Question/Assistance - django-url-filter-relatedfielderror

I am working on DRF generic listview with DUF as filter backend.

Could you please assist me to get around this error? I am sure i am doing something wrong here with related to related fields.

When i try to filter on url I get the following error. I would like to filter on all columns of child model.

http://127.0.0.1:8000/api/childlist/?customer_id=2

AttributeError at /api/childlist/
'OneToOneField' object has no attribute 'rel'
Below is my work so far:

models.py

from django.db import models
from django.contrib.auth.models import User
# Create your models here.

class Parent(models.Model):
    customer_id = models.BigIntegerField(primary_key=True)
    customer_name = models.CharField(blank=True, null=True, max_length=50)
    age = models.IntegerField(blank=True, null=True)


class Child(models.Model):
    customer_id = models.OneToOneField(Parent, on_delete=models.DO_NOTHING, related_name='customer_id_fk_parent')
    used_by = models.ForeignKey(User, on_delete=models.DO_NOTHING, related_name='rel_user')
    comments = models.TextField(blank=True,null=True)

views.py

from rest_framework import generics

from onetoone.models import Child
from .serializers import Child_Serializer
from url_filter.integrations.drf import DjangoFilterBackend


#Required columns on Child -- All columns
FILTER_REQ_COLUMNS = [field.name for field in Child._meta.get_fields()]


class ChildList(generics.ListAPIView):
    queryset = Child.objects.all()
    serializer_class = Child_Serializer
    filter_backends = [DjangoFilterBackend]
    filter_fields = FILTER_REQ_COLUMNS

serializers.py

from rest_framework import serializers
from onetoone.models import Child


class Child_Serializer(serializers.ModelSerializer):
    class Meta:
        model = Child
        exclude = []

urls.py
path('childlist/', ChildList.as_view(), name='api_child_list'),
Current list data as below

http://127.0.0.1:8000/api/childlist/

HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "count": 3,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 1,
            "comments": "1 is in use",
            "customer_id": 1,
            "used_by": 1
        },
        {
            "id": 2,
            "comments": "2 is in use",
            "customer_id": 2,
            "used_by": 1
        },
        {
            "id": 3,
            "comments": "3 in use",
            "customer_id": 3,
            "used_by": 1
        }
    ]
}

fulltrace back is here
https://gist.github.com/just10minutes/b9add9c00ee3a14764b324ec30c65344

Using without Django

I have plenty of SQLAlchemy code bases that are not based on Django where this library could be useful.

It looks like the sqlalchemy backend itself can be used without Django as I don't see any references to Django imports:

http://django-url-filter.readthedocs.io/en/latest/_modules/url_filter/backends/sqlalchemy.html

Have you considered splitting this part out to a separate library? For now I would have to copy this file in my codebase (keeping the comments + copyright reference off course), but it would be nice not to have to do this in the future.

The requirements.txt pulls in Django as a dependency that is why I can't exactly use it, it would basically trigger it installing Django in a flask project, or bottle project etc.

Model FilterSets should include foreign key integerfields.

Taking these models:

class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)

class Restaurant(models.Model):
    place = models.OneToOneField(Place, primary_key=True)
    serves_hot_dogs = models.BooleanField(default=False)
    serves_pizza = models.BooleanField(default=False)

RestaurantFilterSet should then include both children place filterset and place_id.

Doing that will allow to optimize filtering by not causing unnecessary joins for urls like:

place_id=5
vs
place__id=5 == place=5

Plain filtering

Django URL filter should be able to filter on plain Python lists

Pagination Capabilities/Support

It seems that most query filtering tools for django have poor support for paging/pagination.
Either inbuilt support, Django's built in pagination capabilities or via other existing pagination libraries/apps.

Does django-url-filter support pagination in any way?

If not, can we build it in or support the 'default' django mechanisms?
Being able to just add paginate_by = 10 on my class based views, is pretty damn useful when trying to be productive.

CallableFilter.lookups with only custom_lookups

Hi,

for a project that use drf-yasg, i use CallableFilter for model properties that returns queryset.
But when doc was generated with drf-yasg, many lookups were generated when I didn't create them.

For now, I override the lookups method like this:

    @cached_property
    def lookups(self):
        r = LOOKUP_CALLABLE_FROM_METHOD_REGEX
        custom_lookups = {
            m.groupdict()["filter"]
            for m in (r.match(i) for i in dir(self))
            if m and m.groupdict()["backend"] == self.root.filter_backend.name
        }

        return custom_lookups

Would there be a possibility to choose that this method only returns the custom lookups?
A parameter custom_lookups_only=False in the __init__ of CallableFilter for example?

Django Class Based View Example

Is it possible to get an example of how to use this library with a Class Based View?
Either the built in Django ListView or the Django Vanilla Views ListView, would be enough to show how this can be used without DRF a bit easier than the current example of manually creating things does.

Filters against decimals are removed if the query decimal is too long

It seems that if the decimal in the url is not within the specifications given in the model definition, then the filter fails and returns everything.

class Test(models.Model):
    my_number = models.DecimalField(max_digits=2, decimal_places=1)

Test.objects.create(my_number=1.5)

1 result:
/test/
/test/?my_number__gte=1
/test/?my_number__gte=1.0
/test/?my_number__gte=.0
/test/?my_number__gte=2.00 <- incorrect
/test/?my_number__gte=20 <- incorrect

0 results:
/test/?my_number__gte=2
/test/?my_number__gte=2.0

ModelFilterSet change filter source

This should work:

class MyFilterSet(ModelFilterSet):
  class Meta:
    model = Foo
    fields = ['foo']  # not a model field
    extra_kwargs = {'foo': {'source': 'bar'}}  # bar is a field on model

Lookup options in Meta

ModelFilterSet should support to specify lookups in Meta:

class Meta:
    model = Foo
    lookups = {
        "slug": ('exact', 'startswith',),
        "title": ALL,
    }

Dont import contenttype to avoid import issues when contenttypes is not in installed apps

that should fix:

Traceback (most recent call last):                                  
  File "/home/serkan/.local/share/virtualenvs/slides-2sl0-4FG/src/sliderepl/sliderepl/core.py", line 292, in run                        
    exec_(co, environ)            
  File "<input>", line 1, in <module>                               
  File "/home/serkan/.local/share/virtualenvs/slides-2sl0-4FG/lib/python3.6/site-packages/url_filter/filtersets/__init__.py", line 5, in <module>
    from .django import *  # noqa 
  File "/home/serkan/.local/share/virtualenvs/slides-2sl0-4FG/lib/python3.6/site-packages/url_filter/filtersets/django.py", line 6, in <module>
    from django.contrib.contenttypes.fields import GenericForeignKey                                                                    
  File "/home/serkan/.local/share/virtualenvs/slides-2sl0-4FG/lib/python3.6/site-packages/django/contrib/contenttypes/fields.py", line 5, in <module>
    from django.contrib.contenttypes.models import ContentType      
  File "/home/serkan/.local/share/virtualenvs/slides-2sl0-4FG/lib/python3.6/site-packages/django/contrib/contenttypes/models.py", line 139, in <module>
    class ContentType(models.Model):                                
  File "/home/serkan/.local/share/virtualenvs/slides-2sl0-4FG/lib/python3.6/site-packages/django/db/models/base.py", line 118, in __new__
    "INSTALLED_APPS." % (module, name)                              
RuntimeError: Model class django.contrib.contenttypes.models.ContentType doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.

Filtering on a related model that contains a generic foreign key leads to an uncaught error.

Hello,
first let me thank you for sharing this useful code!

What i found is that if you try to filter by a field that point to a related model which has defined a generic foreign key followinf error is returned:
AttributeError at /api/v1/projects/a/ 'GenericForeignKey' object has no attribute 'formfield'

I tried with ForeignKey and ManyToMany on django 1.9.7 and url_filter from github master branch.

You can test it with the following two models:

from django.db import models
from django.contrib.contenttypes.fields import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation


class A(models.Model):
    name = models.CharField(max_length=256, blank=False, null=False)


class B(models.Model):
    name = models.CharField(max_length=256, blank=False, null=False)
    a = models.ForeignKey('A',
                          models.DO_NOTHING,
                          blank=True,
                          null=True,
                          related_name='b_rel')
    content_type = models.ForeignKey(ContentType, models.DO_NOTHING)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

If you try to filter the model 'A' list by the 'b_rel' field the error appears.

Since i actually tried filtering trough djangorestframework 3.3.3 (even if i think that thi issue is generic), i will leave here the relevant code to publish model 'A' to a rest API so you can test it easily.
Just create an 'A' record and paste the following url after you authenticated (trough the django rest framework browsable api or standard django admin):
http://localhost:8000/api/your-app-name/a/?b_rel=1

views.py

from .serializers import *
from projects.models import A, B
from rest_framework.viewsets import ModelViewSet


class ASerializer(serializers.ModelSerializer):
    class Meta:
        model = A
        fields = [
            'name',
            'b_rel',
        ]


class AViewSet(ModelViewSet):
    serializer_class = ASerializer
    queryset = A.objects.all()
    filter_backends = [DjangoFilterBackend]
    filter_fields = [
        'name',
        'b_rel',
    ]

urls.py

from django.conf.urls import include, url
from rest_framework import routers
from projects.views import AViewSet

router = routers.DefaultRouter()

router.register(r'a', AViewSet, 'projects-a')

urlpatterns = [
    url(r'^api/your-app-name/', include(router.urls)),
]

Since the error occurs when filters for the related model ('B') are built automatically, imho the solution is to check wheter a field actually has a formfield or at least exclude the 'GenericForeignKey' field from filters because they do not have a form field by default, see relevant django documentation..

If you prefer a pull request, just tell me.

Filter foreign key field by null

I can't seem to find documentation on filtering fields by null value. By logic, Django's isnull=True should work, but it doesn't work for me:
/api/houses/?ownerid__isnull=True doesn't filter houses with no owner

Support filtering on aggregate fields.

I am not sure how complex to implement this, but it would be really useful if we can filter on aggregate (annotated) fields.

Exmaple:
Consider these models

from django.db import models

class Reporter(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    email = models.EmailField()

class Article(models.Model):
    headline = models.CharField(max_length=100)
    pub_date = models.DateField()
    reporter = models.ForeignKey(Reporter)

And the DRF viewset

from rest_framework import viewsets

class ReporterViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = models.Reporter.objects.annotate(article_count=Count("reporter_set"))

    filter_backends = [DjangoFilterBackend]
    filter_fields = ['last_name', 'article_count']

We filter reporters that have at least n articles by reporter?article_count__gte=5.

This setup currently result in error Reporter has no field named 'article_count'. Since the filtering is done on the queryset not the model, I am not sure why the model is being checked.

Thanks.

Filter by list of ids of a FK

Hi there,

First of all many thanks for sharing this with the world. It might have saved me a lot of time :)

I'm using django-url-filter 0.2.0 DRF integration with DRF 3.3.2 and Django 1.9.2.

One of the 2 uses I'd like to give it I think is not working though. Here's how my code looks like (I'm not pasting my settings since the rest seems to be working fine):

# In models.py
class E(models.Model):

    title = models.CharField(max_length=200)
    p = models.ForeignKey('P')

class P(models.Model):

    name = models.CharField(max_length=200)

# In views.py
class EViewSet(viewsets.ModelViewSet):

    serializer_class = ESerializer
    queryset = E.objects.all()
    filter_fields = ['p']


class PViewSet(viewsets.ModelViewSet):

    serializer_class = PSerializer
    queryset = P.objects.all()

What I'd like to do is filter all E instances that belong to a certain list of Ps (ie. being able to do http://example.com/v1/e/?p__in=1,2,3 or similar).

The result I'm getting is just all the E objects, unfiltered. I'm not sure if this is supposed to be working but broken or if it's a functionally yet to be added, or maybe I'm just doing it wrong. Sorry I didn't dive in the code to pin point the exact cause of the problem.

Thanks for your help!

Use tox for testing in travis

Currently only django 1.11 is tested in travis, because the MakeFile command doesn't run tox. Instead theres'

It's rather confusing to have a tox config and not actually use it for continuous integration. Tox is more configurable than just using varibles in the .travis.yml file.

https://github.com/miki725/django-url-filter/blob/master/Makefile
https://github.com/miki725/django-url-filter/blob/master/.travis.yml

There is a tox config file, but there's some problems when installing pip packages with pypy.
https://github.com/miki725/django-url-filter/blob/master/tox.ini

usage.rst: Django section fails to explain Django usage

Forgive me. But on this page:

https://github.com/miki725/django-url-filter/blob/master/docs/usage.rst

There is an enticing Django section after a Vanilla section that makes no sense to me. And in it I expect to see how I might use this in Django. But that section helps me naught.

It presents some code snippets out of context and I'm a tad clueless as to to use filters from it.

Where does what sit in urls.py, models.py, views.py, settings.pi etc. in the Django context? What am I missing? How could this page improve to actually elucidate things for a punter like me (building a site with Django, pretty au fait with much of Django but unable to decrypt this so clearly not a pro).

error __init__() takes at least 2 arguments (1 given)

I have a ViewSet that runs well with django-filter but in django-url-filter I have an error (at the end)
The viewSet:

from url_filter.backends.django import DjangoFilterBackend
class PersonaViewSet(viewsets.ModelViewSet):
filter_fields = ['nom', 'cognoms', 'data_naixament', 'fills', 'casat']
queryset = Persona.objects.all()
serializer_class = PersonaSerializer
filter_backends = [DjangoFilterBackend]

My packages are:
Django==1.9.8
django-filter==0.15.0
django-url-filter==0.2.0
djangorestframework==3.4.6

The error:

Environment:

Request Method: GET
Request URL: http://devel-trusty.local:8000/persones/?id=1

Django Version: 1.9.8
Python Version: 2.7.6
Installed Applications:
['django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'quickstart']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware']

Traceback:

File "/devel/infraplan/layer_manager/env/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response

  1.                 response = self.process_exception_by_middleware(e, request)
    

File "/devel/infraplan/layer_manager/env/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response

  1.                 response = wrapped_callback(request, _callback_args, *_callback_kwargs)
    

File "/devel/infraplan/layer_manager/env/local/lib/python2.7/site-packages/django/views/decorators/csrf.py" in wrapped_view

  1.     return view_func(_args, *_kwargs)
    

File "/devel/infraplan/layer_manager/env/local/lib/python2.7/site-packages/rest_framework/viewsets.py" in view

  1.         return self.dispatch(request, _args, *_kwargs)
    

File "/devel/infraplan/layer_manager/env/local/lib/python2.7/site-packages/rest_framework/views.py" in dispatch

  1.         response = self.handle_exception(exc)
    

File "/devel/infraplan/layer_manager/env/local/lib/python2.7/site-packages/rest_framework/views.py" in handle_exception

  1.         self.raise_uncaught_exception(exc)
    

File "/devel/infraplan/layer_manager/env/local/lib/python2.7/site-packages/rest_framework/views.py" in dispatch

  1.         response = handler(request, _args, *_kwargs)
    

File "/devel/infraplan/layer_manager/env/local/lib/python2.7/site-packages/rest_framework/mixins.py" in list

  1.     queryset = self.filter_queryset(self.get_queryset())
    

File "/devel/infraplan/layer_manager/env/local/lib/python2.7/site-packages/rest_framework/generics.py" in filter_queryset

  1.         queryset = backend().filter_queryset(self.request, queryset, self)
    

Exception Type: TypeError at /persones/
Exception Value: init() takes at least 2 arguments (1 given)

Max and Min filter

how could I filter a model by the smallest and highest price for example?

Support for has_any_keys ?

Hi, I have a model with a JSONField which contains an array of strings:

class TransferSession(models.Model):
...
status = JSONField(default=[], validators=[validate_session_status])

I can use filters like this in the URL which works fine:

/api/sessions/?status__contains="running"

Now I'd like to use the "has_any_keys" filter to match any of the given values:

/api/sessions/?status__has_any_keys=["running","stopped"]

but it doesn't seem to work. Is it not currently supported?

Thanks
-Selim

Complex lookups with Django models

Is there a way possibility to do complex lookups via the url?

Suppose I have a model "Car" with a field called "fuel_tank_capacity" that can be null. How can I filter for all Cars with a fuel_tank_capacity__gte=80 but also include those cars where fuel_tank_capacity is empty?

In Django terms, what I'd like to be able to do via url filtering is

 Car.objects.filter(Q(fuel_tank_capacity__gte=80) | Q(fuel_tank_capacity=None))

Thanks for the great work by the way, keep it up!

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.