From 18507469755dffbce6aca1687569815c0360afcb Mon Sep 17 00:00:00 2001 From: Guillaume Bertholon Date: Sat, 28 Nov 2020 00:33:33 +0100 Subject: [PATCH] Add inventory search with haystack Also give a coherent look to all inventory lists --- .gitignore | 1 + gestiojeux/settings.dev.py | 9 +++ gestiojeux/settings_base.py | 4 ++ inventory/search_indexes.py | 27 +++++++++ inventory/templates/inventory/category.html | 2 +- .../templates/inventory/category_list.html | 4 +- inventory/templates/inventory/game_list.html | 2 +- inventory/templates/inventory/inventory.html | 9 +++ .../inventory/partials/game_item.html | 19 ++++++ inventory/templates/inventory/search.html | 39 ++++++++++++ .../inventory/search_indexes/game.txt | 4 ++ inventory/templates/inventory/tag.html | 2 +- inventory/templates/inventory/tag_list.html | 4 +- inventory/urls.py | 2 + inventory/views.py | 11 ++++ mainsite/scss/forms.scss | 19 ++---- mainsite/scss/style.scss | 59 +++++++++++++++---- mainsite/static/css/style.css | 43 ++++++++++---- requirements.txt | 2 + 19 files changed, 217 insertions(+), 45 deletions(-) create mode 100644 inventory/search_indexes.py create mode 100644 inventory/templates/inventory/partials/game_item.html create mode 100644 inventory/templates/inventory/search.html create mode 100644 inventory/templates/inventory/search_indexes/game.txt diff --git a/.gitignore b/.gitignore index 2a330b9..d26855f 100644 --- a/.gitignore +++ b/.gitignore @@ -63,6 +63,7 @@ venv # Project specific db.sqlite3 +whoosh_index/ public/ # Vim recover files diff --git a/gestiojeux/settings.dev.py b/gestiojeux/settings.dev.py index d0dde1a..ce6aa03 100644 --- a/gestiojeux/settings.dev.py +++ b/gestiojeux/settings.dev.py @@ -23,6 +23,15 @@ DATABASES = { } } +# Search engine +# https://django-haystack.readthedocs.io/en/latest/tutorial.html#configuration + +HAYSTACK_CONNECTIONS = { + "default": { + "ENGINE": "haystack.backends.whoosh_backend.WhooshEngine", + "PATH": os.path.join(BASE_DIR, "whoosh_index"), + }, +} # Internationalization # https://docs.djangoproject.com/en/3.0/topics/i18n/ diff --git a/gestiojeux/settings_base.py b/gestiojeux/settings_base.py index 697a044..126c8ac 100644 --- a/gestiojeux/settings_base.py +++ b/gestiojeux/settings_base.py @@ -25,6 +25,7 @@ INSTALLED_APPS = [ "django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles", + "haystack", "mainsite", "inventory", "django_cas_ng", @@ -79,6 +80,9 @@ AUTH_PASSWORD_VALIDATORS = [ {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"}, ] +# Update the search database on save +HAYSTACK_SIGNAL_PROCESSOR = "haystack.signals.RealtimeSignalProcessor" + # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.0/howto/static-files/ diff --git a/inventory/search_indexes.py b/inventory/search_indexes.py new file mode 100644 index 0000000..b19c343 --- /dev/null +++ b/inventory/search_indexes.py @@ -0,0 +1,27 @@ +from haystack import indexes +from .models import Category, Tag, Game + + +class CategoryIndex(indexes.SearchIndex, indexes.Indexable): + text = indexes.CharField(document=True, model_attr="name") + + def get_model(self): + return Category + + +class TagIndex(indexes.SearchIndex, indexes.Indexable): + text = indexes.CharField(document=True, model_attr="name") + + def get_model(self): + return Tag + + +class GameIndex(indexes.SearchIndex, indexes.Indexable): + text = indexes.CharField( + document=True, + use_template=True, + template_name="inventory/search_indexes/game.txt", + ) + + def get_model(self): + return Game diff --git a/inventory/templates/inventory/category.html b/inventory/templates/inventory/category.html index f28aefd..27a6e29 100644 --- a/inventory/templates/inventory/category.html +++ b/inventory/templates/inventory/category.html @@ -7,7 +7,7 @@ Il y a {{ game_list|length }} jeu{{ game_list|pluralize:"x" }} dans cette catégorie : {% endwith %} diff --git a/inventory/templates/inventory/category_list.html b/inventory/templates/inventory/category_list.html index 2cee0a4..1eabbf2 100644 --- a/inventory/templates/inventory/category_list.html +++ b/inventory/templates/inventory/category_list.html @@ -1,12 +1,12 @@ {% extends "base.html" %} {% block "content" %} -

Liste des catégories

+

Liste des catégories

Il y a {{ category_list|length }} catégorie{{ category_list|pluralize }} de jeux : {% endblock %} diff --git a/inventory/templates/inventory/game_list.html b/inventory/templates/inventory/game_list.html index a5f4efd..db43ab9 100644 --- a/inventory/templates/inventory/game_list.html +++ b/inventory/templates/inventory/game_list.html @@ -6,7 +6,7 @@ Il y a {{ game_list|length }} jeu{{ game_list|pluralize:"x" }} en salle jeux : {% endblock %} diff --git a/inventory/templates/inventory/inventory.html b/inventory/templates/inventory/inventory.html index 64a4d68..c69e1a0 100644 --- a/inventory/templates/inventory/inventory.html +++ b/inventory/templates/inventory/inventory.html @@ -3,7 +3,16 @@ {% block "content" %}

Inventaire du club Jeux

+ Rechercher dans la ludothèque: + + +
+
+ Liste des catégories

diff --git a/inventory/templates/inventory/partials/game_item.html b/inventory/templates/inventory/partials/game_item.html new file mode 100644 index 0000000..b364bcc --- /dev/null +++ b/inventory/templates/inventory/partials/game_item.html @@ -0,0 +1,19 @@ +

  • + + {{game.title}} +
    +

    {{ game.player_range }}

    +

    {{ game.duration }} +

    {{ game.category }}

    + {% for tag in game.tags.all %} +

    {{ tag }}

    + {% endfor %} + {% if game.game_designer %} +

    {{ game.game_designer }} + {% endif %} + {% if game.editor %} +

    {{ game.editor }}

    + {% endif %} +
    +
    +
  • diff --git a/inventory/templates/inventory/search.html b/inventory/templates/inventory/search.html new file mode 100644 index 0000000..44faa6e --- /dev/null +++ b/inventory/templates/inventory/search.html @@ -0,0 +1,39 @@ +{% extends "base.html" %} + +{% block "content" %} +

    Recherche

    + + + {% if query %} +
    + + + + {% if page_obj.has_previous or page_obj.has_next %} +
    + {% if page_obj.has_previous %}{% endif %}« Précédent{% if page_obj.has_previous %}{% endif %} + | + {% if page_obj.has_next %}{% endif %}Suivant »{% if page_obj.has_next %}{% endif %} +
    + {% endif %} + {% endif %} +{% endblock %} diff --git a/inventory/templates/inventory/search_indexes/game.txt b/inventory/templates/inventory/search_indexes/game.txt new file mode 100644 index 0000000..cf19c30 --- /dev/null +++ b/inventory/templates/inventory/search_indexes/game.txt @@ -0,0 +1,4 @@ +{{ object.title }} +{{ object.editor }} +{{ object.game_designer }} +{{ object.description }} diff --git a/inventory/templates/inventory/tag.html b/inventory/templates/inventory/tag.html index fd8b6f5..f872fcf 100644 --- a/inventory/templates/inventory/tag.html +++ b/inventory/templates/inventory/tag.html @@ -7,7 +7,7 @@ Il y a {{ game_list|length }} jeu{{ game_list|pluralize:"x" }} marqué{{ game_list|pluralize }} avec ce tag : {% endwith %} diff --git a/inventory/templates/inventory/tag_list.html b/inventory/templates/inventory/tag_list.html index d1aba79..950b414 100644 --- a/inventory/templates/inventory/tag_list.html +++ b/inventory/templates/inventory/tag_list.html @@ -1,12 +1,12 @@ {% extends "base.html" %} {% block "content" %} -

    Liste des tags

    +

    Liste des tags

    Il y a {{ tag_list|length }} tag{{ tag_list|pluralize }} dans la ludothèque : {% endblock %} diff --git a/inventory/urls.py b/inventory/urls.py index de16a07..ce3a262 100644 --- a/inventory/urls.py +++ b/inventory/urls.py @@ -7,6 +7,7 @@ from .views import ( TagView, GameListView, GameView, + InventorySearchView, ) app_name = "inventory" @@ -19,4 +20,5 @@ urlpatterns = [ path("tag//", TagView.as_view(), name="tag"), path("game/", GameListView.as_view(), name="game_list"), path("game//", GameView.as_view(), name="game"), + path("search/", InventorySearchView.as_view(), name="search"), ] diff --git a/inventory/views.py b/inventory/views.py index f59cd2f..76d27c0 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -1,4 +1,7 @@ from django.views.generic import TemplateView, ListView, DetailView +from haystack.generic_views import SearchView +from haystack.forms import SearchForm +from haystack.query import SearchQuerySet from .models import Category, Tag, Game @@ -34,3 +37,11 @@ class GameListView(ListView): class GameView(DetailView): model = Game template_name = "inventory/game.html" + + +class InventorySearchView(SearchView): + form_class = SearchForm + template_name = "inventory/search.html" + + def get_queryset(self): + return SearchQuerySet().models(Category, Tag, Game) diff --git a/mainsite/scss/forms.scss b/mainsite/scss/forms.scss index 4dd10da..509c3cc 100644 --- a/mainsite/scss/forms.scss +++ b/mainsite/scss/forms.scss @@ -97,20 +97,11 @@ select { background-color: rgba($error_box_color, .4); } -.checkbox_input { - display: flex; - justify-content: space-evenly; - align-items: center; +form.search { + flex-direction: row; + gap: 10px; - .label_line { - order: 1; - flex: 1 1 500px; - } - input { - flex: 0 1 50px; + button { + margin: 0; } } - -.fieldgroup { - margin: 15px 0; -} diff --git a/mainsite/scss/style.scss b/mainsite/scss/style.scss index cc555ec..0cbf82e 100644 --- a/mainsite/scss/style.scss +++ b/mainsite/scss/style.scss @@ -44,7 +44,7 @@ main { text-align: justify; &.small_page { - width: $small_page_width; + width: $small_page_width; } } @@ -136,13 +136,13 @@ button, .btn_row a { border-radius: 3px; .tooltiptext { - visibility: hidden; + visibility: hidden; display: block; - background-color: black; - color: rgba(white, 0.80); - text-align: justify; - padding: 10px; - border-radius: 6px; + background-color: black; + color: rgba(white, 0.80); + text-align: justify; + padding: 10px; + border-radius: 6px; font-size: 0.8em; width: 250px; @@ -152,10 +152,10 @@ button, .btn_row a { left: -75px; } - /* Position the tooltip text - see examples below! */ - position: absolute; + /* Position the tooltip text - see examples below! */ + position: absolute; left: -75px; - z-index: 1; + z-index: 1; ul { margin: 0; @@ -242,7 +242,7 @@ iframe { display: flex; align-items: center; gap: 20px; - + @media (max-width: 500px) { flex-direction: column; } @@ -261,7 +261,7 @@ iframe { flex: 1 0 auto; text-align: left; max-width: 50%; - + @media (max-width: 500px) { max-width: 100%; } @@ -276,3 +276,38 @@ iframe { } } +ul { + padding: 0 20px; + list-style-type: none; + + li>a { + display: block; + text-decoration: none; + padding: 15px; + margin: 10px 5px; + border-radius: 10px; + border: 1px solid transparent; + + &:hover { + border-color: $header_border_color; + background-color: lighten($header_border_color, 70%); + } + &:focus { + border-color: $header_border_color; + background-color: lighten($header_border_color, 70%); + box-shadow: 0 0 1.5px 1px $header_bg_color; + } + + .details { + font-size: 0.7em; + display: flex; + flex-wrap: wrap; + margin: 5px; + gap: 5px 20px; + + p { + margin: 0; + } + } + } +} diff --git a/mainsite/static/css/style.css b/mainsite/static/css/style.css index 27723c2..23d8475 100644 --- a/mainsite/static/css/style.css +++ b/mainsite/static/css/style.css @@ -151,18 +151,11 @@ select { border-radius: 10px; background-color: rgba(255, 205, 221, 0.4); } -.checkbox_input { - display: flex; - justify-content: space-evenly; - align-items: center; } - .checkbox_input .label_line { - order: 1; - flex: 1 1 500px; } - .checkbox_input input { - flex: 0 1 50px; } - -.fieldgroup { - margin: 15px 0; } +form.search { + flex-direction: row; + gap: 10px; } + form.search button { + margin: 0; } html { box-sizing: border-box; } @@ -413,3 +406,29 @@ iframe { margin: 1ex; } #game_infos #details hr { margin: 1ex; } + +ul { + padding: 0 20px; + list-style-type: none; } + ul li > a { + display: block; + text-decoration: none; + padding: 15px; + margin: 10px 5px; + border-radius: 10px; + border: 1px solid transparent; } + ul li > a:hover { + border-color: #51808c; + background-color: white; } + ul li > a:focus { + border-color: #51808c; + background-color: white; + box-shadow: 0 0 1.5px 1px #6bb8c4; } + ul li > a .details { + font-size: 0.7em; + display: flex; + flex-wrap: wrap; + margin: 5px; + gap: 5px 20px; } + ul li > a .details p { + margin: 0; } diff --git a/requirements.txt b/requirements.txt index fb87978..5d8ca8d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,5 @@ Django django-autoslug Pillow django-cas-ng +django-haystack +Whoosh