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.
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.
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.
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.
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")
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>© Coffee House</small></p>
</div>
</footer>
{% endblock %}
So far, we have created a submission form. Next, create a function to save the articles posted from the posting form to the database.
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.
Next, add a blog detail function so that details such as the article body are displayed.
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>© 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 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)
.
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 %}
Add an article editing function so that you can edit the posted article.
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 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 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>© Coffee House</small></p>
</div>
</footer>
{% endblock %}
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.
Finally, add the ability to delete articles.
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 ** 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