Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to search by integer field as a string (e.g. "priority") with django-haystack?

I've got a Ticket model that I'm trying to search by its IntegerField priority attribute as a string. I can get haystack+solr to search by the integer value, but not as a string.

I thought you could do this with a prepare_priority function in the search index class, but I'm not having any luck. Here's my search_index.py:

from haystack import indexes
from helpdesk.models import Ticket

class TicketIndex(indexes.SearchIndex, indexes.Indexable):
    text = indexes.CharField(document=True, use_template=True)
    title = indexes.CharField(model_attr='title')
    priority = indexes.CharField(model_attr='priority')

    def prepare_priority(self, obj):
        priorities = {1:'critical', 2:'high', 3:'normal', 4:'low'}
        return priorities[obj.priority]

    def get_model(self):
        return Ticket

    def index_queryset(self):
        """Used when the entire index for model is updated."""
        return self.get_model().objects.all()

Here's my ticket_text.txt template:

{{ object.title }}
{{ object.priority }}
{{ object.body }}

Am I misunderstanding something or doing something wrong?

Thanks.

like image 805
Tony Avatar asked Jan 26 '26 13:01

Tony


1 Answers

Why prepare_priority() "doesn't work"

A SearchIndex is used to convert individual objects of a given model into entries in your Whoosh index. I'll call these entries SearchResults, since that's how they show up in the shell. Now, the fields you defined in TicketIndex are (of course) present on the SearchResults for the Tickets:

>>> from haystack.query import SearchQuerySet
>>> q = SearchQuerySet()
>>> ticket0 = q.all()[0]
>>> type(ticket0)
<class 'haystack.models.SearchResult'>
>>> hasattr(ticket0, 'text') and hasattr(ticket0, 'title') and hasattr(ticket0, 'priority')
True

That means that 'priority' shows up twice--once as independent field and once as part of the content of 'text'. The independent field does go through the prepare_X procedure. The text field goes through a template (where object refers to the original model object, not a dictionary of prepared data).

>>> print ticket0.priority
critical
>>> print ticket0.text
OH NOES!!!!
1
There's a problem. Very problematic. Please fix at once.

Fixing it

In the models:

PRIORITIES = {1:'critical', 2:'high', 3:'normal', 4:'low'}
class Ticket(models.Model):
  ...
  priority = models.IntegerField(choices=PRIORITIES.items())

Use the automatically provided get_priority_display as the model_attr:

class TicketIndex(indexes.SearchIndex):
  ...
  priority = indexes.CharField(model_attr='get_priority_display')

Use get_priority_display in the template:

{{ object.get_priority_display }}
like image 87
Stumpy Joe Pete Avatar answered Jan 29 '26 13:01

Stumpy Joe Pete



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!