Найти - Пользователи
Полная версия: Вопрос про Flask
Начало » Web » Вопрос про Flask
1 2
pyser
Всем привет!
Совсем недавно стал изучать фреймворк Flask и вот решил сделать небольшое, тестовое приложение, в стиле блога с постами. Вот только появилась такая проблема: при заполнении всех полей (title, intro, text & date) и нажатия кнопки Save, ничего не происходит. Хотя я прописал чтоб при удачном добавлении всех данных в БД, всплывало сообщение об это и происходил редирект на страницу с постами. Подскажите, что я делаю не так, возможно я что-то не так понимаю

Код:
Инициализация всего и вся:
 from flask import Flask, render_template, url_for, redirect, flash
from flask_sqlalchemy import SQLAlchemy
from forms import NewsCreator
from datetime import datetime
app = Flask(__name__)
app.config['SECRET_KEY'] = "kbfihlfnfar3r23rff32r2r2"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blog.db'
db = SQLAlchemy(app)
.......
if __name__ == '__main__':
    app.run(debug=True)

Для создания полей, использую Flask-WTF. Весь код в отдельном файле forms.py
 from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, PasswordField, SelectField, TextAreaField, DateTimeField
from wtforms.validators import DataRequired, Email, Length
class NewsCreator(FlaskForm):
    title = StringField("Title", validators=[DataRequired(), Length(min=1, max=40)])
    intro = TextAreaField("Synopsys", validators=[DataRequired(), Length(min=1, max=150)])
    text = TextAreaField("Post", validators=[DataRequired(), Length(min=1, max=500)])
    date = DateTimeField("Date", validators=[DataRequired()])
    save_post = SubmitField("Save")

Класс таблицы БД находится в main.py (изначально был отдельно в models.py)

 class Article(db.Model):
    __tablename__ = 'article'
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(40), nullable=False)
    intro = db.Column(db.String(150), nullable=False)
    text = db.Column(db.Text, nullable=False)
    date = db.Column(db.DateTime, default=datetime.utcnow)
    def __repr__(self):
        return f'{self.title} {self.intro} {self.date}'

Так выглядит Route:
 @app.route('/create_article', methods=['GET', 'POST'])
def create_article():
    form = NewsCreator()
    if form.validate_on_submit():
        flash("Post created with success")
        return redirect(url_for('news'))
    return render_template('create_article.html', form=form)

Сюда должен происходить редирект:
 @app.route('/news')
def news():
    return render_template('news.html')

В basic.html есть такой код для вывода сообщения об успешном добавлении поста:
 {% block content %}
{% with messages = get_flashed_messages() %}
    {% if messages %}
        {% for message in messages %}
            <div>
                {{ message }}
            </div>
        {% endfor %}
    {% endif %}
{% endwith %}
{% endblock %}

Ну и сам create_article.html:
 {% extends 'basic.html' %}
{% block title %} Create Article Form {% endblock %}
{% block content %}
<div>
    <h1>Add article</h1>
    <form action="http://127.0.0.1:5000/create_article" method="POST">
        {{ form.hidden_tag() }}
        {{ form.title.label }} {{ form.title() }}
        {{ form.intro.label }} {{ form.intro() }}
        {{ form.text.label }} {{ form.text() }}
        {{ form.date.label }} {{ form.date() }}
        {{ form.save_post() }}
    </form>
</div>
{% endblock %}

Возможно это важно, после того как создал класс таблицы, в терминале запустил команду
>>> from main import db
>>>db.create_all()

В тот момент, класс таблицы находился в файле models.py, потом я подумал что это может быть причиной и перевёл класс в main.py а сам model.py удалил.

pyser
py.user.next
По пробовал, никаких изменений
После нажатия кнопки, страница будто перезагружается вместо того чтоб срабатывал редирект.
py.user.next
pyser
По пробовал, никаких изменений
После нажатия кнопки, страница будто перезагружается вместо того чтоб срабатывал редирект.
Просто перезагружается? У меня вообще исключение вылезло на всю страницу.
Это я просто забыл, как работает url_for().

Для отладки запускай вот так
#!/bin/bash

# Run local server localhost:5000

export FLASK_APP=app.py
export FLASK_DEBUG=1
flask-3 run


pyser
Ну и сам create_article.html:
Там в примерах кнопка submit ставится прямо в странице
https://flask-wtf.readthedocs.io/en/1.0.x/quickstart/#validating-forms
Попробуй убрать form.save_post() и поставить туда кнопку в виде HTML-кода, как в примерах.
pyser
py.user.next
Кароче, всё заработало. Ошибка была в том чтоб в таблице я указал что дата будет браться автоматом, datetime.utcnow, в тоже время, создав форму я создал и поле для даты, видимо питон просто не понимал что я хочу делать и зачем я пытаюсь передать дату если она уже есть из функции datetime.utcnow. Я поле для даты убрал и теперь редирект работает.

По поводу:
export FLASK_APP=app.py
export FLASK_DEBUG=1
flask-3 ru

да, я так и запускаю, только на винде set вместо export.


Но! У меня есть ещё такой вопрос. Вот тут я создал БД и в ней уже есть таблица, когда я захочу к примеру сделать форму регистрации, нужно будет создать ещё одну таблицу. Вопрос такой, мне потом снова делать
>>> from main import db
>>>db.create_all()
?

или есть команды только для обновления? И вообще, это обязательно всё прописывать каждый раз в терминале или можно к примеру записать всё внутри if __name__ == ‘__main__’:?
py.user.next
pyser
да, я так и запускаю, только на винде set вместо export.
Ну, оно должно все ошибки писать либо в консоль, либо в самом браузере. К тому же любые изменения файлов должы сразу отражаться на приложении без перезапуска тестового сервера.

pyser
Вот тут я создал БД и в ней уже есть таблица, когда я захочу к примеру сделать форму регистрации, нужно будет создать ещё одну таблицу.
Это вопрос относится к SQLAlchemy. К Flask'у это вообще никаким боком.
В SQLAlchemy куча разных способов для всего, читай документацию по ней.

Тут вопрос в том, а зачем тебе таблицы создавать на ходу? Все таблицы надо изначально сделать.

pyser
И вообще, это обязательно всё прописывать каждый раз в терминале или можно к примеру записать всё внутри if __name__ == ‘__main__’:?
Не, если тебе надо что-то сделать, то для этого надо скрипт написать, который это и делает, а потом просто запускать этот скрипт. Если ты пишешь каждый раз что-то в консоль, то задумайся “а почему я скрипт не написал ещё для этого, который всё это делает вместо меня?”. Даже в винде этой тупой есть батники, ими и скриптуют обычно там всё ещё с древних времён.

Вот пример простейший, там db.create_all() под воротами
https://pythonbasics.org/flask-sqlalchemy/
  
from flask import Flask, request, flash, url_for, redirect, render_template
from flask_sqlalchemy import SQLAlchemy
 
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///students.sqlite3'
app.config['SECRET_KEY'] = 'random string'
 
db = SQLAlchemy(app)
 
class students(db.Model):
   id = db.Column('student_id', db.Integer, primary_key=True)
   name = db.Column(db.String(100))
   city = db.Column(db.String(50))
   addr = db.Column(db.String(200)) 
   pin = db.Column(db.String(10))
   def __init__(self, name, city, addr,pin):
       self.name = name
       self.city = city
       self.addr = addr
       self.pin = pin
 
@app.route('/')
def show_all():
   return render_template('show_all.html', students=students.query.all())
 
@app.route('/new', methods=['GET', 'POST'])
def new():
   if request.method == 'POST':
      if (not request.form['name']
          or not request.form['city']
          or not request.form['addr']):
         flash('Please enter all the fields', 'error')
      else:
         student = students(request.form['name'], request.form['city'],
             request.form['addr'], request.form['pin'])
         db.session.add(student)
         db.session.commit()
         flash('Record was successfully added')
         return redirect(url_for('show_all'))
   return render_template('new.html')
 
if __name__ == '__main__':
    db.create_all()
    app.run(debug=True)
Ну, наверное, автор этого туториала прочитал это где-то в какой-то книжке и теперь так делает, или он просто код этот откуда-то скопировал у того, кто читал книжку какую-то. Сам этот автор не очень шарит, потому что мне пришлось поправлять его некоторые нарушения PEP8 какие-то элементарнейшие.

Я этот код через Яндекс нашёл по фразе “flask sqlalchemy example”.

pyser
да, я так и запускаю, только на винде set вместо export.
Поставь себе Linux. У тебя тогда мозги разовьются больше, потому что это система для программистов, поэтому там есть очень много примеров хороших программ. И поэтому в этой среде ты будешь учиться именно хорошим всяким привычкам, в том числе и скриптованию всего и вся.
pyser
Ну, оно должно все ошибки писать либо в консоль, либо в самом браузере. К тому же любые изменения файлов должы сразу отражаться на приложении без перезапуска тестового сервера.
Я тоже подумал что должно было выводится сообщение о том что что-то не так

Это вопрос относится к SQLAlchemy. К Flask'у это вообще никаким боком.
В SQLAlchemy куча разных способов для всего, читай документацию по ней.

Да, это я понял, просто не правильно выразился.

Тут вопрос в том, а зачем тебе таблицы создавать на ходу? Все таблицы надо изначально сделать.
Ну, это понятно. Просто сейчас пока учусь, идем приходят во время написания кода, поэтому и получается что ищу возможность создавать таблицы на ходу.

Поставь себе Linux.
Да, я как раз думал на второй ноут установить Линукс дистрибутив. Кстати, что лучше ставить начинающему? Я думал ставить какой-нибудь Ubuntu или Linux Mint. Толком ещё не вдавался в подробности по этому поводу.
py.user.next
pyser
поэтому и получается что ищу возможность создавать таблицы на ходу
Там можно создавать. Способов много, какой из них самый правильный, мне неизвестно, так как SQLAlchemy я не изучал вообще, потому что она стоит там у меня на десятом месте по приоритету, если не на двадцатом. Читай доку, ищи сообщества, в которых фанатеют от SQLAlchemy. Здесь ты можешь зайти в Telegram-канал, выслушать все истории про тайский бокс, мотоциклы и булочки и, может быть, там тебе скажут, как создать таблицу и добавить её в базу, а может и нет. Я просто к тому, что зачем её создавать на лету, если приложение у тебя должно быть полностью спроектировано ещё до его написания, и, соответственно, все таблицы у тебя уже к началу этого написания уже должны быть все придуманы, спроектированы и распланированы. Даже если ты поднимаешь версию приложения и добавляешь эту таблицу, которой не было раньше, ты всё равно просто перезапускаешь приложение, которое в итоге все эти таблицы один раз создаёт или подцепляет в самом начале при запуске.

pyser
Да, я как раз думал на второй ноут установить Линукс дистрибутив. Кстати, что лучше ставить начинающему? Я думал ставить какой-нибудь Ubuntu или Linux Mint. Толком ещё не вдавался в подробности по этому поводу.
Они сейчас все одинаковые. Это раньше они сильно различались на те, которые нужно было сначала сидеть компилировать целую неделю, чтобы просто что-то запустить хотя бы, и те, которые можно было сразу поставить. Сейчас большинство из них ставится сразу, а потом ты уже в них разбираешься детально.
Ставь Ubuntu или Fedora. Используй в них KDE по возможности, она более функциональная, чем GNOME. Дальше сможешь без переустановки на другие графические системы переехать. Это не винда, где всё надо переустанавливать чуть что.
pyser
py.user.next
Ок, спасибо за дельные советы
pyser
И снова я со своими баранами…

Решил я что лучше будет изучать создание приложений с БД MySQL. Нашёл я пару статей про всё это дело и решил самому написать, простенькое приложение, которое будет принимать через форму имя пользователя, сохранять его в БД а потом, на другой странице должно появится приветствие с именем взятым из БД.

Проблема в том, что я опять что-то делаю не так и имя в БД никак не хочет попадать. Будет круто если кто-то подскажет где я накосячил.

Код:
main.py
 from flask import Flask, redirect, render_template, url_for
from flask_mysqldb import MySQL
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
app = Flask(__name__)
app.config['SECRET_KEY'] = '1234567989'
app.config['MYSQL_USER'] = 'root'
app.config['MYSQL_PASSWORD'] = 'password'
app.config['MYSQL_HOST'] = 'localhost'
app.config['MYSQL_DB'] = 'nametest'
app.config['MYSQL_CURSORCLASS'] = 'DictCursor'
mysql = MySQL(app)
class NameForm(FlaskForm):
    name = StringField('Your name', validators=[DataRequired()])
    submit = SubmitField('Say your Name')
@app.route('/')
def index():
    return render_template('index.html')
@app.route('/say_name', methods=['GET', 'POST'])
def say():
    form = NameForm()
    if form.validate_on_submit():
        name = form.name.data()
        curs = mysql.connection.cursor()
        curs.execute(f"INSERT INTO tbl_names VALUES('NULL, {name}')")
        mysql.connection.commit()
        curs.close()
        print("Saved " + name)
        return redirect(url_for('hello'))
    return render_template('say_name.html', form=form)
@app.route('/hello')
def hello():
    curs = mysql.connection.cursor()
    curs.execute(f'SELECT * FROM tbl_names')
    data = curs.fetchone()
    print(data)
    curs.close()
    return render_template('hello.html', data=data)
if __name__ == '__main__':
    app.run(debug=True)

say_name.html
 {% extends 'basic.html' %}
{% block title %} Say Name Form {% endblock %}
{% block content %}
<form action="http://127.0.0.1:5000/say_name" method="POST">
  {{ form.name.label }} {{ form.name() }}
  {{ form.submit() }}
</form>
{% endblock %}

hello.html
 {% extends 'basic.html' %}
{% block title %} Hello Page {% endblock %}
{% block content %}
    <h1>Hello, {{ data }}</h1>
{% endblock %}
ZerG
создайте для начала тестовый файл в котором реализуйте методы чтения записи в базу - когда получиться
пихайте уже в фласк
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB