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)"]
|
||||
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]]
|
||||
name = "filelock"
|
||||
version = "3.0.12"
|
||||
|
@ -294,7 +302,7 @@ testing = ["coverage (>=4)", "coverage-enable-subprocess (>=1)", "flaky (>=3)",
|
|||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.9"
|
||||
content-hash = "c30849d31e4af28a2048d39ee36777d08501143c80e1fd08fa2f1c04108a92ce"
|
||||
content-hash = "cdf8eea1e8834cd9a055fdbb2d4d4edf58111c8666e92542f4e6f2e0359bc499"
|
||||
|
||||
[metadata.files]
|
||||
appdirs = [
|
||||
|
@ -365,6 +373,10 @@ django = [
|
|||
{file = "Django-3.1.3-py3-none-any.whl", hash = "sha256:14a4b7cd77297fba516fc0d92444cc2e2e388aa9de32d7a68d4a83d58f5a4927"},
|
||||
{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 = [
|
||||
{file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"},
|
||||
{file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"},
|
||||
|
|
|
@ -7,6 +7,7 @@ authors = ["Gabriel Augendre <gabriel@augendre.info>"]
|
|||
[tool.poetry.dependencies]
|
||||
python = "^3.9"
|
||||
Django = "^3.1.3"
|
||||
django-crispy-forms = "^1.10.0"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
pytest = "^6.1"
|
||||
|
|
|
@ -12,3 +12,5 @@ class BodyRegionAdmin(admin.ModelAdmin):
|
|||
@register(Exercise)
|
||||
class ExerciseAdmin(admin.ModelAdmin):
|
||||
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.core.validators import MinValueValidator
|
||||
|
||||
from exercises.models import BodyRegion, Exercise
|
||||
|
||||
|
||||
class QueryForm(forms.Form):
|
||||
CARDIO_CHOICE = "cardio"
|
||||
STRENGTHENING_CHOICE = "strengthening"
|
||||
BALANCED_CHOICE = "balanced"
|
||||
EVERYTHING_CHOICE = "everything"
|
||||
RATING_CHOICES = [
|
||||
(CARDIO_CHOICE, "Cardio"),
|
||||
(STRENGTHENING_CHOICE, "Strengthening"),
|
||||
(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>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<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>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,16 +1,23 @@
|
|||
{% extends "exercises/base.html" %}
|
||||
{% load crispy_forms_filters %}
|
||||
|
||||
{% block title %}
|
||||
Random exercises
|
||||
Exercices
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<h1>Random exercises</h1>
|
||||
<ul>
|
||||
<h1>Exercices</h1>
|
||||
<ul class="list-group">
|
||||
{% 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 %}
|
||||
</ul>
|
||||
<hr>
|
||||
<form action="" method="get">
|
||||
{{ form.as_p }}
|
||||
<button type="submit">Submit</button>
|
||||
<h2>Filtres</h2>
|
||||
{{ form|crispy }}
|
||||
<button class="btn btn-primary" type="submit">Filtrer</button>
|
||||
</form>
|
||||
{% 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"
|
||||
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):
|
||||
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():
|
||||
return Exercise.objects.all()
|
||||
data = form.cleaned_data
|
||||
print(form.errors)
|
||||
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")
|
||||
if rating == QueryForm.BALANCED_CHOICE:
|
||||
return Exercise.objects.get_balanced()
|
||||
|
@ -26,6 +35,8 @@ class RandomExercisesView(generic.ListView, FormMixin):
|
|||
return Exercise.objects.get_mostly_cardio()
|
||||
elif rating == QueryForm.STRENGTHENING_CHOICE:
|
||||
return Exercise.objects.get_mostly_strengthening()
|
||||
else:
|
||||
return Exercise.objects.all()
|
||||
|
||||
def get_form_kwargs(self):
|
||||
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!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
ALLOWED_HOSTS = ["192.168.0.23", "localhost"]
|
||||
|
||||
|
||||
# Application definition
|
||||
|
@ -37,6 +37,7 @@ INSTALLED_APPS = [
|
|||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
"crispy_forms",
|
||||
"custom_auth",
|
||||
"exercises",
|
||||
]
|
||||
|
@ -122,3 +123,4 @@ USE_TZ = True
|
|||
STATIC_URL = "/static/"
|
||||
|
||||
AUTH_USER_MODEL = "custom_auth.User"
|
||||
CRISPY_TEMPLATE_PACK = "bootstrap4"
|
||||
|
|
Loading…
Reference in a new issue