可以在 Django 视图中使用 Python 生成器吗?

Posted

技术标签:

【中文标题】可以在 Django 视图中使用 Python 生成器吗?【英文标题】:Can Python Generators be used in Django Views? 【发布时间】:2015-01-23 01:14:08 【问题描述】:

问题:

基本上我想在每次调用视图时从数据库中返回一个唯一的结果(直到我用完唯一的对象并不得不重新开始)。我在想一个简单而优雅的解决方案是使用生成器来处理这个问题。这是可能的吗?如果可以,如何从 ORM 中提取值?

注意:

我认为会话或使用像 Memento 这样的设计模式可能是一个解决方案,但我真的很想知道 Python 生成器是否以及如何在这种情况下使用。

【问题讨论】:

这完全取决于您期望如何使用它们。请记住,在正常生产中,您有多个进程正在运行。这使得难以维持全局状态。你可能想看看使用缓存来做这种事情。 【参考方案1】:

由于 Django 是同步 wsgi,您必须单独处理每个请求,您的 python 环境可以随时终止或切换到另一个环境。

如果你没有恐惧和单一进程,你可以创建一个文件范围字典,其中包含每次都会使用的会话 ID 和迭代器

from django.shortcuts import render
from collections import defaultdict
import uuid

def iterator():
    for item in DatabaseTable.objects.all():
    yield item

sessions_current_iterators = defaultdict(iterator)

def my_view(request):
    id = request.session.get("iterator_id", None)
    if id is None:
        request.session["iterator_id"] = str(uuid.uuid4())
    try:
        return render(request, "item_template.html", "item": next(sessions_current_iterators)
    except StopIteration:
        request.session.pop("iterator_id")
        return render(request, "end_template.html", )

但是:永远不要在生产环境中使用它!

生成器非常适合在计算请求时减少内存消耗,或者对 tornado web 服务很有用,但显然,django 不应该在局部变量中的请求之间共享数据。

【讨论】:

【参考方案2】:

你总是可以在可以使用 return 的地方使用 yield(因为这些是 python 的东西而不是 Django 的东西)。这里唯一需要注意的是,每个请求都会调用相同的函数;因此收益率之后的延续可能会为另一个客户提供服务,而不是您想要的客户。但是,您可以通过使用更高级别的函数(此处的生成器)来解决这个问题。基本上,该函数将有一个生成器字典,该字典由从请求派生的唯一键索引。每次调用该函数时,检查字典中是否已存在该请求的条目。如果没有为该请求添加新功能。然后为给定的请求调用生成器,确保存储生成器产生或返回的任何内容。为了将字典保存在内存中,让 main 函数现在产生存储的值。最后,为了让每次调用main函数都不会清空字典,通过将字典初始化为空字典来启动函数体;然后将其他所有内容包装在无限的while循环中。这将确保 main 函数,也是一个生成器,永远不会真正退出。第一次调用时,字典被初始化;然后开始。同时,如果给定请求不存在任何条目,该函数将创建一个生成器并将其存储在字典中。然后该函数为请求调用生成器并生成生成器返回的任何内容或在 while 底部生成的内容。再次调用时; main 函数在 while 的顶部恢复。代码是这样的:

def main_func(request, *args) :
    funcs =  
    while True:
        request_key = make_key(request)
        If request_key not in funcs.keys():
            def generator_func():
                # your generator code here... 
                # remember to delete the func item in funcs before returning... 
            funcs[request_key]  = generator_func
        yield funcs[request_key] () 

    def make_key(request):
        # quick and dirty impl
        return str(request.session) 

【讨论】:

以上是关于可以在 Django 视图中使用 Python 生成器吗?的主要内容,如果未能解决你的问题,请参考以下文章

在 django 视图中使用 subprocess.Popen() 执行 python 脚本

Django之视图函数总结

在 Python 中使用 Django - 尝试导入时未定义视图

Django将Python对象从视图传递到模板中的Javascript脚本

Django 框架之视图函数(Views)

python django -3 视图