ajt
ajt

Reputation: 1381

Querying a second model with django haystack

I would like to add a field from a second model to a django-haystack query. I have two models that have the following structure:

class Product(models.Model):
    created_date = models.DateField(auto_now_add=True)
    name = models.CharField(max_length=254)
    summary = models.CharField(null=True, blank=True, max_length=255)
    ....

class Color(models.Model):
    product_color = models.CharField(max_length=256,  blank=True, null=True)
    created_date = models.DateField(auto_now_add=True)
    slug = models.SlugField(max_length=254)
    product = models.ForeignKey('Product')

I have the following search_index.py:

from django.utils import timezone
from haystack import indexes
from .models import Product
from .models import Color


class ProductIndex(indexes.SearchIndex, indexes.Indexable):
    text = indexes.CharField(document=True, use_template=True)

    def get_model(self):
        return Product

    def index_queryset(self, using=None):
        """Used when the entire index for model is updated."""
        return self.get_model().objects.filter(
            created_date__lte=timezone.now())

How can I add the Color model's product_color to the search index so that if someone includes a partial portion of a product_color in a search query it will return a Product that has a ForeignKey relationship to the color?

Upvotes: 1

Views: 332

Answers (2)

Aamir Rind
Aamir Rind

Reputation: 39659

Use MultiValueField which will store all colors associated with product:

product_colors = indexes.MultiValueField()

Prepare it:

def prepare_product_colors(self, obj):
    return [o.product_color for o in obj.color_set.all()]

And use that field directly to filter by product color. Or If you don't want to use search on specific field rather do an auto query then append the product colors to the final indexed text:

def prepare(self, obj):
    prepared_data = super(SlateUpIndex, self).prepare(obj)
    prepared_data['text'] += ' '.join(self.prepare_product_colors(obj))
    return prepared_data

Instead of doing all the above things just add the colors in the template search/indexes/{app_label}/{model_name}_{field_name}.txt:

{% for color in object.color_set.all %}
    {{ color.product_color }}
{% endfor %}

Upvotes: 2

Esteban
Esteban

Reputation: 2513

Do products have multiple colors? If not, i'd FK to 'Color' from the 'Product' model.

As-is, you can add a MultiValue Field to your index and prepare the values using a 'prepare_foo' function that is a built-in helper a-la 'clean_foo' in django forms.

See the docs for more info: SearchIndex Api

For example:

colors = indexes.MultValueField()
def prepare_colors(self, obj):
    return [color.product_color for color in obj.color_set.all()]

Upvotes: 0

Related Questions