gpt4 book ai didi

python - 如何避免在 Django 中导入时访问数据库?

转载 作者:搜寻专家 更新时间:2023-10-30 19:45:17 25 4
gpt4 key购买 nike

我的 Django 应用程序有许多类别,我将它们存储在 Category 模型中。我在代码中经常引用这些,所以我发现有一个模块引用(“常量”)对这些类别和它们的组很有用,所以拼写错误很快就会失败。这也提供了缓存的好处。最后,它是实际模型,因此它具有所有相关功能。它看起来像这样:

def load_category(name):
return Category.objects.get(name=name)

DOGS = load_category("dogs")
CATS = load_category("cats")

但是,这会导致导入时数据库访问并导致各种问题。添加具有此类引用的新类别后,我必须在 ./manage.py 运行之前运行数据迁移。我在切换到使用 Django 的测试框架时遇到了一个新问题,即这些从默认(例如,dev 或 prod)数据库加载,而不是从 this warning 中明确提到的测试数据库加载。 .

If your code attempts to access the database when its modules are compiled, this will occur before the test database is set up, with potentially unexpected results. For example, if you have a database query in module-level code and a real database exists, production data could pollute your tests. It is a bad idea to have such import-time database queries in your code anyway - rewrite your code so that it doesn’t do this.

获得这些引用的好处同时避免导入时数据库访问的最佳模式是什么?

一种可能的解决方案是代理模式,它返回一个伪类别,它转发所有模型的功能,但在必要时才访问数据库。我想看看其他人是如何用这种方法或其他解决方案解决这个问题的。

(相关但不同的问题:Django test. Finding data from your production database when running tests?)

final方法

@kevin-christopher-henry 的方法对我很有效。但是,除了修复这些已声明的引用之外,我还不得不延迟从其他代码访问这些引用。在这里,我发现了两种有用的方法。

首先,我发现了Python Lazy Object Proxy .这个简单的对象将工厂函数作为输入,延迟执行以生成包装对象。

MAP_OF_THINGS = Proxy(lambda: {
DOG: ...
CAT: ...
})

完成同一件事的类似方法是将代码推送到用 memoize 修饰的工厂函数中所以它们只会被执行一次。

注意:我最初尝试使用上面的 Proxy 对象作为我延迟访问模型对象问题的直接解决方案。然而,尽管是非常好的模仿,但在查询和过滤这些对象时,我得到了:

TypeError: 'Category' object is not callable

果然,Proxycallable 返回 True(尽管文档说这不能保证它是可调用的)。似乎 Django 查询太聪明了,必然会找到与假模型不兼容的东西。

对于您的应用程序,Proxy 可能就足够了。

最佳答案

我自己也遇到过同样的问题,并且同意在这里有一些最佳实践会很棒。

我最终采用了一种基于 descriptor protocol 的方法:

class LazyInstance:
def __init__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
self.instance = None

def __get__(self, obj, cls):
if self.instance is None:
self.instance, _ = cls.objects.get_or_create(*self.args, **self.kwargs)

return self.instance

然后在我的模型类中我有一些特殊的对象:

class Category(models.Model):
name = models.CharField()

DOGS = LazyInstance(name="dogs")
CATS = LazyInstance(name="cats")

所以在导入时没有任何反应。第一次访问特殊对象时,将查找(并在必要时创建)并缓存相关实例。

关于python - 如何避免在 Django 中导入时访问数据库?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43326132/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com