2014-02-18 6 views
4

Во-первых, я сделал домашнее задание и огляделся перед публикацией! Мой вопрос кажется очень простой, что, должно быть, было рассмотрено раньше.django model search form

В настоящее время я рассматриваю Django-filter как потенциальное решение, но хотел бы посоветовать, если это правильный путь, и если есть какие-либо другие решения.

У меня есть приложение Django с 10 моделями, каждая модель имеет несколько полей. В большинстве полей ChoiceField пользователи заполняют формы с помощью стандартного select виджета. Для каждой модели есть отдельная форма.

Я хочу создать отдельную форму для каждой модели (в отдельных представлениях), которую пользователи будут использовать для поиска в базе данных. Форма поиска будет содержать только раскрывающийся список (select виджетов) с теми же вариантами, что и формы, используемые для заполнения базы данных с добавлением опции «любой».

Я знаю, как использовать .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() 

Пользователи могут выбрать только «тип», только «расположение» или оба (не делает выбор равно любому) и в этом случае я в конечном итоге с 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) 

ответ

3

У меня был подобный случай, как ваши (проект недвижимости), я закончил со следующим подходом, вы можете уточнить это для ваших потребностей ... Я удалил 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'})) 

Затем в свойствах/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 

В вашем фактической точке зрения (я применяю форму поиска как боковой элемент в моем DetailView только:

# 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

Ваше решение работает. Я изменил его, и я не использую ModelChoiceField, но стандартную форму. ChoiceField. Причина в том, что я хотел добавить опцию «Any». Мои утверждения «если» выглядят следующим образом:

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. Он близок к тому, что я хочу, но я не мог добавить «Любой» выбор, и он фильтрует встроенную, а не возвращающую. Он должен делать некоторые изменения.

Cheers