Indexing and searching related objects with haystack
Asked Answered
B

1

9

I'm pretty new to search implementation, bear with me while I'm learning!

So my pet project is a recipe site and each recipe can have n steps. the model looks something like:

class Recipe(models.Model):
    title = models.CharField(max_length=255)
    description = models.TextField()
    hotness = models.ForeignKey(Hotness)
    recipe_diet = models.ManyToManyField(DietType)
    ingredients = models.ManyToManyField(Ingredient, through="RecipeIngredient")

class DietType(models.Model):
    diet_type = models.CharField(max_length=50)
    description = models.TextField(null=True, blank=True)

class RecipeIngredient(models.Model):
    recipe = models.ForeignKey(Recipe)
    ingredient = models.ForeignKey(Ingredient)
    quantifier = models.ForeignKey(Quantifier)
    quantity = models.FloatField()

class RecipeSteps(models.Model):
    step_number = models.IntegerField()
    description = models.TextField()
    recipe = models.ForeignKey(Recipe)

(shortened for brevity)

I want to index all of it: Recipe, RecipeIngredient, DietType and Steps... The DietType and RecipeIngredient seem to be working fine, but the Steps are not. I assume this has to do with the usage of 'RelatedSearchQuerySet' ?

Here is my search_indexes.py:

from haystack import indexes
from recipes.models import Recipe

class RecipeIndex(indexes.SearchIndex, indexes.Indexable):
    text = indexes.CharField(document=True, use_template=True)
    title = indexes.CharField(model_attr='title')
    ingredients = indexes.MultiValueField(indexed=True, stored=True)
    description = indexes.CharField(model_attr='description')
    hotness = indexes.CharField(model_attr='hotness')
    diet_type = indexes.MultiValueField(indexed=True, stored=True)
    recipesteps = indexes.MultiValueField(indexed=True, stored=True)

    def prepare_steps(self, object):
        return [step.description for step in object.recipesteps.all()]

    def get_model(self):
        return Recipe

    def load_all_queryset(self):
        # Pull all objects related to the Note in search results.
        return Recipe.objects.all().select_related()

Here is the template recipe_text.txt:

{{ object.title }}
{{ object.cuisine }}
{% for ingr in object.ingredients.all %}
  {{ ingr.title }}
{% endfor %}
{{ object.description }}
{% for dt in object.recipe_diet.all %}
  {{ dt.diet_type }}
{% endfor %}
{{ object.user }}
{{ object.hotness }}
{% for step in object.recipesteps.all %}
  {{ step.description }}
{% endfor %}
{{ object.body }}

I can search ingredients, title, description, diet type - everything works, except the RecipeSteps.

Finally, I'm making queries through the shell only at the moment:

#producing results:
sq = SearchQuerySet().filter(content='onion') #ingredient
sq = SearchQuerySet().filter(content='bolognese') #title
sq = SearchQuerySet().filter(content='bologna') #description
#not producing any results:
sq = SearchQuerySet().filter(content='chop') #step
sq = RelatedSearchQuerySet().filter(content='chop').load_all() #assuming this does the expanded search

Any idea?

Bigname answered 26/6, 2017 at 20:20 Comment(5)
I want to be able to get recipes that contain a step that matches a search query. IE: I want to search the steps themselves but get the recipe back.Bigname
Does RecipeSteps have its own index?Denunciatory
No, I haven't indexed this for search at all yet. Is that the key?Bigname
I am fairly sure that will set you right.Denunciatory
Was it any help?Denunciatory
H
4

I have identified two issues:

  1. The name prepare_steps in your RecipeIndex is wrong it should be prepare_{field_name} so change it to prepare_recipesteps

  2. You are trying to access related steps object.recipesteps.all objects recipe_text.txt in a wrong way, it should be object.recipesteps_set.all. Or keep using recipesteps but add this as a related_name in RecipeSteps model for ForeignKey Recipe e.g.

    class RecipeSteps(models.Model):
        # //
        recipe = models.ForeignKey(Recipe, related_name='recipesteps')
    
Havildar answered 5/7, 2017 at 15:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.