Задать вопрос

Тел: +7 965 3737 888

479

Просмотров

4

Ответов

Tags & filters for rendering search results

<p>Use these tags and filter when you're rolling your own search results. This is intended to be a whole templatetags module. I keep it in my apps as templatetags/search.py. These should not be used to perform search queries, but rather render the results.</p>
<h3>Basics</h3>
<p>There are three functions, each has both a tag <em>and</em> a filter of the same name. These functions accept, at a minimum, a body of text and a list of search terms:</p>
<ul><li><strong>searchexcerpt</strong>: Truncate the text so that each search term is shown, surrounded by some number of words of context.</li>
<li><strong>highlight</strong>: Wrap all found search terms in an HTML span that can be styled to highlight the terms.</li>
<li><strong>hits</strong>: Count the occurrences of the search terms in the text.</li>
</ul><p>The filters provide the most basic functionality as described above, while the tags offer more options as arguments, such as case sensitivity, whole word search, and saving the results to a context variable. </p>
<h3>Settings</h3>
<p>Defaults for both the tags and filters can be changed with the following settings. Note that these settings are merely a convenience for the tags, which accept these as arguments, but are necessary for changing behavior of the filters.</p>
<ul><li>SEARCH_CONTEXT_WORDS: Number of words to show on the left and right of each search term. Default: 10</li>
<li>SEARCH_IGNORE_CASE: False for case sensitive, True otherwise. Default: True</li>
<li>SEARCH_WORD_BOUNDARY: Find whole words and not strings in the middle of words. Default: False</li>
<li>SEARCH_HIGHLIGHT_CLASS: The class to give the HTML span element when wrapping highlighted search terms. Default: "highlight"</li>
</ul><h3>Examples</h3>
<p>Suppose you have a list flatpages resulting from a search query, and the search terms (split into a list) are in the context variable terms. This will show 5 words of context around each term and highlight matches in the title:</p>
{% for page in flatpages %}
    &lt;h3&gt;{{ page.title|highlight:terms }}&lt;/h3&gt;
    &lt;p&gt;
        {% searchexcerpt terms 5 %}
            {{ page.content|striptags }}
        {% endsearchexcerpt %}
    &lt;/p&gt;
{% endfor %}

<p>Add highlighting to the excerpt, and use a custom span class (the two flags are for case insensitivity and respecting word boundaries):</p>
{% highlight 1 1 "match" %}
{% searchexcerpt terms 5 1 1 %}
    {{ page.content|striptags }}
{% endsearchexcerpt %}
{% endhighlight %}

<p>Show the number of hits in the body:</p>
&lt;h3&gt;{{ page.title }}
    (Hits: {{ page.content|striptags|hits:terms }})
&lt;/h3&gt;

<p>All tags support an as name suffix, in which case an object will be stored in the template context with the given name; output will be suppressed. This is more efficient when you want both the excerpt and the number of hits. The stored object depends on the tag:</p>
<ul><li><strong>searchexcerpt</strong>: A dictionary with keys "original" (the text searched), "excerpt" (the summarized text with search terms), and "hits" (the number of hits in the text).</li>
<li><strong>searchcontext</strong>: A dictionary with keys "original", "highlighted", and "hits", with obvious values.</li>
<li><strong>hits</strong>: Just the number of hits, nothing special.</li>
</ul><p>Getting both the hits and the excerpt with "as":</p>
{% searchexcerpt terms 3 as content %}
    {{ page.content|striptags }}
{% endsearchexcerpt %}
&lt;p&gt;Hits: {{ content.hits }}&lt;br&gt;{{ content.excerpt }}&lt;/p&gt;

<h3>More</h3>
<p>For more examples see <a href="http://blog.brianbeck.com/post/29707610">Brian Beck's Text Adventure</a>.</p>

Вопрос полезен? Да0/Нет0
file_2361.py(7.7Кб)
None

Ответы (4):

Ответulope:23.03.2009
Ответ полезен? Да0/Нет0

Argh... please ignore the code in the previous post. That was my devel version.

Here is the correct one:

def highlight(text, phrases, ignore_case=None, word_boundary=None, class_name=None):
    if isinstance(phrases, basestring):
        phrases = [phrases]
    if ignore_case is None:
        ignore_case = get_setting('IGNORE_CASE')
    if word_boundary is None:
        word_boundary = get_setting('WORD_BOUNDARY')
    if class_name is None:
        class_name = get_setting('HIGHLIGHT_CLASS')

    phrases = map(re.escape, phrases)
    flags = ignore_case and re.I or 0
    re_template = word_boundary and r"\b(%s)\b" or r"(%s)"
    expr = re.compile(re_template % "|".join(phrases), flags)
    inner_expr = re.compile('<a[^>]+?href="[^>]*?(%s)$' % "|".join(phrases), flags)
    template = '<span class="%s">%%s</span>' % class_name
    matches = []

    def replace(match):
        if not word_boundary:
            span = match.span()
            if inner_expr.search(text, span[0]-100, span[1]):
                return match.group(0)
        matches.append(match)
        return template % match.group(0)

    highlighted = mark_safe(expr.sub(replace, text))
    count = len(matches)
    return dict(original=text, highlighted=highlighted, hits=count)

Ответulope:23.03.2009
Ответ полезен? Да0/Нет0

Very useful!

I added some code to the highlight function to avoid highlighting strings inside of href attributes:

def highlight(text, phrases, ignore_case=None, word_boundary=None, class_name=None):
    if isinstance(phrases, basestring):
        phrases = [phrases]
    if ignore_case is None:
        ignore_case = get_setting('IGNORE_CASE')
    if word_boundary is None:
        word_boundary = get_setting('WORD_BOUNDARY')
    if class_name is None:
        class_name = get_setting('HIGHLIGHT_CLASS')

    phrases = map(re.escape, phrases)
    flags = ignore_case and re.I or 0
    re_template = word_boundary and r"\b(%s)\b" or r"(%s)"
    expr = re.compile(re_template % "|".join(phrases), flags)
    inner_expr = re.compile('<a href="[^>]*?(%s)$' % "|".join(phrases), flags)
    template = '<span class="%s">%%s</span>' % class_name
    matches = []

    def replace(match):
        import pdb
        pdb.set_trace()
        if not word_boundary:
            span = match.span()
            if inner_expr.search(text, span[0]-100, span[1]):
                return match.group(0)
        matches.append(match)
        return template % match.group(0)

    highlighted = mark_safe(expr.sub(replace, text))
    count = len(matches)
    return dict(original=text, highlighted=highlighted, hits=count)

Ответnikhil:07.06.2008
Ответ полезен? Да0/Нет0

Thanks. Great work.

Ответrichardh:29.03.2008
Ответ полезен? Да0/Нет0

Very nice. I particularly like the excerpts.

One question. Is there a simple way of ordering the search results in the html page by the number of hits (highest first)?

Richard