奇怪的Django导入行为

4

请问有人能解释一下这种行为吗:

django项目名为foo

文件bar/models.py:

class MyModelError(TypeError):
    pass

class MyModel(models.Model):
    ...

./manage.py shell

>>> from foo.bar.models import MyModel as m1
>>> from bar.models import MyModel as m2
>>> from foo.bar.models import MyModelError as e1
>>> from bar.models import MyModelError as e2
>>> m1 is m2
True
>>> e1 is e2
False

假的?!

>>> m1
<class 'foo.bar.models.MyModel'>
>>> m2
<class 'foo.bar.models.MyModel'>
>>> e1
<class 'foo.bar.models.MyModelError'>
>>> e1
<class 'bar.models.MyModelError'>

我在这里做错了什么?我的解决方法(除了确保我以“正确的方式”导入)是将错误类作为模型本身的成员(就像Django中的model.DoesNotExists),但我想知道发生了什么。


不要在模块名称中使用点。 - Cat Plus Plus
1
我相当确定这是一个打字错误,因为你不能通过import导入名称中带有点的模块。 - Ignacio Vazquez-Abrams
2个回答

4

Django使用元类来定义模型。其中有一个检查,以避免重复定义模型,因此当创建类时,如果已经定义过,则会得到之前定义的版本。请参见django.db.models.base.ModelBase

from django.db.models.loading import get_model

# Bail out early if we have already created this class.
m = get_model(new_class._meta.app_label, name, False)
if m is not None:
    return m

错误类是普通的Python类,没有缓存,因此您会得到不同版本,因为它们所属的模块不同。我认为这是因为在运行Django runserver时,您会以两种方式从路径加载相同的模块:

  • 当前目录
  • 当前目录上面的目录

这样您就可以导入完全限定的包(包括项目名称),并且可以正常工作。

我倾向于永远不使用项目名称进行导入,以避免出现此问题。


0
在大多数编程语言中,错误处理都有一种类似于楼梯的机制。因此,如果发生错误,异常机制开始搜索用于处理错误的异常。如果该类无法处理异常,则通过从该类派生的类级别向上搜索... 它会一直保持这个过程,直到继承的最高级别...
因此,您正在定义一个从TypeError派生的ModelError类,并从不同路径导入该类可能会导致Python解释器将这两个类识别为不同的类。 Python文档

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接