iT邦幫忙

2021 iThome 鐵人賽

DAY 29
0
Modern Web

Flask系列 第 29

Day 29 實作 admin_bp (2)

前言

快要結束了,今天要繼續寫 admin_bp。今天的內容會用到 JS,但我不會多加解釋。

posts & comments

我們直接把 admin_dashboard_posts_backendadmin_dashboard_comments_backend 一起看,,因為他們真的很接近,一樣從資料庫開始。

def delete_post_admin(post_id):
    post = Posts.query.filter_by(id=post_id).first()
    comments = Comments.query.filter_by(post_id=post_id).all()
    db.session.delete(post)
    for comment in comments:
        db.session.delete(comment)
    db.session.commit()

def delete_comment_admin(comment_id):
    comment = Comments.query.filter_by(id=comment_id).first()
    db.session.delete(comment)
    db.session.commit()

雖然兩個都是刪除,但刪除貼文比較麻煩一點,因為留言是附在貼文下面的,所以要連著留言一起刪掉才行。

在進入 HTML 之前,我們要先看看 JS。

admin.js

function del_post(post_id) {
    $.ajax({
        url: "/admin_dashboard_posts_backend",
        type: "delete",
        data: JSON.stringify({ "post_id": post_id }),
        dataType: "json",
    })
        .always(function (r) {
            if (r.status == 200) {
                alert("OK.", "success");
            }
            else {
                alert("Error.", "alert");
            }
        })
}

function del_comment(comment_id) {
    $.ajax({
        url: "/admin_dashboard_comments_backend",
        type: "delete",
        data: JSON.stringify({ "comment_id": comment_id }),
        dataType: "json",
    })
        .always(function (r) {
            if (r.status == 200) {
                alert("OK.", "success");
            }
            else {
                alert("Error.", "alert");
            }
        })
}

這裡我們使用了 jquery 來做 ajax,在使用者按下刪除按鈕之後就送出 request 讓後端刪除。

接下來是 HTML,基本上就是昨天寫好的檔案,只是要稍微加一些東西。

admin_dashboard_comments.html

{% block extra_import %}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script src="/static/admin.js"></script>
{% endblock %}

<button onclick="del_comment({{ comment['id'] }});">Delete</button>

admin_dashboard_posts.html

{% block extra_import %}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script src="/static/admin.js"></script>
{% endblock %}

<button onclick="del_post({{ post['id'] }});">Delete</button>

我們多引入了剛剛寫的 admin.js 以及 jquery 的 JS 檔案。接著我們調整了一下刪除的按鈕,把他多加了一個 onclick 來執行剛剛寫的 JS。

最後要看到路徑的部分,兩個非常接近。

@admin_bp.route("/admin_dashboard_posts_backend", methods=["DELETE"])
def admin_dashboard_posts_backend():
    data = request.get_json(force=True)
    post_id = data["post_id"]
    try:
        delete_post_admin(post_id)
        return "OK"
    except:
        abort(400)


@admin_bp.route("/admin_dashboard_comments_backend", methods=["DELETE"])
def admin_dashboard_comments_backend():
    data = request.get_json(force=True)
    comment_id = data["comment_id"]
    try:
        delete_comment_admin(comment_id)
        return "OK"
    except:
        abort(400)

在這邊我們又看到 request 並用了他的 get_json 函式。這邊加了一個 force=True,是因為 flask 會偵測 request 的 MIME type,如果不是 JSON 他就會不讓你 parse,加了這個參數之後他不管如何就是會 parse,但如果內容不是 JSON 的話他還是會噴錯誤。接下來就是嘗試刪除,不成功的話就 abort

manage_user

最後要做的部分是管理使用者頁面的更新和刪除按鈕。一樣先從資料庫看起。

def delete_user(user_id):
    user = Users.query.filter_by(id=user_id).first()
    posts = Posts.query.filter_by(author_id=user_id).all()
    for post in posts:
        delete_post_admin(post)
    comments = Comments.query.filter_by(author_id=user_id).all()
    for comment in comments:
        db.session.delete(comment)
    db.session.delete(user)
    db.session.commit()

這邊只有刪除的,因為更新的函式在之前寫過了。跟剛剛刪除貼文類似,我們也需要把使用者的貼文和留言一起刪掉。

再來一樣先看看 JS,更新的部分跟剛剛稍微有些不同。

admin.js

function del_user(user_id) {
    $.ajax({
        url: "/manage_user_backend",
        type: "delete",
        data: JSON.stringify({ "user_id": user_id }),
        dataType: "json",
    })
        .always(function (r) {
            if (r.status == 200) {
                alert("OK.", "success");
            }
            else {
                alert("Error.", "alert");
            }
        })
}

function update_user(element) {
    var parent = element.parentElement;
    var user_id = parent.children[0].innerText;
    var email = parent.children[2].value;
    var is_admin = parent.children[3].checked;
    var data = { "user_id": user_id, "username": username, "email": email, "is_admin": is_admin }
    $.ajax({
        url: "/manage_user_backend",
        type: "patch",
        data: JSON.stringify(data),
        dataType: "json",
    })
        .always(function (r) {
            if (r.status == 200) {
                alert("OK.", "success");
            }
            else {
                alert("Error.", "alert");
            }
        })
}

光看這樣子應該無法理解 update_userelement 在幹嘛,所以我們直接看看 HTML,JS 的引入就不重複打了。

manage_user.html

<span>{{ user['id'] }}</span>
<span>{{ user['username'] }}</span>
<input type="email" value="{{ user['email'] }}">
<input type="checkbox" {% if user['is_admin'] %} checked {% endif %}>
<input type="text" value="{{ user['introduction'] }}">
<span>{{ user['register_time'] }}</span>
<button onclick="del_user({{ user['id'] }});">Delete</button>
<button onclick="update_user(this);">Update</button>

我們修改了底下的兩個按鈕,更新的按鈕直接把自己這個 element 傳入 JS,所以剛剛看到的 element 就是這個按鈕。然後在 update_user 裡面就去把每個欄位的值抓出來,丟給後端 python 處理。

最後來看到路徑。

@admin_bp.route("/manage_user_backend", methods=["PATCH", "DELETE"])
def manage_user_backend():
    if request.method == "PATCH":
        data = request.get_json(force=True)
        if (
            update_user_data(
                data["user_id"], email=data["email"], is_admin=data["is_admin"]
            )
            == True
        ):
            return "OK"
        else:
            abort(400)
    if request.method == "DELETE":
        data = request.get_json(force=True)
        user_id = data["user_id"]
        try:
            delete_user(user_id)
            return "OK"
        except:
            abort(400)

因為有更新和刪除兩個功能,所以要先判斷 request.method,然後再分別去更新,有問題的話就 abort(400)


上一篇
Day 28 實作 admin_bp (1)
下一篇
Day 30 最後的收尾
系列文
Flask30

尚未有邦友留言

立即登入留言