Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django manytomany field, how to get check for 80% subset/ match?

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
like image 534
Deepti Avatar asked Jul 06 '15 07:07

Deepti


1 Answers

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())
like image 79
CJ4 Avatar answered Oct 27 '22 00:10

CJ4