Недопустимый тип данных datetime и ошибка в приложении Flask - PullRequest
0 голосов
/ 23 октября 2019

Фон

Я хотел бы реализовать форму для вставки даты и времени с определенным типом данных (например, 2019-10-23 22:38:18) в веб-приложение, написанное на Python Flask. и SQLAlchemy.

полное изображение

 id |  name  | city    | datetime
----+--------+---------+---------
  1 | Hans   | London |2019-10-23 22:37:10
  2 | John   | NewYork |2019-10-23 22:38:18

база данных

       List of relations
 Schema | Name  | Type  | Owner 
--------+-------+-------+-------
 public | todos | table | username

Проблема

Я проверил, что вставка данных для столбца имени и города изформы успешно перед добавлением столбца datetime и его формы. Но я застрял со следующей ошибкой, чтобы вставить datetime из формы GUI в базу данных.

jinja2.exceptions.UndefinedError: 'form' is undefined

Программы

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>

Среда

Python 3.6.0

Flask 1.1.1

SQLAlchemy 1.3.10

PostgreSQL 11.5

1 Ответ

1 голос
/ 23 октября 2019

Во-первых, вы используете свой form довольно нетрадиционным способом. Не в том, что это неправильно, просто в том, что он отличается от типичного, что делает googling помощь более трудной.

Теперь к вашему вопросу ...

Причина, по которой вы получаете эту ошибкупотому что вы не передали переменную form для вашего шаблона. Ваш индексный маршрут будет выглядеть примерно так:

@app.route('/')
def index():
    return render_template('index.html', data=Todo.query.all(), form=form)

Однако вышеприведенное не сработает, потому что вы не определили форму в своем маршруте index(). Таким образом, вы должны реализовать свой атрибут datetime так же, как вы это сделали для name и city внутри шаблона jinja. Вместо:

{{ form.datetime(class_ = 'form-control', placeholder='YYYY-MM-DD HH:MM', autofocus = true) }}

вам нужно будет создать html самостоятельно. Например:

<input id="datetime" type="datetime-local">

Вы можете просмотреть документы , чтобы увидеть все опции, которые вы можете указать для ввода datetime-local типа ввода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...