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()
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>© 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 *.)
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.
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
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'])
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.
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.)
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')
Here, I would like to divide Flask into three parts, Model, Template, and View, and process each function.
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>© 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>© 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>© 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>© 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;
}
}
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.
This time, the following processing is realized.
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'))
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).
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.
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'
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