# Input Types

Input types allow you to specify more advanced query behavior. They serve as a way to alter the query, often in backend-specific ways, without altering your Python code; as well as enabling use of more advanced features.

Input types currently are only useful with the `filter/exclude` methods on `SearchQuerySet`. Expanding this support to other methods is on the roadmap.

## Available Input Types

Included with Haystack are the following input types:

### `Raw`

class haystack.inputs.Raw

Raw allows you to specify backend-specific query syntax. If Haystack doesn’t provide a way to access special query functionality, you can make use of this input type to pass it along.

Example:

    # Fielded.
    sqs = SearchQuerySet().filter(author=Raw('daniel OR jones'))

    # Non-fielded.
    # See ``AltParser`` for a better way to construct this.
    sqs = SearchQuerySet().filter(content=Raw('{!dismax qf=author mm=1}haystack'))

### `Clean`

class haystack.inputs.Clean

`Clean` takes standard user (untrusted) input and sanitizes it. It ensures that no unintended operators or special characters make it into the query.

This is roughly analogous to Django’s `autoescape` support.

Note

By default, if you hand a `SearchQuerySet` a bare string, it will get wrapped in this class.

Example:

    # This becomes "daniel or jones".
    sqs = SearchQuerySet().filter(content=Clean('daniel OR jones'))

    # Things like ``:`` & ``/`` get escaped.
    sqs = SearchQuerySet().filter(url=Clean('http://www.example.com'))

    # Equivalent (automatically wrapped in ``Clean``).
    sqs = SearchQuerySet().filter(url='http://www.example.com')

### `Exact`

class haystack.inputs.Exact

`Exact` allows for making sure a phrase is exactly matched, unlike the usual `AND` lookups, where words may be far apart.

Example:

    sqs = SearchQuerySet().filter(author=Exact('n-gram support'))

    # Equivalent.
    sqs = SearchQuerySet().filter(author__exact='n-gram support')

### `Not`

class haystack.inputs.Not

`Not` allows negation of the query fragment it wraps. As `Not` is a subclass of `Clean`, it will also sanitize the query.

This is generally only used internally. Most people prefer to use the `SearchQuerySet.exclude` method.

Example:

    sqs = SearchQuerySet().filter(author=Not('daniel'))

### `AutoQuery`

class haystack.inputs.AutoQuery

`AutoQuery` takes a more complex user query (that includes simple, standard query syntax bits) & forms a proper query out of them. It also handles sanitizing that query using `Clean` to ensure the query doesn’t break.

`AutoQuery` accommodates for handling regular words, NOT-ing words & extracting exact phrases.

Example:

    # Against the main text field with an accidental ":" before "search".
    # Generates a query like ``haystack (NOT whoosh) "fast search"``
    sqs = SearchQuerySet().filter(content=AutoQuery('haystack -whoosh "fast :search"'))

    # Equivalent.
    sqs = SearchQuerySet().auto_query('haystack -whoosh "fast :search"')

    # Fielded.
    sqs = SearchQuerySet().filter(author=AutoQuery('daniel -day -lewis'))

### `AltParser`

class haystack.inputs.AltParser

`AltParser` lets you specify that a portion of the query should use a separate parser in the search engine. This is search-engine-specific, so it may decrease the portability of your app.

Currently only supported under Solr.

Example:

    # DisMax.
    sqs = SearchQuerySet().filter(content=AltParser('dismax', 'haystack', qf='text', mm=1))

    # Prior to the spatial support, you could do...
    sqs = SearchQuerySet().filter(content=AltParser('dismax', 'haystack', qf='author', mm=1))

## Creating Your Own Input Types

Building your own input type is relatively simple. All input types are simple classes that provide an `__init__` & a `prepare` method.

The `__init__` may accept any `args/kwargs`, though the typical use usually just involves a query string.

The `prepare` method lets you alter the query the user provided before it becomes of the main query. It is lazy, called as late as possible, right before the final query is built & shipped to the engine.

A full, if somewhat silly, example looks like:

    from haystack.inputs import Clean

    class NoShoutCaps(Clean):
        input_type_name = 'no_shout_caps'
        # This is the default & doesn't need to be specified.
        post_process = True

        def __init__(self, query_string, **kwargs):
            # Stash the original, if you need it.
            self.original = query_string
            super().__init__(query_string, **kwargs)

        def prepare(self, query_obj):
            # We need a reference to the current ``SearchQuery`` object this
            # will run against, in case we need backend-specific code.
            query_string = super().prepare(query_obj)

            # Take that, capital letters!
            return query_string.lower()