Improve form filtering and design
This commit is contained in:
parent
eb7da95a4f
commit
11e0202a7c
11 changed files with 83 additions and 19 deletions
14
poetry.lock
generated
14
poetry.lock
generated
|
@ -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"},
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"]
|
||||||
|
|
|
@ -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"
|
||||||
|
)
|
||||||
|
|
0
src/exercises/static/exercises/style.css
Normal file
0
src/exercises/static/exercises/style.css
Normal 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>
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
1
src/exercises/templates/exercises/rating_badge.html
Normal file
1
src/exercises/templates/exercises/rating_badge.html
Normal 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>
|
|
@ -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"),
|
||||||
]
|
]
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in a new issue