Редактирование статей сайта на Flask ‒ обновление записей в базе данных

На данном этапе может показаться, что наше flask-приложение вполне рабочее. Если страница только создается, данные записываются в БД, а страница открывается по своему адресу с заполненной формой. Если же мы открываем ранее созданную страницу путем ввода ее адреса в браузере, то она открывается методом GET и тоже с заполненной формой.

И даже если, изменив страницу, мы нажмем на кнопку "Сохранить", форма загрузится с внесенными изменениями. Это происходит потому, что данные берутся из объекта request.form. Однако изменения не записываются в БД. Чтобы убедиться в этом, измените данные и нажмите кнопку отправки формы. После этого перезагрузите страницу методом GET (нажать Enter в адресной строке). Страница загрузится в первоначальной версии, а не измененной.

Действительно, запись данных в базу у нас реализована в функции index. В функции page происходит только чтение, когда запрос выполняется методом GET. Но когда на странице статьи нажимается кнопка сохранения, данные отправляются методом POST, и в этой части ничего не сказано об обновлении полей записи в таблице БД.

Однако как разделить POST-запрос страницы, который выполняется при редиректе из функции index, и тот, который происходит при отправке формы на самой странице? Допустим, чтобы не обрабатывать разные "источники" запроса, мы могли бы перенести из функции index в функцию page команды записи в базу данных. Ведь если потом мы все равно перенаправляем на страницу статьи, без разницы в какой момент происходит добавление статьи в БД.

Сложность в том, в функции index запись добавляется. При этом используется sql-команда INSERT. А по адресу страницы запись будет обновляться. При этом используется sql-команда UPDATE.

В данном курсе мы пренебрежем эффективностью работы приложения в пользу упрощения и ясности логики. Поэтому сделаем так, чтобы в функции page код, отвечающий за POST-запросы, обрабатывал только данные, приходящие из формы самой страницы. Когда же на страницу происходит перенаправление из index, то запрашиваться страница будет методом GET (там надо убрать аргумент code=307), при этом данные будут считываться из базы данных. Так, как это происходит при простом обращении к странице по ее адресу.

В результате код функции page может выглядеть так:

@app.route('/<path:file_name>', methods=['GET', 'POST'])
def page(file_name):
    c = sqlite3.connect(db_name)
    c.row_factory = sqlite3.Row
    p = c.execute('SELECT * FROM articles WHERE path=?',
                  (file_name,)).fetchone()
    c.close()

    def update(column, field):
        c = sqlite3.connect(db_name)
        c.execute(f'UPDATE articles SET {column}=(?) WHERE path=(?)',
                  (request.form[field], file_name))
        c.commit()
        c.close()
        return True

    if request.method == 'POST':
        updated = False

        if request.form['h1'] == '':
            flash('Заголовок не может быть пустым!', 'error')
        elif request.form['h1'] != p['h1']:
            updated = update('h1', 'h1')

        if request.form['article'] != p['body']:
            updated = update('body', 'article')

        if request.form['description'] != p['short_desc']:
            updated = update('short_desc', 'description')

        if updated:
            c = sqlite3.connect(db_name)
            c.execute('INSERT INTO dates(content) VALUES (?)', (p['id'],))
            c.commit()
            c.close()
            flash('Страница обновлена!', 'success')

        if int(request.form['section']) != p['theme']:
            update('theme', 'section')
            flash('Раздел изменен!', 'success')
        if int(request.form['position']) != p['pos_in_theme']:
            update('pos_in_theme', 'position')
            flash('Позиция в разделе изменена!', 'success')

        if request.form['path'] == '':
            flash('Строка адреса не может быть пуста!', 'error')
        elif request.form['path'] != p['path']:
            if not test_path(request.form['path']):
                flash('Страница с таким адресом уже есть!', 'error')
            else:
                update('path', 'path')
                flash('Адрес страницы изменен!', 'success')
                return redirect(url_for('page',
                                        file_name=request.form['path']))

        return render_template('create.html', sections=sections)

    elif request.method == 'GET':
        if p:
            return render_template('create.html', sections=sections, post=p)
        else:
            abort(404)

По сравнению с предыдущей версией здесь мы вынесли из ветки, обрабатывающей GET-запрос, получение записи из БД. Эти данные понадобятся также для POST-запроса, чтобы сравнивать их с текущим значением полей из request.form.

Дата изменения страницы фиксируется, только если менялся заголовок, описание или тело статьи.

При изменении пути страницы мы должны выполнить редирект на новый адрес. Если были выполнены еще какие-либо изменения, они должны быть сохранены в базу данных, а также не потеряться связанные с ними flask-сообщения. Поэтому проверка поля path выполняется последней.

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




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