Day 26 实作 user_bp (4)

前言

今天我们要来处理 dashboard 的部分,但仅限於贴文的,留言的要留到明天。

/dashboard

第一个要来看的是 dashboard,有些东西还没有写好 (像是删除之类的),会等写完这边再回去看。

一样,先来看看资料库方面的程序码。

def get_posts(user_id=None, start=None, end=None):
    query = Posts.query
    if user_id:
        query = query.filter_by(author_id=user_id)
    if start:
        query = query.filter(Posts.time > start)
    if end:
        query = query.filter(Posts.time < end)
    posts = [post.id for post in query.all()]
    posts = list(map(render_post, posts))
    return posts

这边我们让他接收一些过滤器去做筛选,然後把过滤过的贴文都抓出来,再丢进昨天写的 render_post 让他转成 dict。这边值得注意一下的是我们有 filter 也有 filter_by,後者是我们熟悉的,而前者也一样是筛选器,只是它里面放的是判断式,所以如果之前的 filter_by 想要改成 filter,那就要把 = 改成 ==

接下来进入 HTML,这次会比前面复杂一些,因为要加上显示贴文。

dashboard.html

{% extends "base.html" %}

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

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

最上面我们一样放了表单,是 filter 那个。然後在下面我们用到了 posts,这是刚刚 get_posts 弄出来的,所以会是一个有很多贴文 dict 的 list,我们就一个一个抓出来,然後把它的资讯呈现出来。我们放了很多连结,现在只有编辑的部分昨天实作了,剩下的我们会等等完成。

最後来到路径本身,他也相对复杂。

@user_bp.route("/dashboard", methods=["GET", "POST"])
@login_required
def dashboard_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")
    form = DashboardFilterForm(**filter_args)
    if request.method == "GET":
        posts = get_posts(user_id=None, **filter_args)
        return render_template("dashboard.html", posts=posts, form=form)
    if request.method == "POST":
        response = make_response(redirect(url_for("user.dashboard_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")))
            response.delete_cookie("start")
            response.delete_cookie("end")
            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

在判断 request.method 前,我们有一小串跟其他路径不一样的程序码,它是用来取出 cookie 的,因为我们会把使用者指定的 filter 存在 cookie 里面。以现在的状况来看这基本上是多余的,直接把过滤过的贴文送出去就好,但如果未来我们加入分页的功能,那就没有这麽好处理了,所以我们在这边选择用 cookie。这个从 cookie 抓出来的 dict 除了要给 get_posts 用之外,也要给 DashboardFilterForm 当作预设值,这样使用者就可以看到他设定的过滤器是什麽。後面的部分基本上就是处理 cookie,要把表单送过来的东西都转成 cookie。

这里会有一个小问题发生在处理日期结束的地方,假设我们说结束时间是 2021-01-02,但事实上在资料库时间比大小的时候 2021-01-02 的资料不会跑出来,因为我们说的结束时间会被当成 2021-01-02 00:00:00,这样就会让那些 2021-01-02 的资料被过滤掉,平常我自己会直接手动加一天,不过为了简洁一点,我这边就跳过这个部分。

/post/delete

接着我们来看看删除文章也一样从资料库的部分看起。

def delete_post(user_id, post_id):
    post = Posts.query.filter_by(id=post_id).first()
    if post.author_id == user_id:
        db.session.delete(post)
        db.session.commit()
        return True
    else:
        return False

他有 user_idpost_id 两个参数,会需要前者是因为我们不能让莫名其妙的人乱删别人的文章,所以必须确定要删除这篇文章的人的确是其所有者。我们删除的方法是用 db.session.delete(),里面的参数是物件,而不是 query,所以要记得 .first()

而他不会有 HTML,来看路径就知道为什麽了。

@user_bp.route("/post/delete/<int:post_id>", methods=["GET"])
@login_required
def delete_post_page(post_id):
    if delete_post(current_user.id, post_id):
        flash("OK.")
    else:
        flash("Failed.")
    return redirect(url_for("user.dashboard"))

他的路径非常简单,基本上就是把 post_id 转送给刚刚的 delete_post,最後再重新导向到 dashboard。


<<:  Day 26:Google Map 范本学习(1)

>>:  Day14

[影片]第28天:英雄指南-5. 新增应用内导航(3)

GitHub:https://github.com/dannypc1628/Angular-Tou...

[Day27] 第二十七章-建立订单api (nodejs)

前言 我们目前把laravel的服务都写得差不多了 後来发现没有实际测试过订单建立 这边我们来把订单...

【Side Project】 程序码整理 -Model运用

之前为方便快速了解我们程序完整的功能, 所以把所有的资料都放在Controller里面。 今天这篇我...

[Day 27] Edge Impulse + BLE Sense实现影像分类(上)

在前面章节已介绍如何让Arduino Nano 33 BLE Sense(以下简称BLE Sense...

Day31 | 提供程序码编辑的editor区域

大家好,我是韦恩,今天是铁人赛的第三十一天,今天我们来练习一下在web里怎麽提供editor区块编辑...