PageRenderTime 48ms CodeModel.GetById 17ms app.highlight 26ms RepoModel.GetById 1ms app.codeStats 0ms

/bangkokhotel/lib/python2.5/site-packages/haystack/views.py

https://bitbucket.org/luisrodriguez/bangkokhotel
Python | 235 lines | 225 code | 5 blank | 5 comment | 0 complexity | 50a4907458326ee88c2bea3c65a67ab7 MD5 | raw file
  1from django.conf import settings
  2from django.core.paginator import Paginator, InvalidPage
  3from django.http import Http404
  4from django.shortcuts import render_to_response
  5from django.template import RequestContext
  6from haystack.forms import ModelSearchForm, FacetedSearchForm
  7from haystack.query import EmptySearchQuerySet
  8
  9
 10RESULTS_PER_PAGE = getattr(settings, 'HAYSTACK_SEARCH_RESULTS_PER_PAGE', 20)
 11
 12
 13class SearchView(object):
 14    __name__ = 'SearchView'
 15    template = 'search/search.html'
 16    extra_context = {}
 17    query = ''
 18    results = EmptySearchQuerySet()
 19    request = None
 20    form = None
 21    results_per_page = RESULTS_PER_PAGE
 22    
 23    def __init__(self, template=None, load_all=True, form_class=None, searchqueryset=None, context_class=RequestContext, results_per_page=None):
 24        self.load_all = load_all
 25        self.form_class = form_class
 26        self.context_class = context_class
 27        self.searchqueryset = searchqueryset
 28        
 29        if form_class is None:
 30            self.form_class = ModelSearchForm
 31        
 32        if not results_per_page is None:
 33            self.results_per_page = results_per_page
 34        
 35        if template:
 36            self.template = template
 37    
 38    def __call__(self, request):
 39        """
 40        Generates the actual response to the search.
 41        
 42        Relies on internal, overridable methods to construct the response.
 43        """
 44        self.request = request
 45        
 46        self.form = self.build_form()
 47        self.query = self.get_query()
 48        self.results = self.get_results()
 49        
 50        return self.create_response()
 51    
 52    def build_form(self, form_kwargs=None):
 53        """
 54        Instantiates the form the class should use to process the search query.
 55        """
 56        data = None
 57        kwargs = {
 58            'load_all': self.load_all,
 59        }
 60        if form_kwargs:
 61            kwargs.update(form_kwargs)
 62        
 63        if len(self.request.GET):
 64            data = self.request.GET
 65        
 66        if self.searchqueryset is not None:
 67            kwargs['searchqueryset'] = self.searchqueryset
 68        
 69        return self.form_class(data, **kwargs)
 70    
 71    def get_query(self):
 72        """
 73        Returns the query provided by the user.
 74        
 75        Returns an empty string if the query is invalid.
 76        """
 77        if self.form.is_valid():
 78            return self.form.cleaned_data['q']
 79        
 80        return ''
 81    
 82    def get_results(self):
 83        """
 84        Fetches the results via the form.
 85        
 86        Returns an empty list if there's no query to search with.
 87        """
 88        return self.form.search()
 89    
 90    def build_page(self):
 91        """
 92        Paginates the results appropriately.
 93
 94        In case someone does not want to use Django's built-in pagination, it
 95        should be a simple matter to override this method to do what they would
 96        like.
 97        """
 98
 99        try:
100            page_no = int(self.request.GET.get('page', 1))
101        except (TypeError, ValueError):
102            raise Http404("Not a valid number for page.")
103
104        if page_no < 1:
105            raise Http404("Pages should be 1 or greater.")
106
107        start_offset = (page_no - 1) * self.results_per_page
108        self.results[start_offset:start_offset + self.results_per_page]
109
110        paginator = Paginator(self.results, self.results_per_page)
111
112        try:
113            page = paginator.page(page_no)
114        except InvalidPage:
115            raise Http404("No such page!")
116
117        return (paginator, page)
118    
119    def extra_context(self):
120        """
121        Allows the addition of more context variables as needed.
122        
123        Must return a dictionary.
124        """
125        return {}
126    
127    def create_response(self):
128        """
129        Generates the actual HttpResponse to send back to the user.
130        """
131        (paginator, page) = self.build_page()
132        
133        context = {
134            'query': self.query,
135            'form': self.form,
136            'page': page,
137            'paginator': paginator,
138            'suggestion': None,
139        }
140        
141        if getattr(settings, 'HAYSTACK_INCLUDE_SPELLING', False):
142            context['suggestion'] = self.form.get_suggestion()
143        
144        context.update(self.extra_context())
145        return render_to_response(self.template, context, context_instance=self.context_class(self.request))
146
147
148def search_view_factory(view_class=SearchView, *args, **kwargs):
149    def search_view(request):
150        return view_class(*args, **kwargs)(request)
151    return search_view
152
153
154class FacetedSearchView(SearchView):
155    __name__ = 'FacetedSearchView'
156    
157    def __init__(self, *args, **kwargs):
158        # Needed to switch out the default form class.
159        if kwargs.get('form_class') is None:
160            kwargs['form_class'] = FacetedSearchForm
161        
162        super(FacetedSearchView, self).__init__(*args, **kwargs)
163    
164    def build_form(self, form_kwargs=None):
165        if form_kwargs is None:
166            form_kwargs = {}
167        
168        # This way the form can always receive a list containing zero or more
169        # facet expressions:
170        form_kwargs['selected_facets'] = self.request.GET.getlist("selected_facets")
171        
172        return super(FacetedSearchView, self).build_form(form_kwargs)
173    
174    def extra_context(self):
175        extra = super(FacetedSearchView, self).extra_context()
176        extra['request'] = self.request
177        extra['facets'] = self.results.facet_counts()
178        return extra
179
180
181def basic_search(request, template='search/search.html', load_all=True, form_class=ModelSearchForm, searchqueryset=None, context_class=RequestContext, extra_context=None, results_per_page=None):
182    """
183    A more traditional view that also demonstrate an alternative
184    way to use Haystack.
185    
186    Useful as an example of for basing heavily custom views off of.
187    
188    Also has the benefit of thread-safety, which the ``SearchView`` class may
189    not be.
190    
191    Template:: ``search/search.html``
192    Context::
193        * form
194          An instance of the ``form_class``. (default: ``ModelSearchForm``)
195        * page
196          The current page of search results.
197        * paginator
198          A paginator instance for the results.
199        * query
200          The query received by the form.
201    """
202    query = ''
203    results = EmptySearchQuerySet()
204    
205    if request.GET.get('q'):
206        form = form_class(request.GET, searchqueryset=searchqueryset, load_all=load_all)
207        
208        if form.is_valid():
209            query = form.cleaned_data['q']
210            results = form.search()
211    else:
212        form = form_class(searchqueryset=searchqueryset, load_all=load_all)
213    
214    paginator = Paginator(results, results_per_page or RESULTS_PER_PAGE)
215    
216    try:
217        page = paginator.page(int(request.GET.get('page', 1)))
218    except InvalidPage:
219        raise Http404("No such page of results!")
220    
221    context = {
222        'form': form,
223        'page': page,
224        'paginator': paginator,
225        'query': query,
226        'suggestion': None,
227    }
228    
229    if getattr(settings, 'HAYSTACK_INCLUDE_SPELLING', False):
230        context['suggestion'] = form.get_suggestion()
231    
232    if extra_context:
233        context.update(extra_context)
234    
235    return render_to_response(template, context, context_instance=context_class(request))