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

问题:

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

注意:

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

【问题讨论】:

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

标签: python django django-views django-orm


【解决方案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) 
    

    【讨论】:

      猜你喜欢
      • 2014-12-15
      • 2013-08-30
      • 1970-01-01
      • 2016-11-05
      • 1970-01-01
      • 2023-03-28
      • 2019-04-19
      • 2016-12-22
      • 1970-01-01
      相关资源
      最近更新 更多