Filtering🔗

ModelFilterSet🔗

A custom FilterSet class for optimizing the filtering of GraphQL queries.

from graphene_django_extensions import ModelFilterSet
from example.models import Example

class ExampleFilterSet(ModelFilterSet):
    class Meta:
        model = Example
        fields = [...]

Extends django_filters.filterset.FilterSet and adds the following features:

  • Automatically a order_by = CustomOrderingFilter(fields=["pk"]) to the class for ordering the filterset.
  • Changes the default filters for all relationships (one-to-one, many-to-one, etc.) to not make a database queries to check if the filtered rows exists.

Subclasses can be configured through the Meta-class. Here are the most useful options:

Option Type Description
model type[Model] Required. The model class for the filterset.
fields list[str] or dict[str, list[str]] or __all__ Required. The fields to include in the node. If __all__ is used, all fields are included.
order_by list[str] or list[tuple[str, str]] Optional. Ordering filters to add to the filterset. Can also add non-field orderings, or customize field orderings by adding a order_by_{field_name} method to the ModelFilterSet subclass.
combination_methods list[str] Optional. Allows combining method filters so that they will use the same filter function. The combination method will always run, and its value will be a mapping of the field names of the combined filters to their values.

CustomOrderingFilter🔗

Extends django_filters.filters.OrderingFilter by adding option for custom orderings by defining order_by_{name} functions on its subclasses or filtersets it is defined on. This filter is automatically added to ModelFilterSet subclasses, and its Meta.order_by can be used to add custom orderings.

from graphene_django_extensions import ModelFilterSet

class ExampleFilterSet(ModelFilterSet):
    class Meta:
        model = Example
        fields = [...]
        order_by = ["name"]

    def order_by_name(self, qs: QuerySet, desc: bool) -> QuerySet:
        return qs.order_by("-name" if desc else "name")

Additionally, the ordering choices are converted to GraphQL enums (e.g. "name" -> nameAsc & "-name" -> nameDesc), which gives better autocomplete results in GraphiQL, and makes the available orderings more explicit.


UserDefinedFilter🔗

A filter which allows users to define custom filtering rules for a set of predefined model fields. The idea is similar in concept to the GraphQL itself; allowing users to select which data they actually need vs. what has been predefined.

from graphene_django_extensions.filters import ModelFilterSet, UserDefinedFilter

class ExampleFilterSet(ModelFilterSet):
    filter = UserDefinedFilter(
        model=Example,
        fields=["name", "number", "email"],
    )

Given the above filter, the user can define the following filter:

query {
    examples(
        filter: {
            field: name,
            operation: CONTAINS,
            value: "foo",
        }
    ) {
        edges {
            node {
                pk
            }
        }
    }
}

This creates a simple Q(name__contains="foo") filter for the queryset.

Notice that the field values are enums created from the defined fields in the UserDefinedFilter. If no fields are given, all fields from the given model can be filtered on. Related fields can also be added via the "__" lookup syntax. Filter aliases can be given by specifying a tuple of ("field_lookup", "alias") in the fields list.

The model argument is mandatory, and is used to rename the filter input type after the field enum field has been added to it (in additions fetching the default fields if no fields are defined).

Let's see a more complex example:

query {
    examples(
        filter: {
            operation: AND,
            operations: [
                {
                    operation: OR,
                    operations: [
                        {
                            field: name,
                            operation: CONTAINS,
                            value: "foo",
                        },
                        {
                            field: email,
                            operation: CONTAINS,
                            value: "foo",
                        },
                    ],
                },
                {
                    operation: NOT,
                    operations: [
                        {
                            field: number,
                            operation: LT,
                            value: 10,
                        }
                    ]
                },
            ],
        }
    ) {
        edges {
            node {
                pk
            }
        }
    }
}

This configuration corresponds to (Q(name__contains="foo") | Q(email__contains="foo") & ~Q(number__lt=10)).

As the above example demonstrates, logical operations can also be used, allowing for complex filtering rules to be defined, which regular filter fields cannot do.


EnumChoiceFilter & EnumMultipleChoiceFilter🔗

Custom fields for handling enums better in GraphQL filters. Using django_filters.ChoiceFilter causes the Enums to be converted to strings in GraphQL filters. This class uses GraphQL Enums instead, which gives better autocomplete results.


IntegerChoiceFilter & IntegerMultipleChoiceFilter🔗

Allows plain integers as choices in GraphQL filters. Normally, integer enums are converted to string enums in GraphQL by prefixing them with A_, but this filter allows using plain integers.