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


<<:  调节磁碟和CPU的矛盾 - InnoDB的Buffer Pool

>>:  Proxmox VE 虚拟机防火墙管理 (一)

寻觅 webpack - 27 - 真实世界的 webpack - 建立 webpack 生产环境 - 追踪建置

本系列已集结成书从 0 到 Webpack:学习 Modern Web 专案的建置方式,这是一本完...

JS读书笔记30天 - Day26 Bootstrap的Class设定3

表单 一般input、textarea、select(包含多重选择) 结构 最外层:Class中加上...

2021 资通讯高峰论坛 !

https://edm.bnext.com.tw/2021cpx/?utm_source=%E3%8...

Dependency injection

谈到 Android 的 dependency injection (DI),大家一定会想到 Dag...

[27] 用 python 刷 Leetcode: 455

原始题目 Assume you are an awesome parent and want to ...