devind-team / graphene-django-filter

Advanced filters for Graphene
MIT License
19 stars 7 forks source link

Have support for __all__ fields and exclude #33

Open keystroke3 opened 2 years ago

keystroke3 commented 2 years ago

Problem

The current behavior does not have support for __all__ in fields parameter in an AdvancedFilterSet class. If a the fields parameter is set as

fields = '__all__'

without any filter_fields parameter will result in no model fields being added as arguments in the api. Given a model like this:


class Event(models.Model):
    STATUS = (
        ("Scheduled", "Scheduled"),
        ("Cancelled", "Cancelled"),
        ("Complete", "Complete"),
    )
    location = models.ForeignKey(
        Location, on_delete=models.SET_NULL, null=True, related_name="event_location"
    )
    photographer = models.ForeignKey(
        Photographer,
        on_delete=models.SET_NULL,
        null=True,
        related_name="event_photographer",
    )
    event_date = models.DateField()
    status = models.CharField(max_length=15, choices=STATUS, default="Scheduled")
    created = models.DateTimeField(auto_now_add=True)

If all the fields have to be included as possible filter fields, each of them would have to be specified in the filter class. So would all the other additional filter fields eg. photographer__name, photographer__email, event_date__year etc. This issue is related to this comment https://github.com/graphql-python/graphene-django/issues/1314#issuecomment-1075051019 I made on an issue I raised on the graphene repo. There could also be a relationship with issue https://github.com/devind-team/graphene-django-filter/issues/29 on this repo.

Proposed Solution

Add support for __all__ fields and pass any queries on those fields back to django_filters.FilterSet. Then capture any extra fields specified in filter_fields from a field like extra_filters array in the query. This would allow all the fields described in the models to be accessible via the api and allow for extra filter rules to be specified and executed through AdvancedFilters like so:

allEvents(
    eventDate: 2022-5-2,
    status: "Cancelled",
    extra_filters: {
        photographer_FirstName: "John",
        location_Name: "Berlin",
        }
){ ... return fields ... }

A query like this would allow the client to get very specific with the filters and get exactly what they want. In the above example, it would be all cancelled events previously scheduled for 2022-5-2 in Berlin by photographers whose first name is John. To reduce verbosity spoken of in the graphene comment linked above, the filter field can be do exact matching by default especially, but if contains is specified, then it can do partial matching. That way, we don't have to keep specifying {exact: "search term"} for every field we are filtering against. So in the above example query, all the extra_filters are assumed to be exact matches. Something like this comes to mind:

    extra_filters: {
        photographer_FirstName_Contains: "John",
        ...
    }

or as currently implemented:

    extra_filters: {
        photographer_FirstName: {contains: "John"},
        ...
    }

These should match with photographers with first name John and Johnathan.