Day 67 - RESTful route Blog Project & IP


Posted by pei_______ on 2022-06-21

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']

Point 3. datetime - formatted

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)
  1. in this case, you'll get yout url in http://127.0.0.1:5000/
  2. 127.0.0.1 is a special ip which is the loopback address (also known as localhost).
  3. 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)
  1. in this case, you'll get yout url in http://your-ip-address:5000/
  2. you can type ipconfig in terminal or command prompt to get your IP dress
  3. The 0.0.0.0 IP address is sometimes called a wildcard address, unspecified address, or INADDR_ANY.
  4. 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


#Python #課堂筆記 #100 Days of Code







Related Posts

MTR04_0627

MTR04_0627

[IIS] 拒絕存取路徑 & 開啟資料夾權限

[IIS] 拒絕存取路徑 & 開啟資料夾權限

nvm (Node Version Manager)

nvm (Node Version Manager)


Comments