Form validation
This commit is contained in:
@ -1,10 +1,20 @@
|
||||
from typing import Any
|
||||
|
||||
from jinja2 import Environment
|
||||
|
||||
|
||||
def conditional_cls(conditions: dict[str, Any]) -> str:
|
||||
result = []
|
||||
for cls, condition in conditions.items():
|
||||
if condition:
|
||||
result.append(cls)
|
||||
return " ".join(result)
|
||||
|
||||
|
||||
def environment(**options):
|
||||
env = Environment(**options)
|
||||
|
||||
env.globals.update({
|
||||
# "url": reverse_url,
|
||||
"conditional_cls": conditional_cls,
|
||||
})
|
||||
return env
|
||||
|
||||
@ -2,7 +2,18 @@
|
||||
|
||||
|
||||
{% block content %}
|
||||
<p>
|
||||
This is some form validation content bellow.
|
||||
</p>
|
||||
<form
|
||||
hx-post="{{ url("form-validation") }}"
|
||||
hx-target="#validation-form-content"
|
||||
hx-swap="outerHTML"
|
||||
>
|
||||
<div class="card p-4">
|
||||
{% include "main/form_validation_content.html" %}
|
||||
<div class="d-flex">
|
||||
<button type="submit" class="btn btn-success ms-auto">
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
59
project/main/templates/main/form_validation_content.html
Normal file
59
project/main/templates/main/form_validation_content.html
Normal file
@ -0,0 +1,59 @@
|
||||
<div id="validation-form-content">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="mb-3">
|
||||
<label for="validation-form-number" class="form-label">Enter name, length 3..10</label>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control {{ conditional_cls({
|
||||
"is-invalid": validation.name_error,
|
||||
"is-valid": validation.validated and not validation.name_error,
|
||||
}) }}"
|
||||
name="name"
|
||||
id="validation-form-number"
|
||||
value="{{ validation.name | default_if_none("") }}"
|
||||
/>
|
||||
{% if validation.name_error %}
|
||||
<div class="invalid-feedback">{{ validation.name_error }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="mb-3">
|
||||
<label for="validation-form-number" class="form-label">Enter age, 1..100</label>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control {{ conditional_cls({
|
||||
"is-invalid": validation.age_error,
|
||||
"is-valid": validation.validated and not validation.age_error,
|
||||
}) }}"
|
||||
name="age"
|
||||
id="validation-form-number"
|
||||
value="{{ validation.age | default_if_none("") }}"
|
||||
/>
|
||||
{% if validation.age_error %}
|
||||
<div class="invalid-feedback">{{ validation.age_error }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input
|
||||
class="form-check-input {{ conditional_cls({
|
||||
"is-invalid": validation.consent_error,
|
||||
"is-valid": validation.validated and not validation.consent_error,
|
||||
}) }}"
|
||||
type="checkbox"
|
||||
name="consent"
|
||||
id="consent-checkbox"
|
||||
{% if validation.consent %}checked{% endif %}
|
||||
>
|
||||
<label class="form-check-label" for="consent-checkbox">
|
||||
I consent to use this data for what ever you want
|
||||
</label>
|
||||
{% if validation.consent_error %}
|
||||
<div class="invalid-feedback">{{ validation.consent_error }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
@ -1,7 +1,66 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Optional
|
||||
|
||||
from django.core.handlers.wsgi import WSGIRequest
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import render
|
||||
|
||||
from project.main.views.demo_view_base import DemoViewBase
|
||||
|
||||
|
||||
@dataclass
|
||||
class Validation:
|
||||
validated: bool = False
|
||||
|
||||
name: Optional[str] = None
|
||||
consent: Optional[bool] = None
|
||||
age: Optional[int] = None
|
||||
|
||||
name_error: Optional[str] = None
|
||||
age_error: Optional[str] = None
|
||||
consent_error: Optional[str] = None
|
||||
|
||||
|
||||
class FormValidationView(DemoViewBase):
|
||||
template_name = "main/form_validation.html"
|
||||
active_section = "form-validation"
|
||||
title = "Form Validation"
|
||||
|
||||
def get_context_data(self, **kwargs) -> dict[str, Any]:
|
||||
context = super().get_context_data(**kwargs)
|
||||
context.update(
|
||||
{
|
||||
"validation": Validation(),
|
||||
}
|
||||
)
|
||||
return context
|
||||
|
||||
def post(self, request: WSGIRequest, *args, **kwargs) -> HttpResponse:
|
||||
validation = Validation(
|
||||
validated=True,
|
||||
name=request.POST.get("name", ""),
|
||||
age=request.POST.get("age", ""),
|
||||
consent=request.POST.get("consent") == "on",
|
||||
)
|
||||
|
||||
if len(validation.name) < 3 or len(validation.name) > 10:
|
||||
validation.name_error = "Name must be between 3 and 10 chars long"
|
||||
|
||||
try:
|
||||
age = int(validation.age)
|
||||
except ValueError:
|
||||
validation.age_error = "Invalid integer"
|
||||
else:
|
||||
if age < 1 or age > 100:
|
||||
validation.age_error = "Age should be between 1 and 100"
|
||||
|
||||
if not validation.consent:
|
||||
validation.consent_error = "You should consent"
|
||||
|
||||
return render(
|
||||
context={
|
||||
"validation": validation,
|
||||
},
|
||||
template_name="main/form_validation_content.html",
|
||||
request=request,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user