【问题标题】:django model search formdjango 模型搜索表​​单
【发布时间】:2014-03-17 23:43:46
【问题描述】:

首先,我在发布之前做了功课并环顾四周!我的问题似乎是一个非常基本的问题,以前必须讨论过。

我现在正在将 Django-filter 视为一种潜在的解决方案,但想了解这是否是正确的方法以及是否有其他解决方案。

我有一个包含 10 个模型的 Django 应用程序,每个模型都有几个字段。大多数字段是ChoiceField,用户使用带有默认select 小部件的表单填充。每个模型都有一个单独的表格。

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

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

我曾短暂地将 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()

用户只能选择“类型”,只能选择“位置”或两者都选择(不选择等于 ANY)在这种情况下,我最终会得到 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)

【问题讨论】:

    标签: django forms search model


    【解决方案1】:

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

    properties/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
    

    【讨论】:

      【解决方案2】:

      您的解决方案有效。我已经对其进行了修改,但我没有使用 ModelChoiceField,而是使用标准 form.ChoiceField。原因是我想添加选项“任何”。我的“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)
      

      等等……

      这可以完成工作,但它似乎是一个简单问题的丑陋和 hacky 解决方案。我认为这是一个常见的用例。我觉得应该有一个更清洁的解决方案......

      我已经尝试过 django 过滤器。它接近于做我想做的事,但我无法添加“任何”选项,它会过滤内联而不是返回。它应该做一些修改。

      干杯

      【讨论】:

        猜你喜欢
        • 2011-12-08
        • 1970-01-01
        • 2011-09-22
        • 2018-07-11
        • 1970-01-01
        • 1970-01-01
        • 2012-04-21
        • 2021-08-29
        • 2023-03-23
        相关资源
        最近更新 更多