Редактирование статей сайта на 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 выполняется последней.