django-haystack / django-haystack/django-haystack

Nested model_attr lookup doesn't work as expected with iterable fields

Open
#1,411 7 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
3.7k
Forks
1.3k
Avg merge
3h 18m
Merged PRs (30d)
3

Description

2a450d8 changed how nested model_attr lookups work such that if a model field is iterable, a nested lookup may fail.

  • Tested with the latest Haystack release
  • Tested with the current Haystack master branch

Expected behaviour

Indexing a nested attribute of an iterable field should work.

Actual behaviour

Indexing a nested attribute of an iterable field does not work in some cases, specifically with GeoDjango PointFields (and probably with any field type that is iterable).

Steps to reproduce the behaviour

  1. Create a model with a GeoDjango GeometryField (e.g., geom = models.PointField())
  2. Create a SearchIndex for that model with a field like longitude = indexes.FloatField(model_attr='geom__x', indexed=False)
  3. Index the model using manage.py rebuild_index
  4. rebuild_index fails with a message like "haystack.exceptions.SearchFieldError: The model '-122.67912' does not have a model_attr 'x'." (this happens because SearchField.resolve_attributes_lookup() iterates over the x and y fields of GeoDjango Points)

Configuration

  • Operating system version: N/A
  • Search engine version: N/A
  • Python version: 3
  • Django version: 1.8.13
  • Haystack version: 2.5.0

I don't understand what 2a450d8 meant to do beyond supporting many-to-many fields, so I'm not sure what a proper fix would be, but here's a hacky fix that works for my specific use case (but causes some of the tests introduced in 2a450d8 to fail):

diff --git a/haystack/fields.py b/haystack/fields.py
index 0fa1abc..25adb54 100644
--- a/haystack/fields.py
+++ b/haystack/fields.py
@@ -153,7 +153,7 @@ class SearchField(object):
                 return current_objects.all()
             return []

-        elif not hasattr(current_objects, '__iter__'):
+        else:
             current_objects = [current_objects]

         return current_objects

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in haystack/fields.py at SearchField.resolve_attributes_lookup(), then inspect the tests introduced by commit 2a450d8. Reproduce the GeoDjango PointField case from the issue and run the affected tests. Done means nested model_attr lookup works for iterable fields while the existing many-to-many behavior remains passing.

Written by the indexing model from the issue text.

Assessment

Tech stack
django, python
Domain
backend, search
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.