当前位置: 首页 > news >正文

西安市招聘网最新招聘信息/网络推广优化招聘

西安市招聘网最新招聘信息,网络推广优化招聘,网站转小程序,邹平做网站哪家好示例:创建一个最小的django demo$ django-admin.py startproject minidemo这条命令有3个参数:django-admin.pystartprojectminidemo解析参数django-admin.py既然能执行django-admin.py这条命令,说明它一定在可执行命令目录下执行which django…

526fea7d92ef24ed3d44f53d801bdcf5.png

示例:

创建一个最小的django demo

$ django-admin.py startproject minidemo

这条命令有3个参数:

  • django-admin.py
  • startproject
  • minidemo

解析参数django-admin.py

既然能执行django-admin.py这条命令,说明它一定在可执行命令目录下

执行which django-admin.py可以看到django-admin.py在venv/bin/目录下

/Users/xxx/my_project/venv/bin/django-admin.py

查看此目录 ls venv/bin/

__pycache__      activate.csh     django-admin     easy_install     iptest           ipython          pip              pip3.6           python           sqlformat
activate         activate.fish    django-admin.py  easy_install-3.6 iptest3          ipython3         pip3             pygmentize       python3

可以看到除了django-admin.py以外,还有django-admin也在

既然找到文件了,对比一下两者的代码

# django-admin import re
import sysfrom django.core.management import execute_from_command_lineif __name__ == '__main__':sys.argv[0] = re.sub(r'(-script.pyw?|.exe)?$', '', sys.argv[0])sys.exit(execute_from_command_line())
# django-admin.pyfrom django.core import managementif __name__ == "__main__":management.execute_from_command_line()

可以看到两者基本是一样的,除了前者会自动进行后缀补全。这就解释了为什么既可以用django-admin.py startproject xxx 也可以用django-admin startproject xxx 生成项目。

excute_from_command_line()这个函数名字也非常清晰明了,从命令行开始执行,这里就是我们创建项目的入口

至此,第一个参数django-admin.py解析完毕。

解析execute_from_command_line()

# django-admin.py
from django.core import management
if __name__ == "__main__":management.execute_from_command_line()

从上面的代码可以看到,当我们执行django-admin.py时,其实执行的是

management的execute_from_command_line()函数

我们进入execute_from_command_line()函数内部查看,函数源码在 django/core/management/__init__ 文件的第378行

def execute_from_command_line(argv=None):"""Run a ManagementUtility."""utility = ManagementUtility(argv)utility.execute()

可以看到,excute_from_command_line()函数实例化了一个ManagementUtility()类,执行了excute()方法,这里代码分为

  • 实例化
  • 执行excute()

实例化

class ManagementUtility:"""Encapsulate the logic of the django-admin and manage.py utilities."""def __init__(self, argv=None):self.argv = argv or sys.argv[:]# ['/Users/kaka/PycharmProjects/my_project/kk.py', 'startproject', 'minidemo']self.prog_name = os.path.basename(self.argv[0])if self.prog_name == '__main__.py':self.prog_name = 'python -m django'self.settings_exception = None

可以看到在实例化的过程中将命令行参数传入到了self.argv中,self.prog_name含义???待查

实例化完毕,即开始执行excute()方法

excute()

excute()方法在django/core/management/__init__ 文件的301行,粗略概览,此方法没有返回任何东西,所以它只是执行了IO操作,excute方法代码分为几大块,我将会在代码中进行注释。

def execute(self):"""给出命令行参数,识别出正在运行的是什么子命令,创建与命令对应的解析器,然后运行它"""# 取出第二个命令行参数,此处为startproject命令try:subcommand = self.argv[1]   except IndexError:subcommand = 'help'  # 如果没有找到命令,就显示help指令# 解析是否有指定settings.py和Python路径 parser = CommandParser(usage='%(prog)s subcommand [options] [args]', add_help=False, allow_abbrev=False)parser.add_argument('--settings')parser.add_argument('--pythonpath')parser.add_argument('args', nargs='*')  # catch-alltry:options, args = parser.parse_known_args(self.argv[2:])handle_default_options(options)except CommandError:pass  # Ignore any option errors at this point.try:settings.INSTALLED_APPSexcept ImproperlyConfigured as exc:self.settings_exception = excexcept ImportError as exc:self.settings_exception = exc# 检查是否已经对settings进行了配置,configured是一个属性,在django.conf中,# 如果进行了配置,表示已经建立了项目,应该寻找runserver这一类的命令了,此处我们忽略    # @property# def configured(self):#     """Return True if the settings have already been configured."""#     return self._wrapped is not emptyif settings.configured:# Start the auto-reloading dev server even if the code is broken.# The hardcoded condition is a code smell but we can't rely on a# flag on the command class because we haven't located it yet.if subcommand == 'runserver' and '--noreload' not in self.argv:try:autoreload.check_errors(django.setup)()except Exception:# The exception will be raised later in the child process# started by the autoreloader. Pretend it didn't happen by# loading an empty list of applications.apps.all_models = defaultdict(OrderedDict)apps.app_configs = OrderedDict()apps.apps_ready = apps.models_ready = apps.ready = True# Remove options not compatible with the built-in runserver# (e.g. options for the contrib.staticfiles' runserver).# Changes here require manually testing as described in# #27522._parser = self.fetch_command('runserver').create_parser('django', 'runserver')_options, _args = _parser.parse_known_args(self.argv[2:])for _arg in _args:self.argv.remove(_arg)# In all other cases, django.setup() is required to succeed.else:django.setup()# 自动补齐,略        self.autocomplete()# 如果命令是help,略if subcommand == 'help':if '--commands' in args:sys.stdout.write(self.main_help_text(commands_only=True) + 'n')elif not options.args:sys.stdout.write(self.main_help_text() + 'n')else:self.fetch_command(options.args[0]).print_help(self.prog_name, options.args[0])# Special-cases: We want 'django-admin --version' and# 'django-admin --help' to work, for backwards compatibility.# 如果命令是version或--version,略elif subcommand == 'version' or self.argv[1:] == ['--version']:sys.stdout.write(django.get_version() + 'n')# 如果命令是-h或--help,略    elif self.argv[1:] in (['--help'], ['-h']):sys.stdout.write(self.main_help_text() + 'n')# 终于到了我们真正执行IO的地方了else:# 此处subcommand是startproject,fetch_command函数是self.fetch_command(subcommand).run_from_argv(self.argv)

通过对excute()方法的拆解,我们发现,大部分代码和我们这次分析无关,真正有关的是这一行

self.fetch_command(subcommand).run_from_argv(self.argv)

我们再次把这条命令拆成self.fetch_command(subcommand)run_from_argv(self.argv)两部分来看


excute()方法分为两步:

  • self.fetch_command(subcommand)
  • run_from_argv(self.argv)

一、 self.fetch_command(subcommand)

Fetch_command方法的代码在django/core/management目录下的__init__文件195行。

本方法有返回,为一个类,所以我们查看返回了什么类

def fetch_command(self, subcommand):"""查找获取给予的命令subcommand为startproject"""commands = get_commands()# commands为如下的一个字典# <class 'dict'>: {#     'check': 'django.core',#     'compilemessages': 'django.core',#     'createcachetable': 'django.core',#     'dbshell': 'django.core',#     'diffsettings': 'django.core',#     'dumpdata': 'django.core',#     'flush': 'django.core',#     'inspectdb': 'django.core',#     'loaddata': 'django.core',#     'makemessages': 'django.core',#     'makemigrations': 'django.core',#     'migrate': 'django.core',#     'runserver': 'django.core',#     'sendtestemail': 'django.core',#     'shell': 'django.core',#     'showmigrations': 'django.core',#     'sqlflush': 'django.core',#     'sqlmigrate': 'django.core',#     'sqlsequencereset': 'django.core',#     'squashmigrations': 'django.core',#     'startapp': 'django.core',#     'startproject': 'django.core',#     'test': 'django.core',#     'testserver': 'django.core'# }# 获取获取要安装的django app,如果没传,就是安装django核心部分try:app_name = commands[subcommand]# app_name为从上述字典中取出键为startproject的值,即django.core,# 具体含义就是安装django核心部分except KeyError:if os.environ.get('DJANGO_SETTINGS_MODULE'):# If `subcommand` is missing due to misconfigured settings, the# following line will retrigger an ImproperlyConfigured exception# (get_commands() swallows the original one) so the user is# informed about it.settings.INSTALLED_APPSelse:sys.stderr.write("No Django settings specified.n")possible_matches = get_close_matches(subcommand, commands)sys.stderr.write('Unknown command: %r' % subcommand)if possible_matches:sys.stderr.write('. Did you mean %s?' % possible_matches[0])sys.stderr.write("nType '%s help' for usage.n" % self.prog_name)sys.exit(1)# 略    if isinstance(app_name, BaseCommand): # False,不是实例# If the command is already loaded, use it directly.klass = app_nameelse:# 此处是我们本次要执行的,要返回的类在这里klass = load_command_class(app_name, subcommand) # klass = load_command_class(django.core, startproject) return klass

查看load_command_class函数搞明白返回了什么类

def load_command_class(app_name, name):"""Given a command name and an application name, return the Commandclass instance. Allow all errors raised by the import process(ImportError, AttributeError) to propagate."""module = import_module('%s.management.commands.%s' % (app_name, name))# import_module函数的说明是"Import a module."这里知道它是导入了一个模块就行,不深究了,略# module补全后为'django.core.management.commands.startproject',所以导入的是# django.core.management.commands目录下的startproject.py模块,此模块下有一个Command()类return module.Command()# 返回的是django项目中 django/core/management/commands/startproject.py文件中的Command()类

到这里,我们可以明白self.fetch_command(subcommand)这部分代码返回的是startproject.py中的Command类,所以self.fetch_command(subcommand).run_from_argv(self.argv)可以直接替换为Command.run_from_argv(self.argv)

参数self.argv还是我们之前分析的那个列表:

<class 'list'>: ['/Users/kaka/PycharmProjects/my_project/kk.py', 'startproject', 'minidjango']

分析完前半部分,我们再来分析run_from_argv函数

二、 run_from_argv(self.argv)

def run_from_argv(self, argv):"""Set up any environment changes requested (e.g., Python pathand Django settings), then run this command. If thecommand raises a ``CommandError``, intercept it and print it sensiblyto stderr. If the ``--traceback`` option is present or the raised``Exception`` is not ``CommandError``, raise it."""# 创建一个解析器# CommandParser(prog='kk.py startproject', usage=None, description='Creates a Django project directory structure for the given project name in the current directory or optionally in the given directory.', formatter_class=<class 'django.core.management.base.DjangoHelpFormatter'>, conflict_handler='error', add_help=True)self._called_from_command_line = Trueparser = self.create_parser(argv[0], argv[1])# 可选项,如 --setting之类,略options = parser.parse_args(argv[2:])cmd_options = vars(options)# option相关,略# Move positional args out of options to mimic legacy optparseargs = cmd_options.pop('args', ())handle_default_options(options)try:# 此处是关键,又一个excute()方法,这个excute()方法是BaseCommand类的执行方法,# 我们查看详细代码self.execute(*args, **cmd_options)except Exception as e:if options.traceback or not isinstance(e, CommandError):raise# SystemCheckError takes care of its own formatting.if isinstance(e, SystemCheckError):self.stderr.write(str(e), lambda x: x)else:self.stderr.write('%s: %s' % (e.__class__.__name__, e))sys.exit(1)finally:try:connections.close_all()except ImproperlyConfigured:# Ignore if connections aren't setup at this point (e.g. no# configured settings).pass

通过代码分析,我们可以看到,run_from_argv(self.argv)关键在于 self.execute(*args, **cmd_options)这一句代码

此处有一个地方需要注意,类的继承关系,self.fetch_command(subcommand).run_from_argv(self.argv)代码,它可以换为Command.run_from_argv(self.argv) ,Command继承于TemplateCommand,TemplateCommand继承于BaseCommand。

Command类和TemplateCommand类中均没有excute()方法,所以执行的是BaseCommand类中的excute()方法

BaseCommand类的excute()方法

def execute(self, *args, **options):"""Try to execute this command, performing system checks if needed (ascontrolled by the ``requires_system_checks`` attribute, except ifforce-skipped)."""# option可选相关,各种check,略if options['force_color'] and options['no_color']:raise CommandError("The --no-color and --force-color options can't be used together.")if options['force_color']:self.style = color_style(force_color=True)elif options['no_color']:self.style = no_style()self.stderr.style_func = Noneif options.get('stdout'):self.stdout = OutputWrapper(options['stdout'])if options.get('stderr'):self.stderr = OutputWrapper(options['stderr'], self.stderr.style_func)if self.requires_system_checks and not options.get('skip_checks'):self.check()if self.requires_migrations_checks:self.check_migrations()# 真正的执行代码在这里,handle(),所有的项目建立代码都在handle()方法里,这里才是核心# 位于django/core/management/base.py的364行output = self.handle(*args, **options)# output也略if output:if self.output_transaction:connection = connections[options.get('database', DEFAULT_DB_ALIAS)]output = '%sn%sn%s' % (self.style.SQL_KEYWORD(connection.ops.start_transaction_sql()),output,self.style.SQL_KEYWORD(connection.ops.end_transaction_sql()),)self.stdout.write(output)return output

self.handle(args, *options)

如果你直接跟着Pycharm点进去查看handle方法,会发现啥都没做,只raise了一个错误,因为Pycharm会把你直接带到BaseCommand的handle()方法去。

def handle(self, *args, **options):"""The actual logic of the command. Subclasses must implementthis method."""raise NotImplementedError('subclasses of BaseCommand must provide a handle() method')

真正应该看的是下面的handle()

Command类的handle()

# startproject.py文件中的Command类的handle方法def handle(self, **options):project_name = options.pop('name')# project_name即为我们传的minidemotarget = options.pop('directory')# target是目标目录,但是此处为None,应该在其他地方会有指定# Create a random SECRET_KEY to put it in the main settings.options['secret_key'] = get_random_secret_key()# 生成一个随机secret_key,我们settings.py中就是从这里来的# 执行父类的handle方法,即TemplateCommand类的handle()方法super().handle('project', project_name, target, **options)

TemplateCommand类的handle()

def handle(self, app_or_project, name, target=None, **options):# 判断是生成app还是projectself.app_or_project = app_or_projectself.paths_to_remove = []self.verbosity = options['verbosity']# 校验名称合法性self.validate_name(name, app_or_project)# 此处开始指定项目要生成到哪里了,之前没有指定的target在此处指定# if some directory is given, make sure it's nicely expandedif target is None:# top_dir即指定的项目目录top_dir = path.join(os.getcwd(), name)try:# 创建项目目录os.makedirs(top_dir)except FileExistsError:raise CommandError("'%s' already exists" % top_dir)except OSError as e:raise CommandError(e)else:top_dir = os.path.abspath(path.expanduser(target))if not os.path.exists(top_dir):raise CommandError("Destination directory '%s' does not ""exist, please create it first." % top_dir)# 额外创建的py文件,此处无,略        extensions = tuple(handle_extensions(options['extensions']))extra_files = []for file in options['files']:extra_files.extend(map(lambda x: x.strip(), file.split(',')))if self.verbosity >= 2:self.stdout.write("Rendering %s template files with ""extensions: %sn" %(app_or_project, ', '.join(extensions)))self.stdout.write("Rendering %s template files with ""filenames: %sn" %(app_or_project, ', '.join(extra_files)))base_name = '%s_name' % app_or_projectbase_subdir = '%s_template' % app_or_projectbase_directory = '%s_directory' % app_or_projectcamel_case_name = 'camel_case_%s_name' % app_or_projectcamel_case_value = ''.join(x for x in name.title() if x != '_')# 指定django项目建立时需要的上下文context = Context({**options,base_name: name,                    # project_namebase_directory: top_dir,    # project_directorycamel_case_name: camel_case_value,'docs_version': get_docs_version(),  # 2.2'django_version': django.__version__, # 2.2.1}, autoescape=False)# 如果是新建项目,自动按默认配置configure,然后执行setup()函数# Setup a stub settings environment for template renderingif not settings.configured:settings.configure()django.setup()template_dir = self.handle_template(options['template'],base_subdir)# template_dir为 'venv/lib/python3.6/site-packages/django/conf/project_template'目录# 目录结构为:# project_name#   __init__.py-tpl#   settings.py-tpl#   urls.py-tpl#   wsgi.py-tpl# manage.py-tpl# 可以看出,这就是一个初始新项目的结构prefix_length = len(template_dir) + 1*********************************** 项目文件最终在此处建立 *********************************************************# 在project_template模板目录下遍历,创建需要的文件for root, dirs, files in os.walk(template_dir):path_rest = root[prefix_length:]relative_dir = path_rest.replace(base_name, name)if relative_dir:target_dir = path.join(top_dir, relative_dir)if not path.exists(target_dir):os.mkdir(target_dir)for dirname in dirs[:]:if dirname.startswith('.') or dirname == '__pycache__':dirs.remove(dirname)for filename in files:if filename.endswith(('.pyo', '.pyc', '.py.class')):# Ignore some files as they cause various breakages.continueold_path = path.join(root, filename)new_path = path.join(top_dir, relative_dir,filename.replace(base_name, name))for old_suffix, new_suffix in self.rewrite_template_suffixes:if new_path.endswith(old_suffix):new_path = new_path[:-len(old_suffix)] + new_suffixbreak  # Only rewrite onceif path.exists(new_path):raise CommandError("%s already exists, overlaying a ""project or app into an existing ""directory won't replace conflicting ""files" % new_path)# Only render the Python files, as we don't want to# accidentally render Django templates filesif new_path.endswith(extensions) or filename in extra_files:with open(old_path, 'r', encoding='utf-8') as template_file:content = template_file.read()template = Engine().from_string(content)content = template.render(context)with open(new_path, 'w', encoding='utf-8') as new_file:new_file.write(content)else:shutil.copyfile(old_path, new_path)if self.verbosity >= 2:self.stdout.write("Creating %sn" % new_path)try:shutil.copymode(old_path, new_path)self.make_writeable(new_path)except OSError:self.stderr.write("Notice: Couldn't set permission bits on %s. You're ""probably using an uncommon filesystem setup. No ""problem." % new_path, self.style.NOTICE)if self.paths_to_remove:if self.verbosity >= 2:self.stdout.write("Cleaning up temporary files.n")for path_to_remove in self.paths_to_remove:if path.isfile(path_to_remove):os.remove(path_to_remove)else:shutil.rmtree(path_to_remove)

至此,一个新项目建立完成。

总结

Django通过命令交互代码获取我们输入的命令参数,对其进行判断,是建立项目还是建立app,再通过调用django/core/management目录下对应命令模块中Command类进行项目建立,项目建立过程中通过调用Command类的handle()方法和父类TemplateCommand类的handle()方法查找到对应的模板文件,进行IO操作写入初始文件,到这里,一个Django新项目建立完成。

http://www.jmfq.cn/news/5085937.html

相关文章:

  • 郑州网站开发公/百度网首页登录入口
  • 长沙口碑好网站建设/游戏推广文案
  • 微信微网站是什么格式的/软文推广案例
  • 山东卓商网站建设公司/网站内容优化怎么去优化呢
  • 政府网站集约化建设建议/相似图片在线查找
  • 怎么做网站赚钱吗/什么平台打广告比较好免费的
  • 深圳网站如何制作/百度搜索推广的定义
  • 阿里巴巴怎么做公司网站/官网建站多少钱
  • 网站建设 沈阳/搜索引擎营销与seo优化
  • 大型网站开发项目合同/竞价外包代运营公司
  • 广州个性化网站建设/谷歌搜索网页版入口
  • 独立网站需要怎么做/在线培训系统app
  • 招聘做微信公众号网站维护/seo查询5118
  • 霍山做网站/企业邮箱
  • 做怎么网站收费/谷歌seo怎么做
  • 网络游戏网站网址大全/如何免费搭建自己的网站
  • 网站建设 人性的弱点/游戏推广平台有哪些
  • 慈溪市建设厅网站/在线生成个人网站
  • 专业提供网站建设服务/网站怎么做优化排名
  • bc源码 网站 搭建/电话号码宣传广告
  • 北京做网站设计招聘/网络营销推广方式包括
  • 伊春seo公司/百度首页排名优化哪家专业
  • 中纪委网站两学一做征文/谷歌账号注册
  • 网站怎么做付款平台/汕头seo外包机构
  • 贵州专业网站建设/免费推广网址
  • 长春网站建设/seo网站优化服务
  • axure做网站效果图步骤/全球搜索引擎市场份额
  • 制作网站付费软件/网站策划是什么
  • 电商网站制作流程图/上海抖音seo公司
  • 昆明哪些做网站建设的公司/移动慧生活app下载