Статьи

Flask 101: добавление, редактирование и отображение данных

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

Давайте начнем!

Добавление данных в базу данных

Давайте начнем с написания нашей новой формы альбома. Откройте forms.py файл, который мы создали в последнем уроке, и добавьте следующий класс:

class AlbumForm(Form):
    media_types = [('Digital', 'Digital'),
                   ('CD', 'CD'),
                   ('Cassette Tape', 'Cassette Tape')
                   ]
    artist = StringField('Artist')
    title = StringField('Title')
    release_date = StringField('Release Date')
    publisher = StringField('Publisher')
    media_type = SelectField('Media', choices=media_types)

Это определяет все поля, которые нам нужны для создания нового  Album. Теперь нам нужно открыть main.py и добавить функцию для обработки того, что происходит, когда мы хотим создать новый альбом.

# main.py
 
from app import app
from db_setup import init_db, db_session
from forms import MusicSearchForm, AlbumForm
from flask import flash, render_template, request, redirect
from models import Album
 
init_db()
 
 
@app.route('/', methods=['GET', 'POST'])
def index():
    search = MusicSearchForm(request.form)
    if request.method == 'POST':
        return search_results(search)
 
    return render_template('index.html', form=search)
 
 
@app.route('/results')
def search_results(search):
    results = []
    search_string = search.data['search']
 
    if search.data['search'] == '':
        qry = db_session.query(Album)
        results = qry.all()
 
    if not results:
        flash('No results found!')
        return redirect('/')
    else:
        # display results
        return render_template('results.html', table=table)
 
 
@app.route('/new_album', methods=['GET', 'POST'])
def new_album():
    """
    Add a new album
    """
    form = AlbumForm(request.form)
    return render_template('new_album.html', form=form)
 
 
if __name__ == '__main__':
    app.run()

Здесь мы добавляем импорт для импорта нашей новой формы вверху, а затем создаем новую функцию с именем new_album(). Затем мы создаем экземпляр нашей новой формы и передаем его нашей render_template()функции, которая будет отображать файл с именем new_album.html. Конечно, этот HTML-файл еще не существует, так что это будет следующее, что нам нужно создать. Когда вы сохраняете этот новый HTML-файл, убедитесь, что вы сохранили его в templates папке внутри вашей musicdb папки.

Создав  new_album.html , добавьте в него следующий HTML-код:

<doctype html>
<title>New Album - Flask Music Database</title>
<h2>New Album</h2>
 
{% from "_formhelpers.html" import render_field %}
<form method=post>
    <dl>
        {{ render_field(form.artist) }}
        {{ render_field(form.title) }}
        {{ render_field(form.release_date) }}
        {{ render_field(form.publisher) }}
        {{ render_field(form.media_type) }}
    </dl>
    <p><input type=submit value=Submit>
</form>

Этот код будет отображать каждое поле в форме, а также создает кнопку « Отправить» , чтобы мы могли сохранить наши изменения. Последнее, что нам нужно сделать, это обновить наш  index.html код, чтобы в нем была ссылка, которая загрузит нашу новую страницу альбома. По сути, все, что нам нужно сделать, это добавить следующее:

<a href="{{ url_for('.new_album') }}"> New Album </a>

Таким образом, полное изменение выглядит следующим образом:

<doctype html>
<head>
    <title>Flask Music Database</title>
</head>
 
<h2>Flask Music Database</h2>
 
<p><p>
<a href="{{ url_for('.new_album') }}"> New Album </a>
 
{% with messages = get_flashed_messages() %}
  {% if messages %}
    <ul class=flashes>
    {% for message in messages %}
      <li>{{ message }}</li>
    {% endfor %}
    </ul>
  {% endif %}
{% endwith %}
 
{% from "_formhelpers.html" import render_field %}
<form method=post>
  <dl>
    {{ render_field(form.select) }}
    <p>
    {{ render_field(form.search) }}
  </dl>
  <p><input type=submit value=Search>
</form>

Теперь, если вы загрузите главную страницу вашего веб-приложения, она должна выглядеть так:

Если вы нажмете на  ссылку « Новый альбом» , вы должны увидеть что-то вроде этого в вашем браузере:

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

Сохранение данных

Нам нужна наша новая форма альбома, чтобы сохранить данные при нажатии кнопки отправки. Что происходит при нажатии кнопки « Отправить» ? Если вы вернетесь к  new_album.html файлу, вы заметите, что мы установили метод формы на  POST. Поэтому нам нужно обновить код,  main.py чтобы он что-то делал  POST.

Чтобы сохранить, нам нужно обновить  new_album() функцию,  main.py чтобы она выглядела следующим образом:

@app.route('/new_album', methods=['GET', 'POST'])
def new_album():
    """
    Add a new album
    """
    form = AlbumForm(request.form)
 
    if request.method == 'POST' and form.validate():
        # save the album
        album = Album()
        save_changes(album, form, new=True)
        flash('Album created successfully!')
        return redirect('/')
 
    return render_template('new_album.html', form=form)

Теперь, когда мы публикуем, мы создаем экземпляр Album и передаем его  save_changes() функции вместе с объектом формы. Мы также передаем флаг, который указывает, является ли элемент новым или нет. Мы рассмотрим, почему я добавил этот последний позже в статье. Пока что нам нужно создать save_changes()функцию. Сохраните следующий код в  main.py скрипте.

def save_changes(album, form, new=False):
    """
    Save the changes to the database
    """
    # Get data from form and assign it to the correct attributes
    # of the SQLAlchemy table object
    artist = Artist()
    artist.name = form.artist.data
 
    album.artist = artist
    album.title = form.title.data
    album.release_date = form.release_date.data
    album.publisher = form.publisher.data
    album.media_type = form.media_type.data
 
    if new:
        # Add the new album to the database
        db_session.add(album)
 
    # commit the data to the database
    db_session.commit()

Здесь мы извлекаем данные из формы и назначаем их атрибутам объекта альбома соответственно. Вы также заметите, что нам нужно создать  Artist экземпляр, чтобы правильно добавить исполнителя в альбом. Если вы этого не сделаете, вы получите ошибку, связанную с SQLAlchemy. Новый параметр используется здесь для добавления новой записи в базу данных.

Вот сессия, которую я сделал, чтобы проверить это:

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

Давайте сделаем это дальше!

Отображение результатов поиска

Я предпочитаю иметь табулированные результаты, которые требуют использования таблицы. Вместо того, чтобы возиться с элементами таблицы HTML, вы можете загрузить еще одно расширение Flask, которое называется Flask Table . Чтобы установить его, просто используйте  pip так:

pip install flask_table

Теперь, когда у нас установлена ​​Flask Table, нам нужно создать определение таблицы. Давайте создадим файл, который мы будем вызывать,  tables.py и сохраним его в нашей  musicdb папке. Откройте это в вашем редакторе и добавьте следующий код:

from flask_table import Table, Col
 
class Results(Table):
    id = Col('Id', show=False)
    artist = Col('Artist')
    title = Col('Title')
    release_date = Col('Release Date')
    publisher = Col('Publisher')
    media_type = Col('Media')

Когда вы определяете класс таблицы, вам нужно присвоить атрибутам класса то же имя, что и в объекте, который будет передан ему. В этом случае я использовал атрибуты  Album класса здесь. Теперь нам просто нужно создать  results.html файл и сохранить его в  templates папке. Вот что должно идти в этом файле:

<doctype html>
<title>Search Results - Flask Music Database</title>
{{ table }}

Как видите, все, что нам нужно было сделать, это добавить  title элемент, который на самом деле является необязательным, и добавить табличный объект в Jinja. Теперь, когда вы запустите поиск с пустой строкой, вы должны увидеть что-то вроде этого:

Да, это довольно просто, но это работает, и теперь вы можете видеть все в вашей базе данных.

Редактирование данных в базе данных

Последний пункт, который нам нужно рассмотреть, — это как редактировать данные в базе данных. Один из самых простых способов сделать это — поиск элемента и добавление пользователю способа редактировать найденные элементы. Откройте  tables.py файл и добавьте  LinkCol:

from flask_table import Table, Col, LinkCol
 
class Results(Table):
    id = Col('Id', show=False)
    artist = Col('Artist')
    title = Col('Title')
    release_date = Col('Release Date')
    publisher = Col('Publisher')
    media_type = Col('Media')
    edit = LinkCol('Edit', 'edit', url_kwargs=dict(id='id'))

LinkCol Принимает имя столбца в виде строки вместе с тем, что конечная точка должна быть. Конечная точка — это функция, которая будет вызываться при нажатии на ссылку. Мы также передаем идентификатор записи, чтобы мы могли найти его в базе данных (то есть  url_kwargs аргумент). Теперь нам нужно обновить наш  main.py файл с помощью функции edit():

@app.route('/item/<int:id>', methods=['GET', 'POST'])
def edit(id):
    qry = db_session.query(Album).filter(
                Album.id==id)
    album = qry.first()
 
    if album:
        form = AlbumForm(formdata=request.form, obj=album)
        if request.method == 'POST' and form.validate():
            # save edits
            save_changes(album, form)
            flash('Album updated successfully!')
            return redirect('/')
        return render_template('edit_album.html', form=form)
    else:
        return 'Error loading #{id}'.format(id=id)

Первый пункт, на который следует обратить внимание, это то, что у нас есть настроенный маршрут для URL, который использует ID, который мы передаем ему, чтобы создать уникальный URL. Затем мы выполняем поиск в базе данных для рассматриваемого идентификатора. Если мы найдем идентификатор, то мы можем создать нашу форму, используя ту же форму, которую мы создали ранее. Однако на этот раз мы передаем ему объект альбома, чтобы форма была предварительно заполнена данными, поэтому нам есть что редактировать. Если пользователь нажимает кнопку « Отправить» на этой странице, он сохраняет запись в базе данных и высылает пользователю сообщение об этом. Если мы передадим неверный идентификатор, то пользователю будет показано сообщение.

Теперь, когда мы запускаем пустой поиск из ранее, вы должны увидеть это:

Давайте нажмем на ссылку редактирования первого ряда:

Here, I edit most of the fields on the page. Then I click Submit and get this:

Supposedly, the entry was updated with my changes. To verify, try running another empty search:

That looks right, so now we have the editing functionality complete!

Wrapping Up

At this point, you should be able to add entries to the database, display all the entries, and edit said entries. The main item missing is how to filter the search results so that it actually looks for the search term you want instead of always returning everything in the database. We should probably also add the ability to delete an item from the database. Those are the topics we will look at in the next article. For now, have fun and happy coding!

Download Code

Download a tarball of the code from this article.