1、前言
1、我们执行 python manage.py shell 这个命令后,将会进入到和django的一个会话,就跟在命令行中输入 python 之后,将会进入到跟 python 的交互一样,这实际的效果大概类似于这样:
?2、handle 方法
1、django.core.management.commands.shell.py
2、下面为 Command 类中的 handle 方法
3、核心相当于执行 return getattr(self, 'python')(options)
def handle(self, **options):
if options['command']:
exec(options['command'], globals())
return
if sys.platform != 'win32' and not sys.stdin.isatty() and select.select([sys.stdin], [], [], 0)[0]:
exec(sys.stdin.read(), globals())
return
# 未指定相关的 interface ,因此为默认
# 1、self.shells: ['ipython', 'bpython', 'python']
available_shells = [options['interface']] if options['interface'] else self.shells
for shell in available_shells:
try:
# 2、当前会反射执行已有的 shell
# 3、而实际我们使用的是 python,ipython、bpython均未安装
return getattr(self, shell)(options)
except ImportError:
pass
raise CommandError("Couldn't import {} interface.".format(shell))
4、从上述代码中的 getattr 可知,最后将执行当前类中的 python?方法
5、以下为 Command 类中的 python 方法
def python(self, options):
import code
imported_objects = {}
if not options['no_startup']:
for pythonrc in OrderedSet([os.environ.get("PYTHONSTARTUP"), os.path.expanduser('~/.pythonrc.py')]):
if not pythonrc:
continue
if not os.path.isfile(pythonrc):
continue
with open(pythonrc) as handle:
pythonrc_code = handle.read()
try:
exec(compile(pythonrc_code, pythonrc, 'exec'), imported_objects)
except Exception:
traceback.print_exc()
try:
hook = sys.__interactivehook__
except AttributeError:
pass
else:
try:
hook()
except Exception:
print('Failed calling sys.__interactivehook__')
traceback.print_exc()
try:
import readline
import rlcompleter
readline.set_completer(rlcompleter.Completer(imported_objects).complete)
except ImportError:
pass
# 1、只是执行了这一段代码
# 2、code 模块中的 interact 方法执行后将打来命令行模式
code.interact(local=imported_objects)
6、做一下测试,关于code.interact() 方法以及参数的使用说明
?3、测试
1、直接在命令行输入 python manage.py shell,进入与django的交互模式,一些都很顺利,成功使用模型查询了数据
2、另一次测试,在命令行输入 python,同样导入模型类,看发生了什么
3、代码报错了-_-||。。
4、这与 python manage.py shell 进入的交互,中间缺少了什么会导致如此?
5、按照提示的_setup()函数,进去看一下具体的报错
?6、_setup() 函数如下,发现,当 settings_module 为 False 的时候,将会抛出异常
7、经过查看 manage.py 之后,发现 manage.py 中存在设置环境变量的代码如下
?8、现在已经发现了问题,则我们继续?
9、这次依然出现了异常,-_-||、、、
10、但是已经是不是同一个异常了,点进入之后检查到底是什么原因
11、从上述代码中可以看到当 apps_ready 为 False 的时候,将会抛出异常
12、而 self.apps_read 默认为 False (这里点一下就可以看到,不再截图)
13、分析:如果想要跳过这个异常,则 apps_ready 必须为 True 才可以,则我们需要找出是哪一段代码将 apps_ready 置为了 True
14、在 IDE 的帮助下,很快定位带了这个 self 方法,其代码如下
def populate(self, installed_apps=None):
if self.ready:
return
with self._lock:
if self.ready:
return
if self.loading:
# Prevent reentrant calls to avoid running AppConfig.ready()
# methods twice.
raise RuntimeError("populate() isn't reentrant")
self.loading = True
# Phase 1: initialize app configs and import app modules.
for entry in installed_apps:
if isinstance(entry, AppConfig):
app_config = entry
else:
app_config = AppConfig.create(entry)
if app_config.label in self.app_configs:
raise ImproperlyConfigured(
"Application labels aren't unique, "
"duplicates: %s" % app_config.label)
self.app_configs[app_config.label] = app_config
app_config.apps = self
# Check for duplicate app names.
counts = Counter(
app_config.name for app_config in self.app_configs.values())
duplicates = [
name for name, count in counts.most_common() if count > 1]
if duplicates:
raise ImproperlyConfigured(
"Application names aren't unique, "
"duplicates: %s" % ", ".join(duplicates))
# 1、此处将 apps_ready 置为 True
self.apps_ready = True
... ...
15、已经找到了这个方法将 apps_ready 置为True,那么只剩下一件事,就是在哪里调用了这个方法
16、在 IDE 的帮助下,我们找到了调用该代码的位置,该代码存在 django 的 setup() 方法下
17、问题分析到此,如果想进入到与django的命令行交互,这里再调用 setup 方法应该就可以了,让我们再次尝试一下?
?18、终于成功了,在执行完上述步骤后,实现了与 python manage.py shell 相同的效果
4、总结
1、在 python manage.py shell 这个命令中,shell 规定进入交互模式
2、manage.py 中真正执行了就是 设置环境变量以及导入 setup 并执行,有兴趣可以打开 manage.py 找一下在哪里执行了 setup 方法
|