开发者

Django: How to make a query for on object based on an M2M field (multiple selections for field on search form)

I need help coming up with an efficient way to do a search query for a set of objects, based on a M2M field. My search form is going to look something like Blue Cross Blue Shield's | eg: this image

Now, let's suppose my model开发者_如何转开发 looks like this:

# models.py
class Provider(models.Model)
    title = models.CharField(max_length=150)
    phone = PhoneNumberField()
    services_offered = models.ManyToManyField(ServiceType)
        def __unicode__(self):
            return self.title

class ServiceCategory(models.Model):
    service_category = models.CharField(max_length=30) 
    def __unicode__(self):
    return self.service_category
    class Meta(object):
        verbose_name_plural = "Service Categories"


class ServiceType(models.Model):
    service_type = models.CharField(max_length=30)
    service_category = models.ForeignKey(ServiceCategory)       
    def __unicode__(self):
        return u'%s | %s' % (self.service_category, self.service_type

Also, we have to keep in mind that the options that we select are subject to change, since how they display on the form is dynamic (new ServiceCategories and ServiceTypes can be added at anytime). *How should I go about constructing a query for the Provider objects, given that a person using the search form can select multiple Services_Offered?*

This is currently my HIGHLY INEFFICIENT METHOD:

#managers.py

    from health.providers.models import *
    from django.db.models import Q

    class Query:
        def __init__(self):
        self.provider_objects=Provider.objects.all()
        self.provider_object=Provider.objects
        self.service_object=ServiceType.objects
        self.category_objects=ServiceCategory.objects.all()

        def simple_search_Q(self, **kwargs): #matt's learning note: **kwargs passes any dictionary
        return self.provider_objects.filter(
        Q(services_offered__service_type__icontains=kwargs['service']),
        Q(title__icontains=kwargs['title']),
        Q(state=kwargs['state']),
        ).distinct().order_by('title')

====================

  #views.py
    from django.shortcuts import render_to_response
    from health.providers.models import *
    from health.search.forms import *
    from health.search.managers import Query #location of the query sets
    from django.core.paginator import Paginator,  InvalidPage, EmptyPage
    from django.template import RequestContext


    def simple_search(request):
        if request.method == 'POST':
        SimpleSearch_form = SimpleSearch(request.POST)
        if SimpleSearch_form.is_valid():
            request.session["provider_list"] = None
            kwargs = {'title': request.POST['title'],
                'service': request.POST['service'], 'state': request.POST['state'] }
            provider_list = Query().simple_search_Q(**kwargs)
            return pagination_results(request, provider_list)
        else:
        SimpleSearch_form = SimpleSearch()

        return render_to_response('../templates/index.html', { 'SimpleSearch_form': SimpleSearch_form},
            context_instance=RequestContext(request))

How can I make my query:

  1. Obtain Provider objects based on selecting multiple request.POST['service']

  2. More efficient

Thanks for any help in advanced.

Best Regards, Matt


1: for multiple request.POST['service'], I assume you mean these are CheckBoxes.

I'd make the CheckBox values ID's, not names, and do a PK lookup.

'services_offered__pk__in': request.POST.getlist('service') That would return all Provider objects that have ALL of the services selected.

PS: You are also using CapitalCase for instances which is very confusing. If you want your code to be readable, I highly recommend some changes to your style (don't use CapitalCase for instances or variables) and make your variables more descriptive.

SimpleSearch_form = SimpleSearch() # what is SimpleSearch? 
simplesearch_form = SimpleSearchForm() # now, it's very clear what the class SimpleSearchForm is
# and the form instance is clearly a for instance.

2: making it more efficient? You could get rid of a lot of code and code separation by remove your whole Query class. Also, I don't know why you are using Q objects since you are not doing anything that would require it (like OR or OR + AND).

def simple_search(request):
    if request.method == 'POST':
        searchform = SimpleSearchForm(request.POST)

        if searchform.is_valid():
            request.session['provider_list'] = None
            post = request.POST
            providers = Provider.objects.filter(services_offered__pk__in=post.getlist('services'),
                title=post['title'], state=post['state'])
            return pagination_results(request, provider_list)
    else:
        searchform = SimpleSearchForm()

    return direct_to_template(request, '../templates/index.html', { 'searchform': searchform})
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜