“内部连接”类似于Flask中的MongoDB,Jinja

2024-06-11 07:52:26 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试使用Flask对两个MongoDB集合执行类似于的“内部联接”

我认为我应该使用$lookup来实现这一点,我目前的路线是:

@app.route("/perfumes")
def perfumes():
    perfumes = mongo.db.perfumes.find()
    users = mongo.db.perfumes.aggregate(
        [
            {
                "$lookup": {
                    "from": "mongo.db.users",
                    "localField": "author",
                    "foreignField": "username",
                    "as": "creator",
            }
        }
    ]
)
return render_template("perfumes.html", title="Perfumes", perfumes=perfumes, users=users)

在我的模板中,我在一个集合中遍历perfumes,并希望访问users集合中的所有数据,因为每个香水项目都是由一个用户创建的。 perfumes集合有一个author字段,该字段应用于链接users集合中的username字段。 我的模板的一个非常简化(精简)的版本如下所示:

% for perfume in perfumes %}
    {{ perfume.name }}
    Created by {{ <HERE I WANT TO HAVE MY ITEM CREATOR> }} on {{ perfume.date_updated.strftime('%d-%m-%Y') }}
{% endfor %}

为了让这个“加入”工作并能够从两个集合中访问该项的所有数据,我缺少了什么

谢谢

注意:我想访问的不仅仅是创建者的用户名,如个人资料图片等,这就是为什么我需要加入

更新:以下是我在两个数据库中使用的结构:

{
    "perfumes": {
        "author": "<string>",
        "brand": "<string>",
        "name": "<string>",
        "descritpion": "<text field>",
        "date_updated": "<date>",
        "public": "<boolean>",
        "picture": "<string>"
    },
    "users": {
        "username": "<string>",
        "first_name": "<string>",
        "last_name": "<string>",
        "email": "<string>",
        "is_admin": "<boolean>",
        "avatar": "<string>"
    }
}

因此{}中的{}可以与{}中的{}链接


Tags: 数据name模板dbdatestring链接mongo
2条回答

您可以通过简单的聚合来实现这一点。请尝试以下代码:

cur = mongo.db.perfumes.aggregate(
    [
        {
            '$lookup': {
                'from': 'users', # You can directly specify on which collection you want to lookup
                'localField': 'author',
                'foreignField': 'username',
                'as': 'creator',
            }
        },
        {
            '$unwind' : '$creator'
        },
        {
            '$project': {
                'username' : '$creator.username',
                'perfumeName' : '$name',
                'date_updated' : '$date_updated',
                'profilePicture' : '$creator.avatar',
                ..., # Rest of the items that you want to display
                '_id': 0
            }
        }
    ]
)

返回如下结果:

return render_template("perfumes.html", title="Perfumes", perfumes=cur) # You don't need to pass users

在模板中显示,如下所示:

{% for perfume in perfumes %}
    {{ perfume['perfumeName'] }}
    Created by {{ perfume['username'] }} on {{ perfume['date_updated'].strftime('%d-%m-%Y') }}
{% endfor %}

我希望有帮助

您可以创建一个jinja过滤器,以便将来自两个游标的信息连接起来,然后在jinja上对其进行迭代,就像它是一个目录列表一样

开始创建一个定制的jinja过滤器,其中聚合的游标是mongo.db.perfumes.aggregate行的输出:例如page_filters.py文件

from .. import app

@app.template_filter()
def get_user_information(perfume_cursor):
    """ Creates a generator to get extra info of user """
    # Transform mongo cursor into a list of dicts
    perfume_cursor = list(perfume_cursor)

    for item in perfume_cursor:
        extra_info = mongo.db.users.find_one({"username": item['author']}, {"first_name": 1, "profile_picture": 1})
        # Declare below your desired user info
        item['user_info'] = dict(first_name=extra_info.first_name,profile_picture=extra_info.profile_picture)
        yield item

为了使我们的过滤器在模板中可用,我们只需要将其导入顶级init.py中

# Make sure app has been initialized first to prevent circular imports.
from .util import page_filters

现在在jinja上,只需使用过滤器

{% for perfume in (perfumes | get_user_information) %}
    {{ perfume['name'] }}
    Created by {{ perfume['user_info']['first_name']}} on {{ perfume['date_updated'].strftime('%d-%m-%Y') }}
{% endfor %}

但是,您应该使查询更加具体,只获取必需的用户字段,否则内存中可能会有太多信息。我们使用Generator的原因是提供一种处理数据的方法,而无需首先将整个数据源加载到内存中

参考文献: https://uniwebsidad.com/libros/explore-flask/chapter-8/custom-filtershttps://www.lachlaneagling.com/reducing-memory-consumption-python/

相关问题 更多 >