1 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
2 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
4 from django.apps import apps
5 from django.contrib.postgres.search import SearchHeadline, SearchRank, SearchQuery
6 from django import forms
7 from django.utils.translation import gettext_lazy as _
9 from .fields import JQueryAutoCompleteSearchField, InlineRadioWidget
10 from .utils import build_search_query
13 class SearchForm(forms.Form):
14 q = JQueryAutoCompleteSearchField(label=_('Search'))
15 # {'minChars': 2, 'selectFirst': True, 'cacheLength': 50, 'matchContains': "word"})
17 def __init__(self, source, *args, **kwargs):
18 kwargs['auto_id'] = False
19 super(SearchForm, self).__init__(*args, **kwargs)
20 self.fields['q'].widget.attrs['id'] = 'search'
21 self.fields['q'].widget.attrs['autocomplete'] = 'off'
22 self.fields['q'].widget.attrs['data-source'] = source
23 if 'q' not in self.data:
24 self.fields['q'].widget.attrs['placeholder'] = _('title, author, epoch, kind, genre, phrase')
27 class SearchFilters(forms.Form):
28 q = forms.CharField(required=False, widget=forms.HiddenInput())
29 format = forms.ChoiceField(required=False, choices=[
32 ('audio', 'audiobook'),
36 ], widget=InlineRadioWidget())
37 lang = forms.ChoiceField(required=False)
38 epoch = forms.ChoiceField(required=False)
39 genre = forms.ChoiceField(required=False)
40 category = forms.ChoiceField(required=False, choices=[
43 #('translator', 'tłumacz'),
48 ('collection', 'kolekcja'),
50 ], widget=InlineRadioWidget())
52 def __init__(self, *args, **kwargs):
53 super().__init__(*args, **kwargs)
54 from catalogue.models import Book, Tag
56 self.fields['lang'].choices = [('', 'wszystkie')] + [
58 for b in Book.objects.values_list(
60 ).distinct().order_by()
62 self.fields['epoch'].choices = [('', 'wszystkie')] + [
64 for b in Tag.objects.filter(category='epoch')
66 self.fields['genre'].choices = [('', 'wszystkie')] + [
68 for b in Tag.objects.filter(category='genre')
71 def get_querysets(self):
72 Tag = apps.get_model('catalogue', 'Tag')
73 Book = apps.get_model('catalogue', 'Book')
74 Picture = apps.get_model('picture', 'Picture')
75 Snippet = apps.get_model('catalogue', 'Snippet')
76 Collection = apps.get_model('catalogue', 'Collection')
78 'author': Tag.objects.filter(category='author'),
79 'theme': Tag.objects.filter(category='theme'),
80 'genre': Tag.objects.filter(category='genre'),
81 'collection': Collection.objects.all(),
82 'book': Book.objects.all(), #findable
83 'snippet': Snippet.objects.all(),
84 'art': Picture.objects.all(),
89 if self.cleaned_data['category']:
90 c = self.cleaned_data['category']
91 if c != 'author': qs['author'] = Tag.objects.none()
92 if c != 'theme': qs['theme'] = Tag.objects.none()
93 if c != 'genre': qs['genre'] = Tag.objects.none()
94 if c != 'collection': qs['collection'] = Collection.objects.none()
95 if c != 'book': qs['book'] = Book.objects.none()
96 if c != 'quote': qs['snippet'] = Snippet.objects.none()
97 if c != 'art': qs['art'] = Picture.objects.none()
98 qs['art'] = Picture.objects.none()
100 if self.cleaned_data['format']:
101 c = self.cleaned_data['format']
102 qs['author'] = Tag.objects.none()
103 qs['theme'] = Tag.objects.none()
104 qs['genre'] = Tag.objects.none()
105 qs['collection'] = Collection.objects.none()
107 qs['book'] = Book.objects.none()
108 qs['snippet'] = Snippet.objects.none()
109 if c in ('text', 'audio', 'daisy'):
110 qs['art'] = Picture.objects.none()
112 qs['book'] = qs['book'].filter(media__type='mp3')
113 qs['snippet'] = qs['snippet'].filter(book__media__type='mp3')
115 qs['book'] = qs['book'].filter(media__type='daisy')
116 qs['snippet'] = qs['snippet'].filter(book__media__type='daisy')
118 if self.cleaned_data['lang']:
119 qs['author'] = Tag.objects.none()
120 qs['theme'] = Tag.objects.none()
121 qs['genre'] = Tag.objects.none()
122 qs['art'] = Picture.objects.none()
123 qs['collection'] = Collection.objects.none()
124 qs['book'] = qs['book'].filter(language=self.cleaned_data['lang'])
125 qs['snippet'] = qs['snippet'].filter(book__language=self.cleaned_data['lang'])
127 for tag_cat in ('epoch', 'genre'):
128 c = self.cleaned_data[tag_cat]
131 t = Tag.objects.get(category=tag_cat, slug=c)
132 qs['author'] = Tag.objects.none()
133 qs['theme'] = Tag.objects.none()
134 qs['genre'] = Tag.objects.none()
135 qs['collection'] = Collection.objects.none()
136 qs['book'] = qs['book'].filter(tag_relations__tag=t)
137 qs['snippet'] = qs['snippet'].filter(book__tag_relations__tag=t)
138 qs['art'] = qs['art'].filter(tag_relations__tag=t)
143 qs = self.get_querysets()
144 query = self.cleaned_data['q']
145 squery = build_search_query(query, config='polish')
146 query = SearchQuery(query, config='polish')
147 books = qs['book'].filter(title__search=query)
148 books = books.exclude(ancestor__in=books)
150 'author': qs['author'].filter(slug__search=query),
151 'theme': qs['theme'].filter(slug__search=query),
152 'genre': qs['genre'].filter(slug__search=query),
153 'collection': qs['collection'].filter(title__search=query),
155 'snippet': qs['snippet'].annotate(
156 rank=SearchRank('search_vector', squery)
157 ).filter(rank__gt=0).order_by('-rank').annotate(
158 headline=SearchHeadline(
162 start_sel='<strong>',
163 stop_sel='</strong>',
167 'art': qs['art'].filter(title__search=query)[:100],