我們今天還是沒有離開 user_bp
,我們要來弄寫文章的頁面,也就是 markdown 上場的日子。
首先一樣要先來處理一下資料庫的部分,需要一個加入新貼文的函式。
def add_post(user_id, title, description, content):
post = Posts(user_id, title, description, content)
try:
db.session.add(post)
db.session.commit()
return True
except:
return False
之前都是使用 Users
這個物件,這次要換成用 Posts
了。他會需要傳入一些貼文的基本資料,然後把他加入資料庫,如果有錯誤的話就代表他標題重複了 (空值的部分已經讓 Flask-WTF 處理掉了)。
接下來是 HTML 的部分,他有一些些跟一般表單不一樣的地方。
write.html
{% extends "base.html" %}
{% block title %}Post{% endblock %}
{% block content %}
{{ pagedown.include_pagedown() }}
<form action="{{ route }}" method="post">
{{ form.csrf_token }}
{{ form.title }}
{{ form.description }}
{{ form.content }}
{{ form.submit }}
</form>
{% endblock %}
他有一個 {{ pagedown.include_pagedown() }}
,這是用來引入外部 JS 來及時顯示 markdown 用的。要注意它是 pagedown
的東西,而不是 form
,而這個 pagedown
就是一開始在 create_app
裡面初始化用的那個。接下來會看到有一個 route
變數,這樣 render_template
的時候就可以傳入表單的提交路徑。
接下來就跟之前差不多了,比較可以看一下的是 form.content
,我們用的是最直接簡單的方法,但也可以稍微調整他,有興趣的話可以去他的GitHub repo 看看範例。
最後就要來看路徑了,基本上跟之前的結構都一樣。
views.py
@user_bp.route("/post/add", methods=["GET", "POST"])
@login_required
def add_post_page():
form = AddPostForm()
if request.method == "GET":
return render_template("write.html", form=form, route="/post/add")
if request.method == "POST":
if form.validate_on_submit():
title = form.title.data
description = form.description.data
content = form.content.data
if add_post(current_user.id, title, description, content):
flash("Add post.")
return redirect(url_for("user.dashboard_page"))
else:
flash("The title has been used.")
return redirect(url_for("user.add_post_page"))
else:
for _, errors in form.errors.items():
for error in errors:
flash(error, category="alert")
return redirect(url_for("user.add_post_page"))
差不多就是把欄位都抓出來,然後 add_post
,沒問題就跳到 dashboard,有問題就繼續待在這裡。但是在 render_template
的時候,我們加入了一個 route
,就是剛剛 write.html
裡面的,決定表單要送去哪。
寫完文章就要來改文章,所以接下來我們來處理編輯文章的頁面。一樣,先來看看資料庫。
def edit_post(post_id, title, description, content):
post = Posts.query.filter_by(id=post_id)
try:
data = {"title": title, "description": description, "content": content}
post.update(data)
db.session.commit()
return True
except:
return False
def render_post(post_id):
post = Posts.query.filter_by(id=post_id).first()
return {
"id": post.id,
"author_id": post.author_id,
"title": post.title,
"description": post.description,
"content": post.content,
"comments": [
{
"author_id": comment.author_id,
"content": comment.content,
}
for comment in post.comments
],
}
這裡有 edit_post
和 render_post
兩個函式,前者是用來編輯文章,也就是把現有的文章抓出來再修改內容,所以用 post_id
當參數;而後者是把文章轉成 dict 送出來。
依照慣例,我們應該要來寫 HTML,但這次不需要,因為我們可以直接拿剛剛的 write.html
來用。所以我們可以直接進入路徑的部分,可想而知,也會跟剛剛十分類似。
@user_bp.route("/post/edit/<int:post_id>", methods=["GET", "POST"])
@login_required
def edit_post_page(post_id):
post_data = render_post(post_id)
form = AddPostForm(
title=post_data["title"],
description=post_data["description"],
content=post_data["content"],
)
if request.method == "GET":
return render_template("write.html", form=form, route=f"/post/edit/{post_id}")
if request.method == "POST":
if form.validate_on_submit():
title = form.title.data
description = form.description.data
content = form.content.data
if edit_post(post_id, title, description, content):
flash("Post edited.")
return redirect(url_for("user.dashboard_page"))
else:
flash("The title has been used.")
return redirect(url_for("user.edit_post_page"))
else:
for _, errors in form.errors.items():
for error in errors:
flash(error, category="alert")
return redirect(url_for("user.edit_post_page"))
這裡有比較不同的部分是在最前面我們先用剛剛的 render_post
把貼文的資料送出來,然後在建立表單的時候就直接把資料傳進去,就像昨天弄使用者設定頁面一樣。接下來就十分類似,傳不同的 route
給 jinja 處理,後面就都一樣了。這邊的 url_for
多了一個 post_id
的參數,會有他是因為這個編輯文章的頁面有一個 post_id
的變數,如果不指定的話,flask 會無所適從,然後就噴錯誤了。
Create dynamic URLs in Flask with url_for()
Flask-PageDown