Сохранение статьи в базе данных сайта на Flask и ее получение оттуда

После успешного прохождения всех проверок мы должны записать полученную из формы статью в базе данных (код ниже следует добавить в ветку else функции index):

# Запись статьи и даты ее создания в базу данных
c = sqlite3.connect(db_name)
cur = c.cursor()
cur.execute('INSERT INTO articles \
            (path, h1, short_desc, body, theme, pos_in_theme) \
            VALUES (?, ?, ?, ?, ?, ?)', (
    request.form['path'],
    request.form['h1'],
    request.form['description'],
    request.form['article'],
    int(request.form['section']),
    int(request.form['position'])
))
last_id = cur.lastrowid
cur.execute('INSERT INTO dates (content) VALUES (?)', (last_id,))
c.commit()
c.close()

Свойство lastrowid объекта cursor возвращает значение поля id последней добавленной в БД записи. Вспомним, что в таблице дат мы связываем дату (создается автоматически по текущему времени) с id статьи из таблицы статей. Там id генерируется без нашего участия, поэтому мы не знаем его значения и вынуждены воспользоваться lastrowid.

Что касается перенаправления на только что созданную страницу, то перед этим надо создать функцию-представление для таких страниц:

@app.route('/<path:file_name>', methods=['GET', 'POST'])
def page(file_name):
    return render_template('create.html', sections=sections)

Позже мы изменим эту функцию. Сейчас важно лишь ее наличие для проверки работы перенаправления на только что созданную страницу.

В ветке else функции index после добавления данных статьи в таблицы БД допишем следующий код (также необходимо импортировать из модуля flask функции redirect и url_for):

# Перенаправление на только что созданную страницу
flash('Страница создана!', 'success')
return redirect(url_for('page', file_name=request.form['path']), code=307)

Код 307 нужен, чтобы сохранить передачу данных методом POST. По-умолчанию используется GET, и тогда форма данными из объекта request.form не заполнится. Пришлось бы читать их из базы данных.

Если вы успешно сохраните статью, то в адресной строке браузера увидите ее путь. Так как на сайте пока нет меню, обращаться к ранее созданным страницам придется с помощью ввода их пути в адресной строке.

Перенаправление не самое главное. Когда страница открывается методом GET (вводим ее адрес в строке браузера), данные должны читаться из БД и вставляться в форму.

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

Сейчас там код формы предусматривает обработку двух случаев: когда есть заполненный объект request.form и когда его нет. В случае чтения данных из БД, мы будем передавать их в форму через объект подобный словарю. Обращение к его записям похоже на то, что используется в случае request.form, но все же это разные объекты.

Ранее мы определили переменные, хранящие значения для полей. Этим переменным присваиваются значения ключей request.form при его наличии. Пусть им же присваиваются значения при наличии объекта, в котором хранятся данные из БД. Если же оба отсутствуют (случай, когда статья только создается, и форма открывается методом GET на главной странице), то в полях формы останутся значения по-умолчанию:

{% if request.form %}
  {% set sel = request.form['section'] | int %}
  {% set pos = request.form['position'] %}
  {% set path = request.form['path'] %}
  {% set h1 = request.form['h1'] %}
  {% set desc = request.form['description'] %}
  {% set article = request.form['article'] %}
{% elif post %}
  {% set sel = post['theme'] %}
  {% set pos = post['pos_in_theme'] %}
  {% set path = post['path'] %}
  {% set h1 = post['h1'] %}
  {% set desc = post['short_desc'] %}
  {% set article = post['body'] %}
{% endif %}

Функцию page изменим таким образом:

@app.route('/<path:file_name>', methods=['GET', 'POST'])
def page(file_name):
    if request.method == 'POST':
        return render_template('create.html', sections=sections)
    else:
        c = sqlite3.connect(db_name)
        c.row_factory = sqlite3.Row
        p = c.execute('SELECT * FROM articles WHERE path=?',
                      (file_name,)).fetchone()
        c.close()
        if p:
            return render_template('create.html', sections=sections, post=p)
        else:
            abort(404)

Если страница запрашивается через GET, соединяемся с базой данных и пытаемся получить оттуда запись с переданным адресом. В случае успеха передаем данные записи в шаблон. Иначе сообщаем, что такой страницы нет (функция abort импортируется из модуля werkzeug.exceptions).

Присваивание класса Row атрибуту row_factory экземпляра c, позволяет получить поля записи в виде подобия словаря, а не последовательности "голых" значений.

Теперь когда страница запрашивается по ее адресу, форма заполняется информацией, взятой из базы данных.

Flask для начинающих




Все разделы сайта