【问题标题】:successfully imported class is None, but only inside method成功导入的类是无,但只有内部方法
【发布时间】:2013-08-08 01:33:06
【问题描述】:

我的 Django 应用程序的 models.py 中有如下代码:

from main.models import SmartPrefetchQuerySet

class EventPrivacyManager(SoftDeletablePrivacyManager):
    def get_query_set_for_producer(self, producer):
        return self.get_query_set().filter(users_about=producer)

    def get_query_set(self):
        return SmartPrefetchQuerySet(self.model, using=self._db)

    ...

导入工作正常——我可以在模块本身中使用print SmartPrefetchQuerySet,输出为<class 'main.models.SmartPrefetchQuerySet'>。但是当我真正调用 get_query_set 方法时,我得到了这个:

Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File ".../feeds/models.py", line 29, in smart_prefetch_for
    return self.get_query_set().smart_prefetch_for(*args, **kwargs)
  File ".../feeds/models.py", line 26, in get_query_set
    return SmartPrefetchQuerySet(self.model, using=self._db)
TypeError: 'NoneType' object is not callable

另一方面,如果我将导入移动到 get_query_set 方法本身,它工作正常。如果我打开一个 Django shell 并通过将 Event 模型直接传递给它来实例化 SmartPrefetchQuerySet,那也可以正常工作。只有在方法内部 SmartPrefetchQuerySet 似乎是 None (注入该方法的打印语句验证名称确实指的是 None)。

“SmartPrefetchQuerySet”名称仅用于该类的类定义中,并在此调用它,而代码库中没有其他地方。

考虑到 Python 命名空间的正常工作方式,我不明白这种行为是如何发生的。如何在模块级别将导入的名称定义为一件事,而在同一模块中的方法内定义为完全不同的事情,在模块中的任何地方都没有对该名称的其他分配?到目前为止我唯一的想法是它可能是一个循环导入问题,但我找不到任何这样的循环导入,而且通常循环导入似乎会导致不那么微妙的问题。

编辑:整个 models.py 文件,经过一些清理和缩写:

from django.db import models

from django.conf import settings

from auth.models import HasPrivacy, SoftDeletablePrivacyManager
from lck.django.common.models import TimeTrackable, SoftDeletable
from groups.models import Group

from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.utils import timezone

from main.models import SmartPrefetchQuerySet # not literally from a module named "main", but the name has to be sanitized for this post

print SmartPrefetchQuerySet # prints "<class 'main.models.SmartPrefetchQuerySet'>"

# Note: there is an additional import at the bottom of this file for event signal registration

class EventPrivacyManager(SoftDeletablePrivacyManager):
    def get_query_set_for_producer(self, producer):
        "class that can be overridden by children of this manager for models that don't have a 'user' attrib"
        return self.get_query_set().filter(users_about=producer)

    def get_query_set(self):
        print SmartPrefetchQuerySet # prints "None"
        return SmartPrefetchQuerySet(self.model, using=self._db)

    def smart_prefetch_for(self, *args, **kwargs):
        return self.get_query_set().smart_prefetch_for(*args, **kwargs)

class Event(HasPrivacy, SoftDeletable, TimeTrackable):
    ...

    objects = EventPrivacyManager()

    ...

class Notification(SoftDeletable, TimeTrackable):
    ...

print SmartPrefetchQuerySet # prints "<class 'main.models.SmartPrefetchQuerySet'>"

# this import registers the event signal handlers.
# don't remove it even if it doesn't look like it's being used in this
# file, and don't move it from the bottom of this file in order to avoid
# circular imports!
import events

print SmartPrefetchQuerySet # prints "<class 'main.models.SmartPrefetchQuerySet'>"

【问题讨论】:

  • 您使用的是哪个版本的 Django?在1.6 get_query_set 现在是get_queryset
  • 我使用的是1.5版本,所以这个命名应该是正确的。
  • 尝试在模块末尾添加print SmartPrefetchQuerySet任何其他运行代码之前,看看该类是否已经是None。某处正在重新分配它,否则你会得到一个NameError
  • @Bakuriu 好的,我试过了;不幸的是,结果没有帮助,因为名称仍然定义为类,而不是整个模块中的 None,包括最终导入之前和之后。我将编辑代码示例以显示这些打印语句及其输出。

标签: python django django-1.5


【解决方案1】:

如果SmartPrefetchQuerySet 是用C 编写的,那么问题实际上可能出在调用内部,而不是SmartPrefetchQuerySet 本身就是None。您可以使用内置函数看到类似的结果:

>>> max([1,2], key=None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable

检查您作为参数传递的内容。

【讨论】:

  • SmartPrefetchQuerySet 是纯 Python,是纯 Python django.db.models.query.QuerySet 的子类。此外,如问题中所述,在调用之前放置的打印语句验证该名称在该上下文中确实为 None 。我可以发布 SmartPrefetchQuerySet 模块,但由于模块的 __init__ 肯定没有被调用,它似乎还没有相关性。
  • 嗯。这很奇怪。您能否发布其余代码,以便我们查看是否正在生成其他名称绑定?
  • 属于SmartPrefetchQuerySet,属于EventPrivacyManager,还是属于整个事件模块?
  • 到目前为止您显示的代码的其余文件来自该文件,带有打印语句。
  • 好的,但为简洁起见,我将不得不删除该文件中定义的类,而不是EventPrivacyManager。这应该不是问题,因为我无法想象这里没有调用类定义会如何影响命名空间。
猜你喜欢
  • 2019-07-20
  • 2015-12-12
  • 1970-01-01
  • 2011-07-10
  • 2022-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-14
相关资源
最近更新 更多