[PYTHON] Creating a web application using Flask ①

Set Flask

First of all [HTML template](https://sbcr-dl-and-idea.s3-ap-northeast-1.amazonaws.com/2019-03-16-98892-HTML+%26+CSS%E3%81 % A8Web% E3% 83% 87% E3% 82% B6% E3% 82% A4% E3% 83% B3% E5% 85% A5% E9% 96% 80% E8% AC% 9B% E5% BA% A7 Based on (/HTML-CSS-Webdesign-2.zip), I created an html / css file for the cafe-only site, and performed routing processing using Flask of Python so that it can be accessed from the URL. (Since it is an explanation article of Flask, I will not explain how to create the original HTML file here.)

app.py


flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def index():
     return render_template('index.html', id="home")

@app.route('/menu')
def menu():
     return render_template('menu.html', id="menu")

@app.route('/news')
def news():
     return render_template('news.html', id="news")

@app.route('/contact')
def contact():
     return render_template('contact.html', id="contact")


if __name__ == '__main__':
    app.debug = True
    app.run()

Processing input and output forms

At that time, I had little programming experience, and I had very little experience with Python, let alone Flask, so I tried to process input forms and output forms easily for practice.

app.py


from flask import Flask, request, render_template

app = Flask(__name__)

@app.route('/')
def index():
     return render_template('index.html', id="home")

@app.route('/menu')
def menu():
     return render_template('menu.html', id="menu")

@app.route('/news')
def news():
     return render_template('news.html', id="news")

@app.route('/contact')
def contact():
     return render_template('contact.html', id="contact")

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

@app.route('/review', methods=['POST'])
def view_board():
     if request.form['username'] and request.form['star'] and request.form['review']:
          return render_template('review.html',  username=request.form['username'], star=request.form['star'], review=request.form['review'])


if __name__ == '__main__':
    app.debug = True
    app.run()

review.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="/review">
            <div>
                <label for="name">name</label>
                <input placeholder="name" name="username" type="text"/>
            </div>
            <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="message">message</label>
                <textarea id="message" placeholder="Review" name="review"></textarea>
            </div>
            <input type="submit" class="button" value="Send">
        </form>
    </div>
{% endblock %}
{% block content2 %}
    <div class="wrapper board">
      <p>name : {{username}}</p>
    {% if star == '1' %}
      <p>rating : <img src="/static/images/star.png " width="15" height="15"></p>
    {% endif %}
    {% if star == '2' %}
      <p>rating : <img src="/static/images/star.png " width="15" height="15"><img src="/static/images/star.png " width="15" height="15"></p>
    {% endif %}
    {% if star == '3' %}
    <p>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"></p>
    {% endif %}
    {% if star == '4' %}
    <p>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"></p>
    {% endif %}
    {% if star == '5' %}
    <p>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"></p>
    {% endif %}
      <p>message : {{review}}</p>
    </div>
{% endblock %}
{% block footer %}
    <footer>
        <div class="wrapper">
            <p><small>&copy; Coffee House</small></p>
        </div>
    </footer>
{% endblock %}

I dealt with ** jinja2 ** for the first time here, but I tried to use the loop syntax when processing the star rating output, but it didn't work, so I used the ** if-else statement **. The output processing of star rating is described. (The star rating input was * font-awesome * and the output was a * png file *.)

Application folder structure

In processing various functions, it is better to separate the files for each function because there are advantages such as readability, readability, and ease of updating, so I decided to consider the file structure first.

Creating the application body file

Create a cafe_site folder in the root directory and create a ** __ init__.py ** file in it

python:./cafe_site/__init__.py


from flask import Flask

app=Flask(__name__)

import cafe_site.views

Creating a view file

Next, create a views folder in the cafe_site folder, and save the script that outputs the cafe site created earlier as a views.py file in it.

python:./cafe_site/views.py


from flask import request, redirect, url_for, render_template, flash, session
from cafe_site import app


@app.route('/')
def index():
     return render_template('cafe_site/index.html', id="home")


@app.route('/menu')
def menu():
     return render_template('cafe_site/menu.html', id="menu")


@app.route('/news')
def news():
     return render_template('cafe_site/news.html', id="news")


@app.route('/contact')
def contact():
     return render_template('cafe_site/contact.html', id="contact")


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


@app.route('/review', methods=['POST'])
def view_board():
     if request.form['username'] and request.form['star'] and request.form['review']:
          return render_template('review.html',  username=request.form['username'], star=request.form['star'], review=request.form['review'])

Creating a startup file

Finally, create the startup file server.py “directly under the root directory.

python:./server.py


from cafe_site import app

if __name__ == '__main__':
    app.run(debug=True)

Now you can start the flask application for the time being.

Creating a config file

The config.py file is a file that describes the environment information and setting information of the application.

python:./cafe_site/config.py


DEBUG = True

In this application, debug mode is turned on as setting information. (Delete'debug = True'listed in server.py.)

Enable config.py

Declare to treat the contents of config.py as config in the init.py file to enable the config file.

python:./__init__.py


app.config.from_object('cafe_site.config')

MTV framework

Here, I would like to divide Flask into three parts, Model, Template, and View, and process each function.

When accessed by a user, Flask handles it as follows:

1. User accesses a URL

2. Read the accessed URL and execute the process associated with the predefined URL (View)

3. Access the database through an object called a model as needed during processing (Model)

4. Return a template such as HTML to be displayed to the user at the end of the process (Template)

Template Place the templates folder under the cafe_site folder, and arrange the HTML files to be displayed to the user in it.

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">
                        <li><a href="/news">News</a></li>
                        <li><a href="/menu">Menu</a></li>
                        <li><a href="/contact">Contact</a></li>
                        <li><a href="/review">Review</a></li>
                    </ul>
                </nav>
            </header>
            {% block content %}
            {% endblock %}
        </div>
        {% block content2 %}
        {% endblock %}
        {% block footer %}
        {% endblock %}
    </body>
</html>

html:./cafe_site/templates/index.html


{% extends "theme.html" %}
{% block title %}Coffee House{% endblock %}
{% block head %}
  {{ super() }}
{% endblock %}
{% block content %}
    <div class="home-content wrapper">
        <h2 class="page-title">We Make Your Relax Space </h2>
        <p>Why don't you use a calm cafe in the space where you work or study? We provide a relaxing space.</p>
        <a class="button" href="/menu">View menu</a>
    </div><!-- /.home-content -->
{% endblock %}

html:./cafe_site/templates/menu.html


{% extends "theme.html" %}
{% block title %}Coffee House{% endblock %}
{% block head %}
  {{ super() }}
{% endblock %}
{% block content %}
    <div class="menu-content wrapper">
        <h2 class="page-title">Menu</h2>
        <p>
Coffee House offers a Mediterranean diet that will help you focus. It features a menu that uses seafood ingredients.
Carefully selected mocha beans are used for the blended coffee. Mediterranean food, good coffee and a calm space will allow you to work and study better.
        </p>
    </div><!-- /.menu-content -->
{% endblock %}
{% block content2 %}
    <div class="wrapper grid">
        <div class="item">
            <img src="/static/images/menu1.jpg " alt="">
            <p>Coffee set</p>
        </div>
        <div class="item">
            <img src="/static/images/menu2.jpg " alt="">
            <p>Latte</p>
        </div>
        <div class="item">
            <img src="/static/images/menu3.jpg " alt="">
            <p>pancake</p>
        </div>
        <div class="item">
            <img src="/static/images/menu4.jpg " alt="">
            <p>soup</p>
        </div>
        <div class="item">
            <img src="/static/images/menu5.jpg " alt="">
            <p>salad</p>
        </div>
        <div class="item">
            <img src="/static/images/menu6.jpg " alt="">
            <p>oyster</p>
            </div>
        <div class="item">
            <img src="/static/images/menu7.jpg " alt="">
            <p>Tom yam kung</p>
        </div>
        <div class="item">
            <img src="/static/images/menu8.jpg " alt="">
            <p>Seafood pasta</p>
        </div>
        <div class="item">
            <img src="/static/images/menu9.jpg " alt="">
            <p>Raspberry cake</p>
        </div>
    </div><!-- /.grid -->
{% endblock %}
{% block footer %}
    <footer>
        <div class="wrapper">
            <p><small>&copy; Coffee House</small></p>
        </div>
    </footer>
{% endblock %}

html:./cafe_site/templates/news.html


{% extends "theme.html" %}
{% block title %}Coffee House{% endblock %}
{% block head %}
  {{ super() }}
{% endblock %}
{% block content %}
    <div class="wrapper">
        <h2 class="page-title">News</h2>
    </div><!-- /.wrapper -->
{% endblock %}
{% block content2 %}
    <div class="news-contents wrapper">
        <article>
            <header class="post-info">
                <h2 class="post-title">The interior of the store has been renewed.</h2>
                <p class="post-date">1/1 <span>2020</span></p>
                <p class="post-cat">Category: Shop introduction</p>
            </header>
            <img src="/static/images/wall.jpg " alt="Inside the store">
            <p>
I changed the interior of the store a little.
            </p>
            <p>
The space is more refreshing than before.
            </p>
            <p>WCB CAFE offering Mediterranean diet and blended coffee.</p>
        </article>

        <aside>
            <h3 class="sub-title">Category</h3>
            <ul class="sub-menu">
                <li><a href="#">Shop introduction</a></li>
                <li><a href="#">Limited time menu</a></li>
                <li><a href="#">Event</a></li>
                <li><a href="#">Conversation with customers</a></li>
            </ul>

            <h3 class="sub-title">About this shop</h3>
            <p>
Would you like to use a relaxing space for work or study?
We provide it.
            </p>
        </aside>
    </div><!-- /.news-contents -->
{% endblock %}
{% block footer %}
    <footer>
        <div class="wrapper">
            <p><small>&copy; Coffee House</small></p>
        </div>
    </footer>
{% endblock %}

html:./cafe_site/templates/contact.html


{% extends "theme.html" %}
{% block title %}Coffee House{% endblock %}
{% block head %}
  {{ super() }}
{% endblock %}
{% block content %}
    <div class="wrapper">
        <h2 class="page-title">Contact</h2>
        <form action="#">
            <div>
                <label for="message">message</label>
                <textarea id="message" name="your-message"></textarea>
            </div>

            <input type="submit" class="button" value="Send">
        </form>
    </div><!-- /.wrapper -->
{% endblock %}
{% block content2 %}
    <section id="location">
        <div class="wrapper">
            <div class="location-info">
                <h3 class="sub-title">Coffee House Naha</h3>
                <p>
Address: Naha City, Okinawa Prefecture<br>
                    〇〇〇〇〇〇〇 900-0000<br>
                    〇〇〇〇<br>
Phone: 11-1111-1111<br>
Business hours: 13:00〜20:00<br>
Holidays: Wednesday
                </p>
            </div><!-- /.location-info -->
            <div class="location-map">
                <iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d1789.7269103206745!2d127.6771741081368!3d26.21443990219555!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x34e5699c49922617%3A0xda1a9bb8fcac1213!2z44CSOTAwLTAwMTUg5rKW57iE55yM6YKj6KaH5biC5LmF6IyC5Zyw77yR5LiB55uu!5e0!3m2!1sja!2sjp!4v1585272464198!5m2!1sja!2sjp" width="800" height="400" frameborder="0" style="border:0;" allowfullscreen="" aria-hidden="false" tabindex="0"></iframe>
            </div><!-- /.location-map -->
        </div><!-- /.wrapper -->
    </section><!-- /#location -->

    <section id="sns">
        <div class="wrapper">
            <div class="sns-box">
                <h3 class="sub-title">Facebook</h3>
                <iframe src="https://www.facebook.com/plugins/page.php?href=https%3A%2F%2Fwww.facebook.com%2Ffacebook&tabs=timeline&width=340&height=315&small_header=false&adapt_container_width=true&hide_cover=false&show_facepile=false&appId" width="340" height="315" style="border:none;overflow:hidden" scrolling="no" frameborder="0" allowTransparency="true" allow="encrypted-media"></iframe>
            </div>

            <div class="sns-box">
                <h3 class="sub-title">Twitter</h3>
                <a class="twitter-timeline" data-height="315" href="https://twitter.com/CoffeeH95724918?ref_src=twsrc%5Etfw">Tweets by CoffeeH95724918</a> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
            </div>

            <div class="sns-box">
                <h3 class="sub-title">Youtube</h3>
                <iframe width="560" height="315" src="https://www.youtube.com/embed/VDoTkxg9Rac" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
            </div>
        </div><!-- /.wrapper -->
    </section><!-- /#sns -->
{% endblock %}
{% block footer %}
    <footer>
        <div class="wrapper">
            <p><small>&copy; Coffee House</small></p>
        </div>
    </footer>
{% endblock %}

review.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="/review">
            <div>
                <label for="name">name</label>
                <input placeholder="name" name="username" type="text"/>
            </div>
            <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="message">message</label>
                <textarea id="message" placeholder="Review" name="review"></textarea>
            </div>
            <input type="submit" class="button" value="Send">
        </form>
    </div>
{% endblock %}
{% block content2 %}
    <div class="wrapper board">
      <p>name : {{username}}</p>
    {% if star == '1' %}
      <p>rating : <img src="/static/images/star.png " width="15" height="15"></p>
    {% endif %}
    {% if star == '2' %}
      <p>rating : <img src="/static/images/star.png " width="15" height="15"><img src="/static/images/star.png " width="15" height="15"></p>
    {% endif %}
    {% if star == '3' %}
    <p>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"></p>
    {% endif %}
    {% if star == '4' %}
    <p>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"></p>
    {% endif %}
    {% if star == '5' %}
    <p>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"></p>
    {% endif %}
      <p>message : {{review}}</p>
    </div>
{% endblock %}
{% block footer %}
    <footer>
        <div class="wrapper">
            <p><small>&copy; Coffee House</small></p>
        </div>
    </footer>
{% endblock %}

css:./cafe_site/static/style.css


@charset "UTF-8";

/* ********************
common part
******************** */
html {
    font-size: 100%;
}
body{
    font-family: "Yu Gothic Medium", "Yu Gothic Medium", YuGothic, "Yu Gothic", "Hiragino Kakugo Pro W3", sans-serif;
    line-height: 1.7;
    color: rgb(0, 0, 0);
}
a {
    text-decoration: none;
}
img {
    max-width: 100%;
}
.wrapper {
    max-width: 1100px;
    margin: 0 auto;
    padding: 0 4%;
}

/*background image*/
.big-bg {
    background-size: cover;
    background-position: center top;
    background-repeat: no-repeat;
}

/*Heading*/
.page-title {
    font-size: 5rem;
    font-family: 'Philosopher', serif;
    text-transform: uppercase;
    font-weight: normal;
}
.sub-title {
    font-size: 1.375rem;
    padding: 0 8px 8px;
    border-bottom: 2px #0bd solid;
    font-weight: normal;
}

/*button*/
.button {
    font-size: 1.375rem;
    background: #0bd;
    color: #fff;
    border-radius: 5px;
    padding: 18px 32px;
}
.button:hover {
    background: #0090aa;
}

/* iframe */
iframe {
    width: 100%;
}


/* ********************
    HEADER
******************** */
.page-header {
    display: flex;
    justify-content: space-between;
}
.logo {
    width: 210px;
    margin-top: 14px;
}
.main-nav {
    display: flex;
    font-size: 1.25rem;
    text-transform: uppercase;
    margin-top: 34px;
    list-style: none;
}
.main-nav li {
    margin-left: 36px;
}
.main-nav a {
    color: rgb(0, 0, 0);
}
.main-nav a:hover {
    color: #0bd;
}

/* ********************
    HOME
******************** */
#home {
    background-image: url(./images/main-bg.jpg);
    min-height: 100vh;
}
#home .page-title {
    text-transform: none;
}
.home-content {
    text-align: center;
    margin-top: 10%;
}
.home-content p {
    font-size: 1.125rem;
    margin: 10px 0 42px;
}

/* ********************
    NEWS
******************** */
#news {
    background-image: url(./images/news-bg.jpg);
    height: 270px;
    margin-bottom: 40px;
}
#news .page-title {
    text-align: center;
}
.news-contents {
    display: flex;
    justify-content: space-between;
    margin-bottom: 50px;
}

/* ********************
Article part
******************** */
article {
    width: 74%;
}
.post-info {
    position: relative;
    padding-top: 4px;
    margin-bottom: 40px;
}
.post-date {
    background: #0bd;
    border-radius: 50%;
    color: #fff;
    width: 100px;
    height: 100px;
    font-size: 1.625rem;
    text-align: center;
    position: absolute;
    top: 0;
    padding-top: 10px;
}
.post-date span {
    font-size: 1rem;
    border-top: 1px rgba(255,255,255,.5) solid;
    padding-top: 6px;
    display: block;
    width: 60%;
    margin: 0 auto;
}
.post-title {
    font-family: "Yu Mincho", "YuMincho", serif;
    font-size: 2rem;
    font-weight: normal;
}
.post-title,
.post-cat {
    margin-left: 120px;
}
article img {
    margin-bottom: 20px;
}
article p {
    margin-bottom: 1rem;
}

/*Side bar*/
aside {
    width: 22%;
}
.sub-menu {
    margin-bottom: 60px;
    list-style: none;
}
.sub-menu li {
    border-bottom: 1px #ddd solid;
}
.sub-menu a {
    color: rgb(0, 0, 0);
    padding: 10px;
    display: block;
}
.sub-menu a:hover {
    color: #0bd;
}
aside p {
    padding: 12px 10px;
}

/* ********************
    MENU
******************** */
#menu {
    background-image: url(./images/menu-bg.jpg);
    min-height: 100vh;
}
.menu-content {
    max-width: 560px;
    margin-top: 10%;
}
.menu-content .page-title {
    text-align: center;
}
.menu-content p {
    font-size: 1.125rem;
    margin: 10px 0 0;
}

.grid {
  display: grid;
  gap: 26px;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  margin-top: 6%;
  margin-bottom: 50px;
}

/* ********************
    CONTACT
******************** */
#contact {
    background-image: url(./images/contact-bg.jpg);
    min-height: 100vh;
}

/*Form*/
form div {
    margin-bottom: 14px;
}
label {
    font-size: 1.125rem;
    margin-bottom: 10px;
    display: block;
}
input[type="text"],
input[type="email"],
textarea {
    background: rgba(255,255,255,.5);
    border: 1px #fff solid;
    border-radius: 5px;
    padding: 10px;
    font-size: 1rem;
}
input[type="text"],
input[type="email"] {
    width: 100%;
    max-width: 240px;
}
textarea {
    width: 100%;
    max-width: 480px;
    height: 6rem;
}
input[type="submit"] {
    border: none;
    cursor: pointer;
    line-height: 1;
}

/*Store information / map*/
#location {
    padding: 4% 0;
}
#location .wrapper {
    display: flex;
    justify-content: space-between;
}
.location-info {
    width: 22%;
}
.location-info p {
    padding: 12px 10px;
}
.location-map {
    width: 74%;
}

/* SNS */
#sns {
    background: #FAF7F0;
    padding: 4% 0;
}
#sns .wrapper {
    display: flex;
    justify-content: space-between;
}
#sns .sub-title {
    margin-bottom: 30px;
}
.sns-box {
    width: 30%;
}

/* ********************
    review
******************** */
#review {
    background-image: url(./images/review-bg.jpg);
    min-height: 100vh;
}

.form-content {
    max-width: 560px;
    margin-top: 10%;
}
.form-content .page-title {
    text-align: center;
}
form div {
    margin-bottom: 14px;
}
label {
    font-size: 1.125rem;
    margin-bottom: 10px;
    display: block;
}
input[type="text"],
textarea {
    background: rgba(255,255,255,.5);
    border: 1px #fff solid;
    border-radius: 5px;
    padding: 10px;
    font-size: 1rem;
}
input[type="text"] {
    width: 100%;
    max-width: 240px;
}
textarea {
    width: 100%;
    max-width: 480px;
    height: 6rem;
}
input[type="submit"] {
    border: none;
    cursor: pointer;
    line-height: 1;
}
.star-rating{
	font-size: 0;
}
.star-rating__wrap{
	display: inline-block;
	font-size: 1rem;
}
.star-rating__wrap:after{
	content: "";
	display: table;
	clear: both;
}
.star-rating__ico{
	float: right;
	padding-left: 2px;
	cursor: pointer;
	color: #FFB300;
}
.star-rating__ico:last-child{
	padding-left: 0;
}
.star-rating__input{
	display: none;
}
.star-rating__ico:hover:before,
.star-rating__ico:hover ~ .star-rating__ico:before,
.star-rating__input:checked ~ .star-rating__ico:before
{
	content: "\f005";
}
.board {
    display: grid;
    gap: 26px;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    margin-top: 6%;
    margin-bottom: 50px;
}

/* ********************
footer
******************** */
footer {
    background: rgb(0, 0, 0);
    text-align: center;
    padding: 26px 0;
}
footer p {
    color: #fff;
    font-size: 0.875rem;
}

/* ********************
mobile version
******************** */
@media (max-width: 600px) {
    .page-title {
        font-size: 2.5rem;
    }
    .page-header {
        flex-direction: column;
        align-items: center;
    }

    /* HEADER */
    .main-nav {
        font-size: 1rem;
        margin-top: 10px;
    }
    .main-nav li {
        margin: 0 20px;
    }

    /* HOME */
    .home-content {
        margin-top: 20%;
    }

    /* NEWS */
    .news-contents {
        flex-direction: column;
    }
    #news .page-title {
        margin-top: 30px;
    }
    article,
    aside {
        width: 100%;
    }
    aside {
        margin-top: 60px;
    }
    .post-info {
        margin-bottom: 30px;
    }
    .post-date {
        width: 70px;
        height: 70px;
        font-size: 1rem;
    }
    .post-date span {
        font-size: 0.875rem;
        padding-top: 2px;
    }
    .post-title {
        font-size: 1.375rem;
    }
    .post-cat {
        font-size: 0.875rem;
        margin-top: 10px;
    }
    .post-title,
    .post-cat {
        margin-left: 80px;
    }

    /* MENU */
    .menu-content {
        margin-top: 20%;
    }

    /* CONTACT */
    #contact .page-title {
        margin-top: 40px;
    }

    /*Form*/
    input[type="text"],
    input[type="email"],
    textarea {
        max-width: 100%;
    }

    /*Store information / map/ SNS */
    #location .wrapper,
    #sns .wrapper {
        flex-direction: column;
    }
    .location-info,
    .location-map,
    .sns-box {
        width: 100%;
    }
    .sns-box {
        margin-bottom: 30px;
    }
}

Creating a login form

Now, let's create a user login form. This time, we will create a function that allows you to post a blog by logging in. It would be a problem if anyone could post, edit, or delete a blog, so create HTML that handles the user authentication function so that only people who know the user ID and password can access it.

html:./cafe_site/templates/login.html


{% extends "theme.html" %}
{% block title %}Coffee House{% endblock %}
{% block head %}
  {{ super() }}
{% endblock %}
{% block content %}
{% for message in get_flashed_messages() %}
<div class="alert">
  <font color="red">
    <p>※{{ message }}</p>
  </font>
</div>
{% endfor %}
{% endblock %}

{% block content2 %}
<form action="{{ url_for('login') }}" method=post>
  <div>
    <label for="InputTitle">User name</label>
    <input type="text" id="InputTitle" name=username>
  </div>

  <div>
    <label for="InputPassword">password</label>
    <input type="password" id="InputPassword" name=password>
  </div>
    <input type="submit" class="button" value="Login">
</form>
{% endblock %}

View Next, we will add processing when the URL is accessed. In views.py, the routing process and the process method associated with it are described. Here, we will add a View for login and logout, and add a ** flash ** function to notify the user of ** session ** processing and login and logout.

Add session

This time, the following processing is realized.

1. After successful login, the server returns session information to the browser (client) side.

2. The client stores session information in an area called a cookie.

3. After that, the client makes a request with the session information, and the server determines whether it is logged in by checking whether the session information is correct.

Add flash on the server side

In views.py, save the result you want to display according to each action in flash and change it so that it can be returned to the client.

views.py


from flask import request, redirect, url_for, render_template, flash, session
from cafe_site import app


@app.route('/')
def index():
     return render_template('cafe_site/index.html', id="home")


@app.route('/menu')
def menu():
     return render_template('cafe_site/menu.html', id="menu")


@app.route('/news')
def news():
     return render_template('cafe_site/news.html', id="news")



@app.route('/contact')
def contact():
     return render_template('cafe_site/contact.html', id="contact")


@app.route('/review', methods=['GET'])
def review():
     return render_template('cafe_site/review.html', id="review")


@app.route('/review', methods=['POST'])
def view_board():
     if request.form['star'] and request.form['title'] and request.form['review']:
          return render_template('cafe_site/review.html',  name=app.config['USERNAME'], star=request.form['star'], title=request.form['title'], review=request.form['review'])


@app.route('/review')
def show_entries():
    if not session.get('logged_in'):
        return redirect(url_for('login'))
    return render_template('cafe_site/review.html')


@app.route('/login', methods=['GET', 'POST'])
def login():
    error = None
    if request.method == 'POST':
        if request.form['username'] != app.config['USERNAME']:
            flash('The user name is different')
        elif request.form['password'] != app.config['PASSWORD']:
            flash('Password is different')
        else:
            session['logged_in'] = True
            flash('You are now logged')
            return redirect(url_for('show_entries'))
    return render_template('login.html')


@app.route('/logout')
def logout():
    session.pop('logged_in', None)
    flash('logged out')
    return redirect(url_for('show_entries'))

session processing

In Flask, you can handle session information by handling the session variable. In ** / login **, the value of logged_in during session is set to True by setting session ['logged_in'] = True after successful login. From now on, you can determine if you are logged in by checking this value on every request. After logging out, delete the session information. Make sure to delete it as session.pop ('logged_in', None).

flash processing

The flash function adds one line to flash ('logged in') flash ('logged out') for successful login and logout, respectively. The message is now added to the flash area and you can pass the message to your browser.

secret key setting

Set the secret key in config.py. This secret key is used to encrypt the session information.

python:./cafe_site/config.py


DEBUG = True
SECRET_KEY = 'bjgc5ejrwgwk'
USERNAME = 'syuuhei'
PASSWORD = 'abc123'

Switch the menu display according to session information

Edit theme.html to change the link displayed in the navigation bar depending on whether you are logged in or not.

theme.html


<nav>
    <ul class="main-nav">
       {% if not session.logged_in %}
        <li><a href="/news">News</a></li>
        <li><a href="/menu">Menu</a></li>
        <li><a href="/contact">Contact</a></li>
        <li><a href="/login">login</a></li>
       {% else %}
        <li><a href="/news">News</a></li>
        <li><a href="/menu">Menu</a></li>
        <li><a href="/contact">Contact</a></li>
        <li><a href="/review">Review</a></li>
        <li><a href="/logout">logout</a></li>
       {% endif %}
    </ul>
</nav>

theme.html


{% if not session.logged_in %}
Processing when not logged in
{% else %}
Processing when logged in
{% endif %}

The login link is displayed when you are not logged in, and the logout link is displayed when you are logged in.

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 using django-Development 1-
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]
Creating a Flask server with Docker
Creating a simple table using prettytable
Creating a simple app with flask
Build a web application with Django
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
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-
Impressions of using Flask for a month
WEB application development using Django [Request processing]
WEB application development using Django [Template addition]
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
Create a web app that converts PDF to text using Flask and PyPDF2
Try creating a web application with Vue.js and Django (Mac)-(1) Environment construction, application creation
Create a web application execution environment of Python3.4 + Nginx + uWSGI + Flask with haste using venv on Ubuntu 14.04 LTS
The day when a beginner who started programming for two and a half months made a web application using Flask
Creating a Home screen
Released a web service for scoring handwriting using DeepLearning