iT邦幫忙

2021 iThome 鐵人賽

DAY 28
0
Modern Web

Flask系列 第 28

Day 28 實作 admin_bp (1)

前言

今天要開始寫 admin_bp,有蠻多部分跟之前很像。

/admin_dashboard/posts

先來看看 HTML 的部分。

admin_dashboard_posts.html


{% extends "base.html" %}

{% block title %}Dashboard{% endblock %}

{% block content %}
<form action="/admin_dashboard/posts" method="post">
    {{ form.csrf_token }}
    {{ form.start }}
    {{ form.end }}
    {{ form.user_id }}
    {{ form.submit }}
</form>
<div>
    {% for post in posts %}
    <div>
        {{ post['author_id'] }}
        <a href="/post/{{ post['id'] }}">{{ post['title'] }}</a>
        {{ post['description'] }}
        {{ post['time'] }}
        <button>Delete</button>
    </div>
    {% endfor %}
</div>
{% endblock %}

基本上跟一般使用者的 dashboard 差不多,但 form 的部分新加入了一個 user_id 的欄位。在最後面有一個刪除的按鈕,它今天還不會登場。

接下來進入路徑的部分,也一樣跟使用者的 dashboard 類似,因為都有篩選器。

@admin_bp.route("/admin_dashboard/posts", methods=["GET", "POST"])
def admin_dashboard_posts_page():
    filter_args = {}
    if start := request.cookies.get("start"):
        filter_args["start"] = datetime.datetime.strptime(start, "%Y-%m-%d")
    if end := request.cookies.get("end"):
        filter_args["end"] = datetime.datetime.strptime(end, "%Y-%m-%d")
    if user_id := request.cookies.get("user_id"):
        filter_args["user_id"] = user_id
    form = AdminDashboardFilter(**filter_args)
    if request.method == "GET":
        posts = get_posts(**filter_args)
        return render_template("admin_dashboard_posts.html", posts=posts, form=form)
    if request.method == "POST":
        response = make_response(redirect(url_for("admin.admin_dashboard_posts_page")))
        if form.validate_on_submit():
            cookies = []
            if form.start.data:
                cookies.append(("start", form.start.data.strftime("%Y-%m-%d")))
            if form.end.data:
                cookies.append(("end", form.end.data.strftime("%Y-%m-%d")))
            if form.user_id.data:
                cookies.append(("user_id", str(form.user_id.data)))
            response.delete_cookie("start")
            response.delete_cookie("end")
            response.delete_cookie("user_id")
            for cookie in cookies:
                response.set_cookie(*cookie)
        else:
            for _, errors in form.errors.items():
                for error in errors:
                    flash(error, category="alert")
        return response

基本上就是直接從使用者 dashboard 抄過來的,只是多加一個 user_id 而已。但還是有一個小東西要注意一下,在拉出 user_id 的時候要把他轉成字串,不然會噴錯誤。

/admin_dashboard/comments

接著來到留言的 dashboard,跟剛剛也是很接近,但要先來加一個資料庫的函式。

def get_all_comments(user_id=None, start=None, end=None):
    query = Comments.query
    if user_id:
        query = query.filter_by(user_id)
    if start:
        query = query.filter(Comments.time > start)
    if end:
        query = query.filter(Comments.time < end)
    return [
        {
            "id": comment.id,
            "author_id": comment.author_id,
            "post_id": comment.post_id,
            "content": comment.content,
        }
        for comment in query.all()
    ]

基本上就是把 get_posts 拿來這邊改一下而已。

接下來是他的 HTML。

admin_dashboard_comments.html

{% extends "base.html" %}

{% block title %}comments{% endblock %}

{% block content %}
<form action="/admin_dashboard/comments" method="post">
    {{ form.csrf_token }}
    {{ form.start }}
    {{ form.end }}
    {{ form.user_id }}
    {{ form.submit }}
</form>
<div>
{% for comment in comments %}
    {{ comment['author_id'] }}
    {{ comment['post_id'] }}
    {{ comment['content'] }}
    {{ comment['time'] }}
    <button>Delete</button>
{% endfor %}
</div>
{% endblock %}

表單也是一樣的,就是篩選器。跟剛剛一樣,他也有刪除的按鈕。

最後來到路徑的部分。

@admin_bp.route("/admin_dashboard/comments", methods=["GET"])
def admin_dashboard_comments_page():
    filter_args = {}
    if start := request.cookies.get("start"):
        filter_args["start"] = datetime.datetime.strptime(start, "%Y-%m-%d")
    if end := request.cookies.get("end"):
        filter_args["end"] = datetime.datetime.strptime(end, "%Y-%m-%d")
    if user_id := request.cookies.get("user_id"):
        filter_args["user_id"] = user_id
    form = AdminDashboardFilter(**filter_args)
    if request.method == "GET":
        comments = get_all_comments(**filter_args)
        return render_template("admin_dashboard_comments.html", comments=comments, form=form)
    if request.method == "POST":
        response = make_response(redirect(url_for("admin.admin_dashboard_comments_page")))
        if form.validate_on_submit():
            cookies = []
            if form.start.data:
                cookies.append(("start", form.start.data.strftime("%Y-%m-%d")))
            if form.end.data:
                cookies.append(("end", form.end.data.strftime("%Y-%m-%d")))
            if form.user_id.data:
                cookies.append(("user_id", str(form.user_id.data)))
            response.delete_cookie("start")
            response.delete_cookie("end")
            response.delete_cookie("user_id")
            for cookie in cookies:
                response.set_cookie(*cookie)
        else:
            for _, errors in form.errors.items():
                for error in errors:
                    flash(error, category="alert")
        return response

跟剛剛幾乎一模一樣,只是把貼文換成留言而已。

/manage_user

在今天的最後,我們要處理管理使用者的介面。一樣先從資料庫部分看起。

def get_all_users(user_id=None, username=None, start=None, end=None):
    query = Users.query
    if user_id:
        query = query.filter_by(id=user_id)
    if username:
        query = query.filter_by(username=username)
    if start:
        query = query.filter(Users.register_time > start)
    if end:
        query = query.filter(Users.register_time < end)
    return user_to_dict(query.all())

基本上都跟剛剛很接近,只是這裏我們用已經寫好的 user_to_dict 取代剛剛的 list comprehension。

接著是 HTML 的部分,基本上也蠻類似的。

manage_user.html


{% extends "base.html" %}

{% block title %}Manage User{% endblock %}

{% block content %}
<form action="/manage_user" method="post">
    {{ form.csrf_token }}
    {{ form.start }}
    {{ form.end }}
    {{ form.user_id }}
    {{ form.username }}
    {{ form.submit }}
</form>
<div>
    {% for user in users %}
    <div>
        <span>{{ user['id'] }}</span>
        <input type="text" value="{{ user['username'] }}">
        <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>Delete</button>
        <button>Update</button>
    </div>
    {% endfor %}
</div>
{% endblock %}

稍微不一樣的是我們把單純的顯示出來變成了 input,這樣管理員才可以直接修改,裡面沒有加上密碼的欄位,因為太煩了,而且也是可以想到的東西,就不在這邊做。還有一個不一樣的地方是 user['is_admin'] 的部分,我們在那裏用了一個 if 來判斷他是不是管理員,如果是的話就把那個 checkbox 勾起來。

最後要看的是路徑本身,基本上就是跟前面兩個相同。

@admin_bp.route("/manage_user", methods=["GET", "POST"])
def manage_user_page():
    filter_args = {}
    if start := request.cookies.get("start"):
        filter_args["start"] = datetime.datetime.strptime(start, "%Y-%m-%d")
    if end := request.cookies.get("end"):
        filter_args["end"] = datetime.datetime.strptime(end, "%Y-%m-%d")
    if user_id := request.cookies.get("user_id"):
        filter_args["user_id"] = user_id
    if username := request.cookies.get("username"):
        filter_args["username"] = username
    form = UserFilterForm(**filter_args)
    if request.method == "GET":
        users = get_all_users(**filter_args)
        return render_template("manage_user.html", users=users, form=form)
    if request.method == "POST":
        response = make_response(redirect(url_for("admin.manage_user_page")))
        if form.validate_on_submit():
            cookies = []
            if form.start.data:
                cookies.append(("start", form.start.data.strftime("%Y-%m-%d")))
            if form.end.data:
                cookies.append(("end", form.end.data.strftime("%Y-%m-%d")))
            if form.user_id.data:
                cookies.append(("user_id", str(form.user_id.data)))
            if form.username.data:
                cookies.append(("username", form.username.data))
            response.delete_cookie("start")
            response.delete_cookie("end")
            response.delete_cookie("user_id")
            response.delete_cookie("username")
            for cookie in cookies:
                response.set_cookie(*cookie)
        else:
            for _, errors in form.errors.items():
                for error in errors:
                    flash(error, category="alert")
        return response

要記得把 form 改掉,也要記得多一個欄位 username


上一篇
Day 27 實作 user_bp (5)
下一篇
Day 29 實作 admin_bp (2)
系列文
Flask30

尚未有邦友留言

立即登入留言