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.conf import settings
6 from django.contrib.postgres.search import SearchHeadline, SearchQuery
7 from django import forms
8 from django.utils.translation import gettext_lazy as _
9 from catalogue.constants import LANGUAGES_3TO2
10 import catalogue.models
11 import pdcounter.models
13 from .fields import InlineRadioWidget
14 from .utils import UnaccentSearchQuery, UnaccentSearchVector
17 class SearchFilters(forms.Form):
19 required=False, widget=forms.HiddenInput(),
20 min_length=2, max_length=256,
22 format = forms.ChoiceField(required=False, choices=[
25 ('audio', 'audiobook'),
29 ], widget=InlineRadioWidget())
30 lang = forms.ChoiceField(required=False)
31 epoch = forms.ChoiceField(required=False)
32 genre = forms.ChoiceField(required=False)
33 category = forms.ChoiceField(required=False, choices=[
36 #('translator', 'tłumacz'),
41 ('collection', 'kolekcja'),
43 ], widget=InlineRadioWidget())
45 def __init__(self, *args, **kwargs):
46 super().__init__(*args, **kwargs)
48 langs = dict(settings.LANGUAGES)
49 self.fields['lang'].choices = [('', 'wszystkie')] + [
52 langs.get(LANGUAGES_3TO2.get(b, b), b)
54 for b in catalogue.models.Book.objects.values_list(
56 ).distinct().order_by()
58 self.fields['epoch'].choices = [('', 'wszystkie')] + [
60 for b in catalogue.models.Tag.objects.filter(category='epoch')
62 self.fields['genre'].choices = [('', 'wszystkie')] + [
64 for b in catalogue.models.Tag.objects.filter(category='genre')
67 def get_querysets(self):
69 'author': catalogue.models.Tag.objects.filter(category='author'),
70 'pdauthor': pdcounter.models.Author.objects.all(),
71 'theme': catalogue.models.Tag.objects.filter(category='theme'),
72 'genre': catalogue.models.Tag.objects.filter(category='genre'),
73 'collection': catalogue.models.Collection.objects.all(),
74 'book': catalogue.models.Book.objects.filter(findable=True),
75 'pdbook': pdcounter.models.BookStub.objects.all(),
76 'snippet': catalogue.models.Snippet.objects.filter(book__findable=True),
77 'art': picture.models.Picture.objects.all(),
80 if self.cleaned_data['category']:
81 c = self.cleaned_data['category']
83 qs['author'] = qs['author'].none()
84 qs['pdauthor'] = qs['pdauthor'].none()
85 if c != 'theme': qs['theme'] = qs['theme'].none()
86 if c != 'genre': qs['genre'] = qs['genre'].none()
87 if c != 'collection': qs['collection'] = qs['collection'].none()
89 qs['book'] = qs['book'].none()
90 qs['pdbook'] = qs['pdbook'].none()
91 if c != 'quote': qs['snippet'] = qs['snippet'].none()
92 if c != 'art': qs['art'] = qs['art'].none()
93 qs['art'] = picture.models.Picture.objects.none()
95 if self.cleaned_data['format']:
96 c = self.cleaned_data['format']
97 qs['author'] = qs['author'].none()
98 qs['pdauthor'] = qs['pdauthor'].none()
99 qs['theme'] = qs['theme'].none()
100 qs['genre'] = qs['genre'].none()
101 qs['collection'] = qs['collection'].none()
103 qs['book'] = qs['book'].none()
104 qs['pdbook'] = qs['pdbook'].none()
105 qs['snippet'] = qs['snippet'].none()
106 if c in ('text', 'audio', 'daisy'):
107 qs['art'] = qs['art'].none()
109 qs['book'] = qs['book'].filter(media__type='mp3')
110 qs['pdbook'] = qs['book'].none()
111 qs['snippet'] = qs['snippet'].filter(book__media__type='mp3')
113 qs['book'] = qs['book'].filter(media__type='daisy')
114 qs['snippet'] = qs['snippet'].filter(book__media__type='daisy')
116 if self.cleaned_data['lang']:
117 qs['author'] = qs['author'].none()
118 qs['pdauthor'] = qs['pdauthor'].none()
119 qs['theme'] = qs['theme'].none()
120 qs['genre'] = qs['genre'].none()
121 qs['art'] = qs['art'].none()
122 qs['collection'] = qs['collection'].none()
123 qs['book'] = qs['book'].filter(language=self.cleaned_data['lang'])
124 qs['pdbook'] = qs['pdbook'].none()
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 = catalogue.models.Tag.objects.get(category=tag_cat, slug=c)
132 qs['author'] = qs['author'].none()
133 qs['pdauthor'] = qs['pdauthor'].none()
134 qs['theme'] = qs['theme'].none()
135 qs['genre'] = qs['genre'].none()
136 qs['collection'] = qs['collection'].none()
137 qs['book'] = qs['book'].filter(tag_relations__tag=t)
138 qs['pdbook'] = qs['pdbook'].none()
139 qs['snippet'] = qs['snippet'].filter(book__tag_relations__tag=t)
140 qs['art'] = qs['art'].filter(tag_relations__tag=t)
145 qs = self.get_querysets()
146 query = self.cleaned_data['q']
147 squery = UnaccentSearchQuery(query, config=settings.SEARCH_CONFIG)
148 query = SearchQuery(query, config=settings.SEARCH_CONFIG)
149 books = qs['book'].annotate(
150 search_vector=UnaccentSearchVector('title')
151 ).filter(search_vector=squery)
152 books = books.exclude(ancestor__in=books).order_by('-popularity__count')
154 snippets = qs['snippet'].filter(search_vector=squery).annotate(
155 headline=SearchHeadline(
158 config=settings.SEARCH_CONFIG,
159 start_sel='<strong>',
160 stop_sel='</strong>',
162 ).order_by('-book__popularity__count', 'sec')[:100]
163 snippets_by_book = {}
164 for snippet in snippets:
165 snippet_list = snippets_by_book.setdefault(snippet.book, [])
166 if len(snippet_list) < 3:
167 snippet_list.append(snippet)
170 'author': qs['author'].annotate(
171 search_vector=UnaccentSearchVector('name_pl')
172 ).filter(search_vector=squery),
173 'theme': qs['theme'].annotate(
174 search_vector=UnaccentSearchVector('name_pl')
175 ).filter(search_vector=squery),
176 'genre': qs['genre'].annotate(
177 search_vector=UnaccentSearchVector('name_pl')
178 ).filter(search_vector=squery),
179 'collection': qs['collection'].annotate(
180 search_vector=UnaccentSearchVector('title')
181 ).filter(search_vector=squery),
183 'art': qs['art'].annotate(
184 search_vector=UnaccentSearchVector('title')
185 ).filter(search_vector=squery)[:100],
186 'snippet': snippets_by_book,
187 'pdauthor': pdcounter.models.Author.search(squery, qs=qs['pdauthor']),
188 'pdbook': pdcounter.models.BookStub.search(squery, qs=qs['pdbook']),