graphene-elastic

Elasticsearch (DSL)/ OpenSearch (DSL) integration for Graphene.

PyPI Version Supported Python versions Build Status Documentation Status GPL-2.0-only OR LGPL-2.1-or-later Coverage

Prerequisites

  • Graphene 2.x. Support for Graphene 1.x is not intended.

  • Python 3.6, 3.7, 3.8, 3.9 and 3.10. Support for Python 2 is not intended.

  • Elasticsearch 6.x, 7.x. Support for Elasticsearch 5.x is not intended.

  • OpenSearch 1.x, 2.x.

Main features and highlights

  • Implemented ElasticsearchConnectionField and ElasticsearchObjectType are the core classes to work with graphene.

  • Pluggable backends for searching, filtering, ordering, etc. Don’t like existing ones? Override, extend or write your own.

  • Search backend.

  • Filter backend.

  • Ordering backend.

  • Pagination.

  • Highlighting backend.

  • Source filter backend.

  • Faceted search backend (including global aggregations).

  • Post filter backend.

  • Score filter backend.

  • Query string backend.

  • Simple query string backend.

See the Road-map for what’s yet planned to implemented.

Do you need a similar tool for Django REST Framework? Check django-elasticsearch-dsl-drf.

Demo

Check the live demo app (FastAPI + Graphene 2 + Elasticsearch 7) hosted on Heroku and bonsai.io.

Documentation

Documentation is available on Read the Docs.

Installation

Install latest stable version from PyPI:

pip install graphene-elastic

Or latest development version from GitHub:

pip install https://github.com/barseghyanartur/graphene-elastic/archive/master.zip

Note

Staring from version 0.8, the elasticsearch and elasticsearch-dsl packages are no longer installed by default. You must either install them explicitly in your requirements or install as optional dependencies as follows: pip install graphene-elastic[elasticsearch]. Alternatively, you can use opensearch-py and opensearch-dsl. You would then need to install the opensearch-py and opensearch-dsl packages explicitly in your requirements or install them as optional dependencies as follows: pip install graphene-elastic[opensearch].

Examples

Note

In the examples, we use elasticsearch_dsl package for schema definition. You can however use opensearch_dsl or if you want to achieve portability between Elasticsearch and OpenSearch, use anysearch package. Read more here.

Install requirements

pip install -r requirements.txt

Populate sample data

The following command will create indexes for User and Post documents and populate them with sample data:

./scripts/populate_elasticsearch_data.sh

Sample document definition

search_index/documents/post.py

See examples/search_index/documents/post.py for full example.

import datetime
from elasticsearch_dsl import (
    Boolean,
    Date,
    Document,
    InnerDoc,
    Keyword,
    Nested,
    Text,
    Integer,
)

class Comment(InnerDoc):

    author = Text(fields={'raw': Keyword()})
    content = Text(analyzer='snowball')
    created_at = Date()

    def age(self):
        return datetime.datetime.now() - self.created_at


class Post(Document):

    title = Text(
        fields={'raw': Keyword()}
    )
    content = Text()
    created_at = Date()
    published = Boolean()
    category = Text(
        fields={'raw': Keyword()}
    )
    comments = Nested(Comment)
    tags = Text(
        analyzer=html_strip,
        fields={'raw': Keyword(multi=True)},
        multi=True
    )
    num_views = Integer()

    class Index:
        name = 'blog_post'
        settings = {
            'number_of_shards': 1,
            'number_of_replicas': 1,
            'blocks': {'read_only_allow_delete': None},
        }

Sample apps

Sample Flask app

Run the sample Flask app:

./scripts/run_flask.sh

Open Flask graphiql client

http://127.0.0.1:8001/graphql

Sample Django app

Run the sample Django app:

./scripts/run_django.sh runserver

Open Django graphiql client

http://127.0.0.1:8000/graphql

ConnectionField example

ConnectionField is the most flexible and feature rich solution you have. It uses filter backends which you can tie to your needs the way you want in a declarative manner.

Sample schema definition

import graphene
from graphene_elastic import (
    ElasticsearchObjectType,
    ElasticsearchConnectionField,
)
from graphene_elastic.filter_backends import (
    FilteringFilterBackend,
    SearchFilterBackend,
    HighlightFilterBackend,
    OrderingFilterBackend,
    DefaultOrderingFilterBackend,
)
from graphene_elastic.constants import (
    LOOKUP_FILTER_PREFIX,
    LOOKUP_FILTER_TERM,
    LOOKUP_FILTER_TERMS,
    LOOKUP_FILTER_WILDCARD,
    LOOKUP_QUERY_EXCLUDE,
    LOOKUP_QUERY_IN,
)

# Object type definition
class Post(ElasticsearchObjectType):

    class Meta(object):
        document = PostDocument
        interfaces = (Node,)
        filter_backends = [
            FilteringFilterBackend,
            SearchFilterBackend,
            HighlightFilterBackend,
            OrderingFilterBackend,
            DefaultOrderingFilterBackend,
        ]

        # For `FilteringFilterBackend` backend
        filter_fields = {
            # The dictionary key (in this case `title`) is the name of
            # the corresponding GraphQL query argument. The dictionary
            # value could be simple or complex structure (in this case
            # complex). The `field` key points to the `title.raw`, which
            # is the field name in the Elasticsearch document
            # (`PostDocument`). Since `lookups` key is provided, number
            # of lookups is limited to the given set, while term is the
            # default lookup (as specified in `default_lookup`).
            'title': {
                'field': 'title.raw',
                # Available lookups
                'lookups': [
                    LOOKUP_FILTER_TERM,
                    LOOKUP_FILTER_TERMS,
                    LOOKUP_FILTER_PREFIX,
                    LOOKUP_FILTER_WILDCARD,
                    LOOKUP_QUERY_IN,
                    LOOKUP_QUERY_EXCLUDE,
                ],
                # Default lookup
                'default_lookup': LOOKUP_FILTER_TERM,
            },

            # The dictionary key (in this case `category`) is the name of
            # the corresponding GraphQL query argument. Since no lookups
            # or default_lookup is provided, defaults are used (all lookups
            # available, term is the default lookup). The dictionary value
            # (in this case `category.raw`) is the field name in the
            # Elasticsearch document (`PostDocument`).
            'category': 'category.raw',

            # The dictionary key (in this case `tags`) is the name of
            # the corresponding GraphQL query argument. Since no lookups
            # or default_lookup is provided, defaults are used (all lookups
            # available, term is the default lookup). The dictionary value
            # (in this case `tags.raw`) is the field name in the
            # Elasticsearch document (`PostDocument`).
            'tags': 'tags.raw',

            # The dictionary key (in this case `num_views`) is the name of
            # the corresponding GraphQL query argument. Since no lookups
            # or default_lookup is provided, defaults are used (all lookups
            # available, term is the default lookup). The dictionary value
            # (in this case `num_views`) is the field name in the
            # Elasticsearch document (`PostDocument`).
            'num_views': 'num_views',
        }

        # For `SearchFilterBackend` backend
        search_fields = {
            'title': {'boost': 4},
            'content': {'boost': 2},
            'category': None,
        }

        # For `OrderingFilterBackend` backend
        ordering_fields = {
            # The dictionary key (in this case `tags`) is the name of
            # the corresponding GraphQL query argument. The dictionary
            # value (in this case `tags.raw`) is the field name in the
            # Elasticsearch document (`PostDocument`).
            'title': 'title.raw',

            # The dictionary key (in this case `created_at`) is the name of
            # the corresponding GraphQL query argument. The dictionary
            # value (in this case `created_at`) is the field name in the
            # Elasticsearch document (`PostDocument`).
            'created_at': 'created_at',

            # The dictionary key (in this case `num_views`) is the name of
            # the corresponding GraphQL query argument. The dictionary
            # value (in this case `num_views`) is the field name in the
            # Elasticsearch document (`PostDocument`).
            'num_views': 'num_views',
        }

        # For `DefaultOrderingFilterBackend` backend
        ordering_defaults = (
            '-num_views',  # Field name in the Elasticsearch document
            'title.raw',  # Field name in the Elasticsearch document
        )

        # For `HighlightFilterBackend` backend
        highlight_fields = {
            'title': {
                'enabled': True,
                'options': {
                    'pre_tags': ["<b>"],
                    'post_tags': ["</b>"],
                }
            },
            'content': {
                'options': {
                    'fragment_size': 50,
                    'number_of_fragments': 3
                }
            },
            'category': {},
        }

# Query definition
class Query(graphene.ObjectType):
    all_post_documents = ElasticsearchConnectionField(Post)

# Schema definition
schema = graphene.Schema(query=Query)
Filter
Sample queries

Since we didn’t specify any lookups on category, by default all lookups are available and the default lookup would be term. Note, that in the {value:"Elastic"} part, the value stands for default lookup, whatever it has been set to.

query PostsQuery {
  allPostDocuments(filter:{category:{value:"Elastic"}}) {
    edges {
      node {
        id
        title
        category
        content
        createdAt
        comments
      }
    }
  }
}

But, we could use another lookup (in example below - terms). Note, that in the {terms:["Elastic", "Python"]} part, the terms is the lookup name.

query PostsQuery {
  allPostDocuments(
        filter:{category:{terms:["Elastic", "Python"]}}
    ) {
    edges {
      node {
        id
        title
        category
        content
        createdAt
        comments
      }
    }
  }
}

Or apply a gt (range) query in addition to filtering:

{
  allPostDocuments(filter:{
        category:{term:"Python"},
        numViews:{gt:"700"}
    }) {
    edges {
      node {
        category
        title
        comments
        numViews
      }
    }
  }
}
Implemented filter lookups

The following lookups are available:

  • contains

  • ends_with (or endsWith for camelCase)

  • exclude

  • exists

  • gt

  • gte

  • in

  • is_null (or isNull for camelCase)

  • lt

  • lte

  • prefix

  • range

  • starts_with (or startsWith for camelCase)

  • term

  • terms

  • wildcard

See dedicated documentation on filter lookups for more information.

Ordering

Possible choices are ASC and DESC.

query {
  allPostDocuments(
        filter:{category:{term:"Photography"}},
        ordering:{title:ASC}
    ) {
    edges {
      node {
        category
        title
        content
        numViews
        tags
      }
    }
  }
}
Pagination

The first, last, before and after arguments are supported. By default number of results is limited to 100.

query {
  allPostDocuments(first:12) {
    pageInfo {
      startCursor
      endCursor
      hasNextPage
      hasPreviousPage
    }
    edges {
      cursor
      node {
        category
        title
        content
        numViews
      }
    }
  }
}
Highlighting

Simply, list the fields you want to highlight. This works only in combination with search.

query {
  allPostDocuments(
        search:{content:{value:"alice"}, title:{value:"alice"}},
        highlight:[category, content]
    ) {
    edges {
      node {
        title
        content
        highlight
      }
      cursor
    }
  }
}

Road-map

Road-map and development plans.

This package is designed after django-elasticsearch-dsl-drf and is intended to offer similar functionality.

Lots of features are planned to be released in the upcoming Beta releases:

  • Suggester backend.

  • Nested backend.

  • Geo-spatial backend.

  • Filter lookup geo_bounding_box (or geoBoundingBox for camelCase).

  • Filter lookup geo_distance (or geoDistance for camelCase).

  • Filter lookup geo_polygon (or geoPolygon for camelCase).

  • More-like-this backend.

Stay tuned or reach out if you want to help.

Testing

Project is covered with tests.

Testing with Docker

make docker-test

Running tests with virtualenv or tox

By defaults tests are executed against the Elasticsearch 7.x.

Run Elasticsearch 7.x with Docker

docker-compose up elasticsearch

Install test requirements

pip install -r requirements/test.txt

To test with all supported Python versions type:

tox

To test against specific environment, type:

tox -e py38-elastic7

To test just your working environment type:

./runtests.py

To run a single test module in your working environment type:

./runtests.py src/graphene_elastic/tests/test_filter_backend.py

To run a single test class in a given test module in your working environment type:

./runtests.py src/graphene_elastic/tests/test_filter_backend.py::FilterBackendElasticTestCase

Debugging

For development purposes, you could use the flask app (easy to debug). Standard pdb works (import pdb; pdb.set_trace()). If ipdb does not work well for you, use ptpdb.

Writing documentation

Keep the following hierarchy.

=====
title
=====

header
======

sub-header
----------

sub-sub-header
~~~~~~~~~~~~~~

sub-sub-sub-header
^^^^^^^^^^^^^^^^^^

sub-sub-sub-sub-header
++++++++++++++++++++++

sub-sub-sub-sub-sub-header
**************************

License

GPL-2.0-only OR LGPL-2.1-or-later

Support

For any security issues contact me at the e-mail given in the Author section. For overall issues, go to GitHub.

Author

Artur Barseghyan <artur.barseghyan@gmail.com>

Project documentation

Contents:

Concepts

In order to explain in details, we need an imaginary app.

Sample document definition

search_index/documents/post.py

See examples/search_index/documents/post.py for full example.

import datetime
from elasticsearch_dsl import (
    Boolean,
    Date,
    Document,
    InnerDoc,
    Keyword,
    Nested,
    Text,
    Integer,
)

class Comment(InnerDoc):

    author = Text(fields={'raw': Keyword()})
    content = Text(analyzer='snowball')
    created_at = Date()

    def age(self):
        return datetime.datetime.now() - self.created_at


class Post(Document):

    title = Text(
        fields={'raw': Keyword()}
    )
    content = Text()
    created_at = Date()
    published = Boolean()
    category = Text(
        fields={'raw': Keyword()}
    )
    comments = Nested(Comment)
    tags = Text(
        analyzer=html_strip,
        fields={'raw': Keyword(multi=True)},
        multi=True
    )
    num_views = Integer()

    class Index:
        name = 'blog_post'
        settings = {
            'number_of_shards': 1,
            'number_of_replicas': 1,
            'blocks': {'read_only_allow_delete': None},
        }

Sample schema definition

ConnectionField is the most flexible and feature rich solution you have. It uses filter backends which you can tie to your needs the way you want in a declarative manner.

schema.py

import graphene
from graphene_elastic import (
    ElasticsearchObjectType,
    ElasticsearchConnectionField,
)
from graphene_elastic.filter_backends import (
    FilteringFilterBackend,
    SearchFilterBackend,
    OrderingFilterBackend,
    DefaultOrderingFilterBackend,
)
from graphene_elastic.constants import (
    LOOKUP_FILTER_PREFIX,
    LOOKUP_FILTER_TERM,
    LOOKUP_FILTER_TERMS,
    LOOKUP_FILTER_WILDCARD,
    LOOKUP_QUERY_EXCLUDE,
    LOOKUP_QUERY_IN,
)

# Object type definition
class Post(ElasticsearchObjectType):

    class Meta(object):
        document = PostDocument
        interfaces = (Node,)
        filter_backends = [
            FilteringFilterBackend,
            SearchFilterBackend,
            OrderingFilterBackend,
            DefaultOrderingFilterBackend,
        ]

        # For `FilteringFilterBackend` backend
        filter_fields = {
            # The dictionary key (in this case `title`) is the name of
            # the corresponding GraphQL query argument. The dictionary
            # value could be simple or complex structure (in this case
            # complex). The `field` key points to the `title.raw`, which
            # is the field name in the Elasticsearch document
            # (`PostDocument`). Since `lookups` key is provided, number
            # of lookups is limited to the given set, while term is the
            # default lookup (as specified in `default_lookup`).
            'title': {
                'field': 'title.raw',  # Field name in the Elastic doc
                # Available lookups
                'lookups': [
                    LOOKUP_FILTER_TERM,
                    LOOKUP_FILTER_TERMS,
                    LOOKUP_FILTER_PREFIX,
                    LOOKUP_FILTER_WILDCARD,
                    LOOKUP_QUERY_IN,
                    LOOKUP_QUERY_EXCLUDE,
                ],
                # Default lookup
                'default_lookup': LOOKUP_FILTER_TERM,
            },

            # The dictionary key (in this case `category`) is the name of
            # the corresponding GraphQL query argument. Since no lookups
            # or default_lookup is provided, defaults are used (all lookups
            # available, term is the default lookup). The dictionary value
            # (in this case `category.raw`) is the field name in the
            # Elasticsearch document (`PostDocument`).
            'category': 'category.raw',

            # The dictionary key (in this case `tags`) is the name of
            # the corresponding GraphQL query argument. Since no lookups
            # or default_lookup is provided, defaults are used (all lookups
            # available, term is the default lookup). The dictionary value
            # (in this case `tags.raw`) is the field name in the
            # Elasticsearch document (`PostDocument`).
            'tags': 'tags.raw',

            # The dictionary key (in this case `num_views`) is the name of
            # the corresponding GraphQL query argument. Since no lookups
            # or default_lookup is provided, defaults are used (all lookups
            # available, term is the default lookup). The dictionary value
            # (in this case `num_views`) is the field name in the
            # Elasticsearch document (`PostDocument`).
            'num_views': 'num_views',
        }

        # For `SearchFilterBackend` backend
        search_fields = {
            'title': {'boost': 4},
            'content': {'boost': 2},
            'category': None,
        }

        # For `OrderingFilterBackend` backend
        ordering_fields = {
            # The dictionary key (in this case `tags`) is the name of
            # the corresponding GraphQL query argument. The dictionary
            # value (in this case `tags.raw`) is the field name in the
            # Elasticsearch document (`PostDocument`).
            'title': 'title.raw',

            # The dictionary key (in this case `created_at`) is the name of
            # the corresponding GraphQL query argument. The dictionary
            # value (in this case `created_at`) is the field name in the
            # Elasticsearch document (`PostDocument`).
            'created_at': 'created_at',

            # The dictionary key (in this case `num_views`) is the name of
            # the corresponding GraphQL query argument. The dictionary
            # value (in this case `num_views`) is the field name in the
            # Elasticsearch document (`PostDocument`).
            'num_views': 'num_views',
        }

        # For `DefaultOrderingFilterBackend` backend
        ordering_defaults = (
            '-num_views',  # Field name in the Elasticsearch document
            'title.raw',  # Field name in the Elasticsearch document
        )

# Query definition
class Query(graphene.ObjectType):
    all_post_documents = ElasticsearchConnectionField(Post)

# Schema definition
schema = graphene.Schema(query=Query)
filter_backends

The list of filter backends you want to enable on your schema.

The following filter backends are available at the moment:

  • FilteringFilterBackend,

  • SearchFilterBackend

  • OrderingFilterBackend

  • DefaultOrderingFilterBackend

graphene-elastic would dynamically transform your definitions into fields and arguments to use for searching, filtering, ordering, etc.

filter_fields

Used by FilteringFilterBackend backend.

It’s dict with keys representing names of the arguments that would become available to the GraphQL as input for querying. The values of the dict would be responsible for precise configuration of the queries.

Let’s review the following example:

'title': {
    'field': 'title.raw',
    'lookups': [
        LOOKUP_FILTER_TERM,
        LOOKUP_FILTER_TERMS,
        LOOKUP_FILTER_PREFIX,
        LOOKUP_FILTER_WILDCARD,
        LOOKUP_QUERY_IN,
        LOOKUP_QUERY_EXCLUDE,
    ],
    'default_lookup': LOOKUP_FILTER_TERM,
}

field

The field is the corresponding field of the Elasticsearch Document. In the example below it’s title.raw.

class Post(Document):

    title = Text(
        fields={'raw': Keyword()}
    )

lookups

In the given example, the available lookups for the title.raw would be limited to term, terms, prefix, wildcard, in and exclude. The latter two are functional queries, as you often see such lookups in ORMs (such as Django) while the others are Elasticsearch native lookups.

In our query we would then explicitly specify the lookup name (term in the example below):

query PostsQuery {
  allPostDocuments(filter:{title:{term:"Elasticsearch 7.1 released!"}}) {
    edges {
      node {
        id
        title
        category
        content
        createdAt
        comments
      }
    }
  }
}

default_lookup

But we could also fallback to the default_lookup (term in the example below).

Sample query using default_lookup:

query PostsQuery {
  allPostDocuments(filter:{title:{value:"Elasticsearch 7.1 released!"}}) {
    edges {
      node {
        id
        title
        category
        content
        createdAt
        comments
      }
    }
  }
}

In the block {title:{value:"Elasticsearch 7.1 released!"} the value would stand for the default_lookup value.

search_fields

Used by SearchFilterBackend backend.

ordering_fields

Used by OrderingFilterBackend backend.

Similarly to filter_fields, keys of the dict represent argument names that would become available to the GraphQL for queries. The value would be the field name of the corresponding Elasticsearch document.

ordering_defaults

Used by DefaultOrderingFilterBackend.

If no explicit ordering is given (in the GraphQL query), this would be the fallback - the default ordering. It’s expected to be a list or a tuple with field names to be used as default ordering. For descending ordering, add - (minus sign) as prefix to the field name.

Quick start

Clone the repository

git clone git@github.com:barseghyanartur/graphene-elastic.git && cd graphene-elastic

Start Elasticsearch

docker-compose up elasticsearch

Install requirements

pip install -r requirements.txt

Populate dummy data

./scripts/populate_elasticsearch_data.sh

Run the test server

./scripts/run_flask.sh

Open the graphiql client the browser

http://127.0.0.1:8001/graphql

Make some experiments

{
  allPostDocuments {
    pageInfo {
      startCursor
      endCursor
      hasNextPage
      hasPreviousPage
    }
    edges {
      cursor
      node {
        category
        title
        content
        numViews
      }
    }
  }
}

Run tests

./runtests.py

Filtering

Filter lookups

The following lookups are available:

  • contains

  • ends_with (or endsWith for camelCase)

  • exclude

  • exists

  • gt

  • gte

  • in

  • is_null (or isNull for camelCase)

  • lt

  • lte

  • prefix

  • range

  • starts_with (or startsWith for camelCase)

  • term

  • terms

  • wildcard

Filter lookup contains
query {
  allPostDocuments(filter:{category:{contains:"tho"}}) {
    edges {
      node {
        category
        title
        content
        numViews
      }
    }
  }
}
Filter lookup ends_with

Note

endsWith for camelCase.

query {
  allPostDocuments(filter:{category:{endsWith:"thon"}}) {
    edges {
      node {
        category
        title
        content
        numViews
      }
    }
  }
}
Filter lookup exclude

For a single term:

query {
  allPostDocuments(filter:{category:{exclude:"Python"}}) {
    edges {
      node {
        category
        title
        content
        numViews
      }
    }
  }
}

For multiple terms:

query {
  allPostDocuments(filter:{category:{exclude:["Python", "Django"]}}) {
    edges {
      node {
        category
        title
        content
        numViews
      }
    }
  }
}
Filter lookup exists
query {
  allPostDocuments(filter:{category:{exists:true}}) {
    edges {
      node {
        category
        title
        content
        numViews
      }
    }
  }
}
Filter lookup gt

Available value types are:

  • decimal

  • float

  • int

  • datetime

  • date

query {
  allPostDocuments(filter:{numViews:{gt:{decimal:"100.05"}}}) {
    edges {
      node {
        category
        title
        content
        numViews
      }
    }
  }
}
Filter lookup gte

Same value types as in ``gt``

query {
  allPostDocuments(filter:{numViews:{gte:{decimal:"100.05"}}}) {
    edges {
      node {
        category
        title
        content
        numViews
      }
    }
  }
}
Filter lookup in
query {
  allPostDocuments(filter:{tags:{in:["photography", "models"]}}) {
    edges {
      node {
        category
        title
        content
        numViews
        tags
      }
    }
  }
}
Filter lookup lt

Same value types as in ``gt``

query {
  allPostDocuments(filter:{numViews:{lt:{date:"2019-10-09"}}}) {
    edges {
      node {
        category
        title
        content
        numViews
      }
    }
  }
}
Filter lookup lte

Same value types as in ``gt``

query {
  allPostDocuments(filter:{numViews:{lte:{date:"2009-10-09"}}}) {
    edges {
      node {
        category
        title
        content
        numViews
      }
    }
  }
}
Filter lookup prefix
query {
  allPostDocuments(filter:{category:{prefix:"Pyth"}}) {
    edges {
      node {
        category
        title
        content
        numViews
        comments
      }
    }
  }
}
Filter lookup range

Same value types as in ``gt``

query {
  allPostDocuments(filter:{numViews:{range:{
        lower:{decimal:"100.05"},
        upper:{decimal:"200.05"}
      }}}) {
    edges {
      node {
        category
        title
        content
        numViews
      }
    }
  }
}
Filter lookup starts_with

Note

startsWith for camelCase.

Alias for filter lookup ``prefix``.

Filter lookup term
query {
  allPostDocuments(filter:{category:{term:"Python"}}) {
    edges {
      node {
        category
        title
        content
        numViews
        comments
      }
    }
  }
}
Filter lookup terms
query {
  allPostDocuments(filter:{category:{terms:["Python", "Django"]}}) {
    edges {
      node {
        category
        title
        content
        numViews
        comments
      }
    }
  }
}
Filter lookup wildcard
query {
  allPostDocuments(filter:{category:{wildcard:"*ytho*"}}) {
    edges {
      node {
        category
        title
        content
        numViews
        comments
      }
    }
  }
}

Post-filter backend

Works the same way as FilteringFilterBackend, but does not affect aggregations.

Filter lookups

The following lookups are available:

  • contains

  • ends_with (or endsWith for camelCase)

  • exclude

  • exists

  • gt

  • gte

  • in

  • is_null (or isNull for camelCase)

  • lt

  • lte

  • prefix

  • range

  • starts_with (or startsWith for camelCase)

  • term

  • terms

  • wildcard

Filter lookup contains
query {
  allPostDocuments(postFilter:{category:{contains:"tho"}}) {
    edges {
      node {
        category
        title
        content
        numViews
      }
    }
  }
}
Filter lookup ends_with

Note

endsWith for camelCase.

query {
  allPostDocuments(postFilter:{category:{endsWith:"thon"}}) {
    edges {
      node {
        category
        title
        content
        numViews
      }
    }
  }
}
Filter lookup exclude

For a single term:

query {
  allPostDocuments(postFilter:{category:{exclude:"Python"}}) {
    edges {
      node {
        category
        title
        content
        numViews
      }
    }
  }
}

For multiple terms:

query {
  allPostDocuments(postFilter:{category:{exclude:["Python", "Django"]}}) {
    edges {
      node {
        category
        title
        content
        numViews
      }
    }
  }
}
Filter lookup exists
query {
  allPostDocuments(postFilter:{category:{exists:true}}) {
    edges {
      node {
        category
        title
        content
        numViews
      }
    }
  }
}
Filter lookup gt
query {
  allPostDocuments(postFilter:{numViews:{gt:{decimal:"100"}}}) {
    edges {
      node {
        category
        title
        content
        numViews
      }
    }
  }
}
Filter lookup gte
query {
  allPostDocuments(postFilter:{numViews:{gte:{decimal:"100"}}}) {
    edges {
      node {
        category
        title
        content
        numViews
      }
    }
  }
}
Filter lookup in
query {
  allPostDocuments(postFilter:{tags:{in:["photography", "models"]}}) {
    edges {
      node {
        category
        title
        content
        numViews
        tags
      }
    }
  }
}
Filter lookup lt
query {
  allPostDocuments(postFilter:{numViews:{lt:{decimal:"200"}}}) {
    edges {
      node {
        category
        title
        content
        numViews
      }
    }
  }
}
Filter lookup lte
query {
  allPostDocuments(postFilter:{numViews:{lte:{decimal:"200"}}}) {
    edges {
      node {
        category
        title
        content
        numViews
      }
    }
  }
}
Filter lookup prefix
query {
  allPostDocuments(postFilter:{category:{prefix:"Pyth"}}) {
    edges {
      node {
        category
        title
        content
        numViews
        comments
      }
    }
  }
}
Filter lookup range
query {
  allPostDocuments(postFilter:{numViews:{range:{
        lower:{decimal:"100"},
        upper:{decimal:"200"}
      }}}) {
    edges {
      node {
        category
        title
        content
        numViews
      }
    }
  }
}
Filter lookup starts_with

Note

startsWith for camelCase.

Alias for filter lookup ``prefix``.

Filter lookup term
query {
  allPostDocuments(postFilter:{category:{term:"Python"}}) {
    edges {
      node {
        category
        title
        content
        numViews
        comments
      }
    }
  }
}
Filter lookup terms
query {
  allPostDocuments(postFilter:{category:{terms:["Python", "Django"]}}) {
    edges {
      node {
        category
        title
        content
        numViews
        comments
      }
    }
  }
}
Filter lookup wildcard
query {
  allPostDocuments(postFilter:{category:{wildcard:"*ytho*"}}) {
    edges {
      node {
        category
        title
        content
        numViews
        comments
      }
    }
  }
}

Ordering

Possible choices are ASC and DESC.

query {
  allPostDocuments(
        filter:{category:{term:"Photography"}},
        ordering:{title:ASC}
    ) {
    edges {
      node {
        category
        title
        content
        numViews
        tags
      }
    }
  }
}

Multiple values are allowed:

query {
  allPostDocuments(
        filter:{category:{term:"Photography"}},
        ordering:{numViews:DESC, createdAt:ASC}
    ) {
    edges {
      node {
        category
        title
        content
        numViews
        tags
      }
    }
  }
}

Ordering by score is implemented as well:

query {
  allPostDocuments(
        search:{query:"Alice"},
        ordering:{score:DESC}
    ) {
    edges {
      node {
        id
        title
        content
        category
        createdAt
        score
      }
    }
  }
}

Highlight

Sample type definition:

from graphene import Node
from graphene_elastic import ElasticsearchObjectType
from graphene_elastic.filter_backends import HighlightFilterBackend

class Post(ElasticsearchObjectType):

    class Meta:

        document = PostDocument
        interfaces = (Node,)
        filter_backends = [
            # ...
            HighlightFilterBackend,  # Important
            # ...
        ]

        # ...

        # For `HighlightFilterBackend` backend
        highlight_fields = {
            'title': {
                'enabled': True,
                'options': {
                    'pre_tags': ["<b>"],
                    'post_tags': ["</b>"],
                }
            },
            'content': {
                'options': {
                    'fragment_size': 50,
                    'number_of_fragments': 3
                }
            },
            'category': {},
        }

        # ...

Sample query:

query {
  allPostDocuments(
        search:{content:{value:"since"}, title:{value:"decide"}},
        highlight:[category, content]
    ) {
    edges {
      node {
        title
        content
        highlight
      }
      cursor
    }
  }
}

Sample response:

{
  "data": {
    "allPostDocuments": {
      "edges": [
        {
          "node": {
            "title": "PM decide.",
            "content": "Cut dog young only. Whole natural state Republican year.\nFinancial oil current sea. Mind large similar probably lawyer since. Son control fire remember.",
            "highlight": {
              "title": [
                "PM <b>decide</b>."
              ],
              "content": [
                "Mind large similar probably lawyer <em>since</em>."
              ]
            }
          },
          "cursor": "YXJyYXljb25uZWN0aW9uOjA="
        },
        {
          "node": {
            "title": "Many add.",
            "content": "Read almost consumer perform water. Really protect push send body wind. Training point since involve public last let new.",
            "highlight": {
              "content": [
                "Training point <em>since</em> involve public last let new."
              ]
            }
          },
          "cursor": "YXJyYXljb25uZWN0aW9uOjE="
        }
    }
  }
}

Source

Source query is meant to lighten the Elasticsearch load by reducing amount of data sent around. Although GraphQL seems to have solved the issue between frontend and backend, Elasticsearch would still send all the data to the backend. That’s where we might use the source backend.

Sample type definition:

from graphene import Node
from graphene_elastic import ElasticsearchObjectType
from graphene_elastic.filter_backends import SourceFilterBackend

class Post(ElasticsearchObjectType):

    class Meta:

        document = PostDocument
        interfaces = (Node,)
        filter_backends = [
            # ...
            SourceFilterBackend,  # Important
            # ...
        ]

Sample query:

query {
  allPostDocuments(
        search:{content:{value:"alice"}, title:{value:"alice"}},
        source:[title, id]
    ) {
    edges {
      node {
        id
        title
        content
        category
        comments
      }
      cursor
    }
  }
}

Sample response:

As you could see, although we do ask for more fields in the node {...} part, the requested fields are empty. We only get data in the fields we have specified in source (they are title and id).

{
  "data": {
    "allPostDocuments": {
      "edges": [
        {
          "node": {
            "id": "UG9zdDpvX0huUlcwQlhfYXJjd2RMc0w2aQ==",
            "title": "only Alice miss",
            "content": null,
            "category": null,
            "comments": []
          },
          "cursor": "YXJyYXljb25uZWN0aW9uOjA="
        },
        {
          "node": {
            "id": "UG9zdDpvZkhuUlcwQlhfYXJjd2RMc0w1Nw==",
            "title": "prevent Alice citizen",
            "content": null,
            "category": null,
            "comments": []
          },
          "cursor": "YXJyYXljb25uZWN0aW9uOjE="
        }
      ]
    }
  }
}

Score

Score is relevance in Elasticsearch.

Sample type definition:

from graphene import Node
from graphene_elastic import ElasticsearchObjectType
from graphene_elastic.filter_backends import ScoreFilterBackend, OrderingFilterBackend

class Post(ElasticsearchObjectType):

    class Meta:

        document = PostDocument
        interfaces = (Node,)
        filter_backends = [
            # ...
            ScoreFilterBackend,  # Important
            OrderingFilterBackend,  # Important
            # ...
        ]


        # For `OrderingFilterBackend` backend
        ordering_fields = {
            # Score
            'score': '_score',
        }

Sample query:

Note, that we want to order by relevance (most relevant on top).

query {
  allPostDocuments(
        search:{query:"Alice"},
        ordering:{score:DESC}
    ) {
    edges {
      node {
        id
        title
        content
        category
        createdAt
        score
      }
    }
  }
}

Sample response:

As you could see, score is calculated.

{
  "data": {
    "allPostDocuments": {
      "edges": [
        {
          "node": {
            "id": "UG9zdDpMNnBiV1hNQjhYRzdJclZ2X20waA==",
            "title": "Budget.",
            "category": "Elastic",
            "content": "Bed television public teacher behind human up.\nMind anyone politics ball cost wife try adult. College work for.\nPlay five ten not sort energy.\nCommon word behind spring. All behind voice policy.",
            "createdAt": "1973-03-12T00:00:00",
            "score": 20.420774
          }
        },
        ...
       ]
    }
  }
}

Query string backend

Implementation of Query string query.

Sample type definition

from graphene import Node
from graphene_elastic import ElasticsearchObjectType
from graphene_elastic.filter_backends import QueryStringBackend

class Post(ElasticsearchObjectType):

    class Meta:

        document = PostDocument
        interfaces = (Node,)
        filter_backends = [
            # ...
            QueryStringBackend,  # Important
            # ...
        ]

        query_string_options = {
            "fields": ["title^2", "content", "category"],
            "boost": 2,
        }

Sample query

query PostsQuery {
  allPostDocuments(
    queryString:"(White Rabbit) AND Alice"
  ) {
    edges {
      node {
        id
        title
        category
        content
        createdAt
        comments
      }
    }
  }
}

Sample response

{
  "data": {
    "allPostDocuments": {
      "edges": [
        {
          "node": {
            "id": "UG9zdDppLVozZDNZQmNDeUtjYnh5WTU5Vg==",
            "title": "Alice",
            "category": "MongoDB",
            "content": "Personal green well method day report. White Rabbit is dead. Take stuff newspaper soldier up.",
            "createdAt": "1994-01-01T00:00:00",
            "comments": [
              {
                "author": "Matthew Jones",
                "content": "Despite consumer safe since range opportunity.",
                "created_at": "1970-05-05T00:00:00"
              },
              {
                "author": "Larry Brown",
                "content": "Environment drug artist. Pattern source sound hope trip.",
                "created_at": "2005-07-24T00:00:00"
              }
            ]
          }
        }
      ]
    }
  }
}

Simple query string backend

Implementation of Simple query string query.

Sample type definition

from graphene import Node
from graphene_elastic import ElasticsearchObjectType
from graphene_elastic.filter_backends import SimpleQueryStringBackend

class Post(ElasticsearchObjectType):

    class Meta:

        document = PostDocument
        interfaces = (Node,)
        filter_backends = [
            # ...
            SimpleQueryStringBackend,  # Important
            # ...
        ]

        simple_query_string_options = {
            "fields": ["title^2", "content", "category"],
            "boost": 2,
        }

Sample query

query PostsQuery {
  allPostDocuments(
    simpleQueryString:"'White Rabbit' +Alice"
  ) {
    edges {
      node {
        id
        title
        category
        content
        createdAt
        comments
      }
    }
  }
}

Sample response

{
  "data": {
    "allPostDocuments": {
      "edges": [
        {
          "node": {
            "id": "UG9zdDppLVozZDNZQmNDeUtjYnh5WTU5Vg==",
            "title": "Alice",
            "category": "MongoDB",
            "content": "Personal green well method day report. White Rabbit is dead. Take stuff newspaper soldier up.",
            "createdAt": "1994-01-01T00:00:00",
            "comments": [
              {
                "author": "Matthew Jones",
                "content": "Despite consumer safe since range opportunity.",
                "created_at": "1970-05-05T00:00:00"
              },
              {
                "author": "Larry Brown",
                "content": "Environment drug artist. Pattern source sound hope trip.",
                "created_at": "2005-07-24T00:00:00"
              }
            ]
          }
        }
      ]
    }
  }
}

Pagination

Limits

By default, max number of fetched items is limited to 100. It’s configurable. Set the RELAY_CONNECTION_MAX_LIMIT setting to the desired value.

Enforce first or last

You could force users to provide first or last. Set RELAY_CONNECTION_ENFORCE_FIRST_OR_LAST to True for that.

User controlled pagination

The following (standard) arguments are available:

  • first

  • last

  • before

  • after

Sample query to return all results (limited by RELAY_CONNECTION_MAX_LIMIT setting only):

{
  allPostDocuments {
    pageInfo {
      startCursor
      endCursor
      hasNextPage
      hasPreviousPage
    }
    edges {
      cursor
      node {
        category
        title
        content
        numViews
      }
    }
  }
}

Sample query to return first 12 results:

{
  allPostDocuments(first:12) {
    pageInfo {
      startCursor
      endCursor
      hasNextPage
      hasPreviousPage
    }
    edges {
      cursor
      node {
        category
        title
        content
        numViews
      }
    }
  }
}

Sample query to return first 12 results after the given offset:

Custom filter backends

Filter backends can:

  • Add new graphene input types to the (query) schema.

  • Allow you to request additional information by adding new graphene fields to the schema.

  • Alter current queryset.

  • Alter slice, add additional information next to pageInfo and edges, such as facets, for example.

Let’s learn by example on the SourceFilterBackend which allows us to apply source query to the current search queryset.

import enum
import graphene

from graphen_elastic.filter_backends.base import BaseBackend
from graphen_elastic.constants import DYNAMIC_CLASS_NAME_PREFIX

class SourceFilterBackend(BaseBackend):
    """Source filter backend."""

    prefix = 'source'  # Name of the GraphQL query filter
    has_query_fields = True  # Indicates whether backend has own filtering fields

    # The ``source_fields`` is the config options that we set on the
    # ``Post`` object type. In this case - absolutely optional.
    @property
    def source_fields(self):
        """Source filter fields."""
        return getattr(
            self.connection_field.type._meta.node._meta,
            'filter_backend_options',
            {}
        ).get('source_fields', {})

    # This is where we dynamically create GraphQL filter fields for this
    # backend.
    def get_backend_filtering_fields(self, items, is_filterable_func, get_type_func):
        """Construct backend fields.

        :param items:
        :param is_filterable_func:
        :param get_type_func:
        :return:
        """
        _keys = list(
            self.connection_field.type._meta.node._meta.fields.keys()
        )
        _keys.remove('_id')
        params = zip(_keys, _keys)
        return {
            self.prefix: graphene.Argument(
                graphene.List(
                    graphene.Enum.from_enum(
                        enum.Enum(
                            "{}{}{}BackendEnum".format(
                                DYNAMIC_CLASS_NAME_PREFIX,
                                self.prefix.title(),
                                self.connection_field.type.__name__
                            ),
                            params
                        )
                    )
                )
            )
        }

    # Some data normalisation.
    def prepare_source_fields(self):
        """Prepare source fields.

        Possible structures:

            source_fields = ["title"]

        Or:

            search_fields = ["title", "author.*"]

        Or:

            source = {
                "includes": ["title", "author.*"],
                "excludes": [ "*.description" ]
            }

        :return: Filtering options.
        :rtype: dict
        """
        source_args = dict(self.args).get(self.prefix, [])

        source_fields = dict(self.source_fields)

        if source_args:
            return source_args
        return source_fields

    # This is where the queryset is being altered.
    def filter(self, queryset):
        """Filter.

        :param queryset:
        :return:
        """
        source_fields = self.prepare_source_fields()

        if source_fields:
            queryset = queryset.source(source_fields)

        return queryset

Settings

Defaults are:

DEFAULTS = {
    "SCHEMA": None,
    "SCHEMA_OUTPUT": "schema.json",
    "SCHEMA_INDENT": 2,
    # "MIDDLEWARE": (),
    # Set to True if the connection fields must have
    # either the first or last argument
    "RELAY_CONNECTION_ENFORCE_FIRST_OR_LAST": False,
    # Max items returned in ConnectionFields / FilterConnectionFields
    "RELAY_CONNECTION_MAX_LIMIT": 100,
    "LOGGING_LEVEL": logging.ERROR,
}

See the example below to get a grasp on how to override:

import json
import logging
import os

DEFAULTS = {
    "SCHEMA": None,
    "SCHEMA_OUTPUT": "schema.json",
    "SCHEMA_INDENT": 2,
    # Set to True if the connection fields must have
    # either the first or last argument
    "RELAY_CONNECTION_ENFORCE_FIRST_OR_LAST": False,
    # Max items returned in ConnectionFields / FilterConnectionFields
    "RELAY_CONNECTION_MAX_LIMIT": 100,
    "LOGGING_LEVEL": logging.DEBUG,
}

os.environ.setdefault(
    "GRAPHENE_ELASTIC",
    json.dumps(DEFAULTS)
)

Running Elasticsearch

For development and testing purposes, it’s often handy to be able to quickly switch between different Elasticsearch versions. You could make use of the following boxes/containers for development and testing.

For all containers/boxes mentioned below, no authentication is required (for Elasticsearch).

Docker

Project default
docker-compose up elasticsearch
Run specific version
6.x

6.3.2

docker pull docker.elastic.co/elasticsearch/elasticsearch:6.3.2
docker run -p 9200:9200 -e "discovery.type=single-node" -e "xpack.security.enabled=false" docker.elastic.co/elasticsearch/elasticsearch:6.3.2

6.4.0

docker pull docker.elastic.co/elasticsearch/elasticsearch:6.4.0
docker run -p 9200:9200 -e "discovery.type=single-node" -e "xpack.security.enabled=false" docker.elastic.co/elasticsearch/elasticsearch:6.4.0
7.x

7.1.1

docker pull docker.elastic.co/elasticsearch/elasticsearch:7.1.1
docker run -p 9200:9200 -e "discovery.type=single-node" -e "xpack.security.enabled=false" docker.elastic.co/elasticsearch/elasticsearch:7.1.1

FAQ

You will find a lot of useful information in the documentation.

Additionally, all raised issues that were questions have been marked as question, so you could take a look at the closed (question) issues.

Questions and answers

Question

What about authentication and/or filtering the results based on authenticated user.

Answer

Check this doc


Debugging

Logging queries to console

The LOGGING_LEVEL key represents the logging level (defaults to logging.ERROR). Override if needed.

Typical development setup would be:

import json
import logging
import os

DEFAULTS = {
    # ...
    "LOGGING_LEVEL": logging.DEBUG,
    # ...
}

os.environ.setdefault(
    "GRAPHENE_ELASTIC",
    json.dumps(DEFAULTS)
)

Release history and notes

Sequence based identifiers are used for versioning (schema follows below):

major.minor[.revision]
  • It’s always safe to upgrade within the same minor version (for example, from 0.3 to 0.3.4).

  • Minor version changes might be backwards incompatible. Read the release notes carefully before upgrading (for example, when upgrading from 0.3.4 to 0.4).

  • All backwards incompatible changes are mentioned in this document.

0.8.1

Unreleased

  • Drop support for Python 3.6. No specific code changes. However, since it’s no longer possible to pull Python 3.6 directly from GitHub CI, to simplify things we simply drop it.

0.8

2022-07-31

Note

The elasticsearch and elasticsearch-dsl packages are no longer installed by default. You must either install them explicitly in your requirements or install alongside this package as optional dependencies as follows: pip install graphene-elastic[elasticsearch]. Alternatively, you can use opensearch-py and opensearch-dsl. You would then need to install the opensearch-py and opensearch-dsl packages explicitly in your requirements or install alongside this package as optional dependencies as follows: pip install graphene-elastic[opensearch].

  • Added support for OpenSearch (1.x and 2.x).

  • Belated migration to GitHub Actions.

0.7

2021-03-08

Note

First beta release.

Note

Release dedicated to defenders of Armenia and Artsakh (Nagorno Karabakh) and all the victims of Turkish and Azerbaijani aggression.

  • ObjectField/NestedField to ObjectType and added nested filter to FilteringFilterBackend.

0.6.6

2020-12-26

  • Enable middleware.

  • Tested against Python 3.9 and 3.10.

0.6.5

2020-12-19

Note

Release dedicated to defenders of Armenia and Artsakh (Nagorno Karabakh) and all the victims of Turkish and Azerbaijani aggression.

  • Added QueryStringBackend.

0.6.4

2020-12-12

Note

Release dedicated to defenders of Armenia and Artsakh (Nagorno Karabakh) and all the victims of Turkish and Azerbaijani aggression.

  • Added SimpleQueryStringBackend.

0.6.3

2020-07-19

Note

Release dedicated to defenders of Armenia and Artsakh (Nagorno Karabakh) and all the victims of Turkish and Azerbaijani aggression.

  • Added ScoreFilterBackend and ordering by score.

0.6.2

2020-07-07

  • Renamed JSONString to ElasticJSONString and changed references in related files. The reason for this change is to support grapehene_federation build_schema which eventually helps build federated schemas

0.6.1

2020-02-13

  • Tested against Python 3.8.

  • Tested against Elasticsearch 6.x and 7.x on Travis.

  • Replace some custom code parts (casing related) with stringcase package functionality.

0.6

2019-10-11

Note

Release dedicated to John Lennon. Happy birthday, dear John!

Note

This release introduces minor backwards incompatibility for range, gt, gte, lt and lte filters. You should update your code.

  • The range, gt, gte, lt and lte filters are now complex input types. This makes it possible to use the following types in comparison: decimal.Decimal, float, int, datetime.datetime and datetime.date.

Sample new GraphQL query:

query {
  allPostDocuments(postFilter:{numViews:{gt:{decimal:"100.00"}}}) {
    edges {
      node {
        category
        title
        content
        numViews
      }
    }
  }
}

Sample old GraphQL query:

query {
  allPostDocuments(postFilter:{numViews:{gt:"100.00"}}) {
    edges {
      node {
        category
        title
        content
        numViews
      }
    }
  }
}

0.5

2019-09-29

  • PostFilter backend.

  • Documentation improvements.

0.4

2019-09-23

  • Added faceted search backend (with global aggregations support).

  • Some refactoring which makes possible for the backends to alter the connection. A lot of minor changes. If you have written custom filter backend, you most likely need to modify some parts.

0.3

2019-09-20

  • Minor refactoring allowing third-party independent backends do a lot more without touching the core.

  • Source filter backend.

  • More tests.

0.2

2019-09-18

  • Highlight filter backend.

0.1

2019-09-08

  • Documentation fixes.

  • Speed up tests.

  • Clean up requirements.

0.0.13

2019-09-07

  • Documentation improvements and fixes.

  • Clean up.

0.0.12

2019-09-06

Note

In memory of Erik Slim. RIP.

  • More tests.

0.0.11

2019-09-05

  • Fixes in search backend.

0.0.10

2019-09-04

  • Fixes.

  • Clean up.

0.0.9

2019-09-03

  • Added pagination.

  • Documentation improvements.

0.0.8

2019-09-02

  • Tested default ordering backend.

  • Documentation improvements.

0.0.7

2019-09-01

  • Ordering backend.

  • Added more filter lookups.

  • Minor fixes in existing filter lookups.

  • Improved test coverage for the filtering backend.

  • Documentation improvements.

0.0.6

2019-08-30

  • Added more filter lookups.

  • Fixes in filtering backend.

  • Improved test coverage for the filtering backend.

  • Documentation improvements.

0.0.5

2019-08-30

  • Implemented custom lookups in favour of a single lookup attribute.

  • Updated tests.

0.0.4

2019-08-28

  • Fixed travis config (moved to elasticsearch 6.x on travis, since 7.x was causing problems).

  • Fixes in setup.py.

0.0.3

2019-08-26

  • Documentation fixes.

  • Add test suite and initial tests for filter backend and search backend.

0.0.2

2019-08-25

  • Added dynamic lookup generation for the filter backend.

  • Working lookup param argument handling on the schema (filter backend).

0.0.1

2019-08-24

  • Initial alpha release.

graphene_elastic package

Subpackages

graphene_elastic.filter_backends package
Subpackages
graphene_elastic.filter_backends.faceted_search package
Submodules
graphene_elastic.filter_backends.faceted_search.common module
class graphene_elastic.filter_backends.faceted_search.common.FacetedSearchFilterBackend(connection_field, args=None)[source]

Bases: BaseBackend

Faceted search filter backend.

aggregate(queryset, agg_field_name_getter=<function default_agg_field_name_getter>, agg_bucket_name_getter=<function default_agg_bucket_name_getter>)[source]

Aggregate.

Parameters:
  • queryset

  • agg_field_name_getter – callable.

  • agg_bucket_name_getter

Returns:

alter_connection(connection, slice)[source]

Alter connection object.

You can add various properties here, returning the altered object. Typical use-case would be adding facets to the connection.

Parameters:
  • connection

  • slice

Returns:

construct_facets()[source]

Construct facets.

Turns the following structure:

>>> {
>>>     'publisher': {
>>>         'field': 'publisher.raw',
>>>         'facet': TermsFacet,
>>>         'enabled': False,
>>>     }
>>>     'date_published': {
>>>         'field': 'date_published',
>>>         'facet': DateHistogramFacet,
>>>         'options': {
>>>             'interval': 'month',
>>>         },
>>>         'enabled': True,
>>>     },
>>> }

Into the following structure:

>>> {
>>>     'publisher': TermsFacet(field='publisher.raw'),
>>>     'publishing_frequency': DateHistogramFacet(
>>>         field='date_published.raw',
>>>         interval='month'
>>>     ),
>>> }
property faceted_search_fields

Faceted search filter fields.

field_belongs_to(field_name)[source]

Check if given filter field belongs to the backend.

Parameters:

field_name

Returns:

filter(queryset)[source]

Filter the queryset.

Parameters:

queryset (elasticsearch_dsl.search.Search) – Base queryset.

Returns:

Updated queryset.

Return type:

elasticsearch_dsl.search.Search

get_backend_query_fields(items, is_filterable_func, get_type_func)[source]

Construct backend filtering fields.

Parameters:
  • items

  • is_filterable_func

  • get_type_func

Returns:

get_faceted_search_query_params()[source]

Get highlight query params.

Returns:

List of search query params.

Return type:

list

has_connection_fields = True
has_query_fields = True
prefix = 'facets'
prepare_faceted_search_fields()[source]

Prepare faceted search fields.

Prepares the following structure:

>>> {
>>>     'publisher': {
>>>         'field': 'publisher.raw',
>>>         'facet': TermsFacet,
>>>         'enabled': False,
>>>     }
>>>     'date_published': {
>>>         'field': 'date_published.raw',
>>>         'facet': DateHistogramFacet,
>>>         'options': {
>>>             'interval': 'month',
>>>         },
>>>         'enabled': True,
>>>     },
>>> }
Returns:

Faceted search fields options.

Return type:

dict

graphene_elastic.filter_backends.filtering package
Submodules
graphene_elastic.filter_backends.filtering.common module
class graphene_elastic.filter_backends.filtering.common.FilteringFilterBackend(connection_field, args=None)[source]

Bases: BaseBackend, FilteringFilterMixin

Filtering filter backend.

field_belongs_to(field_name)[source]

Check if given filter field belongs to the backend.

Parameters:

field_name

Returns:

filter(queryset)[source]

Filter.

property filter_args_mapping
property filter_fields

Filtering filter fields.

get_backend_query_fields(items, is_filterable_func, get_type_func)[source]

Fail proof override.

Parameters:
  • items

  • is_filterable_func

  • get_type_func

Returns:

get_field_lookup_param(field_name)[source]

Get field lookup param.

Parameters:

field_name

Returns:

get_field_options(field_name, filter_fields=None)[source]

默认从Node中配置中读取,如果没有则从document中读取

可能的字段名: 1. author 2. comments.author 3. comments.author.name

get_field_type(field_name, field_value, base_field_type)[source]

Get field type.

Returns:

get_filter_query_params()[source]

Get query params to be filtered on.

We can either specify it like this:

query_params = {
‘category’: {

‘value’: ‘Elastic’,

}

}

Or using specific lookup:

query_params = {
‘category’: {

‘term’: ‘Elastic’, ‘range’: {

‘lower’: Decimal(‘3.0’)

}

}

}

Note, that value would only work on simple types (string, integer, decimal). For complex types you would have to use complex param anyway. Therefore, it should be forbidden to set default_lookup to a complex field type.

Sample values:

query_params = {
‘category’: {

‘value’: ‘Elastic’,

}, ‘comments’: {

‘author’: {
‘name’: {

‘value’: ‘Elastic’

}

}

}

}

filter_fields = {
‘category’: {

‘field’: ‘category.raw’, ‘type’: ‘normal’, ‘default_lookup’: ‘term’, ‘lookups’: (

‘term’, ‘terms’, ‘range’, ‘exists’, ‘prefix’, ‘wildcard’, ‘contains’, ‘in’, ‘gt’, ‘gte’, ‘lt’, ‘lte’, ‘starts_with’, ‘ends_with’, ‘is_null’, ‘exclude’

)

}, ‘comments’: {

‘field’: ‘comments’, ‘type’: ‘nested’, ‘properties’: {

‘author’: {

‘type’: ‘object’, ‘path’: ‘comments.author’, ‘properties’: {

‘name’: {

‘type’: ‘normal’, ‘field’: ‘author.name’, ‘default_lookups’: ‘term’, ‘lookups’: (

)

}

}

}

}

}

}

field_name = ‘category’ {

‘inventory_type’: {‘value’: ‘1’}, ‘spu’: {

‘supplier_entityms_entity_id’: {

‘contains’: ‘Elastic’

}, ‘brand’: {

‘code’: {

‘term’: ‘Elastic’

}

}

}

}

get_nested_field_type(field_name, field_value, base_field_type, field_options)[source]
has_query_fields = True
prefix = 'filter'
prepare_filter_fields()[source]

Prepare filter fields

Assume that we have a document like this.

```python class Comment(InnerDoc):

author = Text(fields={‘raw’: Keyword()}) content = Text(analyzer=’snowball’) created_at = Date()

def age(self):

return datetime.now() - self.created_at

class Post(Document):

title = Text() title_suggest = Completion() created_at = Date() published = Boolean() category = Text(

analyzer=html_strip, fields={‘raw’: Keyword()}

)

comments = Nested(Comment)

```

Possible structures:

filter_fields = {
‘title’: {

‘type’: ‘normal|object|nested’, ‘field’: ‘title’ # custom field name ‘lookups’: [

… # custom lookup list

], ‘default_lookup’: … # custom default lookup

}, ‘created_at’: {

‘type’: ‘normal’, ‘field’: ‘created_at’, ‘lookups’: [

LOOKUP_FILTER_RANGE # only range

]

}, ‘published’: LOOKUP_FILTER_TERM # treated as default lookup …

}

We shall finally have:

filter_fields = {
‘title’: {

‘type’: ‘normal’, ‘field’: ‘title.raw’, ‘lookups’: [

], ‘default_lookup’: …

}, … # any else fields indexed of this document ‘comments’: {

‘type’: ‘nested’, ‘properties’: {

‘author’: {

‘type’: ‘normal’, ‘field’: ‘comments.author’, …

}, ‘content’: {

‘type’: ‘normal’, ‘field’: ‘comments.content’, …

}

}

}

}

prepare_query_params()[source]

Prepare query params.

Returns:

graphene_elastic.filter_backends.filtering.mixins module
class graphene_elastic.filter_backends.filtering.mixins.FilteringFilterMixin[source]

Bases: object

Filtering filter mixin.

apply_filter: Callable
classmethod apply_filter_prefix(queryset, options, value)[source]

Apply prefix filter.

Syntax:

TODO

Example:

query {
allPostDocuments(filter:{category:{prefix:”Pyth”}}) {
edges {
node {

category title content numViews comments

}

}

}

}

Parameters:
  • queryset (elasticsearch_dsl.search.Search) – Original queryset.

  • options (dict) – Filter options.

  • value (str) – value to filter on.

Returns:

Modified queryset.

Return type:

elasticsearch_dsl.search.Search

classmethod apply_filter_range(queryset, options, value)[source]

Apply range filter.

Syntax:

TODO

Example:

{
allPostDocuments(filter:{numViews:{range:{

lower:{decimal:”100”}, upper:{decimal:”200”}

}}}) {

edges {
node {

category title content numViews

}

}

}

}

Parameters:
  • queryset (elasticsearch_dsl.search.Search) – Original queryset.

  • options (dict) – Filter options.

  • value (str) – value to filter on.

Returns:

Modified queryset.

Return type:

elasticsearch_dsl.search.Search

classmethod apply_filter_term(queryset, options, value)[source]

Apply term filter.

Syntax:

TODO

Example:

query {
allPostDocuments(filter:{category:{term:”Python”}}) {
edges {
node {

category title content numViews comments

}

}

}

}

Parameters:
  • queryset (elasticsearch_dsl.search.Search) – Original queryset.

  • options (dict) – Filter options.

  • value (str) – value to filter on.

Returns:

Modified queryset.

Return type:

elasticsearch_dsl.search.Search

classmethod apply_filter_terms(queryset, options, value)[source]

Apply terms filter.

Syntax:

TODO

Note, that number of values is not limited.

Example:

query {
allPostDocuments(filter:{category:{

terms:[“Python”, “Django”]

}}) {

edges {
node {

category title content numViews comments

}

}

}

}

Parameters:
  • queryset (elasticsearch_dsl.search.Search) – Original queryset.

  • options (dict) – Filter options.

  • value (mixed: either str or iterable (list, tuple).) – value to filter on.

Returns:

Modified queryset.

Return type:

elasticsearch_dsl.search.Search

apply_query: Callable
classmethod apply_query_contains(queryset, options, value)[source]

Apply contains filter.

Syntax:

TODO

Example:

query {
allPostDocuments(filter:{category:{contains:”tho”}}) {
edges {
node {

category title content numViews

}

}

}

}

Parameters:
  • queryset (elasticsearch_dsl.search.Search) – Original queryset.

  • options (dict) – Filter options.

  • value (str) – value to filter on.

Returns:

Modified queryset.

Return type:

elasticsearch_dsl.search.Search

classmethod apply_query_endswith(queryset, options, value)[source]

Apply endswith filter.

Syntax:

TODO

Example:

query {
allPostDocuments(filter:{category:{endsWith:”thon”}}) {
edges {
node {

category title content numViews

}

}

}

}

Parameters:
  • queryset (elasticsearch_dsl.search.Search) – Original queryset.

  • options (dict) – Filter options.

  • value (str) – value to filter on.

Returns:

Modified queryset.

Return type:

elasticsearch_dsl.search.Search

classmethod apply_query_exclude(queryset, options, value)[source]

Apply exclude functional query.

Syntax:

TODO

Note, that number of values is not limited.

Example:

query {
allPostDocuments(filter:{category:{exclude:”Python”}}) {
edges {
node {

category title content numViews

}

}

}

}

Or exclude multiple terms at once:

query {
allPostDocuments(filter:{category:{exclude:[“Ruby”, “Java”]}}) {
edges {
node {

category title content numViews

}

}

}

}

Parameters:
  • queryset (elasticsearch_dsl.search.Search) – Original queryset.

  • options (dict) – Filter options.

  • value (str) – value to filter on.

Returns:

Modified queryset.

Return type:

elasticsearch_dsl.search.Search

classmethod apply_query_exists(queryset, options, value)[source]

Apply exists filter.

Syntax:

TODO

Example:

{
allPostDocuments(filter:{category:{exists:true}}) {
edges {
node {

category title content numViews

}

}

}

}

Parameters:
  • queryset (elasticsearch_dsl.search.Search) – Original queryset.

  • options (dict) – Filter options.

  • value (str) – value to filter on.

Returns:

Modified queryset.

Return type:

elasticsearch_dsl.search.Search

classmethod apply_query_gt(queryset, options, value)[source]

Apply gt functional query.

Syntax:

TODO

Example:

query {
allPostDocuments(filter:{numViews:{

gt:{decimal:”100”}

}}) { edges {

node {

category title content numViews

}

}

}

}

Parameters:
  • queryset (elasticsearch_dsl.search.Search) – Original queryset.

  • options (dict) – Filter options.

  • value (str) – value to filter on.

Returns:

Modified queryset.

Return type:

elasticsearch_dsl.search.Search

classmethod apply_query_gte(queryset, options, value)[source]

Apply gte functional query.

Syntax:

TODO

Example:

query {
allPostDocuments(filter:{numViews:{

gte:{decimal:”100”}

}}) { edges {

node {

category title content numViews

}

}

}

}

Parameters:
  • queryset (elasticsearch_dsl.search.Search) – Original queryset.

  • options (dict) – Filter options.

  • value (str) – value to filter on.

Returns:

Modified queryset.

Return type:

elasticsearch_dsl.search.Search

classmethod apply_query_in(queryset, options, value)[source]

Apply in functional query.

Syntax:

TODO

Note, that number of values is not limited.

Example:

query {
allPostDocuments(postFilter:{tags:{

in:[“photography”, “models”]

}}) { edges {

node {

category title content numViews tags

}

}

}

}

Parameters:
  • queryset (elasticsearch_dsl.search.Search) – Original queryset.

  • options (dict) – Filter options.

  • value (str) – value to filter on.

Returns:

Modified queryset.

Return type:

elasticsearch_dsl.search.Search

classmethod apply_query_isnull(queryset, options, value)[source]

Apply isnull functional query.

Syntax:

TODO

Example:

query {
allPostDocuments(filter:{category:{isNull:true}}) {
edges {
node {

category title content numViews comments

}

}

}

}

Parameters:
  • queryset (elasticsearch_dsl.search.Search) – Original queryset.

  • options (dict) – Filter options.

  • value (str) – value to filter on.

Returns:

Modified queryset.

Return type:

elasticsearch_dsl.search.Search

classmethod apply_query_lt(queryset, options, value)[source]

Apply lt functional query.

Syntax:

TODO

Example:

query {
allPostDocuments(filter:{numViews:{

lt:{decimal:”200”}

}}) { edges {

node {

category title content numViews

}

}

}

}

Parameters:
  • queryset (elasticsearch_dsl.search.Search) – Original queryset.

  • options (dict) – Filter options.

  • value (str) – value to filter on.

Returns:

Modified queryset.

Return type:

elasticsearch_dsl.search.Search

classmethod apply_query_lte(queryset, options, value)[source]

Apply lte functional query.

Syntax:

TODO

Example:

query {
allPostDocuments(filter:{numViews:{

lte:{decimal:”200”}

}}) { edges {

node {

category title content numViews

}

}

}

}

Parameters:
  • queryset (elasticsearch_dsl.search.Search) – Original queryset.

  • options (dict) – Filter options.

  • value (str) – value to filter on.

Returns:

Modified queryset.

Return type:

elasticsearch_dsl.search.Search

classmethod apply_query_wildcard(queryset, options, value)[source]

Apply wildcard filter.

Syntax:

TODO

Example:

query {
allPostDocuments(filter:{category:{wildcard:”ytho”}}) {
edges {
node {

category title content numViews comments

}

}

}

}

Parameters:
  • queryset (elasticsearch_dsl.search.Search) – Original queryset.

  • options (dict) – Filter options.

  • value (str) – value to filter on.

Returns:

Modified queryset.

Return type:

elasticsearch_dsl.search.Search

classmethod get_gte_lte_params(value, lookup, options)[source]

Get params for gte, gt, lte and lt query.

Syntax:

TODO

Example:

{
allPostDocuments(filter:{numViews:{

gt:{decimal:”100”}, lt:{decimal:”200”}

}}) { edges {

node {

category title content numViews

}

}

}

}

Parameters:
  • value (graphene_elastic.filter_backends.filtering.queries.InputObjectType) –

  • lookup (str) –

  • options (dict) –

Returns:

Params to be used in range query.

Return type:

dict

classmethod get_range_param_value(value)[source]

Get range param value.

Parameters:

value (graphene_elastic.filter_backends.filtering.queries.InputObjectType) –

Returns:

classmethod get_range_params(value, options)[source]

Get params for range query.

Syntax:

TODO

Example:

{
allPostDocuments(filter:{numViews:{range:{

lower:{decimal:”100”}, upper:{decimal: “200”}, boost:”2.0”

}}}) {

edges {
node {

category title content numViews

}

}

}

}

Parameters:
  • value (graphene_elastic.filter_backends.filtering.queries.InputObjectType) –

  • options (dict) –

Returns:

Params to be used in range query.

Return type:

dict

split_lookup_complex_value: Callable
graphene_elastic.filter_backends.filtering.queries module
Module contents
graphene_elastic.filter_backends.highlight package
Submodules
graphene_elastic.filter_backends.highlight.common module
class graphene_elastic.filter_backends.highlight.common.HighlightFilterBackend(connection_field, args=None)[source]

Bases: BaseBackend

Highlight filter backend.

field_belongs_to(field_name)[source]

Check if given filter field belongs to the backend.

Parameters:

field_name

Returns:

filter(queryset)[source]

Filter.

Parameters:

queryset

Returns:

get_backend_document_fields()[source]

Get additional document fields for the backend.

For instance, the Highlight backend add additional field named highlight to the list of fields.

Sample query:

query {
allPostDocuments(search:{title:{value:”alice”}}) {
edges {
node {

id title highlight

}

}

}

}

Sample response:

{
“data”: {
“allPostDocuments”: {
“edges”: [
{
“node”: {

“id”: “UG9zdDp5a1ppVlcwQklwZ2dXbVlJQV91Rw==”, “title”: “thus Alice style”, “highlight”: {

“title”: [

“thus <b>Alice</b> style”

]

}

}

]

}

}

}

That highlight part on both sample query and sample response isn’t initially available on the connection level, but added with help of the filter backend. :return:

get_backend_query_fields(items, is_filterable_func, get_type_func)[source]

Construct backend filtering fields.

Parameters:
  • items

  • is_filterable_func

  • get_type_func

Returns:

get_highlight_query_params()[source]

Get highlight query params.

Returns:

List of search query params.

Return type:

list

has_query_fields = True
property highlight_fields

Highlight filter fields.

prefix = 'highlight'
prepare_highlight_fields()[source]

Prepare highlight fields.

Possible structures:

highlight_fields = {
‘title’: {

‘enabled’: True, ‘options’: {

‘pre_tags’: [“<b>”], ‘post_tags’: [“</b>”],

}

}, ‘summary’: {

‘options’: {

‘fragment_size’: 50, ‘number_of_fragments’: 3

}

}, ‘description’: {},

}

Sample query would be:

query {
allPostDocuments(

search:{content:{value:”since”}, title:{value:”decide”}}, highlight:[category, content]

) { edges {

node {

title content highlight

} cursor

}

}

}

Returns:

Filtering options.

Return type:

dict

Module contents
graphene_elastic.filter_backends.ordering package
Submodules
graphene_elastic.filter_backends.ordering.common module

Ordering backend.

class graphene_elastic.filter_backends.ordering.common.DefaultOrderingFilterBackend(connection_field, args=None)[source]

Bases: BaseBackend, OrderingMixin

Default ordering filter backend for Elasticsearch.

Make sure this is your last ordering backend.

Example:

>>>   import graphene
>>>   from graphene import Node
>>>   from graphene_elastic import (
>>>       ElasticsearchObjectType,
>>>       ElasticsearchConnectionField,
>>>   )
>>>   from graphene_elastic.filter_backends import (
>>>       FilteringFilterBackend,
>>>       SearchFilterBackend,
>>>       OrderingFilterBackend,
>>>       DefaultOrderingFilterBackend,
>>>   )
>>>   from graphene_elastic.constants import (
>>>       LOOKUP_FILTER_PREFIX,
>>>       LOOKUP_FILTER_TERM,
>>>       LOOKUP_FILTER_TERMS,
>>>       LOOKUP_FILTER_WILDCARD,
>>>       LOOKUP_QUERY_EXCLUDE,
>>>       LOOKUP_QUERY_IN,
>>>   )
>>>
>>>   from search_index.documents import Post as PostDocument
>>>
>>>   class Post(ElasticsearchObjectType):
>>>
>>>       class Meta(object):
>>>           document = PostDocument
>>>           interfaces = (Node,)
>>>           filter_backends = [
>>>               FilteringFilterBackend,
>>>               SearchFilterBackend,
>>>               OrderingFilterBackend,
>>>               DefaultOrderingFilterBackend
>>>           ]
>>>           filter_fields = {
>>>               'id': '_id',
>>>               'title': {
>>>                   'field': 'title.raw',
>>>                   'lookups': [
>>>                       LOOKUP_FILTER_TERM,
>>>                       LOOKUP_FILTER_TERMS,
>>>                       LOOKUP_FILTER_PREFIX,
>>>                       LOOKUP_FILTER_WILDCARD,
>>>                       LOOKUP_QUERY_IN,
>>>                       LOOKUP_QUERY_EXCLUDE,
>>>                   ],
>>>                   'default_lookup': LOOKUP_FILTER_TERM,
>>>               },
>>>               'category': 'category.raw',
>>>               'tags': 'tags.raw',
>>>               'num_views': 'num_views',
>>>           }
>>>           search_fields = {
>>>               'title': {'boost': 4},
>>>               'content': {'boost': 2},
>>>               'category': None,
>>>           }
>>>           ordering_fields = {
>>>               'id': None,
>>>               'title': 'title.raw',
>>>               'created_at': 'created_at',
>>>               'num_views': 'num_views',
>>>           }
>>>
>>>           ordering_defaults = ('id', 'title',)
filter(queryset)[source]

Filter the queryset.

Parameters:

queryset (elasticsearch_dsl.search.Search) – Base queryset.

Returns:

Updated queryset.

Return type:

elasticsearch_dsl.search.Search

get_default_ordering_params()[source]

Get the default ordering params for the view.

Returns:

Ordering params to be used for ordering.

Return type:

list

get_ordering_query_params()[source]

Get ordering query params.

Returns:

Ordering params to be used for ordering.

Return type:

list

has_query_fields = False
property ordering_defaults

Ordering filter fields.

property ordering_fields

Ordering filter fields.

prefix = 'ordering'
class graphene_elastic.filter_backends.ordering.common.OrderingFilterBackend(connection_field, args=None)[source]

Bases: BaseBackend, OrderingMixin

Ordering filter backend for Elasticsearch.

Example:

>>>   import graphene
>>>   from graphene import Node
>>>   from graphene_elastic import (
>>>       ElasticsearchObjectType,
>>>       ElasticsearchConnectionField,
>>>   )
>>>   from graphene_elastic.filter_backends import (
>>>       FilteringFilterBackend,
>>>       SearchFilterBackend,
>>>       OrderingFilterBackend,
>>>       DefaultOrderingFilterBackend,
>>>   )
>>>   from graphene_elastic.constants import (
>>>       LOOKUP_FILTER_PREFIX,
>>>       LOOKUP_FILTER_TERM,
>>>       LOOKUP_FILTER_TERMS,
>>>       LOOKUP_FILTER_WILDCARD,
>>>       LOOKUP_QUERY_EXCLUDE,
>>>       LOOKUP_QUERY_IN,
>>>   )
>>>
>>>   from search_index.documents import Post as PostDocument
>>>
>>>   class Post(ElasticsearchObjectType):
>>>
>>>       class Meta(object):
>>>           document = PostDocument
>>>           interfaces = (Node,)
>>>           filter_backends = [
>>>               FilteringFilterBackend,
>>>               SearchFilterBackend,
>>>               OrderingFilterBackend,
>>>               DefaultOrderingFilterBackend
>>>           ]
>>>           filter_fields = {
>>>               'id': '_id',
>>>               'title': {
>>>                   'field': 'title.raw',
>>>                   'lookups': [
>>>                       LOOKUP_FILTER_TERM,
>>>                       LOOKUP_FILTER_TERMS,
>>>                       LOOKUP_FILTER_PREFIX,
>>>                       LOOKUP_FILTER_WILDCARD,
>>>                       LOOKUP_QUERY_IN,
>>>                       LOOKUP_QUERY_EXCLUDE,
>>>                   ],
>>>                   'default_lookup': LOOKUP_FILTER_TERM,
>>>               },
>>>               'category': 'category.raw',
>>>               'tags': 'tags.raw',
>>>               'num_views': 'num_views',
>>>           }
>>>           search_fields = {
>>>               'title': {'boost': 4},
>>>               'content': {'boost': 2},
>>>               'category': None,
>>>           }
>>>           ordering_fields = {
>>>               'id': None,
>>>               'title': 'title.raw',
>>>               'created_at': 'created_at',
>>>               'num_views': 'num_views',
>>>           }
>>>
>>>           ordering_defaults = ('id', 'title',)

The basic usage would be:

query {
allPostDocuments(ordering:{title:ASC}) {
edges {
node {

title content category numViews createdAt

}

}

}

}

field_belongs_to(field_name)[source]

Check if given filter field belongs to the backend.

Parameters:

field_name

Returns:

filter(queryset)[source]

Filter the queryset.

Parameters:

queryset (elasticsearch_dsl.search.Search) – Base queryset.

Returns:

Updated queryset.

Return type:

elasticsearch_dsl.search.Search

get_backend_default_query_fields_params()[source]

Get default query fields params for the backend.

Return type:

dict

Returns:

get_field_type(field_name, field_value, base_field_type)[source]

Get field type.

Returns:

get_ordering_query_params()[source]

Get ordering query params.

Returns:

Ordering params to be used for ordering.

Return type:

list

has_query_fields = True
property ordering_args_mapping
property ordering_fields

Ordering filter fields.

prefix = 'ordering'
score_field_name = 'score'
Module contents
graphene_elastic.filter_backends.post_filter package
Submodules
graphene_elastic.filter_backends.post_filter.common module
class graphene_elastic.filter_backends.post_filter.common.PostFilterFilteringBackend(connection_field, args=None)[source]

Bases: BaseBackend, FilteringFilterMixin

Post filter filtering backend.

classmethod apply_filter(queryset, options=None, args=None, kwargs=None)[source]

Apply filter.

Parameters:
  • queryset

  • options

  • args

  • kwargs

Returns:

classmethod apply_query(queryset, options=None, args=None, kwargs=None)[source]

Apply query.

Parameters:
  • queryset

  • options

  • args

  • kwargs

Returns:

field_belongs_to(field_name)[source]

Check if given filter field belongs to the backend.

Parameters:

field_name

Returns:

filter(queryset)[source]

Filter.

property filter_args_mapping
property filter_fields

Filtering filter fields.

get_backend_query_fields(items, is_filterable_func, get_type_func)[source]

Fail proof override.

Parameters:
  • items

  • is_filterable_func

  • get_type_func

Returns:

get_field_lookup_param(field_name)[source]

Get field lookup param.

Parameters:

field_name

Returns:

get_field_options(field_name)[source]

Get field option params.

Parameters:

field_name

Returns:

get_field_type(field_name, field_value, base_field_type)[source]

Get field type.

Returns:

get_filter_query_params()[source]

Get query params to be filtered on.

We can either specify it like this:

query_params = {
‘category’: {

‘value’: ‘Elastic’,

}

}

Or using specific lookup:

query_params = {
‘category’: {

‘term’: ‘Elastic’, ‘range’: {

‘lower’: Decimal(‘3.0’)

}

}

}

Note, that value would only work on simple types (string, integer, decimal). For complex types you would have to use complex param anyway. Therefore, it should be forbidden to set default_lookup to a complex field type.

Sample values:

query_params = {
‘category’: {

‘value’: ‘Elastic’,

}

}

filter_fields = {
‘category’: {

‘field’: ‘category.raw’, ‘default_lookup’: ‘term’, ‘lookups’: (

‘term’, ‘terms’, ‘range’, ‘exists’, ‘prefix’, ‘wildcard’, ‘contains’, ‘in’, ‘gt’, ‘gte’, ‘lt’, ‘lte’, ‘starts_with’, ‘ends_with’, ‘is_null’, ‘exclude’

)

}

}

field_name = ‘category’

has_query_fields = True
prefix = 'postFilter'
prepare_filter_fields()[source]

Prepare filter fields.

Possible structures:

post_filter_fields = {
‘title’: {

‘field’: ‘title.raw’, ‘lookups’: [

LOOKUP_FILTER_TERM, LOOKUP_FILTER_TERMS, LOOKUP_FILTER_PREFIX, LOOKUP_FILTER_WILDCARD, LOOKUP_QUERY_IN, LOOKUP_QUERY_EXCLUDE,

], ‘default_lookup’: LOOKUP_FILTER_TERM,

}, ‘category’: ‘category.raw’,

}

We shall finally have:

post_filter_fields = {
‘title’: {

‘field’: ‘title.raw’, ‘lookups’: [

LOOKUP_FILTER_TERM, LOOKUP_FILTER_TERMS, LOOKUP_FILTER_PREFIX, LOOKUP_FILTER_WILDCARD, LOOKUP_QUERY_IN, LOOKUP_QUERY_EXCLUDE,

], ‘default_lookup’: LOOKUP_FILTER_TERM,

}, ‘category’: {

‘field’: ‘category.raw’, ‘lookups’: [

LOOKUP_FILTER_TERM, LOOKUP_FILTER_TERMS, LOOKUP_FILTER_PREFIX, LOOKUP_FILTER_WILDCARD, LOOKUP_QUERY_IN, LOOKUP_QUERY_EXCLUDE, … # All other lookups

], ‘default_lookup’: LOOKUP_FILTER_TERM,

}

}

prepare_query_params()[source]

Prepare query params.

Returns:

Module contents
graphene_elastic.filter_backends.score package
Submodules
graphene_elastic.filter_backends.score.common module
class graphene_elastic.filter_backends.score.common.ScoreFilterBackend(connection_field, args=None)[source]

Bases: BaseBackend

Score filter backend.

Sample query would be:

query {
allPostDocuments(

search:{content:{value:”since”}, title:{value:”decide”}}

) { edges {

node {

title content score

} cursor

}

}

}

field_belongs_to(field_name)[source]

Check if given filter field belongs to the backend.

Parameters:

field_name

Returns:

filter(queryset)[source]

Filter.

Parameters:

queryset

Returns:

get_backend_document_fields()[source]

Get additional document fields for the backend.

For instance, the Highlight backend add additional field named highlight to the list of fields.

Sample query:

query {
allPostDocuments(search:{title:{value:”alice”}}) {
edges {
node {

id title highlight

}

}

}

}

Sample response:

{
“data”: {
“allPostDocuments”: {
“edges”: [
{
“node”: {

“id”: “UG9zdDp5a1ppVlcwQklwZ2dXbVlJQV91Rw==”, “title”: “thus Alice style”, “highlight”: {

“title”: [

“thus <b>Alice</b> style”

]

}

}

]

}

}

}

That highlight part on both sample query and sample response isn’t initially available on the connection level, but added with help of the filter backend. :return:

has_query_fields = False
prefix = 'score'
score_field_name = 'score'
property score_fields

Score filter fields.

Module contents
graphene_elastic.filter_backends.search package
Submodules
graphene_elastic.filter_backends.search.common module
class graphene_elastic.filter_backends.search.common.SearchFilterBackend(connection_field, args=None)[source]

Bases: BaseBackend

Search filter backend.

clean_all_query_params()[source]

Get cleaned query params. Remove query lookup.

Construct nested search.

Type 1:

>>> search_nested_fields = {
>>>     "comments": {
>>>         "path": "comments",
>>>         "fields": [
>>>             "tag",
>>>             "content"
>>>        ]
>>> }

Type 2:

>>> search_nested_fields = {
>>>     "comments": {
>>>         "path": "comments",
>>>         "fields": [
>>>             {
>>>                 "tag": {
>>>                     "field": "tag.raw",
>>>                     "boost": 4
>>>                 }
>>>             },
>>>             {
>>>                 "content": {
>>>                     "field": "content",
>>>                     "boost": 2
>>>                 }            
>>>             }
>>>        ]
>>> }

In GraphQL shall be:

query {
allPostDocuments(search:{
comments: {
tag: {

value: “Python”, boost: 2

}

}

}) { pageInfo {

startCursor endCursor hasNextPage hasPreviousPage

} edges {

cursor node {

category title content numViews comments{

tag

}

}

}

}

}

Or simply:

query {
allPostDocuments(search:{query:”Python”}) {
pageInfo {

startCursor endCursor hasNextPage hasPreviousPage

} edges {

cursor node {

category title content numViews comments{

tag

}

}

}

}

}

Returns:

Updated queryset.

Return type:

elasticsearch_dsl.search.Search

Construct search.

We have to deal with two types of structures:

Type 1:

>>> search_fields = (
>>>     'title',
>>>     'description',
>>>     'summary',
>>> )

Type 2:

>>> search_fields = {
>>>     'title': {'field': 'title', 'boost': 2},
>>>     'description': None,
>>>     'summary': None,
>>> }

In GraphQL shall be:

query {
allPostDocuments(search:{

query:”Another”, title:{value:”Another”} summary:{value:”Another”}

}) { pageInfo {

startCursor endCursor hasNextPage hasPreviousPage

} edges {

cursor node {

category title content numViews

}

}

}

}

Or simply:

query {
allPostDocuments(search:{query:”education technology”}) {
pageInfo {

startCursor endCursor hasNextPage hasPreviousPage

} edges {

cursor node {

category title content numViews

}

}

}

}

Returns:

Updated queryset.

Return type:

elasticsearch_dsl.search.Search

field_belongs_to(field_name)[source]

Check if given filter field belongs to the backend.

Parameters:

field_name

Returns:

filter(queryset)[source]

Filter.

Parameters:

queryset

Returns:

get_all_query_params()[source]
get_backend_default_query_fields_params()[source]

Get backend default filter params.

Return type:

dict

Returns:

get_field_type(field_name, field_value, base_field_type)[source]

Get field type.

Returns:

TODO: required

get_search_nested_fields_tree(start=None, value=None)[source]

We got a prepared nested fields ,

{
‘country’: {

‘path’: ‘country’, ‘fields’: [

{

‘name’: {‘boost’: 2}

}

]

}, ‘city’: {

‘path’: ‘country.city’, ‘fields’: [

{

‘name’: {‘boost’: 2}

}

]

}

}

Then we should turn it to

{
‘country’: {

‘name’: {}, # {} or None represents no more leaves. ‘city’: {

‘name’: {}

}

}

}

has_query_fields = True
property nested_search_args_mapping
prefix = 'search'
prepare_search_fields()[source]

Prepare search fields.

Possible structures:

search_fields = {

‘title’: {‘boost’: 4, ‘field’: ‘title.raw’}, ‘content’: {‘boost’: 2}, ‘category’: None, ‘comments’: None

}

We shall finally have:

search_fields = {
‘title’: {

‘field’: ‘title.raw’, ‘boost’: 4

}, ‘content’: {

‘field’: ‘content’, ‘boost’: 2

}, ‘category’: {

‘field’: ‘category’

}

}

Sample query would be:

{
allPostDocuments(search:{query:”Another”}) {
pageInfo {

startCursor endCursor hasNextPage hasPreviousPage

} edges {

cursor node {

category title content numViews

}

}

}

}

Returns:

Filtering options.

Return type:

dict

prepare_search_nested_fields()[source]

Prepare search fields.

Possible structures:

Type1
search_nested_fields = {
‘comments’: {

‘path’; ‘comments’, ‘fields’: [

{‘author’: {‘boost’: 4}}, {‘tag’: {‘boost’: 2}},

]

}

}

Type2
search_nested_fields = {
‘comments: {

‘path’; ‘comments’, ‘fields’: [‘author’, ‘tag’]

}

}

We shall finally have:

search_nested_fields = {
‘comments’: {

‘path’: ‘comments’, ‘fields’: {

{‘author’: {‘boost’: 4}}, {‘tag’: {‘boost’: 2}}

}

}

}

Sample query would be:

{
allPostDocuments(search:{query:”Another”}) {
pageInfo {

startCursor endCursor hasNextPage hasPreviousPage

} edges {

cursor node {

category title content numViews

}

}

}

}

Returns:

Filtering options.

Return type:

dict

property search_args_mapping
property search_fields

Search filter fields.

property search_nested_fields

Search nested filter fields.

graphene_elastic.filter_backends.search.query_string module
class graphene_elastic.filter_backends.search.query_string.QueryStringBackend(connection_field, args=None)[source]

Bases: BaseBackend

filter(queryset)[source]

Filter.

Parameters:

queryset

Returns:

get_all_query_params()[source]
get_backend_query_fields(items, is_filterable_func, get_type_func)[source]

Construct backend query fields.

Parameters:
  • items

  • is_filterable_func

  • get_type_func

Returns:

has_query_fields = True
prefix = 'query_string'
property query_string_options

Query string options.

Possible options:

query_string_options = {

‘fields’: [‘title’, ‘category’, ‘tag’], ‘default_operator’: “and”, ‘lenient’: true, ‘minimum_should_match’: 3

}

For list of all options: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html

graphene_elastic.filter_backends.search.simple_query_string module
class graphene_elastic.filter_backends.search.simple_query_string.SimpleQueryStringBackend(connection_field, args=None)[source]

Bases: BaseBackend

filter(queryset)[source]

Filter.

Parameters:

queryset

Returns:

get_all_query_params()[source]
get_backend_query_fields(items, is_filterable_func, get_type_func)[source]

Construct backend query fields.

Parameters:
  • items

  • is_filterable_func

  • get_type_func

Returns:

has_query_fields = True
prefix = 'simple_query_string'
property simple_query_string_options

Simple query string options.

Possible options:

simple_query_string_options = {

‘fields’: [‘title’, ‘category’, ‘tag’], ‘default_operator’: “and”, ‘lenient’: true, ‘minimum_should_match’: 3

}

For list of all options: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html

Module contents
graphene_elastic.filter_backends.source package
Submodules
graphene_elastic.filter_backends.source.common module
class graphene_elastic.filter_backends.source.common.SourceFilterBackend(connection_field, args=None)[source]

Bases: BaseBackend

Source filter backend.

filter(queryset)[source]

Filter.

Parameters:

queryset

Returns:

get_backend_query_fields(items, is_filterable_func, get_type_func)[source]

Construct backend filtering fields.

Parameters:
  • items

  • is_filterable_func

  • get_type_func

Returns:

has_query_fields = True
prefix = 'source'
prepare_source_fields()[source]

Prepare source fields.

Possible structures:

source_fields = [“title”]

Or:

search_fields = [“title”, “author.*”]

Or:

source = {

“includes”: [“title”, “author.*”], “excludes”: [ “*.description” ]

}

Returns:

Filtering options.

Return type:

dict

property source_fields

Source filter fields.

Module contents
Submodules
graphene_elastic.filter_backends.base module
class graphene_elastic.filter_backends.base.BaseBackend(connection_field, args=None)[source]

Bases: object

Base backend.

alter_connection(connection, slice)[source]

Alter connection object.

You can add various properties here, returning the altered object. Typical use-case would be adding facets to the connection.

Parameters:
  • connection

  • slice

Returns:

classmethod apply_filter(queryset, options=None, args=None, kwargs=None)[source]

Apply filter.

Parameters:
  • queryset

  • options

  • args

  • kwargs

Returns:

classmethod apply_query(queryset, options=None, args=None, kwargs=None)[source]

Apply query.

Parameters:
  • queryset

  • options

  • args

  • kwargs

Returns:

property doc_type

Shortcut to the Elasticsearch document type.

Returns:

field_belongs_to(field_name)[source]

Check if given filter field belongs to the backend.

Parameters:

field_name

Returns:

filter(queryset)[source]

Filter. This method alters current queryset.

Parameters:

queryset

Returns:

classmethod generic_query_fields()[source]

Generic backend specific query fields.

For instance, for search filter backend it would be {'search': String()}.

Returns:

Rtype dict:

get_backend_connection_fields()[source]

Get backend connection fields.

Typical use-case - a backend that alters the Connection object and adds additional fields next to edges and pageInfo (see the graphene_elastic.relay.connection.Connection for more information).

Rtype dict:

Returns:

get_backend_connection_fields_type()[source]

Get backend connection fields type.

Typical use-case - a backend that alters the Connection object and adds additional fields next to edges and pageInfo (see the graphene_elastic.relay.connection.Connection for more information).

Returns:

get_backend_default_query_fields_params()[source]

Get default query fields params for the backend.

Return type:

dict

Returns:

get_backend_document_fields()[source]

Get additional document fields for the backend.

For instance, the Highlight backend add additional field named highlight to the list of fields.

Sample query:

query {
allPostDocuments(search:{title:{value:”alice”}}) {
edges {
node {

id title highlight

}

}

}

}

Sample response:

{
“data”: {
“allPostDocuments”: {
“edges”: [
{
“node”: {

“id”: “UG9zdDp5a1ppVlcwQklwZ2dXbVlJQV91Rw==”, “title”: “thus Alice style”, “highlight”: {

“title”: [

“thus <b>Alice</b> style”

]

}

}

]

}

}

}

That highlight part on both sample query and sample response isn’t initially available on the connection level, but added with help of the filter backend. :return:

get_backend_query_fields(items, is_filterable_func, get_type_func)[source]

Construct backend query fields.

Parameters:
  • items

  • is_filterable_func

  • get_type_func

Returns:

get_field_type(field_name, field_value, base_field_type)[source]

Get field type.

Returns:

has_connection_fields = False
has_query_fields = False
prefix = None
classmethod split_lookup_complex_multiple_value(value, maxsplit=-1)[source]

Split lookup complex multiple value.

Parameters:
  • value (str) – Value to split.

  • maxsplit (int) – The maxsplit option of string.split.

Returns:

Lookup filter split into a list.

Return type:

list

classmethod split_lookup_complex_value(value, maxsplit=-1)[source]

Split lookup complex value.

Parameters:
  • value (str) – Value to split.

  • maxsplit (int) – The maxsplit option of string.split.

Returns:

Lookup filter split into a list.

Return type:

list

classmethod split_lookup_filter(value, maxsplit=-1)[source]

Split lookup filter.

Parameters:
  • value (str) – Value to split.

  • maxsplit (int) – The maxsplit option of string.split.

Returns:

Lookup filter split into a list.

Return type:

list

classmethod split_lookup_name(value, maxsplit=-1)[source]

Split lookup value.

Parameters:
  • value (str) – Value to split.

  • maxsplit (int) – The maxsplit option of string.split.

Returns:

Lookup value split into a list.

Return type:

list

graphene_elastic.filter_backends.queries module
class graphene_elastic.filter_backends.queries.Contains(*args, **kwargs)[source]

Bases: String

Wildcard.

filter:[

{category: {contains: “lish”}]}}

]

required = True
class graphene_elastic.filter_backends.queries.Direction(*args, **kwargs)

Bases: Enum

ASC = 'asc'
DESC = 'desc'
class graphene_elastic.filter_backends.queries.EndsWith(*args, **kwargs)[source]

Bases: String

Ends with.

filter:[

{category: {endsWith: “dren”}]}}

]

required = True
class graphene_elastic.filter_backends.queries.Exclude(*args, **kwargs)[source]

Bases: _ListOfTypeString

Exclude.

filter:[

{category: {exclude: [“Python”, “Django”]}}

]

class graphene_elastic.filter_backends.queries.Exists(*args, **kwargs)[source]

Bases: Boolean

Exists.

filter:[

{category: {exist: true}]}}

]

required = True
class graphene_elastic.filter_backends.queries.GeoBoundingBox(*args, **kwargs)[source]

Bases: InputObjectType

Geo polygon.

filter:[
{place: {geoBoundingBox: {

topLeft: {lat: “40.0”, lon=”70.0”}, bottomRight: {lat: “80.0”, lon: “90.0”}

}}}

]

bottom_right = <graphene.types.field.Field object>
top_left = <graphene.types.field.Field object>
class graphene_elastic.filter_backends.queries.GeoDistance(*args, **kwargs)[source]

Bases: InputObjectType

Geo distance.

filter:[

{place: {geoDistance: {distance: “9km”, lat: “40.0”, lon=”70.0”}}}

]

distance = <graphene.types.scalars.String object>
lat = <graphene.types.decimal.Decimal object>
lon = <graphene.types.decimal.Decimal object>
class graphene_elastic.filter_backends.queries.GeoPolygon(*args, **kwargs)[source]

Bases: InputObjectType

Geo polygon.

filter:[

{place: {geoPolygon: {points: [{lat: “40.0”, lon=”70.0”}]}}}

]

points = <graphene.types.structures.List object>
class graphene_elastic.filter_backends.queries.Gt(*args, **kwargs)[source]

Bases: _NumberOrDate

Gt.

filter:[

{category: {gt: “1”}]}}

]

required = True
class graphene_elastic.filter_backends.queries.Gte(*args, **kwargs)[source]

Bases: _NumberOrDate

Gte.

filter:[

{category: {gte: “1”}]}}

]

required = True
class graphene_elastic.filter_backends.queries.In(*args, **kwargs)[source]

Bases: _ListOfTypeString

In.

filter:[

{category: {in: [“Python”, “Django”]}}

]

class graphene_elastic.filter_backends.queries.IsNull(*args, **kwargs)[source]

Bases: Boolean

Is null.

filter:[

{category: {isNull: true}]}}

]

required = True
class graphene_elastic.filter_backends.queries.Lt(*args, **kwargs)[source]

Bases: _NumberOrDate

Lt.

filter:[

{category: {lt: “1”}]}}

]

required = True
class graphene_elastic.filter_backends.queries.Lte(*args, **kwargs)[source]

Bases: _NumberOrDate

Lte.

filter:[

{category: {lte: “1”}]}}

]

required = True
class graphene_elastic.filter_backends.queries.Point(*args, **kwargs)[source]

Bases: InputObjectType

Point. Helper for many geo lookups.

lat = <graphene.types.decimal.Decimal object>
lon = <graphene.types.decimal.Decimal object>
class graphene_elastic.filter_backends.queries.Prefix(*args, **kwargs)[source]

Bases: String

Prefix.

filter:[

{category: {prefix: “bio”}]}}

]

required = True
class graphene_elastic.filter_backends.queries.Range(*args, **kwargs)[source]

Bases: InputObjectType

Range.

filter:[

{range: {lower: “1000”, upper: “2000”, boost: “2.0”}]}}

]

boost = <graphene.types.decimal.Decimal object>
lower = <graphene.types.field.Field object>
upper = <graphene.types.field.Field object>
class graphene_elastic.filter_backends.queries.StartsWith(*args, **kwargs)[source]

Bases: Prefix

Starts with (alias of prefix).

class graphene_elastic.filter_backends.queries.Term(*args, **kwargs)[source]

Bases: String

Terms.

filter:[

{category: {term: “Python”}]}}

]

required = True
class graphene_elastic.filter_backends.queries.Terms(*args, **kwargs)[source]

Bases: _ListOfTypeString

Terms.

filter:[

{category: {terms: [“Python”, “Django”]}}

]

class graphene_elastic.filter_backends.queries.Wildcard(*args, **kwargs)[source]

Bases: String

Wildcard.

filter:[

{category: {wildcard: “bio”}]}}

]

required = True
Module contents
graphene_elastic.relay package
Submodules
graphene_elastic.relay.connection module

Some overrides of the original graphql_relay.connection.connection module. For sanity and ease of updates/sync with modifications from upstream, this module isn’t formatted in accordance with the rest of the package. Pull requests code-style changes wouldn’t be accepted.

class graphene_elastic.relay.connection.Connection(*args, **kwargs)[source]

Bases: ObjectType

class graphene_elastic.relay.connection.ConnectionOptions(class_type)[source]

Bases: ObjectTypeOptions

node = None
graphene_elastic.relay.connectiontypes module

Some overrides of the original graphql_relay.connection.connectiontypes module. For sanity and ease of updates/sync with modifications from upstream, this module isn’t formatted in accordance with the rest of the package. Pull requests code-style changes wouldn’t be accepted.

class graphene_elastic.relay.connectiontypes.Connection(edges, page_info, facets=None)[source]

Bases: object

to_dict()[source]
class graphene_elastic.relay.connectiontypes.Facets(facets)[source]

Bases: object

to_dict()[source]
Module contents
graphene_elastic.tests package
Submodules
graphene_elastic.tests.base module
class graphene_elastic.tests.base.BaseGrapheneElasticTestCase(methodName='runTest')[source]

Bases: TestCase

Base graphene-elastic test case.

create_elasticsearch_indexes()[source]

Create ES indexes.

remove_elasticsearch_index(index_name, retry=0)[source]
remove_elasticsearch_indexes()[source]

Remove all ES indexes.

setUp()[source]

Hook method for setting up the test fixture before exercising it.

classmethod setUpClass()[source]

Hook method for setting up class fixture before running tests in the class.

classmethod sleep(value=3)[source]
tearDown()[source]

Hook method for deconstructing the test fixture after testing it.

graphene_elastic.tests.test_faceted_search_backend module
class graphene_elastic.tests.test_faceted_search_backend.FacetedSearchBackendElasticTestCase(methodName='runTest')[source]

Bases: BaseGrapheneElasticTestCase

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_all()[source]

Test all.

Since we don’t write in specific tests, it’s more efficient to run them all from a single method in order to save on speed ups between tests.

graphene_elastic.tests.test_filter_backend module
class graphene_elastic.tests.test_filter_backend.FilterBackendElasticTestCase(methodName='runTest')[source]

Bases: BaseGrapheneElasticTestCase

endpoint = 'allPostDocuments'
setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_all()[source]

Test all.

Since we don’t write in specific tests, it’s more efficient to run them all from a single method in order to save on speed ups between tests.

graphene_elastic.tests.test_highlight_backend module
class graphene_elastic.tests.test_highlight_backend.HighlightBackendElasticTestCase(methodName='runTest')[source]

Bases: BaseGrapheneElasticTestCase

query_name = 'allPostDocuments'
setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_all()[source]

Test all.

Since we don’t write in specific tests, it’s more efficient to run them all from a single method in order to save on speed ups between tests.

class graphene_elastic.tests.test_highlight_backend.HighlightCompoundBackendElasticTestCase(methodName='runTest')[source]

Bases: HighlightBackendElasticTestCase

query_name = 'allReadOnlyPostDocuments'
graphene_elastic.tests.test_ordering_backend module
class graphene_elastic.tests.test_ordering_backend.OrderingBackendElasticTestCase(methodName='runTest')[source]

Bases: BaseGrapheneElasticTestCase

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_all()[source]

Test all.

Since we don’t write in specific tests, it’s more efficient to run them all from a single method in order to save on speed ups between tests.

graphene_elastic.tests.test_pagination module
class graphene_elastic.tests.test_pagination.PaginationTestCase(methodName='runTest')[source]

Bases: BaseGrapheneElasticTestCase

query_name = 'allPostDocuments'
setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_all()[source]

Test all.

Since we don’t write in specific tests, it’s more efficient to run them all from a single method in order to save on speed ups between tests.

graphene_elastic.tests.test_post_filter_backend module
class graphene_elastic.tests.test_post_filter_backend.PostFilterBackendElasticTestCase(methodName='runTest')[source]

Bases: BaseGrapheneElasticTestCase

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_all()[source]

Test all.

Since we don’t write in specific tests, it’s more efficient to run them all from a single method in order to save on speed ups between tests.

graphene_elastic.tests.test_query_string_backend module
class graphene_elastic.tests.test_query_string_backend.QueryStringBackendElasticTestCase(methodName='runTest')[source]

Bases: BaseGrapheneElasticTestCase

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_all()[source]

Test all.

Since we don’t write in specific tests, it’s more efficient to run them all from a single method in order to save on speed ups between tests.

graphene_elastic.tests.test_score_backend module
class graphene_elastic.tests.test_score_backend.ScoreBackendElasticTestCase(methodName='runTest')[source]

Bases: BaseGrapheneElasticTestCase

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_all()[source]

Test all.

Since we don’t write in specific tests, it’s more efficient to run them all from a single method in order to save on speed ups between tests.

graphene_elastic.tests.test_search_backend module
class graphene_elastic.tests.test_search_backend.CompoundSearchBackendElasticTestCase(methodName='runTest')[source]

Bases: SearchBackendElasticTestCase

query_name = 'allReadOnlyPostDocuments'
class graphene_elastic.tests.test_search_backend.SearchBackendElasticTestCase(methodName='runTest')[source]

Bases: BaseGrapheneElasticTestCase

query_name = 'allPostDocuments'
setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_all()[source]

Test all.

Since we don’t write in specific tests, it’s more efficient to run them all from a single method in order to save on speed ups between tests.

graphene_elastic.tests.test_simple_query_string_backend module
class graphene_elastic.tests.test_simple_query_string_backend.SimpleQueryStringBackendElasticTestCase(methodName='runTest')[source]

Bases: BaseGrapheneElasticTestCase

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_all()[source]

Test all.

Since we don’t write in specific tests, it’s more efficient to run them all from a single method in order to save on speed ups between tests.

graphene_elastic.tests.test_source_backend module
class graphene_elastic.tests.test_source_backend.HighlightBackendElasticTestCase(methodName='runTest')[source]

Bases: BaseGrapheneElasticTestCase

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_all()[source]

Test all.

Since we don’t write in specific tests, it’s more efficient to run them all from a single method in order to save on speed ups between tests.

graphene_elastic.tests.test_versions module
class graphene_elastic.tests.test_versions.VersionsTest(methodName='runTest')[source]

Bases: TestCase

Tests of graphene_elastic.versions module.

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_elasticsearch_dsl_6_3_0()[source]

Tests as if we were using elasticsearch_dsl==6.3.0.

test_elasticsearch_dsl_7_0_0()[source]

Tests as if we were using elasticsearch_dsl==7.0.0.

Module contents
graphene_elastic.types package
Submodules
graphene_elastic.types.elastic_types module
class graphene_elastic.types.elastic_types.ElasticsearchObjectType(*args, **kwargs)[source]

Bases: ObjectType

classmethod get_node(info, id)[source]
property id
classmethod is_type_of(root, info)[source]
classmethod rescan_fields()[source]

Attempts to rescan fields and will insert any not converted initially.

resolve_id(info)[source]
class graphene_elastic.types.elastic_types.ElasticsearchObjectTypeOptions(class_type)[source]

Bases: ObjectTypeOptions

connection = None
document = None
registry = None
graphene_elastic.types.elastic_types.construct_fields(document, registry, only_fields, exclude_fields)[source]
Args:

document (elasticsearch_dsl.Document): registry (graphene_elastic.registry.Registry): only_fields ([str]): exclude_fields ([str]):

Returns:

(OrderedDict, OrderedDict): converted fields and self reference fields.

graphene_elastic.types.elastic_types.construct_self_referenced_fields(self_referenced, registry)[source]
graphene_elastic.types.json_string module
class graphene_elastic.types.json_string.ElasticJSONString(*args, **kwargs)[source]

Bases: JSONString

static serialize(dt)[source]
graphene_elastic.types.json_string.to_serializable(o)[source]
Module contents

Submodules

graphene_elastic.advanced_types module

class graphene_elastic.advanced_types.FileFieldType(*args, **kwargs)[source]

Bases: ObjectType

chunk_size = <graphene.types.scalars.Int object>
content_type = <graphene.types.scalars.String object>
data = <graphene.types.scalars.String object>
length = <graphene.types.scalars.Int object>
md5 = <graphene.types.scalars.String object>
resolve_chunk_size(info)[source]
resolve_content_type(info)[source]
resolve_data(info)[source]
resolve_length(info)[source]
resolve_md5(info)[source]
class graphene_elastic.advanced_types.MultiPolygonFieldType(*args, **kwargs)[source]

Bases: _CoordinatesTypeField

coordinates = <graphene.types.structures.List object>
class graphene_elastic.advanced_types.PointFieldType(*args, **kwargs)[source]

Bases: _CoordinatesTypeField

coordinates = <graphene.types.structures.List object>
class graphene_elastic.advanced_types.PolygonFieldType(*args, **kwargs)[source]

Bases: _CoordinatesTypeField

coordinates = <graphene.types.structures.List object>

graphene_elastic.arrayconnection module

graphene_elastic.arrayconnection.connection_from_list_slice(list_slice, args=None, connection_type=None, edge_type=None, pageinfo_type=None, slice_start=0, list_length=0, list_slice_length=None, connection_field=None)[source]

Given a slice (subset) of an array, returns a connection object for use in GraphQL. This function is similar to connectionFromArray, but is intended for use cases where you know the cardinality of the connection, consider it too large to materialize the entire array, and instead wish pass in a slice of the total result large enough to cover the range specified in args.

graphene_elastic.compat module

graphene_elastic.constants module

Constants module. Contains Elasticsearch constants, lookup constants, functional constants, suggesters, etc.

graphene_elastic.converter module

exception graphene_elastic.converter.ElasticsearchConversionError[source]

Bases: Exception

graphene_elastic.converter.convert_elasticsearch_field(field, registry=None)[source]
graphene_elastic.converter.convert_elasticsearch_field(field: Keyword, registry=None)
graphene_elastic.converter.convert_elasticsearch_field(field: Text, registry=None)
graphene_elastic.converter.convert_elasticsearch_field(field: Short, registry=None)
graphene_elastic.converter.convert_elasticsearch_field(field: Long, registry=None)
graphene_elastic.converter.convert_elasticsearch_field(field: Integer, registry=None)
graphene_elastic.converter.convert_elasticsearch_field(field: Byte, registry=None)
graphene_elastic.converter.convert_elasticsearch_field(field: Boolean, registry=None)
graphene_elastic.converter.convert_elasticsearch_field(field: ScaledFloat, registry=None)
graphene_elastic.converter.convert_elasticsearch_field(field: Float, registry=None)
graphene_elastic.converter.convert_elasticsearch_field(field: HalfFloat, registry=None)
graphene_elastic.converter.convert_elasticsearch_field(field: Double, registry=None)
graphene_elastic.converter.convert_elasticsearch_field(field: Date, registry=None)
graphene_elastic.converter.convert_elasticsearch_field(field: Nested, registry=None)
graphene_elastic.converter.convert_elasticsearch_field(field: Object, registry=None)
graphene_elastic.converter.convert_field_to_boolean(field, registry=None)[source]
graphene_elastic.converter.convert_field_to_complex_object(field, registry=None)[source]
graphene_elastic.converter.convert_field_to_datetime(field, registry=None)[source]
graphene_elastic.converter.convert_field_to_float(field, registry=None)[source]
graphene_elastic.converter.convert_field_to_int(field, registry=None)[source]
graphene_elastic.converter.convert_field_to_jsonstring(field, registry=None)[source]
graphene_elastic.converter.convert_field_to_string(field, registry=None)[source]
graphene_elastic.converter.singledispatch(func)[source]

Single-dispatch generic function decorator.

Transforms a function into a generic function, which can have different behaviours depending upon the type of its first argument. The decorated function acts as the default implementation, and additional implementations can be registered using the register() attribute of the generic function.

graphene_elastic.enums module

class graphene_elastic.enums.NoValue(value)[source]

Bases: Enum

String values in enum.

Example:

>>> class Color(NoValue):
>>>     RED = 'stop'
>>>     GREEN = 'go'
>>>     BLUE = 'too fast!'

Graphene example:

>>> @graphene.Enum.from_enum
>>> class ColorOptions(NoValue):
>>>
>>>     RED = 'stop'
>>>     GREEN = 'go'
>>>     BLUE = 'too fast!'
graphene_elastic.enums.convert_list_to_enum(values, enum_name='DynamicEnum', upper=True)[source]

Prepare list values for creating an Enum.

Example:

>>> values = ['red', 'green', 'blue']
>>> print(prepare_list_for_enum(values))
{'RED': 'red', 'GREEN': 'green', 'BLUE': 'blue'}

graphene_elastic.fields module

class graphene_elastic.fields.ElasticsearchConnectionField(type, *args, **kwargs)[source]

Bases: IterableConnectionField

property args
chained_resolver(resolver, is_partial, root, info, **args)[source]
classmethod connection_resolver(resolver, connection_type, root, info, connection_field=None, **args)[source]
property default_filter_backends
default_resolver(_root, info, **args)[source]
property doc_type
property document
property field_args
property fields
property filter_backends
get_queryset(document, info, **args)[source]
get_resolver(parent_resolver)[source]
property node_type
property reference_args
property registry
classmethod resolve_connection(connection_type, args, resolved, connection_field=None)[source]
property type

graphene_elastic.logging module

graphene_elastic.registry module

class graphene_elastic.registry.Registry[source]

Bases: object

get_converted_field(field)[source]
get_type_for_document(document)[source]
register(cls)[source]
register_converted_field(field, converted)[source]
graphene_elastic.registry.get_global_registry()[source]
graphene_elastic.registry.reset_global_registry()[source]

graphene_elastic.settings module

graphene_elastic.utils module

graphene_elastic.utils.get_document_fields(document, excluding=None)[source]
graphene_elastic.utils.get_field_description(field, registry=None)[source]

Common metadata includes verbose_name and help_text.

http://docs.mongoengine.org/apireference.html#fields

graphene_elastic.utils.get_node_from_global_id(node, info, global_id)[source]
graphene_elastic.utils.get_type_for_document(schema, document)[source]
graphene_elastic.utils.import_single_dispatch()[source]
graphene_elastic.utils.is_valid_elasticsearch_document(document)[source]

graphene_elastic.versions module

Contains information about the current Elasticsearch version in use, including (LTE and GTE).

graphene_elastic.versions.get_elasticsearch_version(default=(2, 0, 0))[source]

Get Elasticsearch version.

Parameters:

default (tuple) – Default value. Mainly added for building the docs when Elasticsearch is not running.

Returns:

Return type:

list

Module contents

class graphene_elastic.ElasticsearchConnectionField(type, *args, **kwargs)[source]

Bases: IterableConnectionField

property args
chained_resolver(resolver, is_partial, root, info, **args)[source]
classmethod connection_resolver(resolver, connection_type, root, info, connection_field=None, **args)[source]
property default_filter_backends
default_resolver(_root, info, **args)[source]
property doc_type
property document
property field_args
property fields
property filter_backends
get_queryset(document, info, **args)[source]
get_resolver(parent_resolver)[source]
property node_type
property reference_args
property registry
classmethod resolve_connection(connection_type, args, resolved, connection_field=None)[source]
property type
class graphene_elastic.ElasticsearchObjectType(*args, **kwargs)[source]

Bases: ObjectType

classmethod get_node(info, id)[source]
property id
classmethod is_type_of(root, info)[source]
classmethod rescan_fields()[source]

Attempts to rescan fields and will insert any not converted initially.

resolve_id(info)[source]

Indices and tables