Django template tags for SOLR queries

November 2, 2011
 by 

Yes, I know the idea is nuts but when you’re a fast moving bootstrapped startup sometimes you build things like this. That being said, you better have good business reasons for making something this hifalutin as there are many other ways to skin the cat.

The reason we opted to do this is to allow us to quickly and easily make SEO friendly pages without changing backend software. This is also built into our CMS so churning out data driven pages happens at the drop of a hat. Currently most of our SOLR queries are AJAX’ed from frontend so web crawlers wont index that data. The alternative is to push all this logic into the backend but then we have to recompile and deploy code for changes.

Without further adieu, here is the django query language I ended up with. As you can see, they work just like regular filters. Note on line 2 I am using urlparam to take in arguments. Strings also work here.

1
2
3
4
5
6
7
8
9
10
{{ "new"|solr_command }}
{{ "__QUERY__"|solr_set_replacement:urlparam_q }}
{{ "text:(__QUERY__)"|solr_set_query }}
{{ "AND recordtype:(company)"|solr_wrap_query }}
{{ "rows"|solr_set_param:"50" }}
{{ "run"|solr_command }}
 
{% for company in solr_results.response.docs %}
  {{ company.name}}
{% endfor %}

Below is the associated python code. Note there are a few App Engine specific things but everything else is standard. Also, note the use of globals in this example. You will have to handle this in your own way.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import logging, simplejson as json
from django import template
from google.appengine.ext import webapp
from google.appengine.api import urlfetch
 
# these should be a part of thread local or
# a similar mechanism, i.e. not here!
SOLR_QUERY_WRAP = []
SOLR_REPLACEMENTS = {}
SOLR_PARAMS = {}
SOLR_QUERY = None
TEMPLATE_CONTEXT = None
 
def set_replacement(key, value):
  value = value.replace(':', '\:')
  SOLR_REPLACEMENTS[key] = value
  return ''
 
def set_param(key, value):
  SOLR_PARAMS[key] = value
  return ''
 
def set_query(value): # pylint:disable=W0613
  global SOLR_QUERY
  SOLR_QUERY = value
  return ''
 
def wrap_query(value): # pylint:disable=W0613
  SOLR_QUERY_WRAP.append(value)
  return ''
 
def run_solr_command(command):
  if command == 'run':
    return _run_query()
  elif command == 'new':
    return _new_query()
  else:
    raise Exception('Solr command not found')
 
def _new_query():
  global SOLR_QUERY_WRAP, SOLR_REPLACEMENTS 
  global SOLR_PARAMS, SOLR_QUERY
  SOLR_QUERY_WRAP = []
  SOLR_REPLACEMENTS = {}
  SOLR_PARAMS = {}
  SOLR_QUERY = None
  return ''
 
def _run_query():
  query_string = SOLR_QUERY
  for value in SOLR_QUERY_WRAP:
    query_string = '(%s) %s' % (query_string, value)
  for key in SOLR_REPLACEMENTS:
    query_string = query_string.replace(key,
                        SOLR_REPLACEMENTS[key])
  for key in SOLR_PARAMS:
    query_string = '%s&%s=%s' % (query_string, 
                        key, SOLR_PARAMS[key])
 
  query_string = query_string.replace(' ', '+')
  url = 'http://localhost:8983/solr/select?wt=json&q=%s'
  url = url % query_string
  result = urlfetch.fetch(url)
  if result.status_code != 200:
    raise urlfetch.DownloadError()
  res = json.loads(result.content)
 
  TEMPLATE_CONTEXT['solr_results'] = res
  return ''
 
register = webapp.template.create_template_register()
register.filter('solr_set_replacement', set_replacement)
register.filter('solr_set_query', set_query)
register.filter('solr_wrap_query', wrap_query)
register.filter('solr_set_param', set_param)
register.filter('solr_command', run_solr_command)

I hope someone finds my hack useful. I was going to try the Solango project but it looks like it was abandoned.


Categories: Computers, Software


Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Copyright © 2005-2011 John Clarke Mills

Wordpress theme is open source and available on github.