├── .editorconfig
├── .github
├── FUNDING.yml
└── ISSUE_TEMPLATE.md
├── .gitignore
├── .travis.yml
├── AUTHORS.md
├── CONTRIBUTING.md
├── HISTORY.md
├── LICENSE
├── MANIFEST.in
├── Makefile
├── README.md
├── docs
├── browser_support.md
├── example_project.md
├── forms.md
├── how_it_works.md
├── index.md
├── limitations.md
├── management_commands.md
├── media
│ ├── django-front-end-validators.gif
│ └── validate-no-gmail-siblings.png
└── template_tags.md
├── example
├── db.sqlite3
├── front_end_validator_example
│ ├── __init__.py
│ ├── forms.py
│ ├── models.py
│ ├── settings.py
│ ├── templates
│ │ ├── base.html
│ │ └── front_end_validator_example
│ │ │ └── samplemodel_form.html
│ ├── urls.py
│ ├── validators.py
│ ├── views.py
│ └── wsgi.py
├── manage.py
└── requirements.txt
├── front_end_validators
├── __init__.py
├── admin.py
├── forms.py
├── management
│ ├── __init__.py
│ └── commands
│ │ ├── __init__.py
│ │ └── transpile_validators.py
├── models.py
├── static
│ ├── css
│ │ └── front_end_validators.css
│ ├── img
│ │ └── .gitignore
│ └── js
│ │ └── front_end_validators.js
├── templates
│ └── front_end_validators
│ │ ├── base.html
│ │ ├── script_tag_transcrypt_36.html
│ │ └── script_tag_transcrypt_37.html
├── templatetags
│ └── front_end_validators.py
├── urls.py
└── utils.py
├── manage.py
├── mkdocs.yml
├── requirements.txt
├── requirements_dev.txt
├── requirements_test.txt
├── runtests.py
├── setup.cfg
├── setup.py
├── tests
├── __init__.py
├── settings.py
└── urls.py
└── tox.ini
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | charset = utf-8
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.{py,rst,ini}]
12 | indent_style = space
13 | indent_size = 4
14 |
15 | [*.{html,css,scss,json,yml}]
16 | indent_style = space
17 | indent_size = 2
18 |
19 | [*.md]
20 | trim_trailing_whitespace = false
21 | indent_size = 2
22 |
23 | [Makefile]
24 | indent_style = tab
25 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [johnfraney]
4 | ko_fi: johnfraney
5 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | * Package version:
2 | * Django version:
3 | * Python version:
4 | * Operating System:
5 |
6 | ### Description
7 |
8 | Describe what you were trying to get done.
9 | Tell us what happened, what went wrong, and what you expected to happen.
10 |
11 | ### What I Did
12 |
13 | ```
14 | Paste the command(s) you ran and the output.
15 | If there was a crash, please include the traceback here.
16 | ```
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.py[cod]
2 | __pycache__
3 |
4 | # C extensions
5 | *.so
6 |
7 | # Packages
8 | *.egg
9 | *.egg-info
10 | dist
11 | build
12 | eggs
13 | parts
14 | bin
15 | var
16 | sdist
17 | develop-eggs
18 | .installed.cfg
19 | lib
20 | lib64
21 |
22 | # Environments
23 | .env
24 | .venv
25 | env/
26 | venv/
27 | ENV/
28 | env.bak/
29 | venv.bak/
30 |
31 | # Node
32 | node_modules/
33 |
34 | # Installer logs
35 | pip-log.txt
36 |
37 | # Unit test / coverage reports
38 | .coverage
39 | .tox
40 | nosetests.xml
41 | htmlcov
42 |
43 | # Translations
44 | *.mo
45 |
46 | # Mr Developer
47 | .mr.developer.cfg
48 | .project
49 | .pydevproject
50 |
51 | # IDEs
52 | .idea
53 | .vscode
54 |
55 | # Complexity
56 | output/*.html
57 | output/*/index.html
58 |
59 | # Docs
60 | docs/_build
61 | site/
62 |
63 | # Example site
64 | /example/front_end_validator_example/__javascript__
65 | /example/front_end_validator_example/__target__
66 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # Config file for automatic testing at travis-ci.org
2 |
3 | language: python
4 |
5 | matrix:
6 | fast_finish: true
7 | allow_failures:
8 | - env: TOX_ENV=py37-django-21
9 | - env: TOX_ENV=py37-django-20
10 | include:
11 | - name: "3.6 Unit Test - Django 2.1"
12 | python: "3.6"
13 | env: TOX_ENV=py36-django-21
14 | - name: "3.7 Unit Test - Django 2.1"
15 | python: "3.7"
16 | env: TOX_ENV=py37-django-21
17 | - name: "3.6 Unit Test - Django 2.0"
18 | python: "3.6"
19 | env: TOX_ENV=py36-django-20
20 | - name: "3.7 Unit Test - Django 2.0"
21 | python: "3.7"
22 | env: TOX_ENV=py37-django-20
23 | - name: "3.6 Unit Test - Django 1.11"
24 | python: "3.6"
25 | env: TOX_ENV=py36-django-111
26 |
27 | # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors
28 | install: pip install -r requirements_test.txt
29 |
30 | # command to run tests using coverage, e.g. python setup.py test
31 | script: tox -e $TOX_ENV
32 |
--------------------------------------------------------------------------------
/AUTHORS.md:
--------------------------------------------------------------------------------
1 | # Credits
2 |
3 | ## Development Lead
4 |
5 | * John Franey (johnfraney)
6 |
7 | ## Contributors
8 |
9 | None yet. Why not be the first?
10 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Contributions are welcome, and they are greatly appreciated! Every
4 | little bit helps, and credit will always be given.
5 |
6 | You can contribute in many ways:
7 |
8 | ## Types of Contributions
9 |
10 | ### Report Bugs
11 |
12 | Report bugs at https://github.com/johnfraney/django-front-end-validators/issues.
13 |
14 | If you are reporting a bug, please include:
15 |
16 | * Your operating system name and version.
17 | * Any details about your local setup that might be helpful in troubleshooting.
18 | * Detailed steps to reproduce the bug.
19 |
20 | ### Fix Bugs
21 |
22 | Look through the GitHub issues for bugs. Anything tagged with "bug" is open to whoever wants to implement it.
23 |
24 | ### Implement Features
25 |
26 | Look through the GitHub issues for features. Anything tagged with "feature" is open to whoever wants to implement it.
27 |
28 | ### Write Documentation
29 |
30 | Django NER Trainer could always use more documentation, whether as part of the official Django NER Trainer docs, in docstrings, or even on the web in blog posts, articles, and such.
31 |
32 | ### Submit Feedback
33 |
34 | The best way to send feedback is to file an issue at https://github.com/johnfraney/django-front-end-validators/issues.
35 |
36 | If you are proposing a feature:
37 |
38 | * Explain in detail how it would work.
39 | * Keep the scope as narrow as possible, to make it easier to implement.
40 | * Remember that this is a volunteer-driven project, and that contributions are welcome :)
41 |
42 | ## Get Started!
43 |
44 | Ready to contribute? Here's how to set up `django-front-end-validators` for local development.
45 |
46 | 1. Fork the `django-front-end-validators` repo on GitHub.
47 | 2. Clone your fork locally
48 |
49 | ```bash
50 | $ git clone git@github.com:your_name_here/django-front-end-validators.git
51 | ```
52 |
53 | 3. Install your local copy into a virtualenv. Assuming you have `virtualenvwrapper` installed, this is how you set up your fork for local development
54 |
55 | ```bash
56 | $ mkvirtualenv django-front-end-validators
57 | $ cd django-front-end-validators/
58 | $ python setup.py develop
59 | ```
60 |
61 | 4. Create a branch for local development
62 | ```bash
63 | $ git checkout -b name-of-your-bugfix-or-feature
64 | ```
65 |
66 | 5. When you're done making changes, check that your changes pass `flake8` and the tests, including testing other Python versions with `tox`
67 |
68 | ```bash
69 | $ pip install flake8 tox
70 | $ flake8 front_end_validators tests
71 | $ python setup.py test
72 | $ tox
73 | ```
74 |
75 | 6. Commit your changes and push your branch to GitHub
76 |
77 | ```bash
78 | $ git add .
79 | $ git commit -m "Your detailed description of your changes."
80 | $ git push origin name-of-your-bugfix-or-feature
81 | ```
82 |
83 | 7. Submit a pull request through the GitHub website.
84 |
85 | ## Pull Request Guidelines
86 |
87 | Before you submit a pull request, check that it meets these guidelines:
88 |
89 | 1. The pull request should include tests.
90 | 2. If the pull request adds functionality, the docs should be updated. Put your new functionality into a function with a docstring, and add the feature to the list in README.md.
91 | 3. The pull request should work for Python 2.6, 2.7, and 3.3, and for PyPy. Check https://travis-ci.org/johnfraney/django-front-end-validators/pull_requests and make sure that the tests pass for all supported Python versions.
92 |
93 | ## Tips
94 |
95 | To run a subset of tests
96 |
97 | ```bash
98 | $ python -m unittest tests.test_front_end_validators
99 | ```
100 |
--------------------------------------------------------------------------------
/HISTORY.md:
--------------------------------------------------------------------------------
1 | # History
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018, John Franey
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include AUTHORS.md
2 | include CONTRIBUTING.md
3 | include HISTORY.md
4 | include LICENSE
5 | include README.md
6 | recursive-include front_end_validators *.html *.png *.gif *js *.css *jpg *jpeg *svg *py
7 | recursive-include front_end_validators/static *
8 | recursive-include front_end_validators/templates *
9 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: clean-pyc clean-build docs help
2 | .DEFAULT_GOAL := help
3 | define BROWSER_PYSCRIPT
4 | import os, webbrowser, sys
5 | try:
6 | from urllib import pathname2url
7 | except:
8 | from urllib.request import pathname2url
9 |
10 | webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1])))
11 | endef
12 | export BROWSER_PYSCRIPT
13 | BROWSER := python -c "$$BROWSER_PYSCRIPT"
14 |
15 | help:
16 | @grep '^[a-zA-Z]' $(MAKEFILE_LIST) | sort | awk -F ':.*?## ' 'NF==2 {printf "\033[36m %-25s\033[0m %s\n", $$1, $$2}'
17 |
18 | clean: clean-build clean-pyc
19 |
20 | clean-build: ## remove build artifacts
21 | rm -fr build/
22 | rm -fr dist/
23 | rm -fr *.egg-info
24 |
25 | clean-pyc: ## remove Python file artifacts
26 | find . -name '*.pyc' -exec rm -f {} +
27 | find . -name '*.pyo' -exec rm -f {} +
28 | find . -name '*~' -exec rm -f {} +
29 |
30 | lint: ## check style with flake8
31 | flake8 front_end_validators tests
32 |
33 | test: ## run tests quickly with the default Python
34 | python runtests.py tests
35 |
36 | test-all: ## run tests on every Python version with tox
37 | tox
38 |
39 | coverage: ## check code coverage quickly with the default Python
40 | coverage run runtests.py
41 | coverage report -m
42 | coverage html
43 | $(BROWSER) htmlcov/index.html
44 |
45 | docs: ## generate documentation
46 | mkdocs build --clean
47 | $(BROWSER) site/index.html
48 |
49 | docs-deploy: ## deploy documentation to GitHub pages
50 | mkdocs gh-deploy
51 |
52 | release: clean ## package and upload a release
53 | python setup.py sdist
54 | python setup.py bdist_wheel
55 | twine upload dist/*
56 |
57 | release-test: clean ## package and upload a release
58 | python setup.py sdist
59 | python setup.py bdist_wheel
60 | twine upload --repository-url https://test.pypi.org/legacy/ dist/*
61 |
62 | sdist: clean ## package
63 | python setup.py sdist
64 | ls -l dist
65 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Django Front End Validators
2 |
3 | [
4 | 
5 | 
6 | 
7 | 
8 | ](https://pypi.org/project/django-front-end-validators/)
9 | [](https://travis-ci.org/johnfraney/django-front-end-validators)
10 |
11 | Django Front End Validators allows you to reuse server-side [model field validators](https://docs.djangoproject.com/en/dev/ref/validators/) to perform front end form validation in JavaScript.
12 |
13 |
14 | ## Documentation
15 |
16 | Documentation is available in the [docs directory](./docs/index.md) and at https://johnfraney.github.io/django-front-end-validators.
17 |
18 |
19 | ## Supported Python versions
20 |
21 | Currently support is planned for only Python 3.6 and 3.7, on which Transcrypt 3.6 and 3.7 depend.
22 |
23 |
24 | ## Credits
25 |
26 | Tools used in rendering this package:
27 |
28 | [Transcrypt](http://www.transcrypt.org/)
29 |
30 | [Cookiecutter](https://github.com/audreyr/cookiecutter)
31 |
32 | [`cookiecutter-djangopackage`](https://github.com/pydanny/cookiecutter-djangopackage)
33 |
34 |
35 |
36 | ## Code of Conduct
37 |
38 | Everyone interacting in the project's codebases, issue trackers, chat rooms, and mailing lists is expected to follow the [PyPA Code of Conduct](https://www.pypa.io/en/latest/code-of-conduct/).
39 |
--------------------------------------------------------------------------------
/docs/browser_support.md:
--------------------------------------------------------------------------------
1 | Because this package uses [Transcrypt](http://www.transcrypt.org/) to transpile Python to JavaScript, browser support depends on the version of Transcrypt installed in your project.
2 |
3 | Currently this package supports Transcrypt versions 3.6 and 3.7, which transpile Python code into different versions of JavaScript:
4 |
5 | | Transcrypt Version | JavaScript Version | Browser Support |
6 | | ------------------ | ------------------ | --------------- |
7 | | 3.6 | ES5 | 100% |
8 | | 3.7 | ES6 | [>75%](https://caniuse.com/#feat=es6-module) |
9 |
10 |
11 | !!! note
12 | This plugin will respect whether you have Transcrypt 3.6 or 3.7 installed, so you can choose whether to generate newer or better-supported JavaScript by specifying the Transcrypt version in your project's requirements.
13 |
--------------------------------------------------------------------------------
/docs/example_project.md:
--------------------------------------------------------------------------------
1 | An example project is included in the repo's `example` directory.
2 |
3 |
4 | ## Set-up
5 |
6 | To run the example project:
7 |
8 | ```bash
9 | # Enter the example directory
10 | cd example
11 |
12 | # Install the dependencies (in a virtual environment, ideally)
13 | pip install -r requirements.txt
14 |
15 | # Transpile the validators from Python to JavaScript
16 |
17 | ./manage.py transpile_validators
18 |
19 | # Run the server
20 | ./manage.py runserver
21 | ```
22 |
23 | Visit `http://127.0.0.1:8000` in your browser to view a form with a number of validator functions.
24 |
25 | ## Demo
26 |
27 | 
28 |
--------------------------------------------------------------------------------
/docs/forms.md:
--------------------------------------------------------------------------------
1 | ## `FrontEndValidatorsModelForm`
2 |
3 | This class extends Django's `ModelForm` to add a `data-validators` attribute to any field that contains validators. `data-validators` lists references to JavaScript validator functions.
4 |
--------------------------------------------------------------------------------
/docs/how_it_works.md:
--------------------------------------------------------------------------------
1 | Django Front End Validators validates your form inputs as-you-type using the same validation logic specified in your model field's `validators`. It plays nicely with native HTML5 input validation, too.
2 |
3 | The heavy lifting of converting model field validators from Python to JavaScript is performed by [Transcrypt](http://www.transcrypt.org/) using the [`transpile_validators` managment command](management_commands.md).
4 |
5 | ## Example
6 |
7 | Let's say you've got this validator on a field called `email`:
8 |
9 | ```python
10 | from django.core.exceptions import ValidationError
11 |
12 |
13 | def validate_no_gmail_siblings(value):
14 | if '+' in value and value.endswith('gmail.com'):
15 | raise ValidationError(
16 | "Please use your plain Gmail address"
17 | )
18 | ```
19 |
20 | When the field is rendered in a [`FrontEndValidatorsModelForm`](forms.md), it will look like this:
21 |
22 | ```html
23 |
24 | ```
25 |
26 | A JavaScript plugin included with the [`{% front_end_validators_js %}` template tag](template_tags.md) checks the input value against the validators listed in `data-validators` in an `oninput` event listener, providing real-time feedback.
27 |
28 | If the value fails the `validators.validate_no_gmail_siblings` check, a custom validation error message is added to the field using the [HTML5 Constraint API](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation). This prevents the form from being submitted until the validation error is fixed:
29 |
30 | 
31 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ## About
2 |
3 | Django Front End Validators allows you to reuse server-side [model field validators](https://docs.djangoproject.com/en/dev/ref/validators/) to perform front end form validation in JavaScript.
4 |
5 | For more information, see [How It Works](how_it_works.md).
6 |
7 | ## Quickstart
8 |
9 | #### Install Django Front End Validators
10 |
11 | ```bash
12 | pip install django-front-end-validators
13 | ```
14 |
15 | #### Update `INSTALLED_APPS`
16 |
17 | ```python
18 | INSTALLED_APPS = (
19 | ...
20 | 'front_end_validators',
21 | ...
22 | )
23 | ```
24 |
25 | #### Configure settings
26 |
27 | ```python
28 | # The directory into which Transcrypt transpiles JS
29 | STATICFILES_DIRS = [
30 | # Transcrypt 3.7:
31 | 'your_project/__target__'
32 | # Transcrypt 3.6:
33 | 'your_project/__javascript__',
34 | ]
35 |
36 | # The path to your validators.py file
37 | VALIDATORS_FILE = os.path.join(BASE_DIR, 'your_project/validators.py')
38 | ```
39 |
40 | #### Add template tag
41 |
42 | ```html+django
43 | {% load front_end_validators %}
44 |
45 |
46 | {{ form.media.css }}
47 |
48 |
49 | {% block content %}{% endblock %}
50 | {% front_end_validators_js %}
51 | {{ form.media.js }}
52 |
53 |
54 | ```
55 |
56 | #### Transpile validators
57 |
58 | ```bash
59 | ./manage.py transpile_validators
60 | ```
61 |
62 | #### Write forms
63 |
64 | ```python
65 | from front_end_validators.forms import FrontEndValidatorsModelForm
66 | from .models import YourModel
67 |
68 |
69 | class YourModelForm(FrontEndValidatorsModelForm):
70 | class Meta:
71 | model = YourModel
72 | fields = '__all__'
73 | ```
74 |
75 | ## Running Tests
76 |
77 | Does the code actually work?
78 |
79 | ```bash
80 | source /bin/activate
81 | (myenv) $ pip install tox
82 | (myenv) $ tox
83 | ```
84 |
--------------------------------------------------------------------------------
/docs/limitations.md:
--------------------------------------------------------------------------------
1 | ## Only function-style validators
2 |
3 | Although Django supports both [class-based and function validators](https://docs.djangoproject.com/en/dev/ref/validators/), this package supports only validators written as functions. If supporting class-based validators is important to you, please open an [issue](https://github.com/johnfraney/django-front-end-validators/issues).
4 |
5 |
6 | ## No i18n
7 |
8 | Because the transpiled JavaScript runs in the browser, it doesn't have direct access to the database or filesystem. If you know of a way to get this to work, please open a [pull request](https://github.com/johnfraney/django-front-end-validators/pulls)!
9 |
10 |
11 | ## Example
12 |
13 | The [Django validators documentation](https://docs.djangoproject.com/en/dev/ref/validators/#writing-validators) gives this as en example `ValidationError`:
14 |
15 | ```python
16 | from django.core.exceptions import ValidationError
17 | from django.utils.translation import gettext_lazy as _
18 |
19 | def validate_even(value):
20 | if value % 2 != 0:
21 | raise ValidationError(
22 | _('%(value)s is not an even number'),
23 | params={'value': value},
24 | )
25 | ```
26 |
27 | After removing `ugettext_lazy`, we get a validator that will work on the front end:
28 |
29 | ```python
30 | from django.core.exceptions import ValidationError
31 |
32 | def validate_even(value):
33 | if value % 2 != 0:
34 | raise ValidationError(
35 | '%(value)s is not an even number',
36 | params={'value': value},
37 | )
38 | ```
39 |
--------------------------------------------------------------------------------
/docs/management_commands.md:
--------------------------------------------------------------------------------
1 | ## `transpile_validators`
2 |
3 | This management command uses [Transcrypt](http://www.transcrypt.org/) to convert your project's `validators.py` file from Python to JavaScript.
4 |
5 | The transpiled JavaScript is placed in alongside your `validators.py` file in the following directory:
6 |
7 | | Transcrypt Version | Output Directory |
8 | | ------------------ | ---------------- |
9 | | 3.6 | `__javascript__` |
10 | | 3.7 | `__target__` |
11 |
12 | !!! info
13 | The relevant directory should be added to your project's `STATICFILES_DIRS` settings.
14 |
--------------------------------------------------------------------------------
/docs/media/django-front-end-validators.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnfraney/django-front-end-validators/a3c8805d9c84b2ac4c6e6a08839a192acf6453c7/docs/media/django-front-end-validators.gif
--------------------------------------------------------------------------------
/docs/media/validate-no-gmail-siblings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnfraney/django-front-end-validators/a3c8805d9c84b2ac4c6e6a08839a192acf6453c7/docs/media/validate-no-gmail-siblings.png
--------------------------------------------------------------------------------
/docs/template_tags.md:
--------------------------------------------------------------------------------
1 | ## `{% front_end_validators_js %}`
2 |
3 | This template tag includes two pieces of JavaScript:
4 |
5 | | JavaScript file | Description |
6 | | --------------- | ----------- |
7 | |`front_end_validators.js` | Form logic tying validation functions to input fields using the [HTML5 Constraint API](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation) |
8 | | `validators.[min.]js` | Transpiled validator functions |
9 |
--------------------------------------------------------------------------------
/example/db.sqlite3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnfraney/django-front-end-validators/a3c8805d9c84b2ac4c6e6a08839a192acf6453c7/example/db.sqlite3
--------------------------------------------------------------------------------
/example/front_end_validator_example/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnfraney/django-front-end-validators/a3c8805d9c84b2ac4c6e6a08839a192acf6453c7/example/front_end_validator_example/__init__.py
--------------------------------------------------------------------------------
/example/front_end_validator_example/forms.py:
--------------------------------------------------------------------------------
1 | from front_end_validators.forms import FrontEndValidatorsModelForm
2 | from .models import SampleModel
3 |
4 |
5 | class SampleModelForm(FrontEndValidatorsModelForm):
6 | class Meta:
7 | model = SampleModel
8 | fields = '__all__'
9 |
--------------------------------------------------------------------------------
/example/front_end_validator_example/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from . import validators
3 |
4 |
5 | class SampleModel(models.Model):
6 | future_year = models.PositiveIntegerField(
7 | validators=[
8 | validators.validate_four_digits,
9 | validators.validate_future_year,
10 | ],
11 | help_text="A four-digit year in the future"
12 | )
13 | all_caps = models.CharField(
14 | max_length=100,
15 | validators=[
16 | validators.validate_all_caps,
17 | ],
18 | help_text="A value in ALL CAPS"
19 | )
20 | https_url = models.URLField(
21 | 'HTTPS URL',
22 | max_length=200,
23 | validators=[
24 | validators.validate_https,
25 | ],
26 | help_text="A URL starting with 'https'. Works on top of native HTML5 URL validation."
27 | )
28 | png_image = models.ImageField(
29 | 'PNG image',
30 | validators=[
31 | validators.validate_png,
32 | ],
33 | help_text="An image file with a .png extension"
34 | )
35 |
--------------------------------------------------------------------------------
/example/front_end_validator_example/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for front_end_validator_example project.
3 |
4 | Generated by 'django-admin startproject' using Django 2.1.2.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/2.1/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/2.1/ref/settings/
11 | """
12 |
13 | import os
14 |
15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
17 |
18 |
19 | # Quick-start development settings - unsuitable for production
20 | # See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/
21 |
22 | # SECURITY WARNING: keep the secret key used in production secret!
23 | SECRET_KEY = '0q$1w*p6dn=6isix7##fmffd$e3153#wt^me_uy+cfro3t^o1r'
24 |
25 | # SECURITY WARNING: don't run with debug turned on in production!
26 | DEBUG = True
27 |
28 | ALLOWED_HOSTS = []
29 |
30 |
31 | # Application definition
32 |
33 | INSTALLED_APPS = [
34 | 'django.contrib.admin',
35 | 'django.contrib.auth',
36 | 'django.contrib.contenttypes',
37 | 'django.contrib.sessions',
38 | 'django.contrib.messages',
39 | 'django.contrib.staticfiles',
40 |
41 | 'front_end_validators',
42 | 'front_end_validator_example',
43 | ]
44 |
45 | MIDDLEWARE = [
46 | 'django.middleware.security.SecurityMiddleware',
47 | 'django.contrib.sessions.middleware.SessionMiddleware',
48 | 'django.middleware.common.CommonMiddleware',
49 | 'django.middleware.csrf.CsrfViewMiddleware',
50 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
51 | 'django.contrib.messages.middleware.MessageMiddleware',
52 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
53 | ]
54 |
55 | ROOT_URLCONF = 'front_end_validator_example.urls'
56 |
57 | TEMPLATES = [
58 | {
59 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
60 | 'DIRS': [],
61 | 'APP_DIRS': True,
62 | 'OPTIONS': {
63 | 'context_processors': [
64 | 'django.template.context_processors.debug',
65 | 'django.template.context_processors.request',
66 | 'django.contrib.auth.context_processors.auth',
67 | 'django.contrib.messages.context_processors.messages',
68 | ],
69 | },
70 | },
71 | ]
72 |
73 | WSGI_APPLICATION = 'front_end_validator_example.wsgi.application'
74 |
75 |
76 | # Database
77 | # https://docs.djangoproject.com/en/2.1/ref/settings/#databases
78 |
79 | DATABASES = {
80 | 'default': {
81 | 'ENGINE': 'django.db.backends.sqlite3',
82 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
83 | }
84 | }
85 |
86 |
87 | # Password validation
88 | # https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators
89 |
90 | AUTH_PASSWORD_VALIDATORS = [
91 | {
92 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
93 | },
94 | {
95 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
96 | },
97 | {
98 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
99 | },
100 | {
101 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
102 | },
103 | ]
104 |
105 |
106 | # Internationalization
107 | # https://docs.djangoproject.com/en/2.1/topics/i18n/
108 |
109 | LANGUAGE_CODE = 'en-us'
110 |
111 | TIME_ZONE = 'UTC'
112 |
113 | USE_I18N = True
114 |
115 | USE_L10N = True
116 |
117 | USE_TZ = True
118 |
119 |
120 | # Static files (CSS, JavaScript, Images)
121 | # https://docs.djangoproject.com/en/2.1/howto/static-files/
122 |
123 | STATIC_URL = '/static/'
124 |
125 | STATICFILES_DIRS = [
126 | # 'front_end_validator_example/__target__',
127 | 'front_end_validator_example/__javascript__',
128 | ]
129 |
130 | # Front End Validators settings
131 | VALIDATORS_FILE = os.path.join(BASE_DIR, 'front_end_validator_example/validators.py')
132 |
--------------------------------------------------------------------------------
/example/front_end_validator_example/templates/base.html:
--------------------------------------------------------------------------------
1 | {% load front_end_validators staticfiles %}
2 |
3 |
4 |
5 | Front End Validator Example
6 |
12 |
13 |
14 | {% block content %}{% endblock %}
15 | {% front_end_validators_js %}
16 | {{ form.media.js }}
17 |
18 |
19 |
--------------------------------------------------------------------------------
/example/front_end_validator_example/templates/front_end_validator_example/samplemodel_form.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 |
3 | {% block content %}
4 |
11 | {% endblock %}
12 |
--------------------------------------------------------------------------------
/example/front_end_validator_example/urls.py:
--------------------------------------------------------------------------------
1 | """front_end_validator_example URL Configuration
2 |
3 | The `urlpatterns` list routes URLs to views. For more information please see:
4 | https://docs.djangoproject.com/en/2.1/topics/http/urls/
5 | Examples:
6 | Function views
7 | 1. Add an import: from my_app import views
8 | 2. Add a URL to urlpatterns: path('', views.home, name='home')
9 | Class-based views
10 | 1. Add an import: from other_app.views import Home
11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
12 | Including another URLconf
13 | 1. Import the include() function: from django.urls import include, path
14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
15 | """
16 | from django.contrib import admin
17 | from django.urls import path
18 | from .views import SampleModelCreate
19 |
20 | urlpatterns = [
21 | path('admin/', admin.site.urls),
22 | path('', SampleModelCreate.as_view()),
23 | ]
24 |
--------------------------------------------------------------------------------
/example/front_end_validator_example/validators.py:
--------------------------------------------------------------------------------
1 | from django.core.exceptions import ValidationError
2 | from datetime import datetime
3 |
4 |
5 | def validate_all_caps(value):
6 | if value != value.upper():
7 | raise ValidationError(
8 | '%(value)s must be all caps',
9 | params={'value': value},
10 | )
11 |
12 |
13 | def validate_four_digits(value):
14 | if len(str(value)) is not 4:
15 | raise ValidationError(
16 | "Value must be four digits"
17 | )
18 |
19 |
20 | def validate_future_year(value):
21 | current_year = datetime.now().year
22 | if value <= current_year:
23 | raise ValidationError(
24 | '%(value)s is not a future year',
25 | params={'value': value},
26 | )
27 |
28 |
29 | def validate_https(value):
30 | if not value.startswith('https'):
31 | raise ValidationError(
32 | "Value must start with 'https'"
33 | )
34 |
35 |
36 | def validate_png(value):
37 | if not str(value).endswith('.png'):
38 | raise ValidationError(
39 | "Image must be a PNG"
40 | )
41 |
--------------------------------------------------------------------------------
/example/front_end_validator_example/views.py:
--------------------------------------------------------------------------------
1 | from django.views.generic import CreateView
2 | from .forms import SampleModelForm
3 | from .models import SampleModel
4 |
5 |
6 | class SampleModelCreate(CreateView):
7 | model = SampleModel
8 | form_class = SampleModelForm
9 |
--------------------------------------------------------------------------------
/example/front_end_validator_example/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for front_end_validator_example project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'front_end_validator_example.settings')
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/example/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import sys
4 |
5 | if __name__ == '__main__':
6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'front_end_validator_example.settings')
7 | try:
8 | from django.core.management import execute_from_command_line
9 | except ImportError as exc:
10 | raise ImportError(
11 | "Couldn't import Django. Are you sure it's installed and "
12 | "available on your PYTHONPATH environment variable? Did you "
13 | "forget to activate a virtual environment?"
14 | ) from exc
15 | execute_from_command_line(sys.argv)
16 |
--------------------------------------------------------------------------------
/example/requirements.txt:
--------------------------------------------------------------------------------
1 | Django
2 | Pillow
3 | # Your app requirements.
4 | -r ../requirements.txt
5 | -r ../requirements_test.txt
6 |
7 | # Your app in editable mode.
8 | -e ../
9 |
--------------------------------------------------------------------------------
/front_end_validators/__init__.py:
--------------------------------------------------------------------------------
1 | __version__ = '0.1.1'
2 |
--------------------------------------------------------------------------------
/front_end_validators/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 |
--------------------------------------------------------------------------------
/front_end_validators/forms.py:
--------------------------------------------------------------------------------
1 | from django import forms
2 |
3 |
4 | class FrontEndValidatorsModelForm(forms.ModelForm):
5 | def __init__(self, *args, **kwargs):
6 | super().__init__(*args, **kwargs)
7 | model = self._meta.model
8 | model_field_map = {}
9 | for model_field in model._meta.fields:
10 | model_field_map[model_field.name] = model_field
11 | for field_name, field in self.fields.items():
12 | if not hasattr(model, field_name):
13 | continue
14 | validators = model_field_map[field_name].validators
15 | valid_validators = []
16 | for validator in validators:
17 | if hasattr(validator, '__name__'):
18 | valid_validators.append(f'validators.{validator.__name__}')
19 |
20 | valid_validators_string = str(valid_validators).replace("'", "")
21 |
22 | self.fields[field_name].widget.attrs.update({
23 | 'data-validators': valid_validators_string
24 | })
25 |
--------------------------------------------------------------------------------
/front_end_validators/management/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnfraney/django-front-end-validators/a3c8805d9c84b2ac4c6e6a08839a192acf6453c7/front_end_validators/management/__init__.py
--------------------------------------------------------------------------------
/front_end_validators/management/commands/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnfraney/django-front-end-validators/a3c8805d9c84b2ac4c6e6a08839a192acf6453c7/front_end_validators/management/commands/__init__.py
--------------------------------------------------------------------------------
/front_end_validators/management/commands/transpile_validators.py:
--------------------------------------------------------------------------------
1 | import inspect
2 | import os
3 | import subprocess
4 | from django.core.exceptions import ImproperlyConfigured
5 | from django.core.management.base import BaseCommand, CommandError
6 | from django.conf import settings
7 |
8 |
9 | class Command(BaseCommand):
10 | help = 'Transpiles Python model field validators to JS using Transcrypt'
11 |
12 | def handle(self, *args, **options):
13 | try:
14 | validators_file = settings.VALIDATORS_FILE
15 | except AttributeError as err:
16 | raise CommandError('VALIDATORS_FILE setting needs to be defined')
17 |
18 | validators_file_basename = os.path.basename(validators_file)
19 |
20 | if not validators_file_basename == 'validators.py':
21 | error_text = (
22 | 'VALIDATORS_FILE setting must point to a file named validators.py. '
23 | 'Your file:\n{}'.format(validators_file_basename)
24 | )
25 | raise CommandError(error_text)
26 |
27 | if not os.path.exists(validators_file):
28 | raise CommandError('validators.py file could not be found: {}'.format(
29 | validators_file
30 | ))
31 |
32 | try:
33 | subprocess.run(['transcrypt', '-b', '-m', validators_file], check=True)
34 | except subprocess.CalledProcessError:
35 | raise CommandError(
36 | 'Transcrypt could not transpile your validators. See above for details.'
37 | )
38 | self.stdout.write(self.style.SUCCESS('Successfully transpiled validators'))
39 |
--------------------------------------------------------------------------------
/front_end_validators/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | # Create your models here.
4 |
--------------------------------------------------------------------------------
/front_end_validators/static/css/front_end_validators.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnfraney/django-front-end-validators/a3c8805d9c84b2ac4c6e6a08839a192acf6453c7/front_end_validators/static/css/front_end_validators.css
--------------------------------------------------------------------------------
/front_end_validators/static/img/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnfraney/django-front-end-validators/a3c8805d9c84b2ac4c6e6a08839a192acf6453c7/front_end_validators/static/img/.gitignore
--------------------------------------------------------------------------------
/front_end_validators/static/js/front_end_validators.js:
--------------------------------------------------------------------------------
1 | var fieldsToValidate = document.querySelectorAll('[data-validators]')
2 | for (fieldToValidate of fieldsToValidate) {
3 | fieldToValidate.oninput = function() {
4 | var fieldValidators = eval(this.attributes['data-validators'].value)
5 | var failingValidators = []
6 | for (validatorFunction of fieldValidators) {
7 | try {
8 | validatorFunction(this.value)
9 | }
10 | catch(e) {
11 | this.setCustomValidity(e.message)
12 | failingValidators.push(validatorFunction)
13 | }
14 | }
15 | if (failingValidators.length === 0) {
16 | this.setCustomValidity('')
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/front_end_validators/templates/front_end_validators/base.html:
--------------------------------------------------------------------------------
1 |
2 | {% comment %}
3 | As the developer of this package, don't place anything here if you can help it
4 | since this allows developers to have interoperability between your template
5 | structure and their own.
6 |
7 | Example: Developer melding the 2SoD pattern to fit inside with another pattern::
8 |
9 | {% extends "base.html" %}
10 | {% load static %}
11 |
12 |
13 | {% block extra_js %}
14 |
15 |
16 | {% block javascript %}
17 |
18 | {% endblock javascript %}
19 |
20 | {% endblock extra_js %}
21 | {% endcomment %}
22 |
--------------------------------------------------------------------------------
/front_end_validators/templates/front_end_validators/script_tag_transcrypt_36.html:
--------------------------------------------------------------------------------
1 | {% load staticfiles %}
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/front_end_validators/templates/front_end_validators/script_tag_transcrypt_37.html:
--------------------------------------------------------------------------------
1 | {% load staticfiles %}
2 |
3 |
4 |
--------------------------------------------------------------------------------
/front_end_validators/templatetags/front_end_validators.py:
--------------------------------------------------------------------------------
1 | from django import template
2 | from django.template.loader import get_template
3 | from front_end_validators.utils import get_transcrypt_version
4 |
5 |
6 | register = template.Library()
7 |
8 | transcrypt_version = get_transcrypt_version()
9 | if transcrypt_version.startswith('3.6'):
10 | script_tag_template_path = 'front_end_validators/script_tag_transcrypt_36.html'
11 | elif transcrypt_version.startswith('3.7'):
12 | script_tag_template_path = 'front_end_validators/script_tag_transcrypt_37.html'
13 | script_tag_template = get_template(script_tag_template_path)
14 |
15 |
16 | @register.inclusion_tag(script_tag_template)
17 | def front_end_validators_js():
18 | return
19 |
--------------------------------------------------------------------------------
/front_end_validators/urls.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from django.conf.urls import include, url
3 |
4 |
5 | app_name = 'front_end_validators'
6 | urlpatterns = [
7 | ]
8 |
--------------------------------------------------------------------------------
/front_end_validators/utils.py:
--------------------------------------------------------------------------------
1 | import pkg_resources
2 |
3 |
4 | def get_transcrypt_version():
5 | """Returns installed Transcrypt version as a string"""
6 | transcrypt_version = pkg_resources.get_distribution('transcrypt').version
7 | return transcrypt_version
8 |
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | from __future__ import unicode_literals, absolute_import
4 |
5 | import os
6 | import sys
7 |
8 | if __name__ == "__main__":
9 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tests.settings")
10 | from django.core.management import execute_from_command_line
11 |
12 | execute_from_command_line(sys.argv)
13 |
--------------------------------------------------------------------------------
/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: 'Django Front End Validators'
2 | repo_name: 'johnfraney/django-front-end-validators'
3 | repo_url: 'https://github.com/johnfraney/django-front-end-validators'
4 |
5 | nav:
6 | - Home: index.md
7 | - How It Works: how_it_works.md
8 | - Limitations: limitations.md
9 | - Browser Support: browser_support.md
10 | - Forms: forms.md
11 | - Template Tags: template_tags.md
12 | - Management Commands: management_commands.md
13 | - Example Project: example_project.md
14 |
15 | dev_addr: '127.0.0.1:8008'
16 |
17 | # Copyright
18 | copyright: 'Copyright © 2018 John Franey'
19 |
20 | extra:
21 | social:
22 | - type: 'github'
23 | link: 'https://github.com/johnfraney'
24 |
25 | # Theme configuration
26 | theme:
27 | name: 'material'
28 | logo:
29 | icon: 'check'
30 | palette:
31 | primary: 'green'
32 | accent: 'light green'
33 |
34 | # Extensions
35 | markdown_extensions:
36 | - admonition
37 | - codehilite
38 |
39 | # Google Analytics
40 | google_analytics:
41 | - 'UA-125394319-3'
42 | - 'auto'
43 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | # Additional requirements go here
2 | transcrypt<3.8
3 |
--------------------------------------------------------------------------------
/requirements_dev.txt:
--------------------------------------------------------------------------------
1 | bumpversion==0.5.3
2 | twine==1.11.0
3 | wheel==0.31.1
4 |
5 | # Docs
6 | mkdocs==1.0.3
7 | mkdocs-material==3.0.4
8 |
--------------------------------------------------------------------------------
/requirements_test.txt:
--------------------------------------------------------------------------------
1 | coverage==4.5.1
2 | mock>=2.0.0
3 | flake8>=3.5.0
4 | tox>=3.2.1
5 | codecov>=2.0.15
6 |
7 | # Additional test requirements go here
8 |
--------------------------------------------------------------------------------
/runtests.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8
3 | from __future__ import unicode_literals, absolute_import
4 |
5 | import os
6 | import sys
7 |
8 | import django
9 | from django.conf import settings
10 | from django.test.utils import get_runner
11 |
12 |
13 | def run_tests(*test_args):
14 | if not test_args:
15 | test_args = ['tests']
16 |
17 | os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.settings'
18 | django.setup()
19 | TestRunner = get_runner(settings)
20 | test_runner = TestRunner()
21 | failures = test_runner.run_tests(test_args)
22 | sys.exit(bool(failures))
23 |
24 |
25 | if __name__ == '__main__':
26 | run_tests(*sys.argv[1:])
27 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [bumpversion]
2 | current_version = 0.1.0
3 | commit = True
4 | tag = True
5 |
6 | [bumpversion:file:setup.py]
7 |
8 | [bumpversion:file:front_end_validators/__init__.py]
9 |
10 | [wheel]
11 | universal = 1
12 |
13 | [flake8]
14 | ignore = D203
15 | exclude =
16 | front_end_validators/migrations,
17 | .git,
18 | .tox,
19 | docs/conf.py,
20 | env,
21 | build,
22 | dist
23 | max-line-length = 119
24 |
25 | [coverage:run]
26 | branch = True
27 | source = front_end_validators
28 | omit =
29 | *migrations*
30 | *tests*
31 | *env*
32 | *venv*
33 |
34 | [coverage:report]
35 | omit =
36 | *site-packages*
37 | *tests*
38 | *.tox*
39 | show_missing = True
40 | exclude_lines =
41 | raise NotImplementedError
42 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | import os
4 | import re
5 | import sys
6 |
7 | try:
8 | from setuptools import setup
9 | except ImportError:
10 | from distutils.core import setup
11 |
12 |
13 | def get_version(*file_paths):
14 | """Retrieves the version from front_end_validators/__init__.py"""
15 | filename = os.path.join(os.path.dirname(__file__), *file_paths)
16 | version_file = open(filename).read()
17 | version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]",
18 | version_file, re.M)
19 | if version_match:
20 | return version_match.group(1)
21 | raise RuntimeError('Unable to find version string.')
22 |
23 |
24 | version = get_version("front_end_validators", "__init__.py")
25 |
26 |
27 | if sys.argv[-1] == 'publish':
28 | try:
29 | import wheel
30 | print("Wheel version: ", wheel.__version__)
31 | except ImportError:
32 | print('Wheel library missing. Please run "pip install wheel"')
33 | sys.exit()
34 | os.system('python setup.py sdist upload')
35 | os.system('python setup.py bdist_wheel upload')
36 | sys.exit()
37 |
38 | if sys.argv[-1] == 'tag':
39 | print("Tagging the version on git:")
40 | os.system("git tag -a %s -m 'version %s'" % (version, version))
41 | os.system("git push --tags")
42 | sys.exit()
43 |
44 | readme = open('README.md').read()
45 | history = open('HISTORY.md').read()
46 |
47 | setup(
48 | name='django-front-end-validators',
49 | version=version,
50 | description="""Use model field validator functions for front end JS validation""",
51 | long_description=readme + '\n\n' + history,
52 | long_description_content_type="text/markdown",
53 | author='John Franey',
54 | author_email='johnfraney@gmail.com',
55 | url='https://github.com/johnfraney/django-front-end-validators',
56 | packages=[
57 | 'front_end_validators',
58 | ],
59 | include_package_data=True,
60 | install_requires=[
61 | 'transcrypt>=3.6'
62 | ],
63 | license="MIT",
64 | zip_safe=False,
65 | keywords='django-front-end-validators',
66 | classifiers=[
67 | 'Development Status :: 3 - Alpha',
68 | 'Framework :: Django :: 1.11',
69 | 'Framework :: Django :: 2.0',
70 | 'Framework :: Django :: 2.1',
71 | 'Intended Audience :: Developers',
72 | 'License :: OSI Approved :: BSD License',
73 | 'Natural Language :: English',
74 | 'Programming Language :: Python :: 3',
75 | 'Programming Language :: Python :: 3.6',
76 | 'Programming Language :: Python :: 3.7',
77 | ],
78 | )
79 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/johnfraney/django-front-end-validators/a3c8805d9c84b2ac4c6e6a08839a192acf6453c7/tests/__init__.py
--------------------------------------------------------------------------------
/tests/settings.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8
2 | from __future__ import unicode_literals, absolute_import
3 |
4 | import django
5 |
6 | DEBUG = True
7 | USE_TZ = True
8 |
9 | # SECURITY WARNING: keep the secret key used in production secret!
10 | SECRET_KEY = "11111111111111111111111111111111111111111111111111"
11 |
12 | DATABASES = {
13 | "default": {
14 | "ENGINE": "django.db.backends.sqlite3",
15 | "NAME": ":memory:",
16 | }
17 | }
18 |
19 | ROOT_URLCONF = "tests.urls"
20 |
21 | INSTALLED_APPS = [
22 | "django.contrib.auth",
23 | "django.contrib.contenttypes",
24 | "django.contrib.sites",
25 | "front_end_validators",
26 | ]
27 |
28 | SITE_ID = 1
29 |
30 | if django.VERSION >= (1, 10):
31 | MIDDLEWARE = ()
32 | else:
33 | MIDDLEWARE_CLASSES = ()
34 |
--------------------------------------------------------------------------------
/tests/urls.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals, absolute_import
3 |
4 | from django.conf.urls import url, include
5 |
6 |
7 | urlpatterns = [
8 | url(r'^', include('front_end_validators.urls', namespace='front_end_validators')),
9 | ]
10 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | envlist =
3 | {py36,py37}-django-21
4 | {py36,py37}-django-20
5 | {py36}-django-111
6 |
7 |
8 | [testenv]
9 | setenv =
10 | PYTHONPATH = {toxinidir}:{toxinidir}/front_end_validators
11 | commands = coverage run --source front_end_validators runtests.py
12 | deps =
13 | django-111: Django>=1.11,<1.12
14 | django-20: Django>=2.0,<2.1
15 | django-21: Django>=2.1,<2.2
16 | -r {toxinidir}/requirements.txt
17 | -r {toxinidir}/requirements_test.txt
18 | basepython =
19 | py37: python3.7
20 | py36: python3.6
21 |
--------------------------------------------------------------------------------