Inappropriate datetime datatype and error on Flask App

旧巷老猫 提交于 2020-01-06 05:16:06

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!