Skip to content

Modified form validation #527

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 20 additions & 23 deletions django_unicorn/components/unicorn_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from ..utils import cache_full_tree, is_non_string_sequence, restore_from_cache
from .fields import UnicornField
from .unicorn_template_response import UnicornTemplateResponse
from django.core.exceptions import ValidationError


try:
Expand Down Expand Up @@ -525,31 +526,27 @@ def validate(self, model_names: List = None) -> Dict:

if form:
form_errors = form.errors.get_json_data(escape_html=True)

# This code is confusing, but handles this use-case:
# the component has two models, one that starts with an error and one
# that is valid. Validating the valid one should not show an error for
# the invalid one. Only after the invalid field is updated, should the
# error show up and persist, even after updating the valid form.
if self.errors:
keys_to_remove = []

for key, value in self.errors.items():
if key in form_errors:
self.errors[key] = value
existing_errors = self.errors
self.errors = dict()

if form.errors:
validate_all_fields = False
if hasattr(self, "validate_all"):
validate_all_fields= self.validate_all

for key in form_errors:
if key == "__all__":
self.errors['all'] = form_errors[key]

if validate_all_fields:
self.errors[key] = form_errors[key]
else:
keys_to_remove.append(key)

for key in keys_to_remove:
self.errors.pop(key)

if model_names is not None:
for key, value in form_errors.items():
if key in model_names:
self.errors[key] = value
else:
self.errors.update(form_errors)
if key in existing_errors:
self.errors[key] = form_errors[key]

if key in model_names:
self.errors[key] = form_errors[key]

return self.errors

@timed
Expand Down
2 changes: 1 addition & 1 deletion example/project/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SECRET_KEY = "p6b$i%36e_xg%*ok+55@uc(h9)#g+2fj#p%7g#-@y8s6+10q#7"
DEBUG = True
ALLOWED_HOSTS = ["localhost"]
ALLOWED_HOSTS = ["*"]


INSTALLED_APPS = [
Expand Down
25 changes: 25 additions & 0 deletions example/unicorn/components/validation_all.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from datetime import datetime

from django_unicorn.components import UnicornView

from ..forms import ValidationForm


class ValidationAllView(UnicornView):
form_class = ValidationForm
validate_all = True

text = "hello"
number = ""
date_time = datetime(2020, 9, 13, 17, 45, 14)
email = ""

def set_text_no_validation(self):
self.text = "no validation"

def set_text_with_validation(self):
self.text = "validation"
self.validate()

def set_number(self, number):
self.number = number
63 changes: 63 additions & 0 deletions example/unicorn/templates/unicorn/validation-all.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{% load unicorn %}

<div>
<style>
[unicorn\:error\:invalid] {
border: 1px solid red !important;
}
[unicorn\:error\:required] {
border: 1px solid red !important;
}

.error {
color: red;
}
</style>

<div>
{% unicorn_errors %}

<div>
<label>Plain text</label>
<input unicorn:model="text" type="text" id="textId">
{% verbatim %}{{ text }}{% endverbatim %}: {{ text }}
</div>

<div>
<label>Number with validation</label>
<input unicorn:model="number" type="text" id="numberId">
{% verbatim %}{{ number }}{% endverbatim %}: {{ number }}<br />
<button unicorn:click="set_number(1)">set_number(1)</button>
</div>

<div>
<label>Datetime attribute with validation</label>
<input unicorn:model="date_time" type="text" id="dateTimeId" unicorn:key="dateTime">
<span class="error">{{ unicorn.errors.date_time.0.message }}</span>

<p>
{% verbatim %}{{ date_time }}{% endverbatim %}: {{ date_time }}
</p>

<p>
{% verbatim %}{{ date_time|date:"s" }}{% endverbatim %}: {{ date_time|date:"s" }}
</p>
</div>

<div>
<label>Email</label>
<input unicorn:model="email" type="text" id="emailId">
{% verbatim %}{{ email }}{% endverbatim %}: {{ email }}
</div>

<div>
<a href="blob" unicorn:click.prevent="text='prevent?'">set_text_no_validation()</a>
<button unicorn:click="set_text_no_validation">set_text_no_validation()</button>
<button unicorn:click="set_text_with_validation">set_text_with_validation()</button>
<button unicorn:click="$validate">$validate</button>
<button unicorn:click="$reset">$reset</button>
<button unicorn:click="$reset()">$reset()</button>
<button unicorn:click="$refresh">$refresh</button>
</div>
</div>
</div>
1 change: 1 addition & 0 deletions example/www/templates/www/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ <h1>django-unicorn</h1>
<li><a href="{% url 'www:template' 'html-inputs' %}">Other inputs</a></li>
<li><a href="{% url 'www:template' 'objects' %}">Objects</a></li>
<li><a href="{% url 'www:template' 'validation' %}">Validation</a></li>
<li><a href="{% url 'www:template' 'validation_all' %}">Validation All</a></li>
<li><a href="{% url 'www:template' 'polling' %}">Polling</a></li>
<li><a href="{% url 'www:template' 'models' %}">Models</a></li>
<li><a href="{% url 'www:template' 'nested' %}">Nested components (table)</a></li>
Expand Down
10 changes: 10 additions & 0 deletions example/www/templates/www/validation_all.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{% extends "www/base.html" %}
{% load static unicorn %}

{% block content %}

<h2>Using Django forms for validation on all fields</h2>

{% unicorn 'validation-all' hello="hello" %}

{% endblock content %}