From cf4b06bca2188ba1e779c8a21a697525dae11f6a Mon Sep 17 00:00:00 2001 From: Aleksei Pirogov Date: Sat, 5 Jun 2021 10:40:48 +0300 Subject: [PATCH] optimize an extraction of notes, update templates, add favicon --- djaif/book/models.py | 26 +++++++++++++++ djaif/book/templates/page.html | 27 ++++++---------- djaif/book/views.py | 56 ++++++++++++++++----------------- djaif/settings.py | 9 +++--- setup.cfg | 3 ++ static/favicon.png | Bin 0 -> 3010 bytes static/page.css | 9 ++++++ 7 files changed, 80 insertions(+), 50 deletions(-) create mode 100644 static/favicon.png create mode 100644 static/page.css diff --git a/djaif/book/models.py b/djaif/book/models.py index 15d505b..39521e3 100644 --- a/djaif/book/models.py +++ b/djaif/book/models.py @@ -103,6 +103,32 @@ def load_from(self, save_id): book_progress=self, ).save() + def notes(self): + """Return a prepared set of notes. + + These notes will be annotated with relation to the + current page and will appear in order: + + 1. pinned notes (key=0, pinned=True) + 2. current page notes (key=1) + 3. other notes (key=0, pinned=False) + + Within each group the notes will be ordered + by decreasing of 'updated_at'. + """ + return Note.objects.filter( + progress=self, + ).annotate( + key=models.Count( + 'page', + filter=models.Q(page=self.book_page), + ), + ).order_by( + '-pinned', + '-key', + '-updated_at', + ) + class ProgressSave(models.Model): progress = models.ForeignKey(BookProgress, on_delete=models.CASCADE) diff --git a/djaif/book/templates/page.html b/djaif/book/templates/page.html index 65bc705..4ab35c6 100644 --- a/djaif/book/templates/page.html +++ b/djaif/book/templates/page.html @@ -3,6 +3,8 @@ {{ page.book.title }}: {{ page.title }} + +
@@ -78,28 +80,19 @@

Заметки

{% for name, noteset in notesets %} -
diff --git a/djaif/book/views.py b/djaif/book/views.py index e6831b2..0090e7a 100644 --- a/djaif/book/views.py +++ b/djaif/book/views.py @@ -1,4 +1,5 @@ from functools import wraps +from itertools import groupby from django.db import transaction from django.db.models import F, Func # noqa: WPS347 @@ -39,6 +40,7 @@ def view_books(request): def view_book(request, book_id): book = get_object_or_404(models.Book, id=book_id) + if not book.first_page: raise ValueError("Book {0.id} hasn't a first page!") try: @@ -50,21 +52,41 @@ def view_book(request, book_id): book=book, user=request.user, ) - page = progress.book_page - links = [ (link, link.has_all_needed(list(progress.items.all()))) - for link in page.pagelink_set.all() + for link in progress.book_page.pagelink_set.all() + ] + + notesets = [ + (name, [ + ( + note.id, + note.text, + note.page.title if note.page else '', + ) + for note in group + ]) + for name, group in groupby( + progress.notes().select_related( + 'page', + ).all(), + key=lambda note: ( + 'page' if note.key else + 'pinned' if note.pinned else + 'other' + ), + ) ] return render( request, 'page.html', context={ - 'page': page, + 'page': progress.book_page, 'progress': progress, 'links': links, - 'page_items': page.items.exclude( + 'notesets': notesets, + 'page_items': progress.book_page.items.exclude( id__in=progress.items.only('id'), ).exclude( id__in=progress.droppeditem_set.values_list( @@ -72,30 +94,8 @@ def view_book(request, book_id): ), ).all(), 'dropped_items': progress.droppeditem_set.filter( - book_page=page, + book_page=progress.book_page, ).all(), - 'notesets': [ - ( - 'pinned', - progress.note_set.filter( - pinned=True, - ).order_by('-updated_at').all(), - ), - ( - 'page', - progress.note_set.filter( - page=page, pinned=False, - ).order_by('-updated_at').all(), - ), - ( - 'other', - progress.note_set.exclude( - page=page, - ).filter( - pinned=False, - ).order_by('-updated_at').all(), - ), - ], }, ) diff --git a/djaif/settings.py b/djaif/settings.py index 56445a1..3e6621a 100644 --- a/djaif/settings.py +++ b/djaif/settings.py @@ -116,9 +116,12 @@ USE_TZ = True +DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' + +SHELL_PLUS_PRINT_SQL = True # Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/3.0/howto/static-files/ +# https://docs.djangoproject.com/en/3.2/howto/static-files/ STATIC_URL = '/static/' @@ -130,7 +133,3 @@ MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media') - -DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' - -SHELL_PLUS_PRINT_SQL = True diff --git a/setup.cfg b/setup.cfg index 5f09f09..bf06b40 100644 --- a/setup.cfg +++ b/setup.cfg @@ -29,13 +29,16 @@ exclude = ignore = # documentation isn't so important for now D100, D101, D102, D103, D104, D105, D106, + DAR201, # yes, we have bad names here and there WPS110, WPS111, # annoying stuff WPS326, WPS306, WPS317, WPS202, WPS226, WPS411, WPS323, + WPS509, # I like multiline conditions! WPS337, W503, W504, per-file-ignores = settings.py: WPS407, E501, C812, WPS221, WPS226, S105 models.py: WPS226 + views.py: WPS210 diff --git a/static/favicon.png b/static/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..adce88a0b5511f1e6d726f5cc2b923d88c7cd285 GIT binary patch literal 3010 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 Ef`!FqDgXcg literal 0 HcmV?d00001 diff --git a/static/page.css b/static/page.css new file mode 100644 index 0000000..23c9075 --- /dev/null +++ b/static/page.css @@ -0,0 +1,9 @@ +.noteset {} + +.noteset-page { + background-color: greenyellow; +} + +.noteset-pinned { + background-color: yellow; +}