-# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+# This file is part of Wolne Lektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Wolne Lektury. See NOTICE for more information.
#
from django.apps import apps
-from django.contrib.postgres.search import SearchHeadline, SearchRank, SearchQuery
+from django.conf import settings
+from django.contrib.postgres.search import SearchHeadline, SearchQuery
from django import forms
from django.utils.translation import gettext_lazy as _
-
-from .fields import JQueryAutoCompleteSearchField, InlineRadioWidget
-from .utils import build_search_query
-
-
-class SearchForm(forms.Form):
- q = JQueryAutoCompleteSearchField(label=_('Search'))
- # {'minChars': 2, 'selectFirst': True, 'cacheLength': 50, 'matchContains': "word"})
-
- def __init__(self, source, *args, **kwargs):
- kwargs['auto_id'] = False
- super(SearchForm, self).__init__(*args, **kwargs)
- self.fields['q'].widget.attrs['id'] = 'search'
- self.fields['q'].widget.attrs['autocomplete'] = 'off'
- self.fields['q'].widget.attrs['data-source'] = source
- if 'q' not in self.data:
- self.fields['q'].widget.attrs['placeholder'] = _('title, author, epoch, kind, genre, phrase')
+from catalogue.constants import LANGUAGES_3TO2
+import catalogue.models
+import pdcounter.models
+from .fields import InlineRadioWidget
+from .utils import UnaccentSearchQuery, UnaccentSearchVector
class SearchFilters(forms.Form):
- q = forms.CharField(required=False, widget=forms.HiddenInput())
+ q = forms.CharField(
+ required=False, widget=forms.HiddenInput(),
+ min_length=2, max_length=256,
+ )
format = forms.ChoiceField(required=False, choices=[
- ('', 'wszystkie'),
- ('text', 'tekst'),
- ('audio', 'audiobook'),
- ('daisy', 'Daisy'),
- ('art', 'obraz'),
- #('theme', 'motywy'),
+ ('', _('wszystkie')),
+ ('audio', _('audiobook')),
+ ('daisy', _('Daisy')),
], widget=InlineRadioWidget())
lang = forms.ChoiceField(required=False)
epoch = forms.ChoiceField(required=False)
genre = forms.ChoiceField(required=False)
category = forms.ChoiceField(required=False, choices=[
- ('', 'wszystkie'),
- ('author', 'autor'),
- #('translator', 'tłumacz'),
- ('theme', 'motyw'),
- ('genre', 'gatunek'),
- ('book', 'tytuł'),
- ('art', 'obraz'),
- ('collection', 'kolekcja'),
- ('quote', 'cytat'),
+ ('', _('wszystkie')),
+ ('author', _('autor')),
+ #('translator', _('tłumacz')),
+ ('theme', _('motyw')),
+ ('genre', _('gatunek')),
+ ('book', _('tytuł')),
+ ('collection', _('kolekcja')),
+ ('quote', _('cytat')),
], widget=InlineRadioWidget())
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- from catalogue.models import Book, Tag
- self.fields['lang'].choices = [('', 'wszystkie')] + [
- (b, b)
- for b in Book.objects.values_list(
+ langs = dict(settings.LANGUAGES)
+ self.fields['lang'].choices = [('', _('wszystkie'))] + [
+ (
+ b,
+ langs.get(LANGUAGES_3TO2.get(b, b), b)
+ )
+ for b in catalogue.models.Book.objects.values_list(
'language', flat=True
).distinct().order_by()
]
- self.fields['epoch'].choices = [('', 'wszystkie')] + [
+ self.fields['epoch'].choices = [('', _('wszystkie'))] + [
(b.slug, b.name)
- for b in Tag.objects.filter(category='epoch')
+ for b in catalogue.models.Tag.objects.filter(category='epoch')
]
- self.fields['genre'].choices = [('', 'wszystkie')] + [
+ self.fields['genre'].choices = [('', _('wszystkie'))] + [
(b.slug, b.name)
- for b in Tag.objects.filter(category='genre')
+ for b in catalogue.models.Tag.objects.filter(category='genre')
]
def get_querysets(self):
- Tag = apps.get_model('catalogue', 'Tag')
- Book = apps.get_model('catalogue', 'Book')
- Picture = apps.get_model('picture', 'Picture')
- Snippet = apps.get_model('catalogue', 'Snippet')
- Collection = apps.get_model('catalogue', 'Collection')
qs = {
- 'author': Tag.objects.filter(category='author'),
- 'theme': Tag.objects.filter(category='theme'),
- 'genre': Tag.objects.filter(category='genre'),
- 'collection': Collection.objects.all(),
- 'book': Book.objects.all(), #findable
- 'snippet': Snippet.objects.all(),
- 'art': Picture.objects.all(),
- # art pieces
- # pdbooks
- # pdauthors
+ 'author': catalogue.models.Tag.objects.filter(category='author'),
+ 'pdauthor': pdcounter.models.Author.objects.all(),
+ 'theme': catalogue.models.Tag.objects.filter(category='theme'),
+ 'genre': catalogue.models.Tag.objects.filter(category='genre'),
+ 'collection': catalogue.models.Collection.objects.all(),
+ 'book': catalogue.models.Book.objects.filter(findable=True),
+ 'pdbook': pdcounter.models.BookStub.objects.all(),
+ 'snippet': catalogue.models.Snippet.objects.filter(book__findable=True),
}
if self.cleaned_data['category']:
c = self.cleaned_data['category']
- if c != 'author': qs['author'] = Tag.objects.none()
- if c != 'theme': qs['theme'] = Tag.objects.none()
- if c != 'genre': qs['genre'] = Tag.objects.none()
- if c != 'collection': qs['collection'] = Collection.objects.none()
- if c != 'book': qs['book'] = Book.objects.none()
- if c != 'quote': qs['snippet'] = Snippet.objects.none()
- if c != 'art': qs['art'] = Picture.objects.none()
- qs['art'] = Picture.objects.none()
+ if c != 'author':
+ qs['author'] = qs['author'].none()
+ qs['pdauthor'] = qs['pdauthor'].none()
+ if c != 'theme': qs['theme'] = qs['theme'].none()
+ if c != 'genre': qs['genre'] = qs['genre'].none()
+ if c != 'collection': qs['collection'] = qs['collection'].none()
+ if c != 'book':
+ qs['book'] = qs['book'].none()
+ qs['pdbook'] = qs['pdbook'].none()
+ if c != 'quote': qs['snippet'] = qs['snippet'].none()
if self.cleaned_data['format']:
c = self.cleaned_data['format']
- qs['author'] = Tag.objects.none()
- qs['theme'] = Tag.objects.none()
- qs['genre'] = Tag.objects.none()
- qs['collection'] = Collection.objects.none()
- if c == 'art':
- qs['book'] = Book.objects.none()
- qs['snippet'] = Snippet.objects.none()
- if c in ('text', 'audio', 'daisy'):
- qs['art'] = Picture.objects.none()
- if c == 'audio':
- qs['book'] = qs['book'].filter(media__type='mp3')
- qs['snippet'] = qs['snippet'].filter(book__media__type='mp3')
- elif c == 'daisy':
- qs['book'] = qs['book'].filter(media__type='daisy')
- qs['snippet'] = qs['snippet'].filter(book__media__type='daisy')
+ qs['author'] = qs['author'].none()
+ qs['pdauthor'] = qs['pdauthor'].none()
+ qs['theme'] = qs['theme'].none()
+ qs['genre'] = qs['genre'].none()
+ qs['collection'] = qs['collection'].none()
+ if c == 'audio':
+ qs['book'] = qs['book'].filter(media__type='mp3')
+ qs['pdbook'] = qs['book'].none()
+ qs['snippet'] = qs['snippet'].filter(book__media__type='mp3')
+ elif c == 'daisy':
+ qs['book'] = qs['book'].filter(media__type='daisy')
+ qs['snippet'] = qs['snippet'].filter(book__media__type='daisy')
if self.cleaned_data['lang']:
- qs['author'] = Tag.objects.none()
- qs['theme'] = Tag.objects.none()
- qs['genre'] = Tag.objects.none()
- qs['art'] = Picture.objects.none()
- qs['collection'] = Collection.objects.none()
+ qs['author'] = qs['author'].none()
+ qs['pdauthor'] = qs['pdauthor'].none()
+ qs['theme'] = qs['theme'].none()
+ qs['genre'] = qs['genre'].none()
+ qs['collection'] = qs['collection'].none()
qs['book'] = qs['book'].filter(language=self.cleaned_data['lang'])
+ qs['pdbook'] = qs['pdbook'].none()
qs['snippet'] = qs['snippet'].filter(book__language=self.cleaned_data['lang'])
for tag_cat in ('epoch', 'genre'):
c = self.cleaned_data[tag_cat]
if c:
# FIXME nonexistent
- t = Tag.objects.get(category=tag_cat, slug=c)
- qs['author'] = Tag.objects.none()
- qs['theme'] = Tag.objects.none()
- qs['genre'] = Tag.objects.none()
- qs['collection'] = Collection.objects.none()
+ t = catalogue.models.Tag.objects.get(category=tag_cat, slug=c)
+ qs['author'] = qs['author'].none()
+ qs['pdauthor'] = qs['pdauthor'].none()
+ qs['theme'] = qs['theme'].none()
+ qs['genre'] = qs['genre'].none()
+ qs['collection'] = qs['collection'].none()
qs['book'] = qs['book'].filter(tag_relations__tag=t)
+ qs['pdbook'] = qs['pdbook'].none()
qs['snippet'] = qs['snippet'].filter(book__tag_relations__tag=t)
- qs['art'] = qs['art'].filter(tag_relations__tag=t)
return qs
def results(self):
qs = self.get_querysets()
query = self.cleaned_data['q']
- squery = build_search_query(query, config='polish')
- query = SearchQuery(query, config='polish')
- books = qs['book'].filter(title__search=query)
- books = books.exclude(ancestor__in=books)
- return {
- 'author': qs['author'].filter(slug__search=query),
- 'theme': qs['theme'].filter(slug__search=query),
- 'genre': qs['genre'].filter(slug__search=query),
- 'collection': qs['collection'].filter(title__search=query),
- 'book': books[:100],
- 'snippet': qs['snippet'].annotate(
- rank=SearchRank('search_vector', squery)
- ).filter(rank__gt=0).order_by('-rank').annotate(
+ squery = UnaccentSearchQuery(query, config=settings.SEARCH_CONFIG)
+ query = SearchQuery(query, config=settings.SEARCH_CONFIG)
+ books = qs['book'].annotate(
+ search_vector=UnaccentSearchVector('title')
+ ).filter(search_vector=squery)
+ books = books.exclude(ancestor__in=books).order_by('-popularity__count')
+
+ snippets = qs['snippet'].filter(search_vector=squery).annotate(
headline=SearchHeadline(
'text',
query,
- config='polish',
+ config=settings.SEARCH_CONFIG,
start_sel='<strong>',
stop_sel='</strong>',
- highlight_all=True
)
- )[:100],
- 'art': qs['art'].filter(title__search=query)[:100],
+ ).order_by('-book__popularity__count', 'sec')[:100]
+ snippets_by_book = {}
+ for snippet in snippets:
+ snippet_list = snippets_by_book.setdefault(snippet.book, [])
+ if len(snippet_list) < 3:
+ snippet_list.append(snippet)
+
+ return {
+ 'author': qs['author'].annotate(
+ search_vector=UnaccentSearchVector('name_pl')
+ ).filter(search_vector=squery),
+ 'theme': qs['theme'].annotate(
+ search_vector=UnaccentSearchVector('name_pl')
+ ).filter(search_vector=squery),
+ 'genre': qs['genre'].annotate(
+ search_vector=UnaccentSearchVector('name_pl')
+ ).filter(search_vector=squery),
+ 'collection': qs['collection'].annotate(
+ search_vector=UnaccentSearchVector('title')
+ ).filter(search_vector=squery),
+ 'book': books[:100],
+ 'snippet': snippets_by_book,
+ 'pdauthor': pdcounter.models.Author.search(squery, qs=qs['pdauthor']),
+ 'pdbook': pdcounter.models.BookStub.search(squery, qs=qs['pdbook']),
}