How to handle multiple facets?

1,135 views
Skip to first unread message

Andy

unread,
Jan 8, 2010, 5:57:57 AM1/8/10
to django-haystack
The example in documentation deals with only one facet dimension -
"author". How to handle multiple facets - say "author" & "publisher" &
"subject".

In the doc example, the GET variable "selected_facets" is used to
indicate "author" is being faceted. But how do I indicate multiple
facets, say author:John & subject:python & publisher:oreily

If I follow the link to say author:John in the doc example, I'd arrive
at the URL:
/search/?q=foo&selected_facets=author:John
What URL do I use to get to the next facet now that selected_facet is
already used by "author"?

FacetedSearchForm() does this to narrow by the selected_facet:
if self.cleaned_data['selected_facets']:
sqs = sqs.narrow(self.cleaned_data['selected_facets'])
But that only deals with 1 facet, right? How do I make it work for
multiple selected facets?

Anders Eriksen

unread,
Jan 17, 2010, 3:03:26 PM1/17/10
to django-haystack
Hi.

You could introduce a separator character between the selected facets
in the url.

Create a search form like i.e. this:

from django import forms
from haystack.forms import FacetedSearchForm

class MultiFacetSearchForm(FacetedSearchForm):

def search(self):
sqs = super(FacetedSearchForm, self).search()

if self.cleaned_data['selected_facets']:

for f in self.cleaned_data['selected_facets'].split("|"):
sqs = sqs.narrow(f)
return sqs

And use urls like this in your search:

search/?q=john&selected_facets=city_exact:"New York"|
profession_exact:"Doctor"

Then there should be logic disabling select of same facet value twice
etc. But I haven't figured out how to do that in the template yet.

Anders

Daniel Lindsley

unread,
Jan 18, 2010, 1:04:20 AM1/18/10
to django-...@googlegroups.com
Andy,


The documentation thinks you're working with the
``FacetedSearchForm``, which dodges the issue slightly by using a
string with ``.narrow()``. The idea is to concatenate the things you
want to limit by as you wanted. That form/view combination are
definitely on the naive side, but it's difficult to build code that
does everything for everyone, so the idea is demonstrating how to go
about it.

That said, Anders' suggestion would work. You could also chain
multiple ``selected_facets`` (i.e.
``?q=Django&selected_facets=author:John&selected_facets=subject:python&selected_facets=publisher:oreily``).
Django will turn ``selected_facets`` into a list within the
``HttpRequest`` object that you can iterate over and use as you
please.


Daniel

> --
> You received this message because you are subscribed to the Google Groups "django-haystack" group.
> To post to this group, send email to django-...@googlegroups.com.
> To unsubscribe from this group, send email to django-haysta...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/django-haystack?hl=en.
>
>
>
>

LarryEitel

unread,
Mar 16, 2010, 10:31:10 PM3/16/10
to django-haystack
I have a request:
?
q=bill&selected_facets=&selected_facets=cng_tags:one&selected_facets=nb_tags:two

When I look at self.cleaned_data['selected_facets'] in debugger, it
returns:
nb_tags:two

Is there a way to get at HttpRequest from


from haystack.forms import FacetedSearchForm

class MyFacetedSearchForm(FacetedSearchForm):
def __name__(self):
return "MyFacetedSearchForm"


selected_facets = forms.CharField(required=False,
widget=forms.HiddenInput)

def search(self):
sqs = super(FacetedSearchForm, self).search()

if self.cleaned_data['selected_facets']:


sqs = sqs.narrow(self.cleaned_data['selected_facets'])

print self.cleaned_data['selected_facets']
assert False
return sqs


Thank you :)

LarryEitel

unread,
Mar 16, 2010, 10:59:06 PM3/16/10
to django-haystack

>    That said, Anders' suggestion would work. You could also chain
> multiple ``selected_facets`` (i.e.
> ``?q=Django&selected_facets=author:John&selected_facets=subject:python&selected_facets=publisher:oreily``).
> Django will turn ``selected_facets`` into a list within the
> ``HttpRequest`` object that you can iterate over and use as you
> please.

Just cutting my teeth on django.

I need to get my hands on HttpRequest so that I can parse multiple
selected_facets. Looks like it is not available in this context.

If anyone has conquered the ability to narrow search based on multiple
selected_facets, please do share. :)

Thank you :)

LarryEitel

unread,
Mar 17, 2010, 7:04:36 PM3/17/10
to django-haystack
Here's what I so far and it seems to work:

In search.html

{% for facet_key, facet_field in facets.fields.items %}
<div class="fieldWrapper">
{{ facet_key }}:
{% for tag, tag_count in facet_field %}
{% ifnotequal tag "None" %}
<a href="{{ request.get_full_path }}
&amp;_fq_{{facet_key}}___{{ tag|urlencode }}">{{ tag }}</
a>({{ tag_count }})
{% endifnotequal %}
{% endfor %}
<br />
</div>
{% endfor %}

---------------
Note in above: &amp;_fq_{{facet_key}}___{{ tag|urlencode }}
will produce a url:
/search/?
q=bill&selected_facets=&_fq_<facet_field>___<facet_tag>&_fq_<facet_field>___<facet_tag>


Then in forms.py

class MyFacetedSearchForm(FacetedSearchForm):
def __name__(self):
return "MyFacetedSearchForm"


selected_facets = forms.CharField(required=False,
widget=forms.HiddenInput)

def search(self):
sqs = super(FacetedSearchForm,
self).search().order_by('fullname_company')


for item in self.data:
if item[0:4] == '_fq_':
facet_tag = item[4:].split('___')
facet = ':'.join(facet_tag)
sqs = sqs.narrow(facet)

return sqs

-------------
The above is a hack and can be cleaned up but it works!!! Now I can
narrow with an arbitrary selection of facets.

Now I need to show currently selected faces to allow user to unselect
facet filters.

Daniel Lindsley

unread,
Mar 19, 2010, 1:28:13 AM3/19/10
to django-...@googlegroups.com
Larry,


As far as getting the results of the ``selected_facets`` into the
form, you'd be best off either serializing all of your facets together
in a single string (like you did, though I've seen people use "|" in
the past instead of many underscores) or ditching the built-in
``FacetedSearchForm`` in favor of a custom, similar form that uses
something like a ``MultipleChoiceField`` (see
http://docs.djangoproject.com/en/1.1/ref/forms/fields/#multiplechoicefield),
which expects a list of items and correctly pulls all of the values
out of the POSTed data.

Otherwise, your overall approach is sane. As far as showing which
facets are selected, you may want to consider post-processing the
facet counts (``FacetedSearchView.extra_context``) with the choices
selected in your form. Once you've got the form down pat, this ought
to mostly fall into place.


Daniel

kapil

unread,
Apr 5, 2010, 3:13:42 AM4/5/10
to django-haystack
You should be able to access the multiple selected facets from the
QueryDict (http://docs.djangoproject.com/en/dev/ref/request-response/
#django.http.QueryDict)

request.GET.getlist('selected_facets') should do the trick

for: ?
q=Django&selected_facets=author:John&selected_facets=subject:python&selected_facets=publisher:oreily
this will return:
[u'author:John', u'subject:python', u'publisher:oreily']

Reply all
Reply to author
Forward
0 new messages