Boolean fields in django-haystack
Say, you're using django-haystack to integrate search & faceting to your project, backed by ElasticSearch. The index that you're building has a boolean field:
class SampleIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True)
sample_bool = indexes.BooleanField(model_attr='sample_bool')
Then, you try filtering by that boolean field like you'd normally do with a Django's QuerySet
:
>>> from haystack.query import SearchQuerySet
>>> SearchQuerySet().count()
42
>>> SearchQuerySet().filter(sample_bool=True).count()
42
Is it really correct? Given that there are only boolean values in existence are True
and False
,
you'd expect filtering on False
should give you exactly zero results. Let's verify that:
>>> SearchQuerySet().filter(sample_bool=False).count()
42
Well, that's because when translating a query to language that ElasticSearch understands, both True
and False
are turned into their stringified representations ("True"
and "False"
) which both evaluate to a truthy value. In fact,
any non-empty string would also yield the same result:
>>> SearchQuerySet().filter(sample_bool='example').count()
42
To get the results we expect we need to pass "true"
and "false"
(lowercase strings):
>>> SearchQuerySet().filter(sample_bool='true').count()
42
>>> SearchQuerySet().filter(sample_bool='false').count()
0
ElasticSearch 5 warns you against passing boolean values directly:
[WARN ][o.e.d.i.m.BooleanFieldMapper] searching using boolean value [False] is deprecated, please use [true] or [false]
And that's what is called a leaky abstraction. In order to query on boolean fields, users need to be aware of how the underlying implementation behaves.