1 # This file is part of Wolne Lektury, licensed under GNU Affero GPLv3 or later.
2 # Copyright © Fundacja Wolne Lektury. 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')),
26 ('daisy', _('Daisy')),
28 ], widget=InlineRadioWidget())
29 lang = forms.ChoiceField(required=False)
30 epoch = forms.ChoiceField(required=False)
31 genre = forms.ChoiceField(required=False)
32 category = forms.ChoiceField(required=False, choices=[
34 ('author', _('autor')),
35 #('translator', _('tłumacz')),
36 ('theme', _('motyw')),
37 ('genre', _('gatunek')),
40 ('collection', _('kolekcja')),
41 ('quote', _('cytat')),
42 ], widget=InlineRadioWidget())
44 def __init__(self, *args, **kwargs):
45 super().__init__(*args, **kwargs)
47 langs = dict(settings.LANGUAGES)
48 self.fields['lang'].choices = [('', _('wszystkie'))] + [
51 langs.get(LANGUAGES_3TO2.get(b, b), b)
53 for b in catalogue.models.Book.objects.values_list(
55 ).distinct().order_by()
57 self.fields['epoch'].choices = [('', _('wszystkie'))] + [
59 for b in catalogue.models.Tag.objects.filter(category='epoch')
61 self.fields['genre'].choices = [('', _('wszystkie'))] + [
63 for b in catalogue.models.Tag.objects.filter(category='genre')
66 def get_querysets(self):
68 'author': catalogue.models.Tag.objects.filter(category='author'),
69 'pdauthor': pdcounter.models.Author.objects.all(),
70 'theme': catalogue.models.Tag.objects.filter(category='theme'),
71 'genre': catalogue.models.Tag.objects.filter(category='genre'),
72 'collection': catalogue.models.Collection.objects.all(),
73 'book': catalogue.models.Book.objects.filter(findable=True),
74 'pdbook': pdcounter.models.BookStub.objects.all(),
75 'snippet': catalogue.models.Snippet.objects.filter(book__findable=True),
76 'art': picture.models.Picture.objects.all(),
79 if self.cleaned_data['category']:
80 c = self.cleaned_data['category']
82 qs['author'] = qs['author'].none()
83 qs['pdauthor'] = qs['pdauthor'].none()
84 if c != 'theme': qs['theme'] = qs['theme'].none()
85 if c != 'genre': qs['genre'] = qs['genre'].none()
86 if c != 'collection': qs['collection'] = qs['collection'].none()
88 qs['book'] = qs['book'].none()
89 qs['pdbook'] = qs['pdbook'].none()
90 if c != 'quote': qs['snippet'] = qs['snippet'].none()
91 if c != 'art': qs['art'] = qs['art'].none()
92 qs['art'] = picture.models.Picture.objects.none()
94 if self.cleaned_data['format']:
95 c = self.cleaned_data['format']
96 qs['author'] = qs['author'].none()
97 qs['pdauthor'] = qs['pdauthor'].none()
98 qs['theme'] = qs['theme'].none()
99 qs['genre'] = qs['genre'].none()
100 qs['collection'] = qs['collection'].none()
102 qs['book'] = qs['book'].none()
103 qs['pdbook'] = qs['pdbook'].none()
104 qs['snippet'] = qs['snippet'].none()
105 if c in ('text', 'audio', 'daisy'):
106 qs['art'] = qs['art'].none()
108 qs['book'] = qs['book'].filter(media__type='mp3')
109 qs['pdbook'] = qs['book'].none()
110 qs['snippet'] = qs['snippet'].filter(book__media__type='mp3')
112 qs['book'] = qs['book'].filter(media__type='daisy')
113 qs['snippet'] = qs['snippet'].filter(book__media__type='daisy')
115 if self.cleaned_data['lang']:
116 qs['author'] = qs['author'].none()
117 qs['pdauthor'] = qs['pdauthor'].none()
118 qs['theme'] = qs['theme'].none()
119 qs['genre'] = qs['genre'].none()
120 qs['art'] = qs['art'].none()
121 qs['collection'] = qs['collection'].none()
122 qs['book'] = qs['book'].filter(language=self.cleaned_data['lang'])
123 qs['pdbook'] = qs['pdbook'].none()
124 qs['snippet'] = qs['snippet'].filter(book__language=self.cleaned_data['lang'])
126 for tag_cat in ('epoch', 'genre'):
127 c = self.cleaned_data[tag_cat]
130 t = catalogue.models.Tag.objects.get(category=tag_cat, slug=c)
131 qs['author'] = qs['author'].none()
132 qs['pdauthor'] = qs['pdauthor'].none()
133 qs['theme'] = qs['theme'].none()
134 qs['genre'] = qs['genre'].none()
135 qs['collection'] = qs['collection'].none()
136 qs['book'] = qs['book'].filter(tag_relations__tag=t)
137 qs['pdbook'] = qs['pdbook'].none()
138 qs['snippet'] = qs['snippet'].filter(book__tag_relations__tag=t)
139 qs['art'] = qs['art'].filter(tag_relations__tag=t)
144 qs = self.get_querysets()
145 query = self.cleaned_data['q']
146 squery = UnaccentSearchQuery(query, config=settings.SEARCH_CONFIG)
147 query = SearchQuery(query, config=settings.SEARCH_CONFIG)
148 books = qs['book'].annotate(
149 search_vector=UnaccentSearchVector('title')
150 ).filter(search_vector=squery)
151 books = books.exclude(ancestor__in=books).order_by('-popularity__count')
153 snippets = qs['snippet'].filter(search_vector=squery).annotate(
154 headline=SearchHeadline(
157 config=settings.SEARCH_CONFIG,
158 start_sel='<strong>',
159 stop_sel='</strong>',
161 ).order_by('-book__popularity__count', 'sec')[:100]
162 snippets_by_book = {}
163 for snippet in snippets:
164 snippet_list = snippets_by_book.setdefault(snippet.book, [])
165 if len(snippet_list) < 3:
166 snippet_list.append(snippet)
169 'author': qs['author'].annotate(
170 search_vector=UnaccentSearchVector('name_pl')
171 ).filter(search_vector=squery),
172 'theme': qs['theme'].annotate(
173 search_vector=UnaccentSearchVector('name_pl')
174 ).filter(search_vector=squery),
175 'genre': qs['genre'].annotate(
176 search_vector=UnaccentSearchVector('name_pl')
177 ).filter(search_vector=squery),
178 'collection': qs['collection'].annotate(
179 search_vector=UnaccentSearchVector('title')
180 ).filter(search_vector=squery),
182 'art': qs['art'].annotate(
183 search_vector=UnaccentSearchVector('title')
184 ).filter(search_vector=squery)[:100],
185 'snippet': snippets_by_book,
186 'pdauthor': pdcounter.models.Author.search(squery, qs=qs['pdauthor']),
187 'pdbook': pdcounter.models.BookStub.search(squery, qs=qs['pdbook']),