django模型搜索表​​单

时间:2014-02-18 09:58:01

标签: django forms search model

首先,我做了我的作业并在张贴之前环顾四周!我的问题似乎是一个非常基本的问题,以前一定要涵盖。

我现在正在考虑Django-filter作为一种潜在的解决方案,但是如果这是正确的方法以及是否有其他解决方案,我想提供一些建议。

我有一个Django应用机智10个模型,每个模型都有几个字段。大多数字段为ChoiceField,用户使用默认select小部件的表单填充。每种型号都有一个单独的表格。

我想为每个模型创建一个单独的表单(在单独的视图中),用户将使用它来搜索数据库。搜索表单将仅包含下拉框(select窗口小部件),其选项与用于填充数据库的表单相同,但添加了“any”选项。

我知道如何使用.object.filter(),但“any”选项对应于不包含过滤器中的特定字段,我不知道如何根据用户的选择将模型字段添加到过滤器< / p>

我简单地看了一下Haystack作为一种选择,但它似乎是为了全文搜索,而不是我所追求的“模型归档搜索”。

样本模型(简化):

class Property():             
      TYPE_CHOICES = (‘apartment’, ‘house’, ‘flat’)        
      type = charfield(choices=TYPE_CHOICES)
      LOC_CHOICES = (‘Brussels’, ‘London’, ‘Dublin’, ‘Paris’)
      location = charfield(choices=LOC_CHOICES)
      price = PostivieInteger()

用户只能选择“类型”,只选择“位置”或两者(不选择等于任何选项),在这种情况下我最终会选择3个不同的过滤器:

Property.objects.filter(type=’apartment’)
Property.objects.filter(location=’Dublin’)
Property.objects.filter(type=’apartment’, location=’Dublin’)

主要问题:django-filter最佳选择?

Question 1: what’s the best option of accomplishing this overall? 
Question 2: how do I add model fields to the filter based on user’s form selection?
Question 3: how do I do the filter based on user selection? (I know how to use .filter(price_lt=).exclude(price_gt=) but again how do I do it dynamically based on selection as “ANY” would mean this is not included in the query)

2 个答案:

答案 0 :(得分:5)

我有一个类似你的案例(房地产项目),我最终采用了以下方法,你可以根据自己的需要进行优化......我删除了select_related和prefetch_related模型以便于阅读

属性/ forms.py:

class SearchPropertyForm(forms.Form):

    property_type = forms.ModelChoiceField(label=_("Property Type"), queryset=HouseType.objects.all(),widget=forms.Select(attrs={'class':'form-control input-sm'}))
    location = forms.ModelChoiceField(label=_('Location'), queryset=HouseLocation.objects.all(), widget=forms.Select(attrs={'class':'form-control input-sm'}))

然后在properties / views.py

# Create a Mixin to inject the search form in our context 

class SeachPropertyMixin(object):
    def get_context_data(self, **kwargs):
        context = super(SeachPropertyMixin, self).get_context_data(**kwargs)
        context['search_property_form'] = SearchPropertyForm()
        return context

在您的实际视图中(我仅在我的详细信息视图中将搜索表单应用为侧边栏元素:

# Use Class Based views, saves you a great deal of repeating code...
class PropertyView(SeachPropertyMixin,DetailView):
    template_name = 'properties/view.html'
    context_object_name = 'house'
    ...
    queryset = HouseModel.objects.select_related(...).prefetch_related(...).filter(flag_active=True, flag_status='a')

最后你的搜索结果视图(这是作为GET请求执行的,因为我们不会改变数据库中的任何数据,我们坚持使用GET方法):

# Search results should return a ListView, here is how we implement it:
class PropertySearchResultView(ListView):
    template_name = "properties/propertysearchresults.html"
    context_object_name = 'houses'
    paginate_by = 6
    queryset = HouseModel.objects.select_related(...).prefetch_related(...).order_by('-sale_price').filter(flag_active=True, flag_status='a')

    def get_queryset(self):
        qs = super(PropertySearchResultView,self).get_queryset()
        property_type = self.request.GET.get('property_type')
        location = self.request.GET.get('location')
        '''
        Start Chaining the filters based on the input, this way if the user has not 
        selected a filter it wont be used.
        '''
        if property_type != '' and property_type is not None:
            qs = qs.filter(housetype=property_type)
        if location != '' and location is not None:
            qs = qs.filter(location=location)
        return qs

    def get_context_data(self, **kwargs):
        context = super(PropertySearchResultView, self).get_context_data()
        ''' 
        Add the current request to the context 
        '''
        context['current_request'] = self.request.META['QUERY_STRING']
        return context

答案 1 :(得分:1)

您的解决方案有效。我修改了它,我没有使用ModelChoiceField,而是使用标准form.ChoiceField。原因是我想添加选项“Any”。我的“if”语句如下:

 if locality != 'Any Locality':
    qs = qs.filter(locality=locality)
if property_type != 'Any Type':
    qs = qs.filter(property_type=property_type)
if int(price_min) != 0:
    qs = qs.filter(price__gte=price_min)
if int(price_max) != 0:
    qs = qs.filter(price__lte=price_max)   
if bedrooms != 'Any Number':
    qs = qs.filter(bedrooms=bedrooms)

依旧......

这可以完成这项任务,但对于一个简单的问题来说,这似乎是一个丑陋而骇人的解决方案。我认为这是一个常见的用例。我觉得应该有一个更清洁的解决方案...

我尝试过django-filter。它接近做我想要的但我无法添加“任何”选择,它过滤内联而不是返回。它应该做一些修改。

干杯