Improve form filtering and design

This commit is contained in:
Gabriel Augendre 2020-11-22 12:59:46 +01:00
parent eb7da95a4f
commit 11e0202a7c
No known key found for this signature in database
GPG key ID: 1E693F4CE4AEE7B4
11 changed files with 83 additions and 19 deletions

14
poetry.lock generated
View file

@ -91,6 +91,14 @@ sqlparse = ">=0.2.2"
argon2 = ["argon2-cffi (>=16.1.0)"] argon2 = ["argon2-cffi (>=16.1.0)"]
bcrypt = ["bcrypt"] bcrypt = ["bcrypt"]
[[package]]
name = "django-crispy-forms"
version = "1.10.0"
description = "Best way to have Django DRY forms"
category = "main"
optional = false
python-versions = ">=3.5"
[[package]] [[package]]
name = "filelock" name = "filelock"
version = "3.0.12" version = "3.0.12"
@ -294,7 +302,7 @@ testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)",
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.9" python-versions = "^3.9"
content-hash = "c30849d31e4af28a2048d39ee36777d08501143c80e1fd08fa2f1c04108a92ce" content-hash = "cdf8eea1e8834cd9a055fdbb2d4d4edf58111c8666e92542f4e6f2e0359bc499"
[metadata.files] [metadata.files]
appdirs = [ appdirs = [
@ -365,6 +373,10 @@ django = [
{file = "Django-3.1.3-py3-none-any.whl", hash = "sha256:14a4b7cd77297fba516fc0d92444cc2e2e388aa9de32d7a68d4a83d58f5a4927"}, {file = "Django-3.1.3-py3-none-any.whl", hash = "sha256:14a4b7cd77297fba516fc0d92444cc2e2e388aa9de32d7a68d4a83d58f5a4927"},
{file = "Django-3.1.3.tar.gz", hash = "sha256:14b87775ffedab2ef6299b73343d1b4b41e5d4e2aa58c6581f114dbec01e3f8f"}, {file = "Django-3.1.3.tar.gz", hash = "sha256:14b87775ffedab2ef6299b73343d1b4b41e5d4e2aa58c6581f114dbec01e3f8f"},
] ]
django-crispy-forms = [
{file = "django-crispy-forms-1.10.0.tar.gz", hash = "sha256:d3f808d20cafe20fd38a49a47e72db1fd519fcf31bef4f47f008619336a3ebff"},
{file = "django_crispy_forms-1.10.0-py3-none-any.whl", hash = "sha256:92ed3fdc52c08d21d60adbb9de24e432c590e66e894f43cee0974fc959209976"},
]
filelock = [ filelock = [
{file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"}, {file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"},
{file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"}, {file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"},

View file

@ -7,6 +7,7 @@ authors = ["Gabriel Augendre <gabriel@augendre.info>"]
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.9" python = "^3.9"
Django = "^3.1.3" Django = "^3.1.3"
django-crispy-forms = "^1.10.0"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
pytest = "^6.1" pytest = "^6.1"

View file

@ -12,3 +12,5 @@ class BodyRegionAdmin(admin.ModelAdmin):
@register(Exercise) @register(Exercise)
class ExerciseAdmin(admin.ModelAdmin): class ExerciseAdmin(admin.ModelAdmin):
list_display = ["name", "get_body_regions", "rating"] list_display = ["name", "get_body_regions", "rating"]
list_filter = ["body_regions", "rating"]
search_fields = ["name"]

View file

@ -1,13 +1,33 @@
from django import forms from django import forms
from django.core.validators import MinValueValidator
from exercises.models import BodyRegion, Exercise
class QueryForm(forms.Form): class QueryForm(forms.Form):
CARDIO_CHOICE = "cardio" CARDIO_CHOICE = "cardio"
STRENGTHENING_CHOICE = "strengthening" STRENGTHENING_CHOICE = "strengthening"
BALANCED_CHOICE = "balanced" BALANCED_CHOICE = "balanced"
EVERYTHING_CHOICE = "everything"
RATING_CHOICES = [ RATING_CHOICES = [
(CARDIO_CHOICE, "Cardio"), (CARDIO_CHOICE, "Cardio"),
(STRENGTHENING_CHOICE, "Strengthening"), (STRENGTHENING_CHOICE, "Strengthening"),
(BALANCED_CHOICE, "Balanced"), (BALANCED_CHOICE, "Balanced"),
(EVERYTHING_CHOICE, "Everything"),
] ]
rating = forms.ChoiceField(choices=RATING_CHOICES, widget=forms.RadioSelect) rating = forms.ChoiceField(
choices=RATING_CHOICES,
widget=forms.RadioSelect,
initial=EVERYTHING_CHOICE,
label="Catégorie",
)
body_regions = forms.ModelMultipleChoiceField(
BodyRegion.objects.filter(
id__in=Exercise.objects.values_list("body_regions", flat=True).distinct()
).order_by("name"),
required=False,
label="Région du corps",
)
number_of_exercises = forms.IntegerField(
validators=[MinValueValidator(1)], initial=5, label="Nombre"
)

View file

View file

@ -1,12 +1,20 @@
{% load static %}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css"
integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2"
crossorigin="anonymous">
<link rel="stylesheet" href="{% static 'exercises/style.css' %}">
<title>{% block title %}{% endblock %}</title> <title>{% block title %}{% endblock %}</title>
</head> </head>
<body> <body>
<div class="container">
{% block content %} {% block content %}
{% endblock %} {% endblock %}
</div>
</body> </body>
</html> </html>

View file

@ -1,16 +1,23 @@
{% extends "exercises/base.html" %} {% extends "exercises/base.html" %}
{% load crispy_forms_filters %}
{% block title %} {% block title %}
Random exercises Exercices
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<h1>Random exercises</h1> <h1>Exercices</h1>
<ul> <ul class="list-group">
{% for exercise in exercises %} {% for exercise in exercises %}
<li>{{ exercise.get_body_regions }}: {{ exercise.name }} ({{ exercise.rating }}/5)</li> <li class="list-group-item d-flex justify-content-between align-items-center">
{{ exercise.get_body_regions }}: {{ exercise.name }}
{% include "exercises/rating_badge.html" %}
</li>
{% endfor %} {% endfor %}
</ul> </ul>
<hr>
<form action="" method="get"> <form action="" method="get">
{{ form.as_p }} <h2>Filtres</h2>
<button type="submit">Submit</button> {{ form|crispy }}
<button class="btn btn-primary" type="submit">Filtrer</button>
</form> </form>
{% endblock %} {% endblock %}

View file

@ -0,0 +1 @@
<span class="badge badge-{% if exercise.is_mostly_cardio %}warning{% elif exercise.is_mostly_strengthening %}success{% else %}primary{% endif %} badge-pill">{{ exercise.rating }}/5</span>

View file

@ -19,5 +19,5 @@ from exercises.views import RandomExercisesView
app_name = "exercises" app_name = "exercises"
urlpatterns = [ urlpatterns = [
path("random", RandomExercisesView.as_view(), name="random"), path("", RandomExercisesView.as_view(), name="base"),
] ]

View file

@ -12,13 +12,22 @@ class RandomExercisesView(generic.ListView, FormMixin):
def get_queryset(self): def get_queryset(self):
form = self.get_form() form = self.get_form()
base_queryset = self.get_base_queryset(form)
return base_queryset.order_by("?")[:5]
def get_base_queryset(self, form):
if not form.is_valid(): if not form.is_valid():
return Exercise.objects.all() print(form.errors)
data = form.cleaned_data for field in form:
print(field.name, field.errors)
return Exercise.objects.order_by("?")[:5]
base_queryset = self.get_base_queryset(form)
filters = {}
body_regions = form.cleaned_data.get("body_regions")
if body_regions:
filters.update({"body_regions__in": body_regions})
number_of_exercises = form.cleaned_data.get("number_of_exercises")
return base_queryset.filter(**filters).order_by("?")[:number_of_exercises]
def get_base_queryset(self, valid_form):
data = valid_form.cleaned_data
rating = data.get("rating") rating = data.get("rating")
if rating == QueryForm.BALANCED_CHOICE: if rating == QueryForm.BALANCED_CHOICE:
return Exercise.objects.get_balanced() return Exercise.objects.get_balanced()
@ -26,6 +35,8 @@ class RandomExercisesView(generic.ListView, FormMixin):
return Exercise.objects.get_mostly_cardio() return Exercise.objects.get_mostly_cardio()
elif rating == QueryForm.STRENGTHENING_CHOICE: elif rating == QueryForm.STRENGTHENING_CHOICE:
return Exercise.objects.get_mostly_strengthening() return Exercise.objects.get_mostly_strengthening()
else:
return Exercise.objects.all()
def get_form_kwargs(self): def get_form_kwargs(self):
kwargs = super().get_form_kwargs() kwargs = super().get_form_kwargs()

View file

@ -25,7 +25,7 @@ SECRET_KEY = "+9(768zpp2r(kj3tqawboetb#8!8t@1x$o1k0&$4!yvdzr%#u6"
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True DEBUG = True
ALLOWED_HOSTS = [] ALLOWED_HOSTS = ["192.168.0.23", "localhost"]
# Application definition # Application definition
@ -37,6 +37,7 @@ INSTALLED_APPS = [
"django.contrib.sessions", "django.contrib.sessions",
"django.contrib.messages", "django.contrib.messages",
"django.contrib.staticfiles", "django.contrib.staticfiles",
"crispy_forms",
"custom_auth", "custom_auth",
"exercises", "exercises",
] ]
@ -122,3 +123,4 @@ USE_TZ = True
STATIC_URL = "/static/" STATIC_URL = "/static/"
AUTH_USER_MODEL = "custom_auth.User" AUTH_USER_MODEL = "custom_auth.User"
CRISPY_TEMPLATE_PACK = "bootstrap4"