I have a small Flask app which has three fields (Destination, Start Time and End Time). I'd like to use DatePicker widget to display the calender when selecting start and end dates.
With my current scripts the date widget doesn't spawn at all. What am I missing here?
app.py:
# -*- coding: utf-8 -*-
from flask.ext.wtf import Form
from wtforms import SubmitField, SelectField, DateField
from flask import Flask, render_template, request
from flask.ext.bootstrap import Bootstrap
from flask.ext.admin.form.widgets import DatePickerWidget
class GeneralForm(Form):
destination = SelectField(choices = data)
start_time = DateField('Start at', widget=DatePickerWidget())
end_time = DateField('End at', widget=DatePickerWidget())
submit = SubmitField('Submit')
#app.route("/", methods=['GET', 'POST'])
def index():
form = GeneralForm(request.form)
if request.method == 'POST':
destination = form.destination.data
start_time = form.start_time.data
end_time = form.end_time.data
return render_template('page.html', form=form)
else:
return render_template('index.html', form=form)
bootstrap = Bootstrap(app)
if __name__ == '__main__':
app.run(debug=True)
index.html:
<link rel="stylesheet"
href="{{url_for('.static', filename='mystyle.css')}}">
<link rel="stylesheet"
href="{{url_for('.static', filename='datepicker.css')}}">
<link rel="javascript"
href="{{url_for('.static', filename='main.js')}}">
<link rel="javascript"
href="{{url_for('.static', filename='bootstrap-datepicker.js')}}"
<form action="#" method="post">
{{ form.destination }}
{{ form.start_time(class='datepicker') }}
{{ form.end_time(class='datepicker') }}
{{ form.submit }}
</form>
Flask-Admin's DatePickerWidget() basically adds data-date-format="YYYY-MM-DD" data-role="datepicker" attributes to an input field. After that a custom JavaScript function located in flask_admin/static/admin/js/form.js activates the Bootstrap-Datepicker widget on these fields.
So you need to include this script in your template (or write your own).
Add this line at the top of your template, which includes a helper macro:
{% import 'admin/static.html' as admin_static with context %}
and then you can include the form.js via adding these lines into your template (this script requires moment.js as well):
<script src="{{ admin_static.url(filename='vendor/moment.min.js') }}"></script>
<script src="{{ admin_static.url(filename='admin/js/form.js') }}"></script>
Note: You can also use the Bootstrap-Datepicker js and css files shipped with Flask-Admin. See the form_css() and form_js() macros in flask_admin/templates/bootstrap3/admin/lib.html and copy the corresponding lines into your template.
Have you declared the flask-bootstrap base.html reference file at the top of your page?
{% extends "bootstrap/base.html" as wtf %}
You can then initiate your form in your page by simply adding in the following
{{ wtf.quick_form(form) }}
Related
The main requirement I need is to limit the amount of files that the end user can upload to the system.
I would also like the files to be listed so that the end user can see what files he uploaded and delete them.
class NameForm(FlaskForm):
field = MultipleFileField('fieldname',validators= [])
I understand that you can make functions and incorporate them into the validator, I am currently doing the verification with jquery.
If you want to use a MultipleFileField but limit the number of files that can be uploaded at once, you can use a Length type validator.
In combination with InputRequired you can also require at least one file.
from flask_wtf import FlaskForm
from wtforms import MultipleFileField
from wtforms.validators import InputRequired, Length
from werkzeug.datastructures import CombinedMultiDict
app = Flask(__name__)
app.secret_key = 'your secret here'
class UploadForm(FlaskForm):
files = MultipleFileField('Files',
validators=[
InputRequired(message='At least one file is required.'),
Length(max=3, message='A maximum of 3 files are allowed.'),
]
)
#app.route('/upload', methods=['GET', 'POST'])
def upload():
form = UploadForm(CombinedMultiDict((request.files, request.form)))
if form.validate_on_submit():
# Handle the uploaded files here!
print(form.files.data)
return render_template('upload.html', **locals())
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
</head>
<body>
<form method="post" enctype="multipart/form-data">
{{ form.csrf_token }}
<div>
{{ form.files.label() }}
{{ form.files() }}
{% if form.files.errors -%}
<ul>
{% for error in form.files.errors -%}
<li>{{ error }}</li>
{% endfor -%}
</ul>
{% endif -%}
</div>
<button type="submit">Upload</button>
</form>
</body>
</html>
In order to display a list of uploaded files and delete individual files, we need more information about your application. This also applies if you want to limit the maximum number of files a user can upload in total.
Problem: There is an arduous update script we run for work. It takes a lot of time to update because of security issues. We want to make sure we have edited the update script correctly/want to avoid all permission issues.
Solution: Using Flask as a front end gui to eliminate the possibility for adding the wrong value. The Flask app will guarantee correct placement of inputs into the update script by auto generating the script, so we can just copy and paste into SSMS.
The current problem I am having is aesthetics. I was able to generate a flask app using user inputs and exports a SQL script. The problem is, the sql looks horrible, here is an example of the output:
Ideally the output would be multi-line, like all current SQL scripts:
UPDATE table_name
SET ordercomplete = 1
WHERE UserName = 'testuser' and OrderID = 12345
Below are my files:
#templates home.html
<!doctype html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>SQL Auto Generate</title>
<link rel="stylesheet" href="https://unpkg.com/purecss#0.6.2/build/pure-min.css" integrity="sha384-UQiGfs9ICog+LwheBSRCt1o5cbyKIHbwjWscjemyBMT9YCUMZffs6UqUTd0hObXD" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css') }}">
</head>
<h1>SQL Auto Generate</h1>
<h2>Add the following inputs, select 'Submit' to generate a script for SQL</h2>
<body>
<div class="main">
<form class="pure-form" method="POST" action="/">
UserName:<br>
<input type="text" name="UserName"><br>
OrderID:<br>
<input type="number" name="OrderID"><br>
<button type="submit" class="pure-button pure-button-primary" value="Submit">Submit</button>
</form>
</div>
<br>
<div class="main">
{% if UserName %}
<p>
{% print('''
UPDATE table_name
SET ordercomplete = 1
WHERE
UserName = {} and OrderID = {}
'''.format(UserName, OrderID)) %}
</p>
{% endif %}
</div>
</body>
# app.py
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route('/', methods=['GET', 'POST'])
def index():
UserName = ''
OrderID = ''
if request.method == 'POST' and 'UserName' in request.form:
UserName = request.form.get('UserName')
OrderID = int(request.form.get('OrderID'))
return render_template("home.html", UserName=UserName, OrderID = OrderID)
if __name__ == '__main__':
app.run(debug=True)
I also uploaded to github: https://github.com/jpf5046/sqlflask
Ask: Is there a better way to create a text output with multi-line via flask?
By default, HTML ignores extra space, such as line endings. If you want to display the query exactly like you generate it, use <pre>:
<pre>
UPDATE table_name
SET ordercomplete = 1
WHERE
UserName = {{UserName}} and OrderID = {{OrderId}}
</pre>
I think you just need to add br tags in your html
{% if UserName %}
<p>UPDATE table_name <br>
SET ordercomplete = 1 <br>
WHERE <br>
UserName = {{ UserName }} and OrderID = {{ OrderID }}
</p>
{% endif %}
I am trying to build an "enterprise grade" version of a flask app so am using blueprints and a fancy directory structure. I have a "toy" version of this app where everything is in a very flat directory structure with no blueprints and it works.
I have a route program that calcs some variables then passes them to render_template to generate html. The html displays in the browser but all of the variables appear to be set to NONE.
My app uses blueprints and SQLite3.
I have tried multiple things to isolate the error.
Make a textual change to html template to ensure the right template is being picked up. It is.
Pass trivial string variable to html template and see if they show up, they don't.
View source of rendered html, there is nothing where the flask variable names {{ x }} occur in the html template, including the {{ x }} text itself. So it appears the value None has been been used.
Test the code leading up to the render_template, it works perfectly.
My directory structure is: -
\myapp
app.py
\app
__init__.py
\main
__init__.py
routes.py
...
\meta
__init__.py
routes.py
...
\templates
...
base.html
index.html
The code in \meta\routes.py (which corresponds to the meta blueprint) works down to and including entitys = stmt.fetchall() and is: -
from flask import Flask, render_template, request
import sqlite3 as sql
from app.meta import bp
from app import Config
config = Config()
metafile = os.path.join(config.META_DIR, config.META_MS, config.META_DB)
#bp.route('/', methods=['GET', 'POST'])
#bp.route('/index', methods=['GET', 'POST'])
def index():
meta = sql.connect(metafile)
stmt = meta.cursor()
stmt.execute("SELECT * FROM [meta.Entity]")
entitys = stmt.fetchall()
return render_template("index.html", entitys = entitys)
In case it is relevant here is \meta\__init__.py: -
from flask import Blueprint
bp = Blueprint('meta', __name__)
The template html is as follows. The base.html is: -
<!doctype html>
<html>
<head>
{% if title %}
<title>{{ title }} - Metapplica</title>
{% else %}
<title>Metapplica</title>
{% endif %}
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="{{ url_for('static', filename = 'w3.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename = 'style.css') }}">
</head>
<body>
<div>
Home
</div>
<hr>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</body>
</html>
and index.html is: -
{% extends "base.html" %}
{% block content %}
<h2>Entities</h2>
<table border = 1>
<thead>
<td>Entity</td>
<td>Action</td>
</thead>
{% for entity in entitys %}
<tr>
<td>{{ entity["Name"] }}</td>
<td>
List
Add
</td>
</tr>
{% endfor %}
</table>
{% endblock %}
Finally the rendered html is this: -
<!doctype html>
<html>
<head>
<title>Home - Metapplica</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/static/w3.css">
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<div>
Home
</div>
<hr>
<h2>Entities </h2>
<table border = 1>
<thead>
<td>Entity</td>
<td>Action</td>
</thead>
</table>
</body>
</html>
In response to #Tobin's comment I have included the code that (should) be registering the blueprint. I use an application factory.
Here is app\__init__()
import logging
from logging.handlers import SMTPHandler, RotatingFileHandler
import os
from flask import Flask, session, redirect, url_for, escape, request, current_app
from config import Config
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
# Register blueprints
from app.errors import bp as errors_bp
app.register_blueprint(errors_bp, url_prefix='/err')
from app.auth import bp as auth_bp
app.register_blueprint(auth_bp, url_prefix='/auth')
from app.meta import bp as meta_bp
app.register_blueprint(meta_bp, url_prefix='/meta')
from app.main import bp as main_bp
app.register_blueprint(main_bp)
return app
and here is the code that calls it: -
from app import create_app
app = create_app()
I suspect that somehow when Flask renders the html template the passed variables are not available to the "flask engine" which is pointing somewhere else.
Nothing fails and there are no error messages.
What am I doing wrong?
Am very much new to Flask & Python, so want to understand/clear my concepts. I have a webpage which i created using flask & wtforms. Html page is very simple having just single field & a submit button. I want to call a python script (test.py) itself or python function(pythonfunction()) when submit button is clicked. Also Is there a way from the webpage,whatever i enter , i can pass as an attribute to that python script (test.py)? help appreciated
**app.py**
from flask import Flask , render_template,flash,redirect,url_for,session,logging,request
from wtforms import Form,StringField,TextAreaField,PasswordField,validators,SelectField,TextAreaField
from wtforms.widgets import TextArea
import subprocess
import test
app=Flask(__name__)
#app.route ('/')
def index():
return render_template('home.html')
class testpython(Form):
testenter=StringField('Enter something')
#app.route ('/testpage',methods=['GET','POST'])
def testpage():
form=testpython(request.form)
return render_template('testpage.html',form=form,python=testfunc(testenter))
if __name__ == '__main__':
app.run(debug=True)
**test.py**
def pythonfunctiontest (self):
print data #<something i can print here from that text field in webpage>
return "all good"
**testpage.html**
{% extends 'sec_layout.html'%}
{% block body %}
{% from "includes/_formhelpers.html" import render_field %}
<form method="POST" action ="">
<div class="form-group">
{{render_field(form.testenter,cols="1", rows="5",class_="form-control")}}
</div>
<div class="input-bar-item input-bar-item-btn">
<button class="btn btn-info">Submit</button>
</div>
</form>
{% endif %}
{% endblock%}
sec_layout.html
<!DOCTYPE <!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>MY PAGE-TEST</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
</head>
<body>
{% include 'includes/_navbar.html' %}
<div class= "container">
{% block body %}{% endblock%}
</div>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" </script>
</body>
</html>
The question is very general so I will try and give you a steer and perhaps you might revisit this question later with a little more clarity.
Flask asks a server and renders webpages. I.e. it executes some code on the server and passes it to the client web browser. The client web browser can then execute client side code (i.e. Javascript) as the user is browsing and can pass data back to the server using submit forms (to different Flask routes) or via JavaScript AJAX requests (again to other Flask routes). So if you want to execute python script based on some input you will need a separate route.
Here is a simple example of an index page and a second route that will execute something else:
#app.route('/index')
def index():
""" very basic template render """
return render_template('index.html')
#app.route('/data-submit', methods=["POST"])
def calc():
data = request.form.information.data
# do something with data..
x = data + data
return render_template('new_page.html', x)
========= (index.html)
<html>
<body>
<form action="{{ url_for('app.calc') }}" method="POST">
<input name="information" type='text'>
<button name="submit">
</form>
</body>
</html>
Wrap whatever temp.py is doing in a function.
Place it in the same directory as flask.py. Call import temp in flask.py, then use temp.myfunction().
I am new to Flask and want to create a On/Off toggle button on my website. I was wondering if and how this is possible also including a dynamic label. The following picture shows what I have in mind:
I was thinking about using a wtfforms SubmitField but I don't quite know how to implement this dynamic behavior between my routes.py file and my html template. I was thinking something like this:
forms.py:
from flask_wtf import FlaskForm
from wtforms import SubmitField
class PowerSwitchForm(FlaskForm):
power_switch = SubmitField("ON")
routes.py:
from flask import render_template, flash, redirect, url_for
from app import app
from app.forms import PowerSwitchForm
#app.route('/power', methods=['GET', 'POST'])
def power():
power_switch = PowerSwitchForm()
if power_switch.power_switch.label.text == "ON" and power_switch.validate():
flash("Power has been turned ON")
power_switch.power_switch.label.text = "OFF"
return redirect(url_for('power')
elif power_switch.power_switch.label.text == "OFF" and power_switch.validate():
flash("Power has been turned OFF")
power_switch.power_switch.label.text = "ON"
return redirect(url_for('power')
return render_template('power.html', form0=power_switch)
power.html:
<!DOCTYPE html>
{% extends "base.html" %}
{% block content %}
<h2>Power switch</h2>
<form action="" method="post" novalidate>
{{ form0.hidden_tag() }}
{{ form0.power_switch() }}
</form>
{% endblock %}
You can use jquery to handle the desired operation when the toggle button is clicked. Also, if there is a backend process that should be performed when the button is toggled, ajax can be used. This answer demonstrates both. bootstrap-toggle is a library that enables simple implementation of a toggle. To use, copy the header tag values below:
Simple toggle that displays "toggled" or "untoggled":
<html>
<body>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js"></script>
<link href="https://gitcdn.github.io/bootstrap-toggle/2.2.2/css/bootstrap-toggle.min.css" rel="stylesheet">
<script src="https://gitcdn.github.io/bootstrap-toggle/2.2.2/js/bootstrap-toggle.min.js"></script>
</head>
<input type="checkbox" class='toggle' checked data-toggle="toggle">
<div class='status'>Toggled</div>
</body>
<script>
$(document).ready(function() {
$('.toggle').click(function() {
var current_status = $('.status').text();
if (current_status === 'Untoggled'){
$('.status').html('Toggled');
}
else{
$('.status').html('Untoggled');
}
});
});
</script>
</html>
Toggle that triggers backend script for both "toggled" or "untoggled":
In the template, slightly change the script:
<script>
$(document).ready(function() {
$('.toggle').click(function() {
var current_status = $('.status').text();
$.ajax({
url: "/get_toggled_status",
type: "get",
data: {status: current_status},
success: function(response) {
$(".status").html(response);
},
error: function(xhr) {
//Do Something to handle error
}
});
});
});
</script>
Then, in your app, create a route /get_toggled_status:
#app.route('/get_toggled_status')
def toggled_status():
current_status = flask.request.args.get('status')
return 'Toggled' if current_status == 'Untoggled' else 'Untoggled'
This example does the same thing as the pure html/jquery solution, however, it does demonstrate how the backend can be communicated with when using the toggle.
I am also new to Flask. And here is the pure python code with flask that I've tried.
Looks it work.
in templates/demo.html :
{% extends "bootstrap/base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block content %}
<div class="page-header">
{{ wtf.quick_form(form) }}
</div>
{% endblock %}
in demo.py :
from flask import Flask, render_template, redirect, url_for
from flask_bootstrap import Bootstrap
from flask_wtf import FlaskForm
from wtforms import SubmitField
class PowerState(FlaskForm) :
state = SubmitField('OFF')
app = Flask(__name__)
Bootstrap(app)
app.config['SECRET_KEY'] = 'YOUR SECRET KEY'
#app.route('/', methods=['GET', 'POST'])
def home() :
form = PowerState()
if form.validate_on_submit() :
if form.state.label.text == 'OFF' :
PowerState.state = SubmitField('ON')
elif form.state.label.text == 'ON' :
PowerState.state = SubmitField('OFF')
return redirect(url_for('home'))
return render_template('demo.html', form=form)
then run :
flask run
Regards, Alex.Wu