learning from 100 Days of Code: The Complete Python Pro Bootcamp for 2022
Learning Point
Point 1. Flask ckeditor & buttons in WTF
Flask ckeditor - Documentation
Flask ckeditor - 5 type tables
Change button color in WTF
# in main.py
class CreatePostForm(FlaskForm):
body = CKEditorField("Blog Content", validators=[DataRequired()])
submit = SubmitField("Submit Post")
# in html
{{ ckeditor.load(pkg_type="standard") }}
{{ wtf.quick_form(form, button_map={'submit': 'primary'}) }}
Point 2. Two ways of getting data from "POST"
# Method 1. <form.%field%.data>
title=form.title.data
# Method 2. <request.form['%field%']>
title=request.form['title']
from datetime import datetime as dt
dt.now().strftime("%B %d, %Y")
Point 4. HTML - formatted in jinja
{{post.body|striptags}}
Point 5. auto-populate the fields in WTF
@app.route("/edit-post/<post_id>")
def edit_post(post_id):
editing_post = BlogPost.query.get(post_id)
form = CreatePostForm(obj=editing_post)
return render_template("make-post.html", form=form, title='Edit Post')
Point 6. use "POST" replace "PUT" & "PATCH"
Point 7. Set host='0.0.0.0', port=5000
What It Means When You See the 0.0.0.0 IP Address
What is the Difference Between 127.0.0.1 and 0.0.0.0?
stackoverflow | What does "app.run(host='0.0.0.0') " mean in Flask
stackoverflow | Configure Flask dev server to be visible across the network
if __name__ == "__main__":
app.run(debug=True)
- in this case, you'll get yout url in
http://127.0.0.1:5000/
- 127.0.0.1 is a special ip which is the loopback address (also known as localhost).
- You can only request the web in where server located, usually is your laptop/computer using now.
if __name__ == "__main__":
app.run(host='0.0.0.0', port=5000)
- in this case, you'll get yout url in
http://your-ip-address:5000/
- you can type
ipconfig
in terminal or command prompt to get your IP dress - The
0.0.0.0
IP address is sometimes called a wildcard address, unspecified address, or INADDR_ANY. - In flask, when you set host='0.0.0.0' mean you allow other device to access your web.
RESTful route Blog Project
main.py
from flask import Flask, render_template, redirect, url_for, request
from flask_bootstrap import Bootstrap
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired, URL
from flask_ckeditor import CKEditor, CKEditorField
from datetime import datetime as dt
app = Flask(__name__)
app.config['SECRET_KEY'] = '8BYkEfBA6O6donzWlSihBXox7C0sKR6b'
ckeditor = CKEditor(app)
Bootstrap(app)
##CONNECT TO DB
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///posts.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
##CONFIGURE TABLE
class BlogPost(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(250), unique=True, nullable=False)
subtitle = db.Column(db.String(250), nullable=False)
date = db.Column(db.String(250), nullable=False)
body = db.Column(db.Text, nullable=False)
author = db.Column(db.String(250), nullable=False)
img_url = db.Column(db.String(250), nullable=False)
##WTForm
class CreatePostForm(FlaskForm):
title = StringField("Blog Post Title", validators=[DataRequired()])
subtitle = StringField("Subtitle", validators=[DataRequired()])
author = StringField("Your Name", validators=[DataRequired()])
img_url = StringField("Blog Image URL", validators=[DataRequired(), URL()])
# ----- Point 1. Flask ckeditor & buttons in WTF ----- #
body = CKEditorField("Blog Content", validators=[DataRequired()])
submit = SubmitField("Submit Post")
@app.route('/')
def get_all_posts():
posts = BlogPost.query.all()
return render_template("index.html", all_posts=posts)
@app.route("/post/<int:index>")
def show_post(index):
requested_post = BlogPost.query.get(index)
return render_template("post.html", post=requested_post)
@app.route("/new-post", methods=['GET', 'POST'])
def create_post():
form = CreatePostForm()
if form.validate_on_submit():
new_post = BlogPost(
# --- Point 2. Two ways of getting data from "POST" --- #
# Method 1. <form.%field%.data>
title=form.title.data,
subtitle=form.subtitle.data,
author=form.author.data,
# Method 2. <request.form['%field%']>
img_url=request.form['img_url'],
body=request.form['body'],
# --- Point 3. Datetime - formatted --- #
date=dt.now().strftime("%B %d, %Y")
)
db.session.add(new_post)
db.session.commit()
return redirect(url_for('get_all_posts'))
return render_template("make-post.html", form=form, title='New Post')
@app.route("/edit-post/<post_id>", methods=["GET", "POST"])
def edit_post(post_id):
editing_post = BlogPost.query.get(post_id)
# ----- Point 5. auto-populate the fields in WTF ----- #
form = CreatePostForm(obj=editing_post)
# ----- Point 6. use "POST" replace "PUT" & "PATCH" ----- #
if form.validate_on_submit():
editing_post.title = request.form['title']
editing_post.subtitle = request.form['subtitle']
editing_post.author = request.form['author']
editing_post.img_url = request.form['img_url']
editing_post.body = request.form['body']
db.session.commit()
return redirect(url_for('show_post', index=post_id))
return render_template("make-post.html", form=form, title='Edit Post')
@app.route("/delete/<post_id>")
def delete(post_id):
delete_post = BlogPost.query.get(post_id)
db.session.delete(delete_post)
db.session.commit()
return redirect(url_for('get_all_posts'))
@app.route("/about")
def about():
return render_template("about.html")
@app.route("/contact")
def contact():
return render_template("contact.html")
# if __name__ == "__main__":
# app.run(debug=True)
# ----- Point 7. Set host='0.0.0.0', port=5000 ----- #
if __name__ == "__main__":
app.run(host='0.0.0.0', port=5000)
make-post.html
{% extends 'bootstrap/base.html' %}
{% import "bootstrap/wtf.html" as wtf %}
{% block content %}
{% include "header.html" %}
<!-- Page Header -->
<header class="masthead" style="background-image: url('{{ url_for('static', filename='img/edit-bg.jpg')}}')">
<div class="overlay"></div>
<div class="container">
<div class="row">
<div class="col-lg-8 col-md-10 mx-auto">
<div class="page-heading">
<h1>{{ title }}</h1>
<span class="subheading">You're going to make a great blog post!</span>
</div>
</div>
</div>
</div>
</header>
<div class="container">
<div class="row">
<div class="col-lg-8 col-md-10 mx-auto">
<!-- Point 1. Flask ckeditor & buttons in WTF -->
{{ ckeditor.load(pkg_type="standard") }}
{{ wtf.quick_form(form, button_map={'submit': 'primary'}) }}
</div>
</div>
</div>
{% include "footer.html" %}
{% endblock %}
post.html
{% include "header.html" %}
<!-- Page Header -->
<header class="masthead" style="background-image: url('{{post.img_url}}')">
<div class="overlay"></div>
<div class="container">
<div class="row">
<div class="col-lg-8 col-md-10 mx-auto">
<div class="post-heading">
<h1>{{post.title}}</h1>
<h2 class="subheading">{{post.subtitle}}</h2>
<span class="meta">Posted by
<a href="#">{{post.author}}</a>
on {{post.date}}</span>
</div>
</div>
</div>
</div>
</header>
<!-- Post Content -->
<article>
<div class="container">
<div class="row">
<div class="col-lg-8 col-md-10 mx-auto">
<p>
<!-- Point 4. HTML - formatted in jinja -->
{{post.body|striptags}}
</p>
<hr>
<div class="clearfix">
<a class="btn btn-primary float-right" href="{{url_for('edit_post', post_id=post.id)}}">Edit Post</a>
</div>
</div>
</div>
</div>
</article>
<hr>
{% include "footer.html" %}
完整語法見GitHub