iT邦幫忙

2021 iThome 鐵人賽

DAY 26
0
Modern Web

Flask系列 第 26

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 25 實作 user_bp (3)
下一篇
Day 27 實作 user_bp (5)
系列文
Flask30

尚未有邦友留言

立即登入留言