Search code examples
djangomodelgetmany-to-many

Django - Query for any objects where any item from list is in ManytoMany field


I have a model in Django that has a ManytoMany field called 'accepted_insurance'. I have a form that submits a get request with a query string that contains of list of insurance providers. I am trying to write a query that says 'If any of the items from the query string list, are in the ManytoMany field list, than filter those objects.'. Is there a Django query shortcut for this ? I attempted to use 'contains', but I got a type error that the related field got an invalid lookup, and I'm sure that would simply say if the list contained the list.

models.py

class Provider(models.Model):
    title = models.CharField(max_length=255, null=True, blank=True)
    first_name = models.CharField(max_length=255, null=True, blank=True)
    middle_name = models.CharField(max_length=255, null=True, blank=True)
    last_name = models.CharField(max_length=255, null=True, blank=True)
    email = models.EmailField(null=True, blank=True)
    phone = models.CharField(max_length=40, null=True, blank=True)
    extension = models.CharField(max_length=10, null=True, blank=True)
    company = models.CharField(max_length=255, null=True, blank=True)
    age = models.IntegerField(null=True, blank=True)
    about = models.TextField(default='', null=True, blank=True)
    position = models.CharField(max_length=255, null=True, blank=True)

    cost_per_session = models.CharField(max_length=255, null=True, blank=True)
    accepts_insurance = models.BooleanField(default=False)
    accepted_insurance = models.ManyToManyField('Insurance', blank=True)
    payment_methods = models.ManyToManyField('PaymentMethod', blank=True)

request.GET

http://localhost:8004/directory/?search=timothy&insurance=cigna,aetna,optum_health,united_behavioral,blue_cross_blue_shield

<QueryDict: {'insurance': ['cigna,aetna,optum_health,united_behavioral,blue_cross_blue_shield'], 'search': ['timothy']}>

views.py Query

for param in request.GET:
    if param.lower() == 'insurance':
        all_providers = all_providers.filter(accepted_insurance__contains=param)

Solution

  • __in is the operator you need here.

    However you have a few other problems. Firstly there is no need to loop through the querydict; it is a dict, you can access it via key.

    Secondly, you currently have a single string; you need to split it into a list of strings with the split(',') method.

    Thirdly, you need to actually filter against a field on the Insurance model - presumably it has a "name" field.

    So:

    insurance = request.GET.get('insurance', '').split(',')
    all_providers = all_providers.filter(accepted_insurance__name__in=insurance)