我正在尝试使用管理器功能来填充模型的默认字段,但我无法使其正常工作。这是我的代码:
class FooManager(models.Manager):
def foo_filter(self):
return Foo.objects.latest('id')
class Foo(models.Model):
objects = FooManager()
name = models.CharField(
max_length=100,
unique=True,
default=objects.foo_filter())
每当我跑的时候,
我在NameError: global name 'Foo' is not defined
return Foo.objects.latest('id')
了
答案 0 :(得分:1)
哈!这很酷:)
第一次加载models.py
时,Python正在尝试解析所有类定义。
所以它看到的第一件事是FooManager
,到目前为止一切都很好。
在您的过滤方法中,您可以使用Foo
,此时此处仍然未知。通常这不会有问题,因为您在方法中使用Foo
,并且该方法仅在运行时调用,此时所有类都已加载。
现在Python看到了Foo
类,并在name
字段上调用了管理器的方法之一。此时,当调用过滤器方法时,Foo
类尚未完全加载,因此当您输入过滤器方法时,Foo
确实未定义。
您必须将经理定义移到Foo
定义下面,但是您不能这样做,因为行objects = FooManager()
会失败,因为FooManager
将是未定义的。< / p>
顺便说一句:这是一个非常常见的新手错误:您必须永远将方法调用放入您的字段定义中。这意味着该方法仅在服务器启动时执行 ,并且Django加载所有模型定义。这导致了非常令人沮丧的错误:
首先,您的字段的默认值确实是最新的Foo
对象,但是当您向数据库添加新对象时,不会将更改为新的最新对象,它将保持服务器启动时最新的对象。
Django通常允许您将方法放入字段定义中,因此您可以编写:
default=objects.foo_filter
没有()
。现在,当加载服务器时,将不会执行该方法。它只会在Django实际需要检索默认值时执行,并且在那个时间点,FooManager
和Foo
都已加载。
但除此之外,您的经理甚至不需要知道它属于哪个型号。在这里查看Django文档:https://docs.djangoproject.com/en/1.7/topics/db/managers/#modifying-initial-manager-querysets
每位经理都有一个get_queryset
方法,您可以覆盖该方法以及应该使用哪种方法,因此您可以执行以下操作:
class FooManager(models.Manager):
def foo_filter(self):
return self.get_queryset().latest('id')
现在你的经理根本不使用Foo
类,你不会遇到任何循环依赖问题。
顺便说一下,我认为latest('id')
不起作用,你必须传入一个日期字段的字段名称,而不是ID字段。
答案 1 :(得分:-1)
您正在创建一个循环,该对象已经 Foo.objects
。您所需要的只是:
def foo_filter(self):
return self.latest('id')
最重要的是,你不能使用数据库为这样的字段设置默认值。