03 创建一个django项目

源码分析

django-admin startproject project1执行的主干逻辑代码

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


# django/core/management/__init__.py
@functools.lru_cache(maxsize=None)    # 函数级别缓存, 666
def get_commands():
    commands = {name: 'django.core' for name in find_commands(__path__[0])}
    return commands

def load_command_class(app_name, name):
    # 如何根据动态的名字字符串拼接导入路径,import_module
    module = import_module('%s.management.commands.%s' % (app_name, name))
    return module.Command()

class ManagementUtility:
    def __init__(self, argv=None):
        self.argv = argv or sys.argv[:]
    def fetch_command(self, subcommand):
        commands = get_commands()
        app_name = commands[subcommand]    # 'djanog.core'
        klass = load_command_class(app_name, subcommand)    # 'startproject'
        return klass
    def execute(self):
        subcommand = self.argv[1]    # startproject
        self.fetch_command(subcommand).run_from_argv(self.argv)

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

# django/core/management/commands/startproject.py
class Command(TemplateCommand):
    def handle(self, **options):
        project_name = options.pop('name')
        target = options.pop('directory')
        options['secret_key'] = get_random_secret_key()
        super().handle('project', project_name, target, **options)
# django/core/management/templates.py
class TemplateCommand(BaseCommand):
    def handle(self, app_or_project, name, target=None, **options):
        '''模板文件拷贝'''
# django/core/management/base.py
class BaseCommand:
    def run_from_argv(self, argv)
        self.execute(*args, **cmd_options)
    def execute(self, *args, **options):
        output = self.handle(*args, **options)
        return output
    def handle(self, *args, **options):
        raise NotImplementedError()

总结经验

  • 对外提供接口,适合以函数方式实现,execute_from_command_line

  • class ManagementUtility: 适合处理解析参数,分发处理

  • 结合目录 commands,实现动态导入

  • BaseCommand - TemplateCommand - Comand,典型的接口-实现模式

Last updated