问题
Background
What I would like to do is to implement a form to insert datetime with the specific data type (like 2019-10-23 22:38:18) on a web application written in Python Flask and SQLAlchemy.
complete image
id | name | city | datetime
----+--------+---------+---------
1 | Hans | London |2019-10-23 22:37:10
2 | John | NewYork |2019-10-23 22:38:18
database
List of relations
Schema | Name | Type | Owner
--------+-------+-------+-------
public | todos | table | username
Problem
I've checked that inserting data for name and city column from forms was succeeded before adding datetime column and its form. But I'm stuck with the following error to insert datetime from the GUI form to the database.
jinja2.exceptions.UndefinedError: 'form' is undefined
Programs
app.py
from flask import Flask, render_template, request, redirect, url_for, abort, jsonify
from flask_sqlalchemy import SQLAlchemy
import sys
import datetime
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres://username@localhost:5432/simplewr'
db = SQLAlchemy(app)
class Todo(db.Model):
__tablename__ = 'todos'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String) # Jon
city = db.Column(db.String(120)) # New York
datetime = db.Column(db.DateTime()) # 2019-10-23 22:38:18
def __repr__(self):
return f'<Todo {self.id} {self.name} {self.city} {self.datetime}>'
db.create_all()
@app.route('/todos/create', methods=['POST'])
def create_todo():
error = False
body = {}
try:
name = request.form['name']
city = request.form['city']
datetime = request.form['datetime']
todo = Todo(name=name, city=city)
db.session.add(todo)
db.session.commit()
body['name'] = todo.name
body['city'] = todo.city
body['datetime'] = todo.datetime
except:
error = True
db.session.rollback()
print(sys.exc_info())
finally:
db.session.close()
if error:
abort (400)
else:
return jsonify(body)
# Filters
def format_datetime(value, format='medium'):
date = dateutil.parser.parse(value)
if format == 'full':
format="EEEE MMMM, d, y 'at' h:mma"
elif format == 'medium':
format="EE MM, dd, y h:mma"
return babel.dates.format_datetime(date, format)
app.jinja_env.filters['datetime'] = format_datetime
@app.route('/')
def index():
return render_template('index.html', data=Todo.query.all())
index.html
<html>
<head>
<title>Todo App</title>
<style>
.hidden{
display: none;
}
</style>
</head>
<body>
<form method="post" action="/todos/create">
<h4>name</h4>
<input type= "text" name="name" />
<h4>city</h4>
<input type= "text" name="city" />
<div>
<label for="datetime">Date Time</label>
{{ form.datetime(class_ = 'form-control', placeholder='YYYY-MM-DD HH:MM', autofocus = true) }}
</div>
<input type= "submit" value="Create" />
</form>
<div id= "error" class="hidden">Something went wrong!</div>
<ul>
{% for d in data %}
<li>{{d.name}}</li>
<li>{{d.city}}</li>
<li>{{d.datetime}}</li>
{% endfor %}
</ul>
<script>
const nameInput = document.getElementById('name');
const cityInput = document.getElementById('city');
const dtInput = document.getElementById('datetime');
document.getElementById('form').onsubmit = function(e) {
e.preventDefault();
const name = nameInput.value;
const city = cityInput.value;
const datetime = dtInput.value;
descInput.value = '';
fetch('/todos/create', {
method: 'POST',
body: JSON.stringify({
'name': name,
'city': city,
'datetime': datetime,
}),
headers: {
'Content-Type': 'application/json',
}
})
.then(response => response.json())
.then(jsonResponse => {
console.log('response', jsonResponse);
li = document.createElement('li');
li.innerText = name;
li.innerText = city;
li.innerText = datetime;
document.getElementById('todos').appendChild(li);
document.getElementById('error').className = 'hidden';
})
.catch(function() {
document.getElementById('error').className = '';
})
}
</script>
</body>
</html>
Environment
Python 3.6.0
Flask 1.1.1
SQLAlchemy 1.3.10
PostgreSQL 11.5
回答1:
First, you are using your form
in quite and unconventional way. Not that its wrong, its just that it's different from the typical which makes googling
for help more difficult.
Now on to your question...
The reason you are getting this error is because you haven't passed a form
variable for your template to use. Your index route would look something like:
@app.route('/')
def index():
return render_template('index.html', data=Todo.query.all(), form=form)
However the above won't work because you haven't defined a form in your index()
route. So you have to implement your datetime
atttribute the same way you did for name
and city
inside your jinja template. Instead of:
{{ form.datetime(class_ = 'form-control', placeholder='YYYY-MM-DD HH:MM', autofocus = true) }}
you will need to create the html yourself. For example:
<input id="datetime" type="datetime-local">
you can look through the docs to see all the options you have for specifying a datetime-local
input type.
来源:https://stackoverflow.com/questions/58525058/inappropriate-datetime-datatype-and-error-on-flask-app