Django:如何基于M2M字段对对象进行查询(搜索表单上的字段有多个选择)

时间:2010-12-23 18:48:26

标签: django manytomanyfield multipleselection

我需要帮助提出一种基于M2M字段对一组对象进行搜索查询的有效方法。我的搜索表格看起来像Blue Cross Blue Shield的|例如:this image

现在,让我们假设我的模型如下:

# 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

此外,我们必须记住,我们选择的选项可能会发生变化,因为它们在表单上的显示方式是动态的(可以随时添加新的ServiceCategories和ServiceTypes)。 *如果使用搜索表单的人可以选择多个Services_Offered,我应该如何构建Provider对象的查询?*

这是我目前非常缺乏的方法:

#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))

如何查询:

  1. 根据选择多个request.POST ['service']

  2. 获取Provider对象
  3. 效率更高

  4. 感谢先进的任何帮助。

    最诚挚的问候, 马特

1 个答案:

答案 0 :(得分:1)

1:对于多个request.POST ['service'],我认为你的意思是这些是CheckBoxes。

我将CheckBox值设为ID,而不是名称,并进行PK查找。

'services_offered__pk__in': request.POST.getlist('service') 这将返回所有已选择所有服务的Provider个对象。

PS:您也使用CapitalCase进行非常混乱的实例。如果您希望您的代码可读,我强烈建议您对样式进行一些更改(不要将CapitalCase用于实例或变量)并使您的变量更具描述性。

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:提高效率?通过删除整个Query类,您可以摆脱大量代码和代码分离。另外,我不知道你为什么使用Q对象,因为你没有做任何需要它的东西(比如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})