Form handling
We often want our download button to be responsive to web forms. In this example, we will create a web form which allows clients to select which files they want to download.
Template
We begin by creating a Jinja template called form-handling.html
in the templates
folder. Our folder structure looks like:
templates/
form-handling.html
index.html
app.py
In form-handling.html
:
<html>
<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
{{ download_btn.script() }}
</head>
<body>
<form>
<div id="selectFiles" name="selectFiles">
<p>Select files to download.</p>
<div class="form-check">
<input id="helloWorld" name="selectFiles" type="checkbox" class="form-check-input" value="hello_world.txt">
<label class="form-check-label" for="helloWorld">Hello World</label>
</div>
<div class="form-check">
<input id="helloMoon" name="selectFiles" type="checkbox" class="form-check-input" value="hello_moon.txt">
<label class="form-check-label" for="helloMoon">Hello Moon</label>
</div>
</div>
</form>
{{ download_btn.btn.render() }}
{{ download_btn.render_progress() }}
</body>
</html>
Function model
Forms are handled by Function models. To begin, we define a Function
model and give DownloadBtn
a relationship to it named handle_form_functions
.
@DownloadBtnManager.register
class DownloadBtn(DownloadBtnMixin, db.Model):
...
handle_form_functions = db.relationship(
'Function',
order_by='Function.index',
collection_class=ordering_list('index'),
foreign_keys='Function.handle_form_id'
)
from sqlalchemy_function import FunctionMixin
class Function(FunctionMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
index = db.Column(db.Integer)
handle_form_id = db.Column(db.Integer, db.ForeignKey('download_btn.id'))
View function
Form handling Functions always take the client's form response as their first argument, and the Download Button to which they are related as their second argument. The response is a werkzeug.datastructures.ImmutableMultiDict
object.
We can pass in additional arguments and keyword arguments by setting the Function's args
and kwargs
attributes.
@app.route('/form-handling')
def form_handling():
btn = DownloadBtn()
btn.handle_form_functions = select_files
db.session.commit()
return render_template('form-handling.html', download_btn=btn)
def select_files(response, btn):
btn.downloads.clear()
files = response.getlist('selectFiles')
if 'hello_world.txt' in files:
btn.downloads.append((HELLO_WORLD_URL, 'hello_world.txt'))
if 'hello_moon.txt' in files:
btn.downloads.append((HELLO_MOON_URL, 'hello_moon.txt'))