7

I have a Django db with cooking recipes. I want to query all users who have at least 80% ingredients to make a recipe. How do I achieve this?

Or how do I query for users who are missing only 1 ingredient for the recipe?

models.py

class ingredient(models.Model):
    id = models.AutoField("id",max_length = 100, primary_key=True)
    name=models.CharField("Ingredient", max_length=100)

    def __unicode__ (self):
        return self.name

class user(models.Model):
    id = models.AutoField("id",max_length = 100, primary_key=True
    ingredient = models.ManyToManyField(ingredient,blank=True)

    def __unicode__ (self):
        return str(self.id)

class recipe(models.Model):
    id = models.AutoField("id", max_length=100, primary_key=True)
    recipe_ingredient = models.ManyToManyField(ingredient,related_name='recipe_ingredient',blank=True)

    def __unicode__ (self):
        return self.id
Deepti
  • 576
  • 2
  • 5
  • 15

1 Answers1

3

I would use django-haystack for this, you can setup an index for your job_opening model and index all the ingredients:

class JobOpeningIndex(indexes.SearchIndex, indexes.Indexable):
    text = indexes.CharField(document=True, use_template=True)
    recipe_ingredient = indexes.MultiValueField()

    def prepare_recipe_ingredient(self, obj):
        return [i.name for i in obj.recipe_ingredient.all()]

    def get_model(self):
        return job_opening

    def index_queryset(self, using=None):
        return self.get_model().objects.all()

After the indexes has been created you can just do a filter by ingredient or list of ingredients, haystack will return all objects which match the search criteria, sorted by relevance. You can then just map the 80% to a score in relevance and filter out the items with a relevancy lower that your required amount.

SearchQuerySet().models(job_opening).filter(recipe_ingredient__in=['ingredient1', 'ingredient2', 'ingredient3'])

EDIT

After reading the edited question, we basically have to use recipe where we used job_opening. And it seems like you want to find relevant users, not recipes. To accomplish this, you would have to index the user model instead of the original job_opening model:

class UserIndex(indexes.SearchIndex, indexes.Indexable):
    text = indexes.CharField(document=True, use_template=True)
    ingredient = indexes.MultiValueField()

    def prepare_ingredient(self, obj):
        return [i.name for i in obj.ingredient.all()]

    def get_model(self):
        return user

    def index_queryset(self, using=None):
        return self.get_model().objects.all()

After the index has been created, you can then do the filter like this:

myrecipe = recipe.objects.get(...)
SearchQuerySet().models(user).filter(ingredient__in=myrecipe.recipe_ingredient.all())
CJ4
  • 2,485
  • 3
  • 26
  • 29
  • I asked the wrong question, I'm sorry. I edited it, could you take a look? – Deepti Jul 06 '15 at 10:19
  • Thank you, but I'm able to do that with for s in recipe.recipe_ingredient.all(): users=users.filter(ingredient__id=s.id) How do I acheive the 80% match or users who are missing only 1 ingredient for the recipe? – Deepti Jul 06 '15 at 10:56
  • That is what the `SearchQuerySet()` does, it is a special queryset which adds a `score` attribute. The score represents the relevancy, which could be mapped to a percentage value ie. 80% – CJ4 Jul 06 '15 at 11:10