在模型定义中使用自定义管理器功能

时间:2014-12-31 23:42:48

标签: django python-2.7

我正在尝试使用管理器功能来填充模型的默认字段,但我无法使其正常工作。这是我的代码:

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')

2 个答案:

答案 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实际需要检索默认值时执行,并且在那个时间点,FooManagerFoo都已加载。

但除此之外,您的经理甚至不需要知道它属于哪个型号。在这里查看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')

最重要的是,你不能使用数据库为这样的字段设置默认值。