Add a basic search (using SeSQL)
This commit is contained in:
parent
52c33bc96f
commit
9d2b6277e9
7 changed files with 216 additions and 9 deletions
|
@ -9,3 +9,4 @@ django==1.4.2
|
|||
git+git://github.com/petry/django-foundation.git
|
||||
git+git://github.com/yohanboniface/django-chickpea.git
|
||||
git+git://github.com/frankban/django-endless-pagination.git
|
||||
hg+https://bitbucket.org/liberation/sesql
|
147
youmap/sesql_config.py
Normal file
147
youmap/sesql_config.py
Normal file
|
@ -0,0 +1,147 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) Pilot Systems and Libération, 2010-2011
|
||||
|
||||
# This file is part of SeSQL.
|
||||
|
||||
# SeSQL is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# Foobar is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with SeSQL. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#
|
||||
# Full text search configuration - we must define that before the imports,
|
||||
# because those are used by the imports
|
||||
#
|
||||
|
||||
# Name of the PostgreSQL Text Search Configuration
|
||||
TS_CONFIG_NAME = "simple_french"
|
||||
|
||||
# Name of the stopwards file, must be plain ASCII
|
||||
STOPWORDS_FILE = "ascii_french"
|
||||
|
||||
# Global charset to use
|
||||
CHARSET = "utf-8"
|
||||
|
||||
from sesql.fields import *
|
||||
from sesql.sources import *
|
||||
from django.db.models import Q
|
||||
from chickpea import models
|
||||
|
||||
#
|
||||
# Select the ORM to use
|
||||
#
|
||||
from sesql.orm.django import DjangoOrmAdapter
|
||||
orm = DjangoOrmAdapter()
|
||||
|
||||
|
||||
#
|
||||
# Fields and tables configuration
|
||||
#
|
||||
|
||||
# Configuration of SeSQL search fields
|
||||
FIELDS = (ClassField("classname"),
|
||||
IntField("id"),
|
||||
DateField("modified_at"),
|
||||
FullTextField("name"),
|
||||
FullTextField("fulltext",
|
||||
['name', 'description',
|
||||
SubField("owner", ["username"])
|
||||
],
|
||||
primary=True,
|
||||
),
|
||||
DateField('indexed_at', sql_default='NOW()'),
|
||||
)
|
||||
|
||||
# Name of the global lookup table that should contain no real data
|
||||
MASTER_TABLE_NAME = "sesql_index"
|
||||
|
||||
# Type map, associating Django classes to SeSQL tables
|
||||
TYPE_MAP = ((models.Map, "sesql_default"), )
|
||||
|
||||
# Additional indexes to create
|
||||
CROSS_INDEXES = ()
|
||||
|
||||
#
|
||||
# Cleanup configuration
|
||||
#
|
||||
|
||||
from htmlentitydefs import name2codepoint
|
||||
from xml.sax import saxutils
|
||||
|
||||
html_entities = dict([('&%s;' % k, unichr(v).encode(config.CHARSET)) for k,v in name2codepoint.items() ])
|
||||
ADDITIONAL_CLEANUP_FUNCTION = lambda value: saxutils.unescape(value, html_entities)
|
||||
|
||||
#
|
||||
# Query configuration
|
||||
#
|
||||
|
||||
# General condition to skip indexing content
|
||||
SKIP_CONDITION = None
|
||||
|
||||
# Default sort order for queries
|
||||
DEFAULT_ORDER = ('-modified_at',)
|
||||
|
||||
# Default LIMIT in short queries
|
||||
DEFAULT_LIMIT = 20
|
||||
|
||||
# First we ask for the SMART_QUERY_INITIAL first sorted items
|
||||
SMART_QUERY_INITIAL = 2500
|
||||
# Then, if we have at least SMART_QUERY_THRESOLD of our limit, we go on
|
||||
SMART_QUERY_THRESOLD = 0.35
|
||||
# If we have a second query, we do * (wanted/result) * SMART_QUERY_RATIO
|
||||
SMART_QUERY_RATIO = 3.0
|
||||
|
||||
#
|
||||
# Long query cache configuration
|
||||
#
|
||||
|
||||
# Maximal number of queries to store in the long query cache
|
||||
QUERY_CACHE_MAX_SIZE = 10000
|
||||
# Life time of a query in the query cache
|
||||
QUERY_CACHE_EXPIRY = 24 * 3600
|
||||
|
||||
#
|
||||
# Daemon configuration
|
||||
#
|
||||
|
||||
DAEMON_DEFAULT_CHUNK = 100
|
||||
DAEMON_DEFAULT_DELAY = 120
|
||||
DAEMON_DEFAULT_PID = '/var/run/sesql/update.pid'
|
||||
|
||||
#
|
||||
# Suggest/history configuration
|
||||
#
|
||||
|
||||
# default number of hit before including query in db
|
||||
HISTORY_DEFAULT_FILTER = 5
|
||||
|
||||
# erode factor for time-based decay of recent searches score
|
||||
HISTORY_ALPHA = 0.95
|
||||
# weight of frequency of the search in the final score
|
||||
HISTORY_BETA = 1.0
|
||||
# weight of number of results in the final score
|
||||
HISTORY_GAMMA = 1.0
|
||||
|
||||
# queries to ignore in history
|
||||
HISTORY_BLACKLIST = []
|
||||
|
||||
|
||||
#
|
||||
# Enable sesql searches from Django admin ?
|
||||
#
|
||||
ENABLE_SESQL_ADMIN = False
|
||||
|
||||
#
|
||||
# Enable to force all updates to be processed asynchronously by the daemon
|
||||
#
|
||||
|
||||
ASYNCHRONOUS_INDEXING = False
|
|
@ -29,6 +29,7 @@ INSTALLED_APPS = (
|
|||
'foundation',
|
||||
'endless_pagination',
|
||||
'youmap',
|
||||
'sesql',
|
||||
|
||||
#'south',
|
||||
|
||||
|
|
|
@ -15,15 +15,11 @@
|
|||
</ul>
|
||||
|
||||
<ul class="right">
|
||||
<li class="search">
|
||||
<form>
|
||||
<input type="search">
|
||||
<li class="search">
|
||||
<form action="{% url search %}" method="GET">
|
||||
<input name="q" type="search" placeholder="Search maps" value="{{ q|default:"" }}" />
|
||||
</form>
|
||||
</li>
|
||||
|
||||
<li class="has-button">
|
||||
<a class="small button" href="#">Search</a>
|
||||
</li>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</nav>
|
||||
|
|
33
youmap/templates/youmap/search.html
Normal file
33
youmap/templates/youmap/search.html
Normal file
|
@ -0,0 +1,33 @@
|
|||
{% extends "youmap/home.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="twelve columns">
|
||||
|
||||
<!-- Navigation -->
|
||||
|
||||
{% include 'youmap/navigation.html' %}
|
||||
<!-- End Navigation -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="twelve columns">
|
||||
<h4>Search for maps containing «{{ q }}»</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="twelve columns">
|
||||
<div class="row map_list">
|
||||
{% if maps %}
|
||||
{% include "chickpea/map_list.html" %}
|
||||
{% else %}
|
||||
<div class="twelve mobile-six columns">
|
||||
Not map found.
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
|
@ -14,6 +14,7 @@ urlpatterns = patterns('',
|
|||
(r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
||||
(r'^admin/', include(admin.site.urls)),
|
||||
url(r'^$', views.home, name="home"),
|
||||
url(r'^search/$', views.search, name="search"),
|
||||
url(r'^user/(?P<username>[-_\w]+)/$', views.user_maps, name='user_maps'),
|
||||
(r'', include('chickpea.urls')),
|
||||
)
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
from django.views.generic import TemplateView
|
||||
from django.contrib.auth.models import User
|
||||
from django.views.generic import DetailView
|
||||
from django.db.models import Q
|
||||
|
||||
from sesql.shortquery import shortquery
|
||||
|
||||
from chickpea.models import Map
|
||||
|
||||
|
@ -53,3 +56,28 @@ class UserMaps(DetailView):
|
|||
return super(UserMaps, self).get_template_names()
|
||||
|
||||
user_maps = UserMaps.as_view()
|
||||
|
||||
|
||||
class Search(TemplateView):
|
||||
template_name = "youmap/search.html"
|
||||
list_template_name = "chickpea/map_list.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
q = self.request.GET['q']
|
||||
maps = shortquery(Q(fulltext__containswords=q))
|
||||
kwargs.update({
|
||||
'maps': maps,
|
||||
'q': q
|
||||
})
|
||||
return kwargs
|
||||
|
||||
def get_template_names(self):
|
||||
"""
|
||||
Dispatch template according to the kind of request: ajax or normal.
|
||||
"""
|
||||
if self.request.is_ajax():
|
||||
return [self.list_template_name]
|
||||
else:
|
||||
return super(Search, self).get_template_names()
|
||||
|
||||
search = Search.as_view()
|
||||
|
|
Loading…
Reference in a new issue