django-forms-frontend-validation 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- django_forms_frontend_validation-1.0.0.dist-info/LICENSE +21 -0
- django_forms_frontend_validation-1.0.0.dist-info/METADATA +86 -0
- django_forms_frontend_validation-1.0.0.dist-info/RECORD +28 -0
- django_forms_frontend_validation-1.0.0.dist-info/WHEEL +5 -0
- django_forms_frontend_validation-1.0.0.dist-info/top_level.txt +1 -0
- formvalidator/__init__.py +0 -0
- formvalidator/admin.py +3 -0
- formvalidator/apps.py +6 -0
- formvalidator/form_utils/__init__.py +1 -0
- formvalidator/form_utils/form_utils.py +21 -0
- formvalidator/forms.py +9 -0
- formvalidator/migrations/__init__.py +0 -0
- formvalidator/models.py +3 -0
- formvalidator/settings.py +14 -0
- formvalidator/static/dist/forms.bundle.js +216 -0
- formvalidator/static/webpack/package-lock.json +2869 -0
- formvalidator/static/webpack/package.json +19 -0
- formvalidator/static/webpack/src/css/style.css +42 -0
- formvalidator/static/webpack/src/js/formFunctions.js +263 -0
- formvalidator/static/webpack/src/js/index.js +2 -0
- formvalidator/static/webpack/webpack.config.js +23 -0
- formvalidator/templates/base.html +26 -0
- formvalidator/templates/formvalidator/sample.html +51 -0
- formvalidator/templates/formvalidator/sample2.html +51 -0
- formvalidator/templates/includes/header.html +18 -0
- formvalidator/tests.py +21 -0
- formvalidator/urls.py +12 -0
- formvalidator/views.py +54 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
{
|
2
|
+
"name": "webpack",
|
3
|
+
"version": "1.0.0",
|
4
|
+
"description": "",
|
5
|
+
"private": true,
|
6
|
+
"scripts": {
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
8
|
+
"build": "webpack"
|
9
|
+
},
|
10
|
+
"keywords": [],
|
11
|
+
"author": "",
|
12
|
+
"license": "ISC",
|
13
|
+
"devDependencies": {
|
14
|
+
"css-loader": "^7.1.2",
|
15
|
+
"style-loader": "^4.0.0",
|
16
|
+
"webpack": "^5.97.1",
|
17
|
+
"webpack-cli": "^5.1.4"
|
18
|
+
}
|
19
|
+
}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
/****** Forms ******/
|
2
|
+
input, select {
|
3
|
+
font-size: 18px!important;
|
4
|
+
}
|
5
|
+
|
6
|
+
.errorlist li, .error-msg {
|
7
|
+
color: red;
|
8
|
+
}
|
9
|
+
|
10
|
+
.error {
|
11
|
+
color: red;
|
12
|
+
font-style: italic;
|
13
|
+
}
|
14
|
+
|
15
|
+
.error-input {
|
16
|
+
background: #edbabf;
|
17
|
+
border-color: #dc3545;
|
18
|
+
}
|
19
|
+
|
20
|
+
.error-msg {
|
21
|
+
color: #dc3545;
|
22
|
+
margin-bottom: 0;
|
23
|
+
}
|
24
|
+
|
25
|
+
.success {
|
26
|
+
color: blue;
|
27
|
+
}
|
28
|
+
|
29
|
+
.readonly {
|
30
|
+
background-color: #e9ecef;
|
31
|
+
opacity: 1;
|
32
|
+
cursor: not-allowed;
|
33
|
+
}
|
34
|
+
|
35
|
+
.required-field {
|
36
|
+
font-weight: 800;
|
37
|
+
}
|
38
|
+
|
39
|
+
.required-field::after {
|
40
|
+
content: " *";
|
41
|
+
color: red;
|
42
|
+
}
|
@@ -0,0 +1,263 @@
|
|
1
|
+
// ########## Getting the csrf token for the fetch calls ##########
|
2
|
+
function getCookie(name) {
|
3
|
+
let cookieValue = null;
|
4
|
+
if (document.cookie && document.cookie !== '') {
|
5
|
+
const cookies = document.cookie.split(';');
|
6
|
+
for (let i = 0; i < cookies.length; i++) {
|
7
|
+
const cookie = cookies[i].trim();
|
8
|
+
// Does this cookie string begin with the name we want?
|
9
|
+
if (cookie.substring(0, name.length + 1) === (name + '=')) {
|
10
|
+
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
11
|
+
break;
|
12
|
+
}
|
13
|
+
}
|
14
|
+
}
|
15
|
+
return cookieValue;
|
16
|
+
}
|
17
|
+
export const csrftoken = getCookie('csrftoken');
|
18
|
+
|
19
|
+
// ##### Fetch Calls #####
|
20
|
+
// performs fetch call to view
|
21
|
+
export const fetchHandleForm = async (form) => {
|
22
|
+
let formData = new FormData(form);
|
23
|
+
return await fetch(form.action, {
|
24
|
+
method: "POST",
|
25
|
+
credentials: "same-origin",
|
26
|
+
headers: {
|
27
|
+
// "Accept": "m",
|
28
|
+
// "X-Requested-With": "XMLHttpRequest",
|
29
|
+
"X-CSRFToken": csrftoken,
|
30
|
+
},
|
31
|
+
body: formData,
|
32
|
+
}).then(async (response) => {
|
33
|
+
return response.json();
|
34
|
+
});
|
35
|
+
}
|
36
|
+
// ***** Adding asterisks to labels of required inputs *****
|
37
|
+
function addAsterisks(form) {
|
38
|
+
// gathering all inputs
|
39
|
+
let formGroups = document.querySelectorAll(`#${form.id} .form-group`);
|
40
|
+
let inputs = getRequiredFields(formGroups);
|
41
|
+
|
42
|
+
// adding the required-field class which will add the asterisk
|
43
|
+
for (let i = 0; i < inputs.length; i++) {
|
44
|
+
let label = document.querySelector(`label[for=${inputs[i].name}]`);
|
45
|
+
if (inputs[i].required) {
|
46
|
+
label.classList.add("required-field");
|
47
|
+
}
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
// In-line validation on required fields
|
52
|
+
function validateInputs(form) {
|
53
|
+
// gathering all inputs
|
54
|
+
let formGroups = document.querySelectorAll(`#${form.id} .form-group`);
|
55
|
+
let inputs = getRequiredFields(formGroups);
|
56
|
+
|
57
|
+
// adding listeners to each input for validation
|
58
|
+
for (let i = 0; i < inputs.length; i++) {
|
59
|
+
inputs[i].addEventListener("focusout", () => {
|
60
|
+
if (inputs[i].value === "" || inputs[i].value === null) {
|
61
|
+
addError(inputs[i]);
|
62
|
+
} else {
|
63
|
+
removeError(inputs[i]);
|
64
|
+
}
|
65
|
+
});
|
66
|
+
}
|
67
|
+
}
|
68
|
+
// validateInputs();
|
69
|
+
|
70
|
+
// check form function
|
71
|
+
export function checkForm(form) {
|
72
|
+
let errors = false;
|
73
|
+
|
74
|
+
// gathering all inputs
|
75
|
+
let formGroups = document.querySelectorAll(`#${form.id} .form-group`);
|
76
|
+
let inputs = getRequiredFields(formGroups);
|
77
|
+
|
78
|
+
// iterating through all required fields to check for invalidation
|
79
|
+
for (let i = 0; i < inputs.length; i++) {
|
80
|
+
let input = inputs[i];
|
81
|
+
if (input.value === "" || !input.value) {
|
82
|
+
addError(input);
|
83
|
+
errors = true;
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
return errors
|
88
|
+
}
|
89
|
+
|
90
|
+
// submit button validation check
|
91
|
+
function submitValidation(form) {
|
92
|
+
form.form.addEventListener("submit", (e) => {
|
93
|
+
// preventing default submission behavior
|
94
|
+
e.preventDefault();
|
95
|
+
|
96
|
+
// gathering all inputs
|
97
|
+
let f = e.target;
|
98
|
+
// let formGroups = document.querySelectorAll(`#${form.id} .form-group`);
|
99
|
+
// let inputs = getRequiredFields(formGroups);
|
100
|
+
// // let form = document.getElementById("form") !== null ? document.getElementById("form") : document.getElementById("userForm");
|
101
|
+
let errors = checkForm(f);
|
102
|
+
|
103
|
+
// submitting the form if there aren't any errors
|
104
|
+
if (!errors) {
|
105
|
+
form.form.submit();
|
106
|
+
} else {
|
107
|
+
let invalidInputs = document.getElementsByClassName("validation-error");
|
108
|
+
// scroll to the first invalid input
|
109
|
+
invalidInputs[0].parentElement.scrollIntoView();
|
110
|
+
}
|
111
|
+
});
|
112
|
+
}
|
113
|
+
|
114
|
+
// adds an error to an input
|
115
|
+
function addError(input) {
|
116
|
+
let inputParent = input.parentElement;
|
117
|
+
if (!inputParent.className.includes("form-group")){
|
118
|
+
inputParent = input.parentElement.parentElement;
|
119
|
+
}
|
120
|
+
let errorAdded = inputParent.dataset.errorAdded;
|
121
|
+
inputParent.classList.add("validation-error");
|
122
|
+
input.classList.add("error-input")
|
123
|
+
if (errorAdded === "false" || !errorAdded) {
|
124
|
+
// creating the error message p
|
125
|
+
let eP = document.createElement("p");
|
126
|
+
eP.setAttribute("class", "error-msg");
|
127
|
+
eP.innerText = "This input is required";
|
128
|
+
inputParent.appendChild(eP);
|
129
|
+
inputParent.dataset.errorAdded = "true";
|
130
|
+
}
|
131
|
+
}
|
132
|
+
|
133
|
+
// removes the error from an input
|
134
|
+
function removeError(input) {
|
135
|
+
let inputParent = input.parentElement;
|
136
|
+
if (!inputParent.className.includes("form-group")){
|
137
|
+
inputParent = input.parentElement.parentElement;
|
138
|
+
}
|
139
|
+
let errorAdded = inputParent.dataset.errorAdded;
|
140
|
+
inputParent.classList.remove("validation-error");
|
141
|
+
input.classList.remove("error-input");
|
142
|
+
// removing the error message p
|
143
|
+
if (errorAdded === "true") {
|
144
|
+
inputParent.removeChild(inputParent.lastElementChild);
|
145
|
+
inputParent.dataset.errorAdded = "false";
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
149
|
+
// function to get all required input
|
150
|
+
function getRequiredFields(formGroups) {
|
151
|
+
let nameList = ["SELECT", "INPUT", "TEXTAREA"];
|
152
|
+
let inputs = [];
|
153
|
+
// let formGroups = document.getElementsByClassName("form-group");
|
154
|
+
for (let i = 0; i < formGroups.length; i++) {
|
155
|
+
let children = formGroups[i].children;
|
156
|
+
for (let j = 0; j < children.length; j++) {
|
157
|
+
if (children[j].tagName === "DIV"){
|
158
|
+
let grandChildren = children[j].children;
|
159
|
+
for (let a = 0; a < grandChildren.length; a++) {
|
160
|
+
if (nameList.includes(grandChildren[a].tagName)) {
|
161
|
+
if (grandChildren[a].required) {
|
162
|
+
inputs.push(grandChildren[a]);
|
163
|
+
}
|
164
|
+
}
|
165
|
+
}
|
166
|
+
}
|
167
|
+
else{
|
168
|
+
if (nameList.includes(children[j].tagName)) {
|
169
|
+
if (children[j].required) {
|
170
|
+
inputs.push(children[j]);
|
171
|
+
}
|
172
|
+
}
|
173
|
+
}
|
174
|
+
}
|
175
|
+
}
|
176
|
+
return inputs
|
177
|
+
}
|
178
|
+
|
179
|
+
// checks if the form will be ignored form validation.
|
180
|
+
function getIgnored(form, ignoredClasses) {
|
181
|
+
let isIgnored = false;
|
182
|
+
let classes = form.classList;
|
183
|
+
if (ignoredClasses.length > 0) {
|
184
|
+
classes.forEach((_class) => {
|
185
|
+
if (ignoredClasses.includes(_class)) {
|
186
|
+
isIgnored = true;
|
187
|
+
return isIgnored;
|
188
|
+
}
|
189
|
+
});
|
190
|
+
}
|
191
|
+
return isIgnored
|
192
|
+
}
|
193
|
+
|
194
|
+
// Checks if the form will be validated.
|
195
|
+
function isValidate(form, ignoredClasses) {
|
196
|
+
let enableValidate = true;
|
197
|
+
let classes = form.classList;
|
198
|
+
if (ignoredClasses.length > 0) {
|
199
|
+
classes.forEach((_class) => {
|
200
|
+
if (ignoredClasses.includes(_class)) {
|
201
|
+
enableValidate = false;
|
202
|
+
return enableValidate;
|
203
|
+
}
|
204
|
+
});
|
205
|
+
}
|
206
|
+
return enableValidate
|
207
|
+
}
|
208
|
+
|
209
|
+
// Confirms if a form will only validate the form on submit, only.
|
210
|
+
function getValidateOnlyValidateOnSubmit(form, validateOnlyOnSubmit, enableValidation) {
|
211
|
+
let validateOnSubmit = false;
|
212
|
+
let trueFlags = ["all", "__all__", "*", "true"];
|
213
|
+
if (enableValidation) {
|
214
|
+
let classes = form.classList;
|
215
|
+
if (trueFlags.includes(validateOnlyOnSubmit[0])) {
|
216
|
+
validateOnSubmit = true;
|
217
|
+
return true;
|
218
|
+
}
|
219
|
+
else {
|
220
|
+
classes.forEach((_class) => {
|
221
|
+
if (validateOnlyOnSubmit.includes(_class)) {
|
222
|
+
validateOnSubmit = true;
|
223
|
+
return validateOnlyOnSubmit;
|
224
|
+
}
|
225
|
+
});
|
226
|
+
}
|
227
|
+
}
|
228
|
+
return validateOnSubmit;
|
229
|
+
}
|
230
|
+
|
231
|
+
// adds listener logic to the form
|
232
|
+
export function _Initialize(form={}){
|
233
|
+
if (!form.ignored || form.enableValidation) {
|
234
|
+
// add all listeners to each form
|
235
|
+
addAsterisks(form);
|
236
|
+
if (!form.validateOnlyOnSubmit) {
|
237
|
+
validateInputs(form);
|
238
|
+
}
|
239
|
+
if (!form.ignored) {
|
240
|
+
submitValidation(form);
|
241
|
+
}
|
242
|
+
}
|
243
|
+
}
|
244
|
+
|
245
|
+
// function to initialize forms into a json object
|
246
|
+
export function _InitializeForms(formNodes, ignoredFormClasses=[], ignoredValidationClasses=[], validateOnlyOnSubmit){
|
247
|
+
for (let i = 0; i < formNodes.length; i++) {
|
248
|
+
let currentForm = formNodes[i];
|
249
|
+
let ignored = getIgnored(currentForm, ignoredFormClasses);
|
250
|
+
let enableValidation = isValidate(currentForm, ignoredValidationClasses);
|
251
|
+
let validateOnSubmit = getValidateOnlyValidateOnSubmit(currentForm, validateOnlyOnSubmit, enableValidation);
|
252
|
+
let _form = {
|
253
|
+
id: currentForm.id,
|
254
|
+
form: currentForm,
|
255
|
+
ignored: ignored,
|
256
|
+
enableValidation: enableValidation,
|
257
|
+
validateOnlyOnSubmit: validateOnSubmit,
|
258
|
+
}
|
259
|
+
|
260
|
+
// adding form functionality
|
261
|
+
_Initialize(_form);
|
262
|
+
}
|
263
|
+
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
const path = require("path");
|
2
|
+
|
3
|
+
module.exports = {
|
4
|
+
mode: "development",
|
5
|
+
entry: {
|
6
|
+
forms: ["./src/css/style.css", "./src/js/formFunctions.js",],
|
7
|
+
},
|
8
|
+
output: {
|
9
|
+
filename: "[name].bundle.js",
|
10
|
+
path: path.resolve(__dirname, "../dist"),
|
11
|
+
library: "fv",
|
12
|
+
libraryTarget: "umd",
|
13
|
+
globalObject: "this",
|
14
|
+
},
|
15
|
+
module: {
|
16
|
+
rules: [
|
17
|
+
{
|
18
|
+
test: /\.css/i,
|
19
|
+
use: ["style-loader", "css-loader"],
|
20
|
+
},
|
21
|
+
],
|
22
|
+
},
|
23
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
{% load static %}
|
3
|
+
<html lang="en">
|
4
|
+
<head>
|
5
|
+
<meta charset="UTF-8">
|
6
|
+
<title>{% block title %}{{ title }}{% endblock %}</title>
|
7
|
+
|
8
|
+
<!-- Bootstrap CDNs -->
|
9
|
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
10
|
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
|
11
|
+
|
12
|
+
{% block extra_head %}{% endblock %}
|
13
|
+
</head>
|
14
|
+
<body>
|
15
|
+
<!-- header -->
|
16
|
+
{% include 'includes/header.html' %}
|
17
|
+
|
18
|
+
<!-- main content -->
|
19
|
+
<div class="container my-3">
|
20
|
+
{% block content %}{% endblock %}
|
21
|
+
</div>
|
22
|
+
|
23
|
+
{% block extra_js %}{% endblock %}
|
24
|
+
|
25
|
+
</body>
|
26
|
+
</html>
|
@@ -0,0 +1,51 @@
|
|
1
|
+
{% extends 'base.html' %}
|
2
|
+
{% load static %}
|
3
|
+
|
4
|
+
{% block content %}
|
5
|
+
<h3>Sample Form</h3>
|
6
|
+
<hr>
|
7
|
+
<p>
|
8
|
+
Sample form where forms.bundle.js is being added via an HTML <code><script></code> tag.
|
9
|
+
Then, the object variable, <code>fv</code>, is being exported and used within another <code><script></code> tag.
|
10
|
+
</p>
|
11
|
+
<div id="formDiv">
|
12
|
+
<form id="sampleForm" action="{% url 'sample-form' %}" method="post" novalidate>
|
13
|
+
{% csrf_token %}
|
14
|
+
{% if form.non_field_errors %}
|
15
|
+
{% for error in form.non_field_errors %}
|
16
|
+
{{ error }}
|
17
|
+
{% endfor %}
|
18
|
+
{% endif %}
|
19
|
+
|
20
|
+
{% for field in form %}
|
21
|
+
<div class="form-group mb-3">
|
22
|
+
<label class="form-label" for="{{ field.name }}">{{ field.label }}</label>
|
23
|
+
{{ field }}
|
24
|
+
{% if field.errors %}
|
25
|
+
{{ field.errors }}
|
26
|
+
{% endif %}
|
27
|
+
</div>
|
28
|
+
{% endfor %}
|
29
|
+
|
30
|
+
<button class="btn btn-primary btn-lg" type="submit">Submit</button>
|
31
|
+
</form>
|
32
|
+
</div>
|
33
|
+
{% endblock %}
|
34
|
+
|
35
|
+
{% block extra_js %}
|
36
|
+
<script src="{% static 'dist/forms.bundle.js' %}"></script>
|
37
|
+
<script>
|
38
|
+
// fv is exported from forms.bundle.js
|
39
|
+
window.addEventListener("load", () => {
|
40
|
+
let ignoredClasses = []; // add more classes that represent forms you want this script to ignore.
|
41
|
+
let ignoreValidation = []; // add any form classes that you want to ignore validation
|
42
|
+
let validateOnlyOnSubmit = []; // for hitting all forms make index 0 either __all__, all, * or leave blank for false or use false
|
43
|
+
let forms = document.getElementsByTagName("form");
|
44
|
+
// if (form || userForm) {
|
45
|
+
if (forms.length > 0) {
|
46
|
+
// calling specific functions on all forms
|
47
|
+
fv._InitializeForms(forms, ignoredClasses, ignoreValidation, validateOnlyOnSubmit);
|
48
|
+
}
|
49
|
+
});
|
50
|
+
</script>
|
51
|
+
{% endblock %}
|
@@ -0,0 +1,51 @@
|
|
1
|
+
{% extends 'base.html' %}
|
2
|
+
{% load static %}
|
3
|
+
|
4
|
+
{% block extra_head %}
|
5
|
+
<script src="https://assets.tucsonaz.gov/share/web/js/forms.bundle.js" crossorigin="anonymous"></script>
|
6
|
+
{% endblock %}
|
7
|
+
|
8
|
+
{% block content %}
|
9
|
+
<h3>Sample Form 2</h3>
|
10
|
+
<hr>
|
11
|
+
<p>This form only validates when the submit button is clicked.</p>
|
12
|
+
<div id="formDiv">
|
13
|
+
<form id="sampleForm" class="sample-form2" action="{% url 'sample-form2' %}" method="post" novalidate>
|
14
|
+
{% csrf_token %}
|
15
|
+
{% if form.non_field_errors %}
|
16
|
+
{% for error in form.non_field_errors %}
|
17
|
+
{{ error }}
|
18
|
+
{% endfor %}
|
19
|
+
{% endif %}
|
20
|
+
|
21
|
+
{% for field in form %}
|
22
|
+
<div class="form-group mb-3">
|
23
|
+
<label class="form-label" for="{{ field.name }}">{{ field.label }}</label>
|
24
|
+
{{ field }}
|
25
|
+
{% if field.errors %}
|
26
|
+
{{ field.errors }}
|
27
|
+
{% endif %}
|
28
|
+
</div>
|
29
|
+
{% endfor %}
|
30
|
+
|
31
|
+
<button class="btn btn-primary btn-lg" type="submit">Submit</button>
|
32
|
+
</form>
|
33
|
+
</div>
|
34
|
+
{% endblock %}
|
35
|
+
|
36
|
+
{% block extra_js %}
|
37
|
+
<script>
|
38
|
+
// fv (formsvalidator) is exported from forms.bundle.js
|
39
|
+
window.addEventListener("load", () => {
|
40
|
+
let ignoredClasses = {{ form_validator.ignored_classes|safe }}; // add more classes that represent forms you want this script to ignore.
|
41
|
+
let ignoreValidation = {{ form_validator.ignore_validation|safe }}; // add any form classes that you want to ignore validation
|
42
|
+
let validateOnlyOnSubmit = {{ form_validator.validate_only_on_submit|safe }}; // for hitting all forms make index 0 either __all__, all, * or leave blank for false or use false
|
43
|
+
let forms = document.getElementsByTagName("form");
|
44
|
+
// if (form || userForm) {
|
45
|
+
if (forms.length > 0) {
|
46
|
+
// calling specific functions on all forms
|
47
|
+
fv._InitializeForms(forms, ignoredClasses, ignoreValidation, validateOnlyOnSubmit);
|
48
|
+
}
|
49
|
+
});
|
50
|
+
</script>
|
51
|
+
{% endblock %}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<nav class="navbar navbar-expand-lg bg-body-tertiary">
|
2
|
+
<div class="container">
|
3
|
+
<a class="navbar-brand" href="{% url 'sample-form' %}">Form Validator</a>
|
4
|
+
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
5
|
+
<span class="navbar-toggler-icon"></span>
|
6
|
+
</button>
|
7
|
+
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
8
|
+
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
9
|
+
<li class="nav-item">
|
10
|
+
<a class="nav-link" href="{% url 'sample-form' %}">Sample Form</a>
|
11
|
+
</li>
|
12
|
+
<li class="nav-item">
|
13
|
+
<a class="nav-link" href="{% url 'sample-form2' %}">Sample Form 2</a>
|
14
|
+
</li>
|
15
|
+
</ul>
|
16
|
+
</div>
|
17
|
+
</div>
|
18
|
+
</nav>
|
formvalidator/tests.py
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
from django.test import TestCase
|
2
|
+
|
3
|
+
from .form_utils.form_utils import FormsValidator
|
4
|
+
|
5
|
+
|
6
|
+
# Create your tests here.
|
7
|
+
class GetContextTest(TestCase):
|
8
|
+
def setUp(self):
|
9
|
+
self.form_validator = FormsValidator()
|
10
|
+
self.context = self.form_validator.get_context()
|
11
|
+
|
12
|
+
def test_get_context(self):
|
13
|
+
"""Ensuring that the context variable is set correctly"""
|
14
|
+
self.assertEqual(type(self.context), dict, msg="The context variable is not a dictionary datatype")
|
15
|
+
|
16
|
+
def test_context_variables(self):
|
17
|
+
"""Tests that the context variables are set correctly"""
|
18
|
+
context_keys = self.context.keys()
|
19
|
+
correct_keys = ["ignored_classes", "ignore_validation", "validate_only_on_submit"]
|
20
|
+
for key in context_keys:
|
21
|
+
self.assertTrue(key in correct_keys, msg=f"The context variable {key} is missing")
|
formvalidator/urls.py
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
from django.urls import path
|
2
|
+
from django.conf import settings
|
3
|
+
|
4
|
+
from . import views
|
5
|
+
|
6
|
+
urlpatterns = []
|
7
|
+
|
8
|
+
if settings.DEBUG:
|
9
|
+
urlpatterns += [
|
10
|
+
path('demo/sample-form/', views.sample, name='sample-form'),
|
11
|
+
path('demo/sample-form2/', views.sample2, name='sample-form2'),
|
12
|
+
]
|
formvalidator/views.py
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
from django.shortcuts import render
|
2
|
+
|
3
|
+
from .forms import SampleForm
|
4
|
+
|
5
|
+
from .form_utils import FormsValidator
|
6
|
+
|
7
|
+
|
8
|
+
# Create your views here.
|
9
|
+
def sample(request):
|
10
|
+
"""
|
11
|
+
Sample form view for demonstration purposes only.
|
12
|
+
Will provide an example of using the forms.bundle.js file as an imported module.
|
13
|
+
Will also not use the settings.py variables.
|
14
|
+
"""
|
15
|
+
title = "Form Validator Sample"
|
16
|
+
template = "formvalidator/sample.html"
|
17
|
+
|
18
|
+
if request.method == 'POST':
|
19
|
+
form = SampleForm(request.POST)
|
20
|
+
if form.is_valid():
|
21
|
+
pass
|
22
|
+
else:
|
23
|
+
form = SampleForm()
|
24
|
+
|
25
|
+
context = {
|
26
|
+
"form": form,
|
27
|
+
"title": title,
|
28
|
+
}
|
29
|
+
return render(request, template, context)
|
30
|
+
|
31
|
+
|
32
|
+
def sample2(request):
|
33
|
+
"""
|
34
|
+
Another sample form view for demonstration purposes only.
|
35
|
+
This demo will show how to use the forms.bundle.js file as a CDN, and using the settings variables
|
36
|
+
for the configuration.
|
37
|
+
"""
|
38
|
+
title = "Form Validator Sample 2"
|
39
|
+
template = "formvalidator/sample2.html"
|
40
|
+
form_validator = FormsValidator()
|
41
|
+
|
42
|
+
if request.method == 'POST':
|
43
|
+
form = SampleForm(request.POST)
|
44
|
+
if form.is_valid():
|
45
|
+
pass
|
46
|
+
else:
|
47
|
+
form = SampleForm()
|
48
|
+
|
49
|
+
context = {
|
50
|
+
"form": form,
|
51
|
+
"title": title,
|
52
|
+
"form_validator": form_validator.get_context(),
|
53
|
+
}
|
54
|
+
return render(request, template, context)
|