add javascript ajax example
This commit is contained in:
parent
d8bf589d48
commit
fce1885f76
21 changed files with 341 additions and 13 deletions
14
examples/javascript/.gitignore
vendored
Normal file
14
examples/javascript/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
venv/
|
||||
*.pyc
|
||||
__pycache__/
|
||||
instance/
|
||||
.cache/
|
||||
.pytest_cache/
|
||||
.coverage
|
||||
htmlcov/
|
||||
dist/
|
||||
build/
|
||||
*.egg-info/
|
||||
.idea/
|
||||
*.swp
|
||||
*~
|
||||
31
examples/javascript/LICENSE
Normal file
31
examples/javascript/LICENSE
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
Copyright © 2010 by the Pallets team.
|
||||
|
||||
Some rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms of the software as
|
||||
well as documentation, with or without modification, are permitted
|
||||
provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
|
||||
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
4
examples/javascript/MANIFEST.in
Normal file
4
examples/javascript/MANIFEST.in
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
include LICENSE
|
||||
graft js_example/templates
|
||||
graft tests
|
||||
global-exclude *.pyc
|
||||
49
examples/javascript/README.rst
Normal file
49
examples/javascript/README.rst
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
JavaScript Ajax Example
|
||||
=======================
|
||||
|
||||
Demonstrates how to post form data and process a JSON response using
|
||||
JavaScript. This allows making requests without navigating away from the
|
||||
page. Demonstrates using |XMLHttpRequest|_, |fetch|_, and
|
||||
|jQuery.ajax|_. See the `Flask docs`_ about jQuery and Ajax.
|
||||
|
||||
.. |XMLHttpRequest| replace:: ``XMLHttpRequest``
|
||||
.. _XMLHttpRequest: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
|
||||
|
||||
.. |fetch| replace:: ``fetch``
|
||||
.. _fetch: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch
|
||||
|
||||
.. |jQuery.ajax| replace:: ``jQuery.ajax``
|
||||
.. _jQuery.ajax: https://api.jquery.com/jQuery.ajax/
|
||||
|
||||
.. _Flask docs: http://flask.pocoo.org/docs/patterns/jquery/
|
||||
|
||||
|
||||
Install
|
||||
-------
|
||||
|
||||
::
|
||||
|
||||
python3 -m venv venv
|
||||
. venv/bin/activate
|
||||
pip install -e .
|
||||
|
||||
|
||||
Run
|
||||
---
|
||||
|
||||
::
|
||||
|
||||
export FLASK_APP=js_example
|
||||
flask run
|
||||
|
||||
Open http://127.0.0.1:5000 in a browser.
|
||||
|
||||
|
||||
Test
|
||||
----
|
||||
|
||||
::
|
||||
|
||||
pip install -e '.[test]'
|
||||
coverage run -m pytest
|
||||
coverage report
|
||||
5
examples/javascript/js_example/__init__.py
Normal file
5
examples/javascript/js_example/__init__.py
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
from flask import Flask
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
from js_example import views
|
||||
33
examples/javascript/js_example/templates/base.html
Normal file
33
examples/javascript/js_example/templates/base.html
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<!doctype html>
|
||||
<title>JavaScript Example</title>
|
||||
<link rel="stylesheet" href="https://unpkg.com/sakura.css@1.0.0/css/normalize.css">
|
||||
<link rel="stylesheet" href="https://unpkg.com/sakura.css@1.0.0/css/sakura-earthly.css">
|
||||
<style>
|
||||
ul { margin: 0; padding: 0; display: flex; list-style-type: none; }
|
||||
li > * { padding: 1em; }
|
||||
li.active > a { color: #5e5e5e; border-bottom: 2px solid #4a4a4a; }
|
||||
form { display: flex; }
|
||||
label > input { width: 3em; }
|
||||
form > * { padding-right: 1em; }
|
||||
#result { font-weight: bold; }
|
||||
</style>
|
||||
<ul>
|
||||
<li><span>Type:</span>
|
||||
<li class="{% if js == 'plain' %}active{% endif %}">
|
||||
<a href="{{ url_for('index', js='plain') }}">Plain</a>
|
||||
<li class="{% if js == 'fetch' %}active{% endif %}">
|
||||
<a href="{{ url_for('index', js='fetch') }}">Fetch</a>
|
||||
<li class="{% if js == 'jquery' %}active{% endif %}">
|
||||
<a href="{{ url_for('index', js='jquery') }}">jQuery</a>
|
||||
</ul>
|
||||
<hr>
|
||||
<p>{% block intro %}{% endblock %}</p>
|
||||
<hr>
|
||||
<form>
|
||||
<label>a <input name="a"></label>
|
||||
<span>+</span>
|
||||
<label>b <input name="b"></label>
|
||||
<input type="submit" value="Calculate">
|
||||
</form>
|
||||
<span>= <span id="result"></span></span>
|
||||
{% block script %}{% endblock %}
|
||||
35
examples/javascript/js_example/templates/fetch.html
Normal file
35
examples/javascript/js_example/templates/fetch.html
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block intro %}
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch"><code>fetch</code></a>
|
||||
is the <em>new</em> plain JavaScript way to make requests. It's
|
||||
supported in all modern browsers except IE, which requires a
|
||||
<a href="https://github.com/github/fetch">polyfill</a>.
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
<script src="https://unpkg.com/promise-polyfill@7.1.2/dist/polyfill.min.js"></script>
|
||||
<script src="https://unpkg.com/whatwg-fetch@2.0.4/fetch.js"></script>
|
||||
<script>
|
||||
function addSubmit(ev) {
|
||||
ev.preventDefault();
|
||||
fetch('{{ url_for('add') }}', {
|
||||
method: 'POST',
|
||||
body: new FormData(this)
|
||||
})
|
||||
.then(parseJSON)
|
||||
.then(addShow);
|
||||
}
|
||||
|
||||
function parseJSON(response) {
|
||||
return response.json();
|
||||
}
|
||||
|
||||
function addShow(data) {
|
||||
var span = document.getElementById('result');
|
||||
span.innerText = data.result;
|
||||
}
|
||||
|
||||
document.forms[0].addEventListener('submit', addSubmit);
|
||||
</script>
|
||||
{% endblock %}
|
||||
27
examples/javascript/js_example/templates/jquery.html
Normal file
27
examples/javascript/js_example/templates/jquery.html
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block intro %}
|
||||
<a href="https://jquery.com/">jQuery</a> is a popular library that
|
||||
adds cross browser APIs for common tasks. However, it requires loading
|
||||
an extra library.
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
|
||||
<script>
|
||||
function addSubmit(ev) {
|
||||
ev.preventDefault();
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: '{{ url_for('add') }}',
|
||||
data: $(this).serialize()
|
||||
}).done(addShow);
|
||||
}
|
||||
|
||||
function addShow(data) {
|
||||
$('#result').text(data.result);
|
||||
}
|
||||
|
||||
$('form:first').on('submit', addSubmit);
|
||||
</script>
|
||||
{% endblock %}
|
||||
27
examples/javascript/js_example/templates/plain.html
Normal file
27
examples/javascript/js_example/templates/plain.html
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block intro %}
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest"><code>XMLHttpRequest</code></a>
|
||||
is the plain JavaScript way to make requests. It's natively supported
|
||||
by all browsers.
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
<script>
|
||||
function addSubmit(ev) {
|
||||
ev.preventDefault();
|
||||
var request = new XMLHttpRequest();
|
||||
request.addEventListener('load', addShow);
|
||||
request.open('POST', '{{ url_for('add') }}');
|
||||
request.send(new FormData(this));
|
||||
}
|
||||
|
||||
function addShow() {
|
||||
var data = JSON.parse(this.responseText);
|
||||
var span = document.getElementById('result');
|
||||
span.innerText = data.result;
|
||||
}
|
||||
|
||||
document.forms[0].addEventListener('submit', addSubmit);
|
||||
</script>
|
||||
{% endblock %}
|
||||
16
examples/javascript/js_example/views.py
Normal file
16
examples/javascript/js_example/views.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
from flask import jsonify, render_template, request
|
||||
|
||||
from js_example import app
|
||||
|
||||
|
||||
@app.route('/', defaults={'js': 'plain'})
|
||||
@app.route('/<any(plain, jquery, fetch):js>')
|
||||
def index(js):
|
||||
return render_template('{0}.html'.format(js), js=js)
|
||||
|
||||
|
||||
@app.route('/add', methods=['POST'])
|
||||
def add():
|
||||
a = request.form.get('a', 0, type=float)
|
||||
b = request.form.get('b', 0, type=float)
|
||||
return jsonify(result=a + b)
|
||||
13
examples/javascript/setup.cfg
Normal file
13
examples/javascript/setup.cfg
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
[metadata]
|
||||
license_file = LICENSE
|
||||
|
||||
[bdist_wheel]
|
||||
universal = True
|
||||
|
||||
[tool:pytest]
|
||||
testpaths = tests
|
||||
|
||||
[coverage:run]
|
||||
branch = True
|
||||
source =
|
||||
js_example
|
||||
30
examples/javascript/setup.py
Normal file
30
examples/javascript/setup.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import io
|
||||
|
||||
from setuptools import find_packages, setup
|
||||
|
||||
with io.open('README.rst', 'rt', encoding='utf8') as f:
|
||||
readme = f.read()
|
||||
|
||||
setup(
|
||||
name='js_example',
|
||||
version='1.0.0',
|
||||
url='http://flask.pocoo.org/docs/patterns/jquery/',
|
||||
license='BSD',
|
||||
maintainer='Pallets team',
|
||||
maintainer_email='contact@palletsprojects.com',
|
||||
description='Demonstrates making Ajax requests to Flask.',
|
||||
long_description=readme,
|
||||
packages=find_packages(),
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
install_requires=[
|
||||
'flask',
|
||||
],
|
||||
extras_require={
|
||||
'test': [
|
||||
'pytest',
|
||||
'coverage',
|
||||
'blinker',
|
||||
],
|
||||
},
|
||||
)
|
||||
15
examples/javascript/tests/conftest.py
Normal file
15
examples/javascript/tests/conftest.py
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import pytest
|
||||
|
||||
from js_example import app
|
||||
|
||||
|
||||
@pytest.fixture(name='app')
|
||||
def fixture_app():
|
||||
app.testing = True
|
||||
yield app
|
||||
app.testing = False
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def client(app):
|
||||
return app.test_client()
|
||||
28
examples/javascript/tests/test_js_example.py
Normal file
28
examples/javascript/tests/test_js_example.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import pytest
|
||||
|
||||
from flask import template_rendered
|
||||
|
||||
|
||||
@pytest.mark.parametrize(('path', 'template_name'), (
|
||||
('/', 'plain.html'),
|
||||
('/plain', 'plain.html'),
|
||||
('/fetch', 'fetch.html'),
|
||||
('/jquery', 'jquery.html'),
|
||||
))
|
||||
def test_index(app, client, path, template_name):
|
||||
def check(sender, template, context):
|
||||
assert template.name == template_name
|
||||
|
||||
with template_rendered.connected_to(check, app):
|
||||
client.get(path)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(('a', 'b', 'result'), (
|
||||
(2, 3, 5),
|
||||
(2.5, 3, 5.5),
|
||||
(2, None, 2),
|
||||
(2, 'b', 2),
|
||||
))
|
||||
def test_add(client, a, b, result):
|
||||
response = client.post('/add', data={'a': a, 'b': b})
|
||||
assert response.get_json()['result'] == result
|
||||
|
|
@ -65,12 +65,11 @@ Test
|
|||
|
||||
::
|
||||
|
||||
pip install pytest
|
||||
pip install '.[test]'
|
||||
pytest
|
||||
|
||||
Run with coverage report::
|
||||
|
||||
pip install pytest coverage
|
||||
coverage run -m pytest
|
||||
coverage report
|
||||
coverage html # open htmlcov/index.html in a browser
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ def register():
|
|||
elif db.execute(
|
||||
'SELECT id FROM user WHERE username = ?', (username,)
|
||||
).fetchone() is not None:
|
||||
error = 'User {} is already registered.'.format(username)
|
||||
error = 'User {0} is already registered.'.format(username)
|
||||
|
||||
if error is None:
|
||||
# the name is available, store it in the database and go to
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
license_file = LICENSE
|
||||
|
||||
[bdist_wheel]
|
||||
universal = False
|
||||
universal = True
|
||||
|
||||
[tool:pytest]
|
||||
testpaths = tests
|
||||
|
|
|
|||
|
|
@ -20,4 +20,10 @@ setup(
|
|||
install_requires=[
|
||||
'flask',
|
||||
],
|
||||
extras_require={
|
||||
'test': [
|
||||
'pytest',
|
||||
'coverage',
|
||||
],
|
||||
},
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue