Skip to content

Commit 9b38228

Browse files
committed
Finally added views/forms documentation. A touch rough still.
1 parent 225e051 commit 9b38228

File tree

4 files changed

+237
-2
lines changed

4 files changed

+237
-2
lines changed

TODO

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
In Progress
22
===========
33

4-
* Docs on forms/views.
5-
* Docs on faceting.
64
* Docs on contributing.
75
* Lucene backend.
86
* Formal packaging.
@@ -58,3 +56,6 @@ Complete
5856
* Docs on SearchIndexes (prepare's).
5957
* Handle missing dependencies.
6058
* Docs on backends.
59+
* Docs on faceting.
60+
* Docs on forms/views.
61+

docs/index.rst

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ you up and running:
2323
.. toctree::
2424
:maxdepth: 1
2525

26+
views_and_forms
2627
faq
2728
installing_search_engines
2829

docs/toc.rst

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Table Of Contents
66

77
index
88
tutorial
9+
views_and_forms
910
architecture_overview
1011
backend_support
1112
installing_search_engines

docs/views_and_forms.rst

+232
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
=============
2+
Views & Forms
3+
=============
4+
5+
Haystack comes with some default, simple views & forms to help you get started
6+
and to cover the common cases. Included is a way to provide:
7+
8+
* Basic, query-only search.
9+
* Search by models.
10+
* Search with basic highlighted results.
11+
* Faceted search.
12+
* Search by models with basic highlighted results.
13+
14+
Most processing is done by the forms provided by Haystack via the ``search``
15+
method. As a result, all but the faceted types (see :doc:`faceting`) use the
16+
standard ``SearchView``.
17+
18+
There is very little coupling between the forms & the views (other than relying
19+
on the existence of a ``search`` method on the form), so you may interchangeably
20+
use forms and/or views anywhere within your own code.
21+
22+
Forms
23+
=====
24+
25+
``SearchForm``
26+
--------------
27+
28+
The most basic of the form types, this form consists of a single field, the
29+
``q`` field (for query). Upon searching, the form will take the cleaned contents
30+
of the ``q`` field and perform an ``auto_query`` on either the custom
31+
``SearchQuerySet`` you provide or off a default ``SearchQuerySet``.
32+
33+
To customize the ``SearchQuerySet`` the form will use, pass it a
34+
``searchqueryset`` parameter to the constructor with the ``SearchQuerySet``
35+
you'd like to use. If using this form in conjunction with a ``SearchView``,
36+
the form will receive whatever ``SearchQuerySet`` you provide to the view with
37+
no additional work needed.
38+
39+
All other forms in Haystack inherit (either directly or indirectly) from this
40+
form.
41+
42+
``HighlightedSearchForm``
43+
-------------------------
44+
45+
Identical to the ``SearchForm`` except that it tags the ``highlight`` method on
46+
to the end of the ``SearchQuerySet`` to enable highlighted results.
47+
48+
``ModelSearchForm``
49+
-------------------
50+
51+
This form adds new fields to form. It iterates through all registered models for
52+
the current ``SearchSite`` and provides a checkbox for each one. If no models
53+
are selected, all types will show up in the results.
54+
55+
``HighlightedModelSearchForm``
56+
------------------------------
57+
58+
Identical to the ``ModelSearchForm`` except that it tags the ``highlight``
59+
method on to the end of the ``SearchQuerySet`` to enable highlighted results on
60+
the selected models.
61+
62+
``FacetedSearchForm``
63+
---------------------
64+
65+
Identical to the ``SearchForm`` except that it adds a hidden ``selected_facets``
66+
field onto the form, allowing the form to narrow the results based on the facets
67+
chosen by the user.
68+
69+
Creating Your Own Form
70+
----------------------
71+
72+
The simplest way to go about creating your own form is to inherit from
73+
``SearchForm`` (or the desired parent) and extend the ``search`` method. By
74+
doing this, you save yourself most of the work of handling data correctly and
75+
stay API compatible with the ``SearchView``.
76+
77+
For example, let's say you're providing search with a user-selectable date range
78+
associated with it. You might create a form that looked as follows::
79+
80+
from django import forms
81+
from haystack.forms import SearchForm
82+
83+
84+
class DateRangeSearchForm(SearchForm):
85+
start_date = forms.DateField(required=False)
86+
end_date = forms.DateField(required=False)
87+
88+
def search(self):
89+
# First, store the SearchQuerySet received from other processing.
90+
sqs = super(DateRangeSearchForm, self).search()
91+
92+
# Check to see if a start_date was chosen.
93+
if self.cleaned_data['start_date']:
94+
sqs = sqs.filter(pub_date__gte=self.cleaned_data['start_date'])
95+
96+
# Check to see if an end_date was chosen.
97+
if self.cleaned_data['end_date']:
98+
sqs = sqs.filter(pub_date__lte=self.cleaned_data['end_date'])
99+
100+
return sqs
101+
102+
This form adds two new fields for (optionally) choosing the start and end dates.
103+
Within the ``search`` method, we grab the results from the parent form's
104+
processing. Then, if a user has selected a start and/or end date, we apply that
105+
filtering. Finally, we simply return the ``SearchQuerySet``.
106+
107+
Views
108+
=====
109+
110+
Haystack comes bundled with two views, the ``SearchView`` and the
111+
``FacetedSearchView``. It uses class-based views for easy extension should you
112+
need to alter the way a view works. Except in the case of faceting (again, see
113+
:doc:`faceting`), the ``SearchView`` works interchangeably with all other forms
114+
provided by Haystack.
115+
116+
``SearchView(template=None, load_all=True, form_class=ModelSearchForm, searchqueryset=None, context_class=RequestContext)``
117+
---------------------------------------------------------------------------------------------------------------------------
118+
119+
The ``SearchView`` is designed to be easy/flexible enough to override common
120+
changes as well as being internally abstracted so that only altering a specific
121+
portion of the code should be easy to do.
122+
123+
Without touching any of the internals of the ``SearchView``, you can modify
124+
which template is used, which form class should be instantiated to search with,
125+
what ``SearchQuerySet`` to use in the event you wish to pre-filter the results.
126+
what ``Context``-style object to use in the response and the ``load_all``
127+
performance optimization to reduce hits on the database. These options can (and
128+
generally should) be overridden at the URLconf level. For example, to have a
129+
custom search limited to the 'John' author, displaying all models to search by
130+
and specifying a custom template (``my/special/path/john_search.html``), your
131+
URLconf should look something like::
132+
133+
from django.conf.urls.defaults import *
134+
from haystack.forms import ModelSearchForm
135+
from haystack.query import SearchQuerySet
136+
from haystack.views import SearchView
137+
138+
sqs = SearchQuerySet().filter(author='john')
139+
140+
urlpatterns = patterns('haystack.views',
141+
url(r'^$', SearchView(
142+
template='my/special/path/john_search.html',
143+
searchqueryset=sqs,
144+
form_class=ModelSearchForm
145+
), name='haystack_search'),
146+
)
147+
148+
Beyond this customizations, you can create your own ``SearchView`` and
149+
extend/override the following methods to change the functionality.
150+
151+
``__call__(self, request)``
152+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
153+
154+
Generates the actual response to the search.
155+
156+
Relies on internal, overridable methods to construct the response. You generally
157+
should avoid altering this method unless you need to change the flow of the
158+
methods or to add a new method into the processing.
159+
160+
``build_form(self)``
161+
~~~~~~~~~~~~~~~~~~~~
162+
163+
Instantiates the form the class should use to process the search query.
164+
165+
You should override this if you write a custom form that needs special
166+
parameters for instantiation.
167+
168+
``get_query(self)``
169+
~~~~~~~~~~~~~~~~~~~
170+
171+
Returns the query provided by the user.
172+
173+
Returns an empty string if the query is invalid. This pulls the cleaned query
174+
from the form, via the ``q`` field, for use elsewhere within the ``SearchView``.
175+
This is used to populate the ``query`` context variable.
176+
177+
``get_results(self)``
178+
~~~~~~~~~~~~~~~~~~~~~
179+
180+
Fetches the results via the form.
181+
182+
Returns an empty list if there's no query to search with. This method relies on
183+
the form to do the heavy lifting as much as possible.
184+
185+
``build_page(self)``
186+
~~~~~~~~~~~~~~~~~~~~
187+
188+
Paginates the results appropriately.
189+
190+
In case someone does not want to use Django's built-in pagination, it
191+
should be a simple matter to override this method to do what they would
192+
like.
193+
194+
``extra_context(self)``
195+
~~~~~~~~~~~~~~~~~~~~~~~
196+
197+
Allows the addition of more context variables as needed. Must return a
198+
dictionary whose contents will add to or overwrite the other variables in the
199+
context.
200+
201+
``create_response(self)``
202+
~~~~~~~~~~~~~~~~~~~~~~~~~
203+
204+
Generates the actual HttpResponse to send back to the user. It builds the page,
205+
creates the context and renders the response for all the aforementioned
206+
processing.
207+
208+
Creating Your Own View
209+
----------------------
210+
211+
As with the forms, inheritance is likely your best bet. In this case, the
212+
``FacetedSearchView`` is a perfect example of how to extend the existing
213+
``SearchView``. The complete code for the ``FacetedSearchView`` looks like::
214+
215+
class FacetedSearchView(SearchView):
216+
def __name__(self):
217+
return "FacetedSearchView"
218+
219+
def extra_context(self):
220+
extra = super(FacetedSearchView, self).extra_context()
221+
222+
if self.results == []:
223+
extra['facets'] = self.form.search().facet_counts()
224+
else:
225+
extra['facets'] = self.results.facet_counts()
226+
227+
return extra
228+
229+
It updates the name of the class (generally for documentation purposes) and
230+
adds the facets from the ``SearchQuerySet`` to the context as the ``facets``
231+
variable. As with the custom form example above, it relies on the parent class
232+
to handle most of the processing and extends that only where needed.

0 commit comments

Comments
 (0)