1
0
Fork 0

Merge pull request #2834 from zachflanders/2678

Add support for title sort to ignore initial article
This commit is contained in:
Mouse Reeve 2023-07-17 06:04:25 -07:00 committed by GitHub
commit ac4276f212
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 96 additions and 5 deletions

View file

@ -20,6 +20,7 @@ class EditionForm(CustomForm):
model = models.Edition model = models.Edition
fields = [ fields = [
"title", "title",
"sort_title",
"subtitle", "subtitle",
"description", "description",
"series", "series",
@ -45,6 +46,9 @@ class EditionForm(CustomForm):
] ]
widgets = { widgets = {
"title": forms.TextInput(attrs={"aria-describedby": "desc_title"}), "title": forms.TextInput(attrs={"aria-describedby": "desc_title"}),
"sort_title": forms.TextInput(
attrs={"aria-describedby": "desc_sort_title"}
),
"subtitle": forms.TextInput(attrs={"aria-describedby": "desc_subtitle"}), "subtitle": forms.TextInput(attrs={"aria-describedby": "desc_subtitle"}),
"description": forms.Textarea( "description": forms.Textarea(
attrs={"aria-describedby": "desc_description"} attrs={"aria-describedby": "desc_description"}

View file

@ -24,7 +24,7 @@ class SortListForm(forms.Form):
sort_by = ChoiceField( sort_by = ChoiceField(
choices=( choices=(
("order", _("List Order")), ("order", _("List Order")),
("title", _("Book Title")), ("sort_title", _("Book Title")),
("rating", _("Rating")), ("rating", _("Rating")),
), ),
label=_("Sort By"), label=_("Sort By"),

View file

@ -0,0 +1,49 @@
import re
from itertools import chain
from django.db import migrations, transaction
from django.db.models import Q
from bookwyrm.settings import LANGUAGE_ARTICLES
def set_sort_title(edition):
articles = chain(
*(LANGUAGE_ARTICLES.get(language, ()) for language in tuple(edition.languages))
)
edition.sort_title = re.sub(
f'^{" |^".join(articles)} ', "", str(edition.title).lower()
)
return edition
@transaction.atomic
def populate_sort_title(apps, schema_editor):
Edition = apps.get_model("bookwyrm", "Edition")
db_alias = schema_editor.connection.alias
editions_wo_sort_title = Edition.objects.using(db_alias).filter(
Q(sort_title__isnull=True) | Q(sort_title__exact="")
)
batch_size = 1000
start = 0
end = batch_size
while True:
batch = editions_wo_sort_title[start:end]
if not batch.exists():
break
Edition.objects.bulk_update(
(set_sort_title(edition) for edition in batch), ["sort_title"]
)
start = end
end += batch_size
class Migration(migrations.Migration):
dependencies = [
("bookwyrm", "0178_auto_20230328_2132"),
]
operations = [
migrations.RunPython(populate_sort_title),
]

View file

@ -1,4 +1,5 @@
""" database schema for books and shelves """ """ database schema for books and shelves """
from itertools import chain
import re import re
from django.contrib.postgres.search import SearchVectorField from django.contrib.postgres.search import SearchVectorField
@ -17,6 +18,7 @@ from bookwyrm.preview_images import generate_edition_preview_image_task
from bookwyrm.settings import ( from bookwyrm.settings import (
DOMAIN, DOMAIN,
DEFAULT_LANGUAGE, DEFAULT_LANGUAGE,
LANGUAGE_ARTICLES,
ENABLE_PREVIEW_IMAGES, ENABLE_PREVIEW_IMAGES,
ENABLE_THUMBNAIL_GENERATION, ENABLE_THUMBNAIL_GENERATION,
) )
@ -363,6 +365,19 @@ class Edition(Book):
for author_id in self.authors.values_list("id", flat=True): for author_id in self.authors.values_list("id", flat=True):
cache.delete(f"author-books-{author_id}") cache.delete(f"author-books-{author_id}")
# Create sort title by removing articles from title
if self.sort_title in [None, ""]:
if self.sort_title in [None, ""]:
articles = chain(
*(
LANGUAGE_ARTICLES.get(language, ())
for language in tuple(self.languages)
)
)
self.sort_title = re.sub(
f'^{" |^".join(articles)} ', "", str(self.title).lower()
)
return super().save(*args, **kwargs) return super().save(*args, **kwargs)
@classmethod @classmethod

View file

@ -312,6 +312,9 @@ LANGUAGES = [
("zh-hant", _("繁體中文 (Traditional Chinese)")), ("zh-hant", _("繁體中文 (Traditional Chinese)")),
] ]
LANGUAGE_ARTICLES = {
"English": {"the", "a", "an"},
}
TIME_ZONE = "UTC" TIME_ZONE = "UTC"

View file

@ -28,6 +28,15 @@
{% include 'snippets/form_errors.html' with errors_list=form.title.errors id="desc_title" %} {% include 'snippets/form_errors.html' with errors_list=form.title.errors id="desc_title" %}
</div> </div>
<div class="field">
<label class="label" for="id_sort_title">
{% trans "Sort Title:" %}
</label>
<input type="text" name="sort_title" value="{{ form.sort_title.value|default:'' }}" maxlength="255" class="input" required="" id="id_sort_title" aria-describedby="desc_sort_title">
{% include 'snippets/form_errors.html' with errors_list=form.sort_title.errors id="desc_sort_title" %}
</div>
<div class="field"> <div class="field">
<label class="label" for="id_subtitle"> <label class="label" for="id_subtitle">
{% trans "Subtitle:" %} {% trans "Subtitle:" %}

View file

@ -145,7 +145,7 @@
<thead> <thead>
<tr> <tr>
<th>{% trans "Cover"%}</th> <th>{% trans "Cover"%}</th>
<th>{% trans "Title" as text %}{% include 'snippets/table-sort-header.html' with field="title" sort=sort text=text %}</th> <th>{% trans "Title" as text %}{% include 'snippets/table-sort-header.html' with field="sort_title" sort=sort text=text %}</th>
<th>{% trans "Author" as text %}{% include 'snippets/table-sort-header.html' with field="author" sort=sort text=text %}</th> <th>{% trans "Author" as text %}{% include 'snippets/table-sort-header.html' with field="author" sort=sort text=text %}</th>
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
{% if is_self %} {% if is_self %}

View file

@ -132,3 +132,14 @@ class Book(TestCase):
self.assertIsNotNone(book.cover_bw_book_xlarge_jpg.url) self.assertIsNotNone(book.cover_bw_book_xlarge_jpg.url)
self.assertIsNotNone(book.cover_bw_book_xxlarge_webp.url) self.assertIsNotNone(book.cover_bw_book_xxlarge_webp.url)
self.assertIsNotNone(book.cover_bw_book_xxlarge_jpg.url) self.assertIsNotNone(book.cover_bw_book_xxlarge_jpg.url)
def test_populate_sort_title(self):
"""The sort title should remove the initial article on save"""
books = (
models.Edition.objects.create(
title=f"{article} Test Edition", languages=[langauge]
)
for langauge, articles in settings.LANGUAGE_ARTICLES.items()
for article in articles
)
self.assertTrue(all(book.sort_title == "test edition" for book in books))

View file

@ -129,7 +129,7 @@ def sort_list(request, items):
"""helper to handle the surprisingly involved sorting""" """helper to handle the surprisingly involved sorting"""
# sort_by shall be "order" unless a valid alternative is given # sort_by shall be "order" unless a valid alternative is given
sort_by = request.GET.get("sort_by", "order") sort_by = request.GET.get("sort_by", "order")
if sort_by not in ("order", "title", "rating"): if sort_by not in ("order", "sort_title", "rating"):
sort_by = "order" sort_by = "order"
# direction shall be "ascending" unless a valid alternative is given # direction shall be "ascending" unless a valid alternative is given
@ -139,7 +139,7 @@ def sort_list(request, items):
directional_sort_by = { directional_sort_by = {
"order": "order", "order": "order",
"title": "book__title", "sort_title": "book__sort_title",
"rating": "average_rating", "rating": "average_rating",
}[sort_by] }[sort_by]
if direction == "descending": if direction == "descending":

View file

@ -128,7 +128,7 @@ class Shelf(View):
def sort_books(books, sort): def sort_books(books, sort):
"""Books in shelf sorting""" """Books in shelf sorting"""
sort_fields = [ sort_fields = [
"title", "sort_title",
"author", "author",
"shelved_date", "shelved_date",
"start_date", "start_date",