how to search a specific model?

14 views
Skip to first unread message

EricHsu

unread,
Jan 7, 2006, 2:59:57 AM1/7/06
to Django users
guys,

by reading simon's AbstractSearching:

https://simon.bofh.ms/cgi-bin/trac-django-projects.cgi/wiki/AbstractSearching

I got my searching for stories work by:

1. settings.py - add:

SEARCH_DEFINITIONS = {
"foo.apps.bar.search",
}

INSTALL_APPS = {
[snip]
'stuff.search'
}

2. urls.py - add:

search_info_dict = {
'template_name': 'bar/search_result',
}

urlpatterns = patterns('',
[snip]
(r'^search/$', 'stuff.search.views.generic.search_objects',
search_info_dict),
[snip]
)

3. apps/bar/search.py:

from stuff.search.helpers import SearchDefinition

class StorySearch(SearchDefinition):
model_module = 'bar.storys'
time_order_by = 'created_date'
search_fields = ('title', 'description',)

Now I have a form that could search for stories:

<form method="get" action="/search/">
<input type="text" name="q" value="{{ query_string|escape }}"
id="search" />
<input type="submit" />
</form>

It works.

Now I would like to add one more function by using AbstractSearching: I
would like to search for users by username, first_name, last_name or
email. how could I achive that?

I've tried to add another class UserSearch in the search.py, however,
the resulted behavior is django searches both the bar.storys and
auth.users with the query_string! weird?

I would like to have urls like this:
. search for storys: /search/story/?q=foo+bar
. search for users: /search/user/?q=eric+hsu

I can get the search for storys work, now I need some hints on search
for users, pls enlighten me, big thanks!

EricHsu

unread,
Jan 7, 2006, 3:28:31 AM1/7/06
to Django users
btw, I tracked down to the stuff/search/views/generic.py, seem that the
kwarg module_list hasn't been passed to the search() funtion from the
utils.py, so I have to set the SEARCH_DEFINITION in the settings.py to
get the searching work properly.

It won't work if I set the search_info_dict like this:

search_info_dict = {
'template_name': 'bar/search_result',

'module_list': ('foo.apps.bar.search',),
}

the module_list will get lost in the generic.py while invoking the line
55:

results = search(*parse(query))

is this a bug?

hugo

unread,
Jan 7, 2006, 4:39:19 AM1/7/06
to Django users
>Now I would like to add one more function by using AbstractSearching: I
>would like to search for users by username, first_name, last_name or
>email. how could I achive that?

You would have to add lookup or filter functions to your search
definition. There are two kind of additional queries that can be added
- they create keyword-queries like the domain:my.site.com in Google.

The first kind is lookup-keywords - they are defined by adding a method
lookup_domain(element, value). This would define a domain: keyword. The
method has to return a dictionary that is added to the query kwargs. So
this is usually used to add searches for specific fields (while the
"global" word search searches in all given fields).

The second kind is filter-keywords. These are used to filter the result
from the database queries - so they are applied on a per-row basis.
This makes them much slower than the lookup keywords, but they can do
anything you can code in Python to weed out results that you don't
want. To get one, you define a filter_user(element, value) function
that could use the value to check wether an element was created by that
user.

Samples for those are given in the AbstractSearching wiki page - the
filter_tagged methods are to filter against my old tagging stuff, they
use standard Django ORM functions to check wether there is a tag
related to an element. The other samples are the lookup_created and
lookup_changed they produce a standard date lookup keyword, the source
is in the AbstractSearching package.

Often you can translate a string value into some more specific query
parameter - for example a user name could be turned into a user id and
that could be used to construct a direct lookup kwarg. That's much
faster than using the filter keywords on large result sets.

What is _not_ possible is to add non-character fields to the global
word search.

Oh, and all search definitions need to adhere to the same search
protocol. So if you have keyword searches that aren't supported by some
models, you will have to put dummy keyword functions on them that just
return None - this will tell the search machinery to skip those models
on those keyword searches.

You can have multiple different searchs (searches that run against
different search definition lists) by passing in the explicit search
definition lists, but usually that's not needed - the idea of the
AbstractSearching package is to have a unified search that works much
like google or Apples spotlight - one search field where you enter all
your queries, regardless of what it is you actually want to search.

Some more samples for lookup keywords in searches are given in my CMS
project:

https://simon.bofh.ms/cgi-bin/trac-django-projects.cgi/file/cms/trunk/apps/cms/search.py

This search definition searches against 4 different models where the
lookup_kind keyword function distinguishes when you want to search only
against one model or some models.

Since the idea is to have a unified search, the "having different
searches with different search definition lists" feature never was
tested, so it's absolutely possible that it doesn't work :-)

bye, Georg

EricHsu

unread,
Jan 7, 2006, 8:40:47 AM1/7/06
to Django users
BiG Thanks to hugo!

"To have a unified search" - that make things clear now :)

I got my site's searching against a single model work with writing
lookup_kind function like yours! Now I can search for stories with
query_string = 'kind:storys foo bar' and search for users with
query_string = 'kind:users eric hsu'! That's pretty cool!

However, here comes another problem:

How could I have different templates for the search form/results?

For example, I would like to have a simple search box on the top right
of my frontpage, the user just types in the keyword(s) and then the
search engine "default" search for stories and list the result in a
story listing page;

then, the user goes to another page which display a form in which he
can type in keyword(s) and search for users, then the search engine
returns the results in a user listing page which is different from the
story listing page.

Is it possible?

btw, I'm not a native English speaker, I'll try my best to make myself
clear :)

Regards

- Eric

EricHsu

unread,
Jan 7, 2006, 9:20:17 AM1/7/06
to Django users
Yet another problem :)

Could I paginate the search result?

hugo

unread,
Jan 7, 2006, 9:41:10 AM1/7/06
to Django users
>How could I have different templates for the search form/results?

In my case it's part of the model itself - I have a template tag
"embed" that just does the right thing for each class that might be
searched. In your case you could just have different search result
templates and have two views that both use the search generic view, but
get passed different template names in the info_dict.

I usually don't have different search forms, but just one that searches
over all models that have search capability - if I need some "search
context" (like in the "Zeitgeist" view, where some search keywords are
predefined), I just add those to the search query string. So in your
case you could just add the kind:users in the user search and put the
template_name into the paramter to the generic view - for example by
writing small wrappers around the generic view.

>Could I paginate the search result?

Not with the standard generic view - I never looked into the pagination
stuff and so don't even know what to do to enable it there. I usually
just set the max_number to limit the maximum number of results returned
and order them by creation date.

You could do that yourself by not using the generic view but using the
high level search interface - it's rather simple to use, only three
functions:

parse: this function parses a query string into a query description
search: this uses the query description to query all defined search
definitions
merge: this merges the different resultsets from all search definitions
into one big result

You could do the querying in one line like this:

result = merge(search(*parse(query_string)), -1)

this would return all results for a given query. Then you could build
your own paginated view on that result.

bye, Georg

EricHsu

unread,
Jan 7, 2006, 10:09:27 PM1/7/06
to Django users
wOW!

I get it done "by writing small wrappers around the generic view"!

Thanks A LOT hugo! You've been a great help!

I'm going to look into the pagination thing later ;)

Reply all
Reply to author
Forward
0 new messages