Обновление Flask-SQLAlchemy создает новую запись в MySQL

Я пытаюсь обновить запись MySQL из flask-sqlalchemy, но вместо обновления текущей записи она добавляет новую. Но вот действительно странная вещь: когда я запускаю тот же код из приглашения Python, он корректно обновляется без добавления новой записи.

Вот соответствующая часть кода:

Во-первых, шаблон, который питает блог:

{% for post in posts %}
  <article class="blog">
    <header>
      <h2>{{ post.title|safe }}</h2>
    </header>
    <main>
      {{ post.content|safe }}
    </main>
    <footer>
      <p>{{ post.posted.strftime('%d %B %Y %I:%M')|safe }}<p>
      {% if session.logged_in %}
        <form action="{{ url_for('blog') }}" method="post">
          <div style="display:none;">
            <input type="hidden" name="blog_id" value="{{ post.id|safe }}">
          </div>

          <div class="form-group submit">
            <input type="submit" name="submit" class="btn" value="Edit Post">
            <input type="submit" name="submit" class="btn" value="Delete Post">
          </div>
        </form>
      {% endif %}
    </footer>
  </article>
{% endfor %}

Теперь код для просмотров:

@app.route('/blog', methods = ['GET', 'POST'])
def blog():
    # Get all records from database blog table:
    posts = models.Blog.query.order_by(models.Blog.posted.desc()).all()
    context = {
        'copyright': COPYRIGHT,
        'posts': posts
    }
    if request.method == 'POST':
        blog_id = request.form.get('blog_id')
        if request.form.get('submit') == 'Edit Post':
            return redirect(url_for('edit_entry', blog_id = blog_id))
        elif request.form.get('submit') == 'Delete Post':
            pass
    elif request.method == 'GET':
        return render_template('blog.html', **context)

@app.route('/edit_entry', methods = ['GET', 'POST'])
def edit_entry():
    form = BlogEntry() # A WTForms object.
    # blog_id is passed from a redirect. Tested and ensured it is passing proper value.
    blog_id = request.args['blog_id']
    post = models.Blog.query.filter_by(id = blog_id).one()
    if request.method == 'POST':
        post.title = form.title.data
        post.content = form.content.data
        db.session.commit()
        return redirect(url_for('blog'))
    elif request.method == 'GET':
        context = {
            'copyright': COPYRIGHT,
            'form': form,
        }
        form.title.data = post.title
        form.content.data = post.content
        return render_template('edit_entry.html', **context)

Это код, который находится сейчас в моем файле приложения. Я запустил точно такой же код из командной строки Python в терминале, и он отлично работает, но когда этот код запускается из файла приложения, он создает новую запись вместо обновления существующей.

Как примечание, я также попробовал:

models.Blog.query.filter_by(id=blog_id).update({
    'title': form.title.data,
    'content': form.content.data
})
db.session.commit()

и путем замены models.Blog на db.session.query(models.Blog). В основном, я попробовал каждый метод и комбинацию кода для обновления записей с использованием flask-sqlalchemy, которые я мог найти на этом форуме и других. Все та же проблема. Когда я запускаю их из приглашения python, они обновляют правильную запись в базе данных. Когда я запускаю их из приложения, они создают новую запись.

Если вы хотите увидеть больше кода, вы можете проверить весь проект здесь: https://github.com/tbellerose/lauraopfelphotography.com

1 ответ

Решение

Хорошо, спасибо Дэниелу и Дубе за то, что они указали мне правильные направления. В основном это было связано с тем, что я не запрашивал blog_id должным образом в методе POST edit_entry. Вот новый (и рабочий) код.

def edit_entry():
    form = BlogEntry()
    if request.method == 'POST':
        blog_id = request.form.get('blog_id')
        update = db.session.query(models.Blog).filter_by(id = blog_id).update({
             'title': request.form.get('title'),
             'content': request.form.get('content')
        })
        db.session.commit()
        return redirect(url_for('blog'))
    elif request.method == 'GET':
        blog_id = int(request.args['blog_id'])
        post = models.Blog.query.filter_by(id = blog_id).first_or_404()
        context = {
            'copyright': COPYRIGHT,
            'form': form,
            'blog_id': blog_id
        }
        form.title.data = post.title
        form.content.data = post.content
        return render_template('edit_entry.html', **context)

Там оказались две основные проблемы. Кулак был недосмотром: когда я скопировал шаблон edit_entry из шаблона new_entry, я забыл изменить действие формы, поэтому форма фактически отправляла по маршруту new_entry, таким образом, дублирование. После того, как я обнаружил эту проблему, я также понял, что хотя blog_id передавался в request.args методу 'GET', он не передавался в методе 'POST' (так как сообщение не приходило из перенаправления), поэтому Я на самом деле создал новое поле в шаблоне edit_entry для передачи blog_id обратно в POST.

Другие вопросы по тегам