包被Django污染的命名空间?

时间:2016-11-02 22:19:59

标签: python django

Django 1.8

由于没有明显的原因,包的模块中定义的全局变量在其初始赋值和延迟函数调用之间被替换。

使用django-admin startproject创建最小Django项目。添加了django-admin startapp simplelib的新空应用程序。新应用simplelib已添加到项目INSTALLED_APPS的{​​{1}}。

Bellow是唯一添加的代码:

settings.py

使用# content of myproject.simplelib.__init__.py from django.db import models from django.db.models.signals import class_prepared def myhandler(sender, **kwargs): print 'models from myhandler: {}'.format(models) def direct_call(): print 'models from direct_call: {}'.format(models) class_prepared.connect(myhandler) print 'models from top namespace: {}'.format(models) direct_call() 运行项目时,会生成以下输出:

manage.py runserver

参见,当调用信号处理函数时,models from top namespace: <module 'django.db.models' from '/home/<snip>/Projects/Python/django-projects/lib/python2.7/site-packages/django/db/models/__init__.pyc'> models from direct_all: <module 'django.db.models' from '/home/<snip>/Projects/Python/django-projects/lib/python2.7/site-packages/django/db/models/__init__.pyc'> models from myhandler: <module 'simplelib.models' from '/home/<snip>/Projects/Python/django-projects/myproject/simplelib/models.pyc'> ^^^^^^^^^^^^^^^^ 全局变量被更改。 没有其他项目的代码。它必须由Django本身改变。

注意:上述效果仅适用于modules tuple开头simplelib的情况。最后添加时,INSTALLED_APPS仍会按预期指向models

知道这里有什么?

1 个答案:

答案 0 :(得分:1)

这是正常的Python行为。

导入子模块时,该子模块将设置为父模块上的属性。在这种情况下,导入simplelib.models时,会在父模块models上设置simplelib子模块。父模块名称空间与该模块的__init__.py全局名称空间相同。这将覆盖旧值。

如果您将simplelib作为INSTALLED_APPS中的第一个条目,其models子模块将是Django导入的第一个模型模块。在任何模型触发simplelib.models信号之前,这将替换class_prepared属性。另一方面,如果您将simplelib放在INSTALLED_APPS的末尾,Django将加载simpellib.models作为最后一个模型模块。之前导入的任何模型都会在导入class_prepared之前以及在使用子模块替换simplelib.models属性之前触发models信号。