Metadata-Version: 2.1
Name: graphene-django-filter
Version: 0.4.0
Summary: Advanced filters for Graphene
Home-page: https://github.com/devind-team/graphene-django-filter
License: MIT
Keywords: django,graphene,filter
Author: devind-team
Author-email: team@devind.ru
Requires-Python: >=3.6.2
Classifier: Framework :: Django
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Requires-Dist: Django (==3.2)
Requires-Dist: anytree (>=2.8.0,<3.0.0)
Requires-Dist: django-filter (>=21.1,<22.0)
Requires-Dist: django-seed (>=0.3.1,<0.4.0)
Requires-Dist: graphene (==2.1.9)
Requires-Dist: graphene-django (>=2.15.0,<3.0.0)
Requires-Dist: psycopg2-binary (>=2.9.3,<3.0.0)
Requires-Dist: stringcase (>=1.2.0,<2.0.0)
Project-URL: Repository, https://github.com/devind-team/graphene-django-filter
Description-Content-Type: text/markdown

# Graphene-Django-Filter
[![CI](https://github.com/devind-team/graphene-django-filter/workflows/CI/badge.svg)](https://github.com/devind-team/graphene-django-filter/actions) [![PyPI version](https://badge.fury.io/py/graphene-django-filter.svg)](https://badge.fury.io/py/graphene-django-filter)

This package contains advanced filters for [graphene-django](https://github.com/graphql-python/graphene-django). The standard filtering feature in Graphene-Django relies on the Django-Filter library and therefore provides a flat API without the ability to use `and` and `or` expressions. This library makes the API nested and adds the `and` and `or` composition by extension of the `DjangoFilterConnectionField` field and the `FilterSet` class.
# Requirements
* Python (3.6, 3.7, 3.8, 3.9, 3.10)
* Graphene-Django (2.15)
# Features
## Nested API with the ability to use `and` and `or` expressions
To use, simply replace all `DjangoFilterConnectionField` fields with `AdvancedDjangoFilterConnectionField` fields in your queries. Also, if you create custom FilterSets, replace the inheritance from the `FilterSet` class with the inheritance from the `AdvancedFilterSet` class. For example, the following task query exposes an old flat API.
```python
import graphene
from django_filters import FilterSet
from graphene_django import DjangoObjectType
from graphene_django.filter import DjangoFilterConnectionField

class TaskFilter(FilterSet)
    class Meta:
        model = Task
        fields = {
            'name': ('exact', 'contains'),
            'user__email': ('exact', 'contains'),
            'user__last_name': ('exact', 'contains'),
        }
 
class UserType(DjangoObjectType):
    class Meta:
        model = User
        interfaces = (graphene.relay.Node,)
        fields = '__all__'
        
class TaskType(DjangoObjectType):
    user = graphene.Field(UserType)

    class Meta:
        model = Task
        interfaces = (graphene.relay.Node,)
        fields = '__all__'
        filterset_class = TaskFilter
        
class Query(graphene.ObjectType):
    tasks = DjangoFilterConnectionField(TaskType)
```
The flat API in which all filters are applied using the "and" operator looks like this.
```graphql
{
  tasks(
    name_Contains: "important"
    user_Email_Contains: "john"
    user_LastName: "Dou"
  ){
    edges {
      node {
        id
        name
      }
    }
  }
}
```
After replacing the field class with the `AdvancedDjangoFilterConnectionField` and the `FilterSet` class with the `AdvancedFilterSet` the API becomes nested with support for `and` and `or` expressions.
```python
from graphene_django_filter import AdvancedDjangoFilterConnectionField, AdvancedFilterSet

class TaskFilter(AdvancedFilterSet)
    class Meta:
        model = Task
        fields = {
            'name': ('exact', 'contains'),
            'user__email': ('exact', 'contains'),
            'user__last_name': ('exact', 'contains'),
        }

class Query(graphene.ObjectType):
    tasks = AdvancedDjangoFilterConnectionField(TaskType)
```
For example, the following query returns tasks whose names contain the word "important" or the user's email address contains the word "john" and the user's last name is "Dou". Note that the operators are applied to lookups such as `contains`, `exact`, etc. at the last level of nesting.
```graphql
{
  tasks(
    filter: {
      or: [
        {name: {contains: "important"}}
        and: [
          {user: email: {contains: "john"}}
          {user: lastName: {exact: "Dou"}}
        ]
      ]
    }
  ){
    edges {
      node {
        id
        name
      }
    }
  }
}
```
The same result can be achieved with an alternative query structure because within the same object the `and` operator is always used.
```graphql
{
  tasks(
    filter: {
      or: [
        {name: {contains: "important"}}
        {
          user: {
            email: {contains: "john"}
            lastName: {exact: "Dou"}
          }
        }
      ]
    }
  ){
    edges {
      node {
        id
        name
      }
    }
  }
}
```
The filter input type has the following structure.
```graphql
input FilterInputType {
  and: [FilterInputType]
  or: [FilterInputType]
  ...FieldLookups
}
```
For more examples, see tests.

