发布于2019-08-22 15:33 阅读(344) 评论(0) 点赞(30) 收藏(5)
Django源码解析(三) Django开发服务器,WSGI规范实现
在使用django-admin.py创建Django项目时,manage.py会被自动生成在项目根目录下.用以对django项目实现命令行操作.
调用django.core.management .execute_manager()方法实现命令执行.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #!/usr/bin/env python from django.core.management import execute_manager import imp try : imp.find_module( 'settings' ) # Assumed to be in the same directory. except ImportError: import sys sys.stderr.write( "Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n" % __file__) sys.exit( 1 ) import settings if __name__ = = "__main__" : execute_manager(settings) |
django-admin.py调用django.core.management .execute_from_command_line()方法实现命令执行.
1 2 3 4 5 | #!/usr/bin/env python from django.core import management if __name__ = = "__main__" : management.execute_from_command_line() |
manage.py与django-admin.py都使用了django.core.management包的方法.execute_manager()方法专门提供给manage.py使用,execute_from_command_line()专门
提供给django-admin.py使用.(地球人都看的出来,⊙﹏⊙b).
这俩个命令的主要差别在于execute_manager()多执行了一个setup_environ(settings_mod)方法.弄清这个方法的作用,就知道manage.py与django-admin.py的主要区别了.
1 2 3 4 5 6 7 8 | def execute_manager(settings_mod, argv = None ): """ Like execute_from_command_line(), but for use by manage.py, a project-specific django-admin.py utility. """ setup_environ(settings_mod) utility = ManagementUtility(argv) utility.execute() |
最主要显示setup_environ(settings_mod)方法功能的代码:
1 2 3 4 5 6 7 8 9 10 11 | # Set DJANGO_SETTINGS_MODULE appropriately. if original_settings_path: os.environ[ 'DJANGO_SETTINGS_MODULE' ] = original_settings_path else : os.environ[ 'DJANGO_SETTINGS_MODULE' ] = '%s.%s' % (project_name, settings_name) # Import the project module. We add the parent directory to PYTHONPATH to # avoid some of the path errors new users can have. sys.path.append(os.path.join(project_directory, os.pardir)) project_module = import_module(project_name) sys.path.pop() |
可见setup_environ(settings_mod)方法的主要功能,即manage.py与django-admin.py的主要区别:
manage.py设置一个名为DJANGO_SETTINGS_MODULE的系统环境变量.
例如我的django项目根目录为”E:\workspace\django\pearl”,settings模块的文件名为settings.py.DJANGO_SETTINGS_MODULE会被设置成为”pearl.settings”
manage.py把当前项目目录的父目录加入到PYTHONPATH,项目目录作为包导入.
例如我的django项目根目录为”E:\workspace\django\pearl”.把”E:\workspace\django”加入到PYTHONPATH,导入包名为”pearl”.
以上2点实际上使在使用manage.py时,不用像使用django-admin.py时输入”--settings”与”--pythonpath”参数.提供更便捷的操作.
注: 当直接使用django-admin.py时,需要设置'DJANGO_SETTINGS_MODULE'环境变量或”—settings”选项.
通过execute_manager()与execute_from_command_line()方法,可以看到Django命令的执行主要通过django.core.management.ManagementUtility类执行.
ManagementUtility类的execute()方法为执行入口.
命令的执行过程:
1.解析命令,获得要执行的子命令名称.通过继承至OptionParser的类LaxOptionParser解析命令行.
2.获得所有可执行子命令的完整模块路径.
命令文件在django/core/management/commands目录下与INSTALLED_APPS(settings.py文件中定义)/management/commands目录下.
通过ManagementUtility.fetch_command()方法中,调用get_commands()方法实现.
3.返回子命令对应同名模块中的Command类的实例.
4.执行命令.调用Command类的实例的run_from_argv()方法.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | def handle_default_options(options): """ 此方法设定'DJANGO_SETTINGS_MODULE'与pythonpath,即在manage.py中设定的2个内容 """ if options.settings: os.environ[ 'DJANGO_SETTINGS_MODULE' ] = options.settings if options.pythonpath: sys.path.insert( 0 , options.pythonpath) class ManagementUtility( object ): """ Encapsulates the logic of the django-admin.py and manage.py utilities. A ManagementUtility has a number of commands, which can be manipulated by editing the self.commands dictionary. """ def __init__( self , argv = None ): # 获取输入参数 self .argv = argv or sys.argv[:] # 执行命令的文件,manage.py或django-admin.py self .prog_name = os.path.basename( self .argv[ 0 ]) ############################################################################ # 省略 ############################################################################ def fetch_command( self , subcommand): """ Tries to fetch the given subcommand, printing a message with the appropriate command called from the command line (usually "django-admin.py" or "manage.py") if it can't be found. """ try : # 获得django/core/management/commands目录下与INSTALLED_APPS/management/commands目录下的子命令对应的模块前缀 # 如"cleanup"对应模块前缀"django.core" app_name = get_commands()[subcommand] except KeyError: sys.stderr.write( "Unknown command: %r\nType '%s help' for usage.\n" % \ (subcommand, self .prog_name)) sys.exit( 1 ) if isinstance (app_name, BaseCommand): # If the command is already loaded, use it directly. klass = app_name else : # load_command_class的核心代码,返回指定子命令模块Command类的实例. # module = import_module('%s.management.commands.%s' % (app_name, name)) # return module.Command() klass = load_command_class(app_name, subcommand) return klass ############################################################################ # 省略 ############################################################################ def execute( self ): """ Given the command-line arguments, this figures out which subcommand is being run, creates a parser appropriate to that command, and runs it. 主要执行入口. 通过继承至OptionParser的类LaxOptionParser解析命令行.执行相应的子命令. """ # Preprocess options to extract --settings and --pythonpath. # These options could affect the commands that are available, so they # must be processed early. parser = LaxOptionParser(usage = "%prog subcommand [options] [args]" , version = get_version(), option_list = BaseCommand.option_list) self .autocomplete() try : options, args = parser.parse_args( self .argv) # 如果输入了settings与pythonpath参数的话,设置这俩个参数 handle_default_options(options) except : pass # Ignore any option errors at this point. try : # 要执行的子命令 如: "manage.py runserver"中的"runserver" subcommand = self .argv[ 1 ] except IndexError: # 未输入子命令的话,打印"help"信息 subcommand = 'help' # Display help if no arguments were given. if subcommand = = 'help' : if len (args) > 2 : self .fetch_command(args[ 2 ]).print_help( self .prog_name, args[ 2 ]) else : parser.print_lax_help() sys.stderr.write( self .main_help_text() + '\n' ) sys.exit( 1 ) # Special-cases: We want 'django-admin.py --version' and # 'django-admin.py --help' to work, for backwards compatibility. elif self .argv[ 1 :] = = [ '--version' ]: # LaxOptionParser already takes care of printing the version. pass elif self .argv[ 1 :] in ([ '--help' ], [ '-h' ]): parser.print_lax_help() sys.stderr.write( self .main_help_text() + '\n' ) else : # 找到相应子命令,并执行. self .fetch_command(subcommand).run_from_argv( self .argv) |
插播广告: settings.SETTINGS_MODULE
时常用到django.conf.settings的SETTINGS_MODULE属性来关联到我们自己项目的settings模块.它是如何实现的呢?
嘿嘿,这个是通过前面提到的DJANGO_SETTINGS_MODULE系统环境变量来实现的.来看这个实现的核心代码.
12345ENVIRONMENT_VARIABLE
=
"DJANGO_SETTINGS_MODULE"
settings_module
=
os.environ[ENVIRONMENT_VARIABLE]
self
.SETTINGS_MODULE
=
settings_module
Django命令需要写在与命令行子命令同名的模块中.模块必须包含一个名为Command的类作为调用入口.
django.core.management.BaseCommand类作为所有命令的基类.还同时提供了AppCommand LabelCommand和NoArgsCommand三个辅助类.
自定义命令可继承自BaseCommand或其他三个辅助类,同时重写父类的不同方法即可.
简单介绍
1. BaseCommand
所有命令的基础类,预留一个handle()方法,供子类重写.
1 2 3 4 5 6 7 | def handle( self , * args, * * options): """ The actual logic of the command. Subclasses must implement this method. """ raise NotImplementedError() |
2. AppCommand
接受一个或多个installed application的名字作为第一部分参数.实现对App操作.预留一个handle_app()方法供子类重写.
1 2 3 4 5 6 7 8 | def handle_app( self , app, * * options): """ Perform the command's actions for ``app``, which will be the Python module corresponding to an application name given on the command line. """ raise NotImplementedError() |
3. LabelCommand
接受一个或多个标签参数,预留一个handle_label()方法供子类重写.
1 2 3 4 5 6 7 | def handle_label( self , label, * * options): """ Perform the command's actions for ``label``, which will be the string as given on the command line. """ raise NotImplementedError() |
4. NoArgsCommand
不接受参数.预留一个handle_label()方法供子类重写.
1 2 3 4 5 6 | def handle_noargs( self , * * options): """ Perform this command's actions. """ raise NotImplementedError() |
作者:短发越来越短
链接:https://www.pythonheidong.com/blog/article/52440/a8cb960e2665dc2774cf/
来源:python黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 python黑洞网 All Rights Reserved 版权所有,并保留所有权利。 京ICP备18063182号-1
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!