[PYTHON] Creating a web application using Flask ③

CRUD description

First, I will explain the concept of CRUD, which is good to know in Web applications. CRUD is an acronym for Create, Read, Update, and Delete. Taking this application as an example, it means the following.

  1. ** Create **: New article creation function (new data creation)
  2. ** Read **: Article list display function, article detail display function (data reading)
  3. ** Update **: Article update function (data update)
  4. ** Delete **: Article deletion function (data deletion) When you think about a certain resource, you can create a set of functions by satisfying this CRUD.

Split views.py

Before adding CRUD functionality, split views.py into three parts: cafe.py, loging.py, and review.py. Create a views folder under the cafe_site folder, and create cafe.py, loging.py, reviews.py files in it. Blueprint Divide the views file for each file created earlier using Blueprint and make each into an application.

python:./cafe_site/views/cafe.py


from flask import Blueprint

cafe = Blueprint('cafe', __name__)

python:./cafe_site/views/loging.py


from flask import Blueprint

loging = Blueprint('loging', __name__)

python:./cafe_site/views/review.py


from flask import Blueprint

review = Blueprint('review', __name__)

And since the application name was changed to ** cafe **, ** logging **, ** review ** instead of ** app **, the routing is also @ cafe.route (), @ logging.route. Change to () ,@ review.route (),. Next, change the part of the **. / Cafe_site / __ init__.py ** file that imports views.

python:./__init__.py


from cafe_site.views.cafe import cafe
app.register_blueprint(cafe)

from cafe_site.views.loging import loging
app.register_blueprint(loging)

from cafe_site.views.reviews import review
app.register_blueprint(review, url_prefix='/users')

Now you can update reviews.py for features related to future articles, logging.py for features related to login, and cafe.py for features related to the cafe homepage.

Create a login authentication decorator

Finally, I would like to create a login authentication decorator that simplifies login authentication before moving on to adding CRUD functionality.

python:./cafe_site/views/loging.py


from functools import wraps

def login_required(loging):
    @wraps(loging)
    def inner(*args, **kwargs):
        if not session.get('logged_in'):
            return redirect(url_for('loging.login'))
        return loging(*args, **kwargs)
    return inner

For processes that require login, login authentication can be performed simply by adding the sentence @login_required immediately before the view method.

Create article posting function

Let's start creating the article posting function. [Creating a web application using Flask ③] Use the database function created in () to create an article posting function.

Added a new post link to the navigation bar

Edit theme.html and add a "review" link to the navigation bar for new posts.

html:./cafe_site/templates/theme.html


<ul class="main-nav">
    {% if not session.logged_in %}

    {% else %}
     <li><a href="{{ url_for('review.new_review') }}">review</a></li>

    {% endif %}
</ul>

html:./cafe_site/templates/theme.html


<!DOCTYPE html>
<html lang="ja">
    <head>
        {% block head %}
        <meta charset="utf-8">
        <title>{% block title %}{% endblock %}</title>
        <meta name="description" content="Cafe that provides a working space">
        <link rel="icon" type="image/png" href="/static/images/favicon.png ">
        <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- CSS -->
        <link rel="stylesheet" href="https://unpkg.com/ress/dist/ress.min.css">
        <link href="https://fonts.googleapis.com/css?family=Philosopher" rel="stylesheet">
        <link href="/static/style.css" rel="stylesheet">
        {% endblock %}
    </head>

    <body>
        <div id="{{ id }}" class="big-bg">
            <header class="page-header wrapper">
                <h1><a href="/"><img class="logo" src="/static/images/logo.svg" alt="Coffee House Home"></a></h1>
                <nav>
                    <ul class="main-nav">
                        {% if not session.logged_in %}
                        <li><a href="{{ url_for('cafe.news') }}">News</a></li>
                        <li><a href="{{ url_for('cafe.menu') }}">Menu</a></li>
                        <li><a href="{{ url_for('cafe.contact') }}">Contact</a></li>
                        <li><a href="{{ url_for('loging.login') }}">login</a></li>
                        {% else %}
                        <li><a href="{{ url_for('cafe.news') }}">News</a></li>
                        <li><a href="{{ url_for('cafe.menu') }}">Menu</a></li>
                        <li><a href="{{ url_for('cafe.contact') }}">Contact</a></li>
                        <li><a href="{{ url_for('review.new_review') }}">review</a></li>
                        <li><a href="{{ url_for('review.show_reviews') }}">board</a></li>
                        <li><a href="{{ url_for('loging.logout') }}">logout</a></li>
                        {% endif %}
                    </ul>
                </nav>
            </header>
            {% for message in get_flashed_messages() %}
                <div class="alert">
                  <font color="red">
                    <p>※{{ message }}</p>
                  </font>
                </div>
            {% endfor %}
            {% block content %}
            {% endblock %}
        </div>
        {% block content2 %}
        {% endblock %}
        {% block footer %}
        {% endblock %}
    </body>
</html>

python:./cafe_site/views/reviews.py


@review.route('/reviews/new', methods=['GET'])
@login_required
def new_review():
    return render_template('reviews/review.html', id="review")

Creating an article submission form

Finally, edit the review.html created in Creating a web application using Flask ① a little.

html:./cafe_site/templates/views/reviews.html


{% extends "theme.html" %}
{% block title %}Coffee House{% endblock %}
{% block head %}
  {{ super() }}
  <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
{% endblock %}
{% block content %}
    <div class="form-content wrapper">
        <h2 class="page-title">Review</h2>
        <form method="POST" action="{{ url_for('review.add_review') }}">

            <div class="star-rating">
                <div class="star-rating__wrap">
                  <input class="star-rating__input" id="star-rating-5" type="radio" name="star" value=5>
                  <label class="star-rating__ico fa fa-star-o fa-lg" for="star-rating-5" title="5 out of 5 stars"></label>
                  <input class="star-rating__input" id="star-rating-4" type="radio" name="star" value=4>
                  <label class="star-rating__ico fa fa-star-o fa-lg" for="star-rating-4" title="4 out of 5 stars"></label>
                  <input class="star-rating__input" id="star-rating-3" type="radio" name="star" value=3>
                  <label class="star-rating__ico fa fa-star-o fa-lg" for="star-rating-3" title="3 out of 5 stars"></label>
                  <input class="star-rating__input" id="star-rating-2" type="radio" name="star" value=2>
                  <label class="star-rating__ico fa fa-star-o fa-lg" for="star-rating-2" title="2 out of 5 stars"></label>
                  <input class="star-rating__input" id="star-rating-1" type="radio" name="star" value=1>
                  <label class="star-rating__ico fa fa-star-o fa-lg" for="star-rating-1" title="1 out of 5 stars"></label>
                </div>
            </div>
            <div>
                <label for="title">title</label>
                <input placeholder="title" name="title" type="text"/>
            </div>
            <div>
                <label for="message">message</label>
                <textarea id="message" placeholder="message" name="text"></textarea>
            </div>
            <input type="submit" class="button" value="Post">
        </form>
    </div>
{% endblock %}
{% block footer %}
    <footer>
        <div class="wrapper">
            <p><small>&copy; Coffee House</small></p>
        </div>
    </footer>
{% endblock %}

Posting function

So far, we have created a submission form. Next, create a function to save the articles posted from the posting form to the database.

Create add_review

In review.html, the form is posted to ʻAction =" {{url_for ('review.add_review')}} "`. Create ** review.add_review ** and add a process to receive the posted content and save it in the database. Add ** add_review ** to views / reviews.py.

python:./cafe_site/views/reviews.py


@review.route('/reviews', methods=['POST'])
@login_required
def add_review():
    review = Review(
        star=request.form['star'],
        title=request.form['title'],
        text=request.form['text']
    )
    db.session.add(review)
    db.session.commit()
    flash('New article created')
    return redirect(url_for('review.show_reviews'))

As with the login form creation, specify the POST method when sending data. We are processing whether you are logged in with @login_required. If you are logged in, use the Review model created in the previous chapter to create a model instance for the article title and content sent.

python:./cafe_site/views/reviews.py


review = Review(
        star=request.form['star'],
        title=request.form['title'],
        text=request.form['text']
    )

Then, for the model instance created, perform the following processing to save the new article content in the database.

python:./cafe_site/views/reviews.py


db.session.add(review)
db.session.commit()

db.session.add () adds new content and db.session.commit () writes the data to the database.

Article detail function creation (Read)

Next, add a blog detail function so that details such as the article body are displayed.

Added "Read more" link

In addition to each title on the list screen, add a "Read more" link.

html:./cafe_site/templates/views/index.html


{% extends "theme.html" %}
{% block title %}Coffee House{% endblock %}
{% block head %}
  {{ super() }}
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
  <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
{% endblock %}
{% block content %}
<div class="wrapper">
  <h2 class="page-title">board</h2>
  {% for review in reviews %}
  <div class="card bg-transparent">
    <div class="card-body">
      {% if review.star == 1 %}
      <h5 class="card-title">rating : <img src="/static/images/star.png " width="15" height="15"></h5>
      {% endif %}
      {% if review.star  == 2 %}
      <h5 class="card-title">rating : <img src="/static/images/star.png " width="15" height="15"><img src="/static/images/star.png " width="15" height="15"></h5>
      {% endif %}
      {% if review.star == 3 %}
      <h5 class="card-title">rating : <img src="/static/images/star.png " width="15" height="15"><img src="/static/images/star.png " width="15" height="15"><img src="/static/images/star.png " width="15" height="15"></h5>
      {% endif %}
      {% if review.star == 4 %}
      <h5 class="card-title">rating : <img src="/static/images/star.png " width="15" height="15"><img src="/static/images/star.png " width="15" height="15"><img src="/static/images/star.png " width="15" height="15"><img src="/static/images/star.png " width="15" height="15"></h5>
      {% endif %}
      {% if review.star == 5 %}
      <h5 class="card-title">rating : <img src="/static/images/star.png " width="15" height="15"><img src="/static/images/star.png " width="15" height="15"><img src="/static/images/star.png " width="15" height="15"><img src="/static/images/star.png " width="15" height="15"><img src="/static/images/star.png " width="15" height="15"></h5>
      {% endif %}
      <h5 class="card-subtitle">{{ review.title }}</h5>
      <a class="card-link" href="{{ url_for('review.show_review', id=review.id) }}" >read more</a>
    </div>
  </div>
      {% else %}
No posts
      {% endfor %}
</div>
{% endblock %}
{% block footer %}
    <footer>
        <div class="wrapper">
            <p><small>&copy; Coffee House</small></p>
        </div>
    </footer>
{% endblock %}

Here, arguments have been added to {{url_for ('review.show_review', id = review.id)}} and url_for. This will allow the id of the article you clicked on to be passed when show_review () is called.

Add show_review

Add a new show_review to views / reviews.py.

python:./cafe_site/views/reviews.py


@review.route('/board')
@login_required
def show_reviews():
    reviews = Review.query.order_by(Review.id.desc()).all()
    return render_template('reviews/index.html', reviews=reviews, id="board")

@review.route('/reviews/<int:id>', methods=['GET'])
@login_required
def show_review(id):
    review = Review.query.get(id)
    return render_template('reviews/show.html', review=review, id="show")

In reviews = Review.query.order_by (Review.id.desc ()). All (), specify the variable * id * passed in url_for. In addition, add show_review (id) and argument name so that the variable * id * can be referenced.

In the show_review method, you can get the article with the passed id from the database just by writing review = Review.query.get (id).

View details of article content

Finally, create a show.html file to display the details of the article content.

html:./cafe_site/templates/views/show.html


{% extends "theme.html" %}
{% block title %}Coffee House{% endblock %}
{% block head %}
  {{ super() }}
{% endblock %}
{% block content %}
<div class="show-content wrapper">

  <h2>{{ review.title }}</h2>

    {% if review.star == 1 %}
      <h2>Evaluation: <img src="/static/images/star.png " width="40" height="40"></h2>
    {% endif %}
    {% if review.star  == 2 %}
      <h2>rating : <img src="/static/images/star.png " width="40" height="40"><img src="/static/images/star.png " width="40" height="40"></h2>
    {% endif %}
    {% if review.star == 3 %}
      <h2>rating : <img src="/static/images/star.png " width="40" height="40"><img src="/static/images/star.png " width="40" height="40"><img src="/static/images/star.png " width="40" height="40"></h2>
    {% endif %}
    {% if review.star == 4 %}
      <h2>rating : <img src="/static/images/star.png " width="40" height="40"><img src="/static/images/star.png " width="40" height="40"><img src="/static/images/star.png " width="40" height="40"><img src="/static/images/star.png " width="40" height="40"></h2>
    {% endif %}
    {% if review.star == 5 %}
      <h2>rating : <img src="/static/images/star.png " width="40" height="40"><img src="/static/images/star.png " width="40" height="40"><img src="/static/images/star.png " width="40" height="40"><img src="/static/images/star.png " width="40" height="40"><img src="/static/images/star.png " width="40" height="40"></h2>
    {% endif %}

    <br> {{ review.text|safe }}

    <br>
    <br>Post date and time{{ review.created_at }}
</div>
{% endblock %}

Creating an article editing function (Update)

Add an article editing function so that you can edit the posted article.

Add edit button

Add an "Edit" button to the article details screen.

html:./cafe_site/templates/views/show.html


<form action="{{ url_for('review.edit_review', id=review.id) }}" method="GET">
    <input type="submit" class="button" value="Edit">
</form>

Add edit_review

Add edit_review to views / reviews.py so that the edit screen is returned when you click the edit button.

python:./cafe_site/views/reviews.py


@review.route('/reviews/<int:id>/edit', methods=['GET'])
@login_required
def edit_review(id):
    review = Review.query.get(id)
    return render_template('reviews/edit.html', review=review)

Create edit screen

Create a new edit.html and create an edit screen.

html:./cafe_site/templates/views/edit.html


{% extends "theme.html" %}
{% block title %}Coffee House{% endblock %}
{% block head %}
  {{ super() }}
  <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
{% endblock %}
{% block content %}
<div class="edit wrapper">
  <h2 class="page-title">review</h2>
  <form action="{{ url_for('review.update_review', id=review.id) }}" method=post class=add-review>

    <div class="star-rating">
      <div class="star-rating__wrap">
        <input class="star-rating__input" id="star-rating-5" type="radio" name="star" value=5>
        <label class="star-rating__ico fa fa-star-o fa-lg" for="star-rating-5" title="5 out of 5 stars"></label>
        <input class="star-rating__input" id="star-rating-4" type="radio" name="star" value=4>
        <label class="star-rating__ico fa fa-star-o fa-lg" for="star-rating-4" title="4 out of 5 stars"></label>
        <input class="star-rating__input" id="star-rating-3" type="radio" name="star" value=3>
        <label class="star-rating__ico fa fa-star-o fa-lg" for="star-rating-3" title="3 out of 5 stars"></label>
        <input class="star-rating__input" id="star-rating-2" type="radio" name="star" value=2>
        <label class="star-rating__ico fa fa-star-o fa-lg" for="star-rating-2" title="2 out of 5 stars"></label>
        <input class="star-rating__input" id="star-rating-1" type="radio" name="star" value=1>
        <label class="star-rating__ico fa fa-star-o fa-lg" for="star-rating-1" title="1 out of 5 stars"></label>
      </div>
    </div>
      <div>
        <label for="name">title</label>
        <input placeholder="title" name="title" type="text" value={{ review.title }}/>
      </div>
      <div class="form-group">
        <label for="message">message</label>
        <textarea id="message" placeholder="Review" name="text">{{ review.text | safe }}</textarea>
      </div>
      <input type="submit" class="button" value="update">
  </form>
{% endblock %}
{% block footer %}
    <footer>
        <div class="wrapper">
            <p><small>&copy; Coffee House</small></p>
        </div>
    </footer>
{% endblock %}

Creating update_review

Create update_review in reviews.py and add a process to receive the edits entered in the form and update the database.

python:./cafe_site/views/reviews.py


@review.route('/reviews/<int:id>/update', methods=['POST'])
@login_required
def update_review(id):
    review = Review.query.get(id)
    review.star = request.form['star']
    review.title = request.form['title']
    review.text = request.form['text']
    db.session.merge(review)
    db.session.commit()
    flash('Article updated')
    return redirect(url_for('review.show_reviews'))

** star **, ** title **, ** text ** are updated for the review obtained by Review.query.get (id). When creating, add, but when updating, use db.session.merge (review) and finally db.session.commit () to update the database.

Creating an article deletion function (Delete)

Finally, add the ability to delete articles.

Add delete button

html:./cafe_site/templates/views/show.html


<form action="{{ url_for('review.delete_review', id=review.id) }}" method="post">
    <input type="submit" class="button" value="Delete">
</form>

Add delete_review

Add ** delete_review ** to views / reviews.py and add a process to delete the article when the delete button is pressed.

python:./cafe_site/views/reviews.py


@review.route('/reviews/<int:id>/delete', methods=['POST'])
@login_required
def delete_review(id):
    review = Review.query.get(id)
    db.session.delete(review)
    db.session.commit()
    flash('Post deleted')
    return redirect(url_for('review.show_reviews'))

To delete the contents of the database, specify db.session.delete (review). You have now added all the CRUD functionality. Finally, let's take a look at the big picture of reviews.py.

python:./cafe_site/views/reviews.py


from flask import request, redirect, url_for, render_template, flash, session
from cafe_site import db
from cafe_site import app
from cafe_site.models.reviews import Review
from cafe_site.views.loging import login_required
from flask import Blueprint

review = Blueprint('review', __name__)

@review.route('/board')
@login_required
def show_reviews():
    reviews = Review.query.order_by(Review.id.desc()).all()
    return render_template('reviews/index.html', reviews=reviews, id="board")

@review.route('/reviews', methods=['POST'])
@login_required
def add_review():
    review = Review(
        star=request.form['star'],
        title=request.form['title'],
        text=request.form['text']
    )
    db.session.add(review)
    db.session.commit()
    flash('New article created')
    return redirect(url_for('review.show_reviews'))

@review.route('/reviews/new', methods=['GET'])
@login_required
def new_review():
    return render_template('reviews/review.html', id="review")

@review.route('/reviews/<int:id>', methods=['GET'])
@login_required
def show_review(id):
    review = Review.query.get(id)
    return render_template('reviews/show.html', review=review, id="show")

@review.route('/reviews/<int:id>/edit', methods=['GET'])
@login_required
def edit_review(id):
    review = Review.query.get(id)
    return render_template('reviews/edit.html', review=review)

@review.route('/reviews/<int:id>/update', methods=['POST'])
@login_required
def update_review(id):
    review = Review.query.get(id)
    review.star = request.form['star']
    review.title = request.form['title']
    review.text = request.form['text']
    db.session.merge(review)
    db.session.commit()
    flash('Article updated')
    return redirect(url_for('review.show_reviews'))

@review.route('/reviews/<int:id>/delete', methods=['POST'])
@login_required
def delete_review(id):
    review = Review.query.get(id)
    db.session.delete(review)
    db.session.commit()
    flash('Post deleted')
    return redirect(url_for('review.show_reviews'))

The continuation will be explained in Creating a web application using Flask ④.

Recommended Posts

Creating a web application using Flask ②
Creating a web application using Flask ①
Creating a web application using Flask ③
Creating a web application using Flask ④
Creating a voice transcription web application
Try using the web application framework Flask
Creating a data analysis application using Streamlit
Web application using Bottle (1)
Creating an interactive application using a topic model
[GCP] Procedure for creating a web application with Cloud Functions (Python + Flask)
I want to make a web application using React and Python flask
Web application development with Flask
Web application with Python + Flask ② ③
Web application with Python + Flask ④
(Python) Try to develop a web application using Django
[Raspberry Pi] Publish a web application on https using Apache + WSGI + Python Flask
WEB application development using Django [Django startup]
WEB application development using Django [Application addition]
Creating a Flask server with Docker
Creating a simple table using prettytable
Creating a simple app with flask
Make Flask a Cloud Native application
Creating a learning model using MNIST
Let's make a WEB application for phone book with flask Part 1
Web application created with Python + Flask (using VScode) # 1-Virtual environment construction-
Python: Introduction to Flask: Creating a number identification app using MNIST
Build a Flask / Bottle-like web application on AWS Lambda with Chalice
Let's make a WEB application for phone book with flask Part 2
Let's make a WEB application for phone book with flask Part 3
Let's make a WEB application for phone book with flask Part 4
WEB application development using Django [Model definition]
WEB application development using Django [Initial settings]
WEB application development using django-Development environment construction-
Display matplotlib diagrams in a web application
Impressions of using Flask for a month
WEB application development using Django [Request processing]
WEB application development using Django [Template addition]
[Python] A quick web application with Bottle!
Create a simple web app with flask
Run a Python web application with Docker
Create a web service with Docker + Flask
I tried benchmarking a web application framework
I made a WEB application with Django
Create a Python3.4 + Nginx + uWSGI + Flask Web application execution environment with haste using pyenv on Ubuntu 12.04
Flask application settings
Start a web server using Bottle and Flask (I also tried using Apache)
Implement a simple application with Python full scratch without using a web framework.
[Python] Split a large Flask file using Blueprint
WEB application development using Django [Admin screen creation]
Create a web map using Python and GDAL
Steps to develop a web application in Python
Launch a web server with Python and Flask
What I was addicted to when creating a web application in a windows environment
Let's make an A to B conversion web application with Flask! From scratch ...
Go beginner tried to create a cloud native web application using Datastore / GAE
[ES Lab] I tried to develop a WEB application with Python and Flask ②
A story about creating a web application that automatically generates Minecraft sound block performances
Try creating a web application with Vue.js and Django (Mac)-(1) Environment construction, application creation
The day when a beginner who started programming for two and a half months made a web application using Flask
[Day 9] Creating a model
Creating a Home screen