Rob G
Rob G

Reputation: 3526

Can OR-clauses be combined with distance filters in Haystack for Django?

I've been using a distance filter using regular django query filters within an OR-clause:

# either it's within the preset distance of the location
# OR it's not an in-person event
self.filter(Q(location__distance_lt=(geometry, LOCATION_WITHIN_D)) | ~Q(type=Event.IN_PERSON))

I want to do a similar filtering as part of a haystack query, using SQ:

queryset = queryset.filter(SQ(location__distance_lt=(geometry, LOCATION_WITHIN_D)) | ~SQ(type=Event.IN_PERSON))

but instead I get back the error: not all arguments converted during string formatting - and that only happens with the distance_lt query part, not the ~SQ(type..)

I'm able to apply the distance filtering with my haystack search query by using

queryset = queryset.dwithin('location', geometry, LOCATION_WITHIN_D)`

but I want to be able to have that 'or' condition in this sub-clause.

Is this even possible with raw querying? How can I construct such a raw query for ElasticSearch and still execute it as part of my haystack query?

Upvotes: 2

Views: 296

Answers (2)

Ken4scholars
Ken4scholars

Reputation: 6296

Got into this exact issue with the same virtual Event scenario (what are the chances right??). Seems the way to go about it is to split the querysets at that point and combine them afterwards

qs1 = queryset.dwithin('location', geometry, LOCATION_WITHIN_D)
qs2 = queryset.exclude(type=Event.IN_PERSON)
queryset = qs1 | qs2

Upvotes: 0

Oluwafemi Sule
Oluwafemi Sule

Reputation: 38982

You can perform the search against the Elasticsearch connection.

from django.contrib.gis.measure import D
from haystack.query import SearchQuerySet

sqs = SearchQuerySet('default')
be = sqs.query.backend
LOCATION_WITHIN_D = D(km=0.1)
geometry = {
    "lat": 60.1939,
    "lon": 11.1003
}

raw_query = {
  "query": {
    "bool": {
      "filter": [
        {
          "bool": {
            "should": [
              {
                "match": {
                  "type": Event.IN_PERSON
                }
              },
              {
                "geo_distance": {
                  "distance": str(LOCATION_WITHIN_D),
                  "location": geometry
                }
              }
            ]
          }
        }
      ]
    }
  }
}
result = be.conn.search(body=raw_query, index='name-of-your-index')

Upvotes: 1

Related Questions