【问题标题】:Flask: when to use session vs. storing user data in db?Flask:何时使用会话与将用户数据存储在数据库中?
【发布时间】:2021-02-20 00:37:41
【问题描述】:

我有一个 Flask 应用程序,需要在用户浏览内容时存储用户的位置。

例如,我有这样一条路线:@main_bp.route('/articles/<category>/<article_number>', defaults={'category': 'new'})

内容的组织方式使您可以浏览某个类别下的文章:从 0 开始,然后是 1,依此类推。第 3 篇文章的 URL 如下所示:articles/<category>/3

我想保存用户的位置,这样如果他们在访问文章 3 后离开网站,当他们导航到文章页面时,他们将登陆 articles/<category>/3,而不是 articles/<category>/0

实现这一目标的最佳方法是什么?目前,我已经对数据库中的数据进行了建模,所以有一列看起来像category_article_last_visited(整数)。我可以在用户浏览网站时存储这些数据,但我不确定当他们返回文章页面时如何检索这些数据。

我尝试过的:

  • @main_bp.route('/articles/<category>/<article_number>', defaults={'category': 'new', 'article_number':current_user.category_article_last_visited}),但是我得到一个错误,没有这样的属性。
  • 在路由函数中检查current_user.category_article_last_visited 并使用文章编号。这会呈现正确的内容,但不会更改 URL,这是行不通的。
  • 如果用户具有current_user.category_article_last_visited 的值,则重定向用户。这似乎没有产生任何变化。

我很好奇存储在数据库中(分配值、db.commit() 等)是否是正确的路径,或者我是否应该更多地探索烧瓶会话。我需要这些信息在会话中持续存在,这样如果用户注销、清除 cookie、使用不同的设备等,它仍然可用。将来我可能还会对这些值进行分析。

  • 我上面描述的方法是实现这一目标的最佳方法吗?是烧瓶会话还是其他更好的东西?
  • 如果上述方法最好,我如何正确路由此信息,以便将用户定向到他们离开的页面,并适当更改 URL?

谢谢

【问题讨论】:

    标签: python session flask flask-sqlalchemy


    【解决方案1】:

    我会选择重定向解决方案,它更清楚。

    我会在路由函数的开头添加一个 if 语句,如果有这个用户的数据,我会重定向到那个页面。例如:

    @main_bp.route('/articles/<category>/<article_number>', defaults={'category': 'new'})
    def routefunc():
        if current_user.category_article_last_visited !=0: #or whatever your column keeps for empty data
            return redirect ('/articles/'+yourcategory +'/'+ current_user.category_article_last_visited #as string
    

    这必须与其他一些功能相结合,以避免不定式重定向到该路由:

    选项 1:

    您可以在路由中添加另一个变量,该变量将对这些重定向具有特定值,并且将忽略此 if 语句。例如:

    @main_bp.route('/articles/<category>/<article_number>/<check>', defaults={'category': 'new'})
    def routefunc():
    if current_user.category_article_last_visited !=0 and check!=1: return redirect ('/articles/'+yourcategory +'/'+ current_user.category_article_last_visited+'/1')
    

    但是在这种情况下,您必须将此变量(具有不同于 1 的其他值)添加到您的所有 urls-hrefs 等,它会使您的 url 更“脏”。它对小型应用程序有效,但对于具有多个内部链接的大型应用程序/网站,我会避免使用它。

    选项 2:

    您可以在数据库表中再添加一列,该列将是 1/0,具体取决于用户访问此路由的时间,直接访问还是从重定向访问。在这种情况下,您必须在重定向前后添加几个查询来检查和/或更新此值。

    选项 3:

    您可以创建另一个类似的路由,它只处理重定向,并产生相同的结果(相同的 html)但没有 if 语句。例如:

    @main_bp.route('/articles/<category>/<article_number>', defaults={'category': 'new'})
        def routefunc():
            if current_user.category_article_last_visited !=0: #or whatever your column keeps for empty data
                return redirect ('/articles2/'+yourcategory +'/'+ current_user.category_article_last_visited #as string
    
    @main_bp.route2('/articles2/<category>/<article_number>', defaults={'category': 'new'})
        def routefunc():
            return ('yourhtml.html')
    

    ***基于会话的方法在这里不好,因为你想要一个长期的解决方案。 由于您可能有许多类别、文章、用户,因此您最好专门为此创建一个单独的表

    【讨论】:

    • 我认为这是一个很好的方法,但是我收到了“重定向太多次”的错误。这种方法只是设置了一个无限循环吗?
    • 嗯,你是对的。对此有多种解决方案,例如,您可以在路由中添加另一个变量,该变量将对这些重定向具有特定值,并且将忽略此 if 语句。例如:@main_bp.route('/articles/&lt;category&gt;/&lt;article_number/&lt;check&gt;&gt;', defaults={'category': 'new'}) def routefunc(): if current_user.category_article_last_visited !=0 and check!=1: return redirect ('/articles/'+yourcategory +'/'+ current_user.category_article_last_visited+'/1' 但是,您必须将此变量添加到您的所有 urls-hrefs 等,它将使您的 urls>>>
    • 更“脏”这对小型应用程序有效,但对于具有多个内部链接的大型应用程序/网站,我会避免使用它。这取决于您,您认为更重要的是什么(整洁、简单、用户体验等)并做出选择 或者,您可以在数据库表中再添加一列,该列将是 1/0,具体取决于用户何时访问这条路线,直接或来自重定向。您还可以创建另一个仅处理重定向的类似路由,并产生相同的结果(相同的 html)但没有 if 语句
    • 我将我的 cmets 添加到我的答案中
    【解决方案2】:

    我不知道实现您想要的最佳方法是什么,但您可以尝试以下方法。假设您想对数据执行一些分析,您可能希望将其存储在数据库中。

    当新用户访问您的页面并将他重定向到带有新 cookie 集的文章页面时,您可以设计一个路由来创建用户 cookie:

    @main_bp.route('/articles/set_cookie', "GET"])
    def set_article_cookie():
    
        sessionserializer = securecookiesessioninterface().get_signing_serializer(main_bp)
        tempcookie = sessionserializer.dumps(dict(session))
        resp = make_response(redirect('/articles')) 
        resp.set_cookie("user", tempcookie)
        return resp
    

    以及您检查用户是否已经访问过该页面的现有路线。在这种情况下,您需要在数据库中检查他阅读的最后一篇文章是什么,并相应地重定向他:

    @main_bp.route('/articles/<category>/<article_number>', defaults={'category': 'new'})
    def articles(category, article_number):
    
        # If the user cookie is already set, check if there is some data is the database and redirect to his last article visited 
        cookie = request.cookies
        if "user" in cookie:
            # Retreive the user cookie value and check the database for this value
            return redirect('/articles/' + last_article_visited)
    
        # Else redirect the user to set_article_cookie
        else:
            return redirect("/set_article_cookie")
    

    【讨论】:

      【解决方案3】:

      好的,这是我决定的解决方案:

      • 我更新了整个站点的导航链接的路径,所以不是/articles/&lt;category&gt;/0,而是/articles/&lt;category&gt;/current_user.article_number_last_visited
      • 由于并非所有用户都访问过每个类别的文章,我添加了默认路由逻辑,类似于:
      @main_bp.route('/articles/<category>/', defaults={'article_number': 0})
      @main_bp.route('/articles/<category>/<article_number>', methods=['GET', 'POST'])
      

      即使 current_user.article_number 为空,这也会正确路由用户。

      我相信如果用户未登录,这也将起作用(因此不会有article_number 属性)。我还没有彻底检查这个案例,因为在我的用例中,用户必须登录才能查看内容。

      【讨论】:

        猜你喜欢
        • 2017-12-22
        • 2012-10-26
        • 1970-01-01
        • 2011-09-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-15
        • 2017-01-10
        • 1970-01-01
        相关资源
        最近更新 更多