2011-06-16 86 views
4

可能有人请解释这种现象:奇怪Django的进口行为

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)但我想知道发生了什么

+0

不要使用点作为模块名称的一部分。 – 2011-06-16 11:56:07

+1

我相当确定这是一个错字,因为您无法通过'import'在名称中导入带有点的模块。 – 2011-06-16 11:58:09

+0

确实是一个错字。固定 – second 2011-06-16 11:59:51

回答

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

在大多数编程语言中,错误挂起具有阶梯式机制。所以如果发生错误,异常机制开始搜索处理错误的异常。如果在该类中无法处理异常,它会通过该类从其派生而来的类继续搜索上层... ....它使此过程始终处于继承的最高级别...

因此,您正在定义ModelError派生的类TypeError,并从不同的路径导入该类可能可能导致python interpereter将这两个类别识别为不同的类。

Python Documentation