Django/startproject時の処理を読む
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
[[Djangoを読む]]
#contents
*django/bin/django-admin.py [#b2eebbce]
Djangoを使うときに初めに打つコマンド、
$ django-admin startproject mysite
流そうと思ったのですがなかなか面白いことをしているのでち...
というわけで、django-admin。
#code(Python){{
#!/usr/bin/env python
from django.core import management
if __name__ == "__main__":
management.execute_from_command_line()
}}
というわけで、core/managementに移動。
*django/core/management/__init__.py [#ofe0765e]
念のため、import fooとした場合、
-fooディレクトリに__init__.pyがあればそれがインポートされる
-fooディレクトリに__init__.pyがなく、fooディレトクリと同...
という動作をします。ちなみに、__init__.pyがなく、foo.pyも...
で、本題。execute_from_command_lineは一番下に書かれていま...
#code(Python){{
def execute_from_command_line(argv=None):
"""
A simple method that runs a ManagementUtility.
"""
utility = ManagementUtility(argv)
utility.execute()
}}
ManagementUtilityはすぐ上にあります。とりあえず__init__。
#code(Python){{
class ManagementUtility(object):
"""
Encapsulates the logic of the django-admin and manage...
A ManagementUtility has a number of commands, which c...
by editing the self.commands dictionary.
"""
def __init__(self, argv=None):
self.argv = argv or sys.argv[:]
self.prog_name = os.path.basename(self.argv[0])
self.settings_exception = None
}}
sys.argv[:]って何やってるのかと思いましたが、[:]と書くと...
exeuteの前半は無視して次のところから、
#code(Python){{
no_settings_commands = [
'help', 'version', '--help', '--version', '-h',
'compilemessages', 'makemessages',
'startapp', 'startproject',
]
try:
settings.INSTALLED_APPS
except ImproperlyConfigured as exc:
self.settings_exception = exc
# A handful of built-in management commands w...
# Load the default settings -- where INSTALLE...
if subcommand in no_settings_commands:
settings.configure()
}}
まだファイルも何も作ってないのだから例外に行きそうなのは...
**django/conf/__init__.py [#g2914fdb]
settingsはファイルの最後に書かれています。
#code(Python){{
settings = LazySettings()
}}
Lazy、よくある遅延処理ですね。LazySettingsはファイルの上...
#code(Python){{
class LazySettings(LazyObject):
"""
A lazy proxy for either global Django settings or a c...
The user can manually configure settings prior to usi...
Django uses the settings module pointed to by DJANGO_...
"""
def __getattr__(self, name):
if self._wrapped is empty:
self._setup(name)
return getattr(self._wrapped, name)
def _setup(self, name=None):
"""
Load the settings module pointed to by the enviro...
is used the first time we need any settings at al...
previously configured the settings manually.
"""
settings_module = os.environ.get(ENVIRONMENT_VARI...
if not settings_module:
desc = ("setting %s" % name) if name else "se...
raise ImproperlyConfigured(
"Requested %s, but settings are not confi...
"You must either define the environment v...
"or call settings.configure() before acce...
% (desc, ENVIRONMENT_VARIABLE))
self._wrapped = Settings(settings_module)
}}
説明の都合上メソッドの順番を入れ替えましたが、LazyObject...
INSTALLED_APPSという属性を取ろうとすると__getattr__が呼ば...
普通の条件分岐っぽい処理を例外処理でやってるのに違和感を...
というわけで例外が送信されて、managementの方に戻ってきて...
#code(Python){{
def configure(self, default_settings=global_settings,...
"""
Called to manually configure the settings. The 'd...
parameter sets where to retrieve any unspecified ...
argument must support attribute access (__getattr...
"""
if self._wrapped is not empty:
raise RuntimeError('Settings already configur...
holder = UserSettingsHolder(default_settings)
for name, value in options.items():
setattr(holder, name, value)
self._wrapped = holder
@property
def configured(self):
"""
Returns True if the settings have already been co...
"""
return self._wrapped is not empty
}}
settings要らないって言ってるのだからデフォルト値も要らな...
**ManagementUtility.execute続き [#cef8ec55]
settingsの初期化が終わるとdjango.setupが呼ばれていますが...
残りはコマンドラインで指定されたコマンドに応じた分岐です。
#code(Python){{
if subcommand == 'help':
if '--commands' in args:
sys.stdout.write(self.main_help_text(comm...
elif len(options.args) < 1:
sys.stdout.write(self.main_help_text() + ...
else:
self.fetch_command(options.args[0]).print...
# Special-cases: We want 'django-admin --version'...
# 'django-admin --help' to work, for backwards co...
elif subcommand == 'version' or self.argv[1:] == ...
sys.stdout.write(django.get_version() + '\n')
elif self.argv[1:] in (['--help'], ['-h']):
sys.stdout.write(self.main_help_text() + '\n')
else:
self.fetch_command(subcommand).run_from_argv(...
}}
というわけでfetch_commandに続く。
**fetch_command [#y38c95bb]
#code(Python){{
def fetch_command(self, subcommand):
"""
Tries to fetch the given subcommand, printing a m...
appropriate command called from the command line ...
"django-admin" or "manage.py") if it can't be fou...
"""
# Get commands outside of try block to prevent sw...
commands = get_commands()
try:
app_name = commands[subcommand]
except KeyError:
# 省略
if isinstance(app_name, BaseCommand):
# If the command is already loaded, use it di...
klass = app_name
else:
klass = load_command_class(app_name, subcomma...
return klass
}}
まずはget_commandsへ。なお、get_commandsはManagementUtili...
#code(Python){{
def get_commands():
"""
Returns a dictionary mapping command names to their c...
This works by looking for a management.commands packa...
in each installed application -- if a commands packag...
in that package are registered.
Core commands are always included. If a settings modu...
specified, user-defined commands will also be included.
The dictionary is in the format {command_name: app_na...
pairs from this dictionary can then be used in calls to
load_command_class(app_name, command_name)
If a specific version of a command must be loaded (e....
startapp command), the instantiated module can be pla...
dictionary in place of the application name.
The dictionary is cached on the first call and reused...
calls.
"""
commands = {name: 'django.core' for name in find_comm...
if not settings.configured:
return commands
for app_config in reversed(list(apps.get_app_configs(...
path = os.path.join(app_config.path, 'management')
commands.update({name: app_config.name for name i...
return commands
}}
__path__はパッケージの__init__.pyがあるディレクトリが入っ...
#code(Python){{
def find_commands(management_dir):
"""
Given a path to a management directory, returns a lis...
names that are available.
Returns an empty list if no commands are defined.
"""
command_dir = os.path.join(management_dir, 'commands')
return [name for _, name, is_pkg in pkgutil.iter_modu...
if not is_pkg and not name.startswith('_')]
}}
パッケージのディレクトリ、つまり、django/core/management...
#code(Python){{
{'startproject': 'django.core'}
}}
みたいな辞書ができるわけですね。
fetch_commandに戻る。ここまでで見てきてapp_nameに入ってい...
#code(Python){{
def load_command_class(app_name, name):
"""
Given a command name and an application name, returns...
class instance. All errors raised by the import process
(ImportError, AttributeError) are allowed to propagate.
"""
module = import_module('%s.management.commands.%s' % ...
return module.Command()
}}
まあ説明は不要ですね(笑)
*django/core/management/commands/startproject.py [#s4b985...
さて、というわけでようやくstartprojectコマンドを実行する...
run_from_argv
create_parser
add_arguments
execute
handle
という順番に実行され、サブクラスはadd_argumentsをオーバー...
#code(Python){{
def run_from_argv(self, argv):
"""
Set up any environment changes requested (e.g., P...
and Django settings), then run this command. If the
command raises a ``CommandError``, intercept it a...
to stderr. If the ``--traceback`` option is prese...
``Exception`` is not ``CommandError``, raise it.
"""
self._called_from_command_line = True
parser = self.create_parser(argv[0], argv[1])
options = parser.parse_args(argv[2:])
cmd_options = vars(options)
# Move positional args out of options to mimic le...
args = cmd_options.pop('args', ())
handle_default_options(options)
try:
self.execute(*args, **cmd_options)
except Exception as e:
# 省略
finally:
connections.close_all()
}}
parserはargparse.ArgumentParser(を少し拡張したクラス)で...
**TemplateCommand.add_arguments [#l030f611]
上で示したように、create_parserはadd_argumentsを呼び出し...
#code(Python){{
def add_arguments(self, parser):
parser.add_argument('name', help='Name of the app...
parser.add_argument('directory', nargs='?', help=...
parser.add_argument('--template', help='The path ...
parser.add_argument(
'--extension', '-e', dest='extensions',
action='append', default=['py'],
help='The file extension(s) to render (defaul...
'Separate multiple extensions with comma...
'-e multiple times.'
)
parser.add_argument(
'--name', '-n', dest='files',
action='append', default=[],
help='The file name(s) to render. Separate mu...
'with commas, or use -n multiple times.'
)
}}
というわけで、
$ django-admin startproject mysite
とした場合、nameに'mysite'、directoryとtemplateにNoneが入...
**startproject.Command.handle [#ad9bc505]
executeはシステムチェックとかが行われていますが今回はコマ...
というわけで、startprojectモジュールのhandleにやってきま...
#code(Python){{
def handle(self, **options):
project_name, target = options.pop('name'), optio...
self.validate_name(project_name, "project")
# Check that the project_name cannot be imported.
try:
import_module(project_name)
except ImportError:
pass
else:
raise CommandError(
"%r conflicts with the name of an existin...
"cannot be used as a project name. Please...
)
# Create a random SECRET_KEY to put it in the mai...
options['secret_key'] = get_random_secret_key()
super(Command, self).handle('project', project_na...
}}
validate_nameはプロジェクト名として指定された名前がPython...
処理のメインはスーパークラス(TemplateCommand)のhandleに...
**TemplateCommand.handle [#yf0ed21c]
TemplateCommandの方のhandle、まずは前半(関係ないところは...
#code(Python){{
def handle(self, app_or_project, name, target=None, *...
self.app_or_project = app_or_project
self.paths_to_remove = []
self.verbosity = options['verbosity']
self.validate_name(name, app_or_project)
# if some directory is given, make sure it's nice...
if target is None:
top_dir = path.join(os.getcwd(), name)
try:
os.makedirs(top_dir)
except OSError as e:
# 省略
else:
# 省略
extensions = tuple(handle_extensions(options['ext...
base_name = '%s_name' % app_or_project
base_subdir = '%s_template' % app_or_project
base_directory = '%s_directory' % app_or_project
camel_case_name = 'camel_case_%s_name' % app_or_p...
camel_case_value = ''.join(x for x in name.title(...
context = Context(dict(options, **{
base_name: name,
base_directory: top_dir,
camel_case_name: camel_case_value,
'docs_version': get_docs_version(),
'django_version': django.__version__,
'unicode_literals': '' if six.PY3 else 'from ...
}), autoescape=False)
}}
Contextはdjango.templateのクラスです。
中盤、
#code(Python){{
template_dir = self.handle_template(options['temp...
base_subdir)
prefix_length = len(template_dir) + 1
for root, dirs, files in os.walk(template_dir):
path_rest = root[prefix_length:]
relative_dir = path_rest.replace(base_name, n...
if relative_dir:
target_dir = path.join(top_dir, relative_...
if not path.exists(target_dir):
os.mkdir(target_dir)
}}
handle_template、
#code(Python){{
def handle_template(self, template, subdir):
"""
Determines where the app or project templates are.
Use django.__path__[0] as the default because we ...
know into which directory Django has been install...
"""
if template is None:
return path.join(django.__path__[0], 'conf', ...
else:
# 省略
}}
というわけで、django/conf/project_templateにあるファイル...
で、handleの中盤に話を戻すと、テンプレートディレクトリと...
後半、
#code(Python){{
for filename in files:
old_path = path.join(root, filename)
new_path = path.join(top_dir, relative_dir,
filename.replace(bas...
for old_suffix, new_suffix in self.rewrit...
if new_path.endswith(old_suffix):
new_path = new_path[:-len(old_suf...
break # Only rewrite once
# Only render the Python files, as we don...
# accidentally render Django templates fi...
with open(old_path, 'rb') as template_file:
content = template_file.read()
if new_path.endswith(extensions) or filen...
content = content.decode('utf-8')
template = Engine().from_string(conte...
content = template.render(context)
content = content.encode('utf-8')
with open(new_path, 'wb') as new_file:
new_file.write(content)
try:
shutil.copymode(old_path, new_path)
self.make_writeable(new_path)
except OSError:
# 省略
}}
テンプレートの中身に踏み込むのはまた今度。ともかくこれで...
*おわりに [#c55d33d0]
ということでDjangoのとっかかり、startprojectの処理を見て...
なお、startappについてはmanage.pyを使う、プロジェクトのse...
終了行:
[[Djangoを読む]]
#contents
*django/bin/django-admin.py [#b2eebbce]
Djangoを使うときに初めに打つコマンド、
$ django-admin startproject mysite
流そうと思ったのですがなかなか面白いことをしているのでち...
というわけで、django-admin。
#code(Python){{
#!/usr/bin/env python
from django.core import management
if __name__ == "__main__":
management.execute_from_command_line()
}}
というわけで、core/managementに移動。
*django/core/management/__init__.py [#ofe0765e]
念のため、import fooとした場合、
-fooディレクトリに__init__.pyがあればそれがインポートされる
-fooディレクトリに__init__.pyがなく、fooディレトクリと同...
という動作をします。ちなみに、__init__.pyがなく、foo.pyも...
で、本題。execute_from_command_lineは一番下に書かれていま...
#code(Python){{
def execute_from_command_line(argv=None):
"""
A simple method that runs a ManagementUtility.
"""
utility = ManagementUtility(argv)
utility.execute()
}}
ManagementUtilityはすぐ上にあります。とりあえず__init__。
#code(Python){{
class ManagementUtility(object):
"""
Encapsulates the logic of the django-admin and manage...
A ManagementUtility has a number of commands, which c...
by editing the self.commands dictionary.
"""
def __init__(self, argv=None):
self.argv = argv or sys.argv[:]
self.prog_name = os.path.basename(self.argv[0])
self.settings_exception = None
}}
sys.argv[:]って何やってるのかと思いましたが、[:]と書くと...
exeuteの前半は無視して次のところから、
#code(Python){{
no_settings_commands = [
'help', 'version', '--help', '--version', '-h',
'compilemessages', 'makemessages',
'startapp', 'startproject',
]
try:
settings.INSTALLED_APPS
except ImproperlyConfigured as exc:
self.settings_exception = exc
# A handful of built-in management commands w...
# Load the default settings -- where INSTALLE...
if subcommand in no_settings_commands:
settings.configure()
}}
まだファイルも何も作ってないのだから例外に行きそうなのは...
**django/conf/__init__.py [#g2914fdb]
settingsはファイルの最後に書かれています。
#code(Python){{
settings = LazySettings()
}}
Lazy、よくある遅延処理ですね。LazySettingsはファイルの上...
#code(Python){{
class LazySettings(LazyObject):
"""
A lazy proxy for either global Django settings or a c...
The user can manually configure settings prior to usi...
Django uses the settings module pointed to by DJANGO_...
"""
def __getattr__(self, name):
if self._wrapped is empty:
self._setup(name)
return getattr(self._wrapped, name)
def _setup(self, name=None):
"""
Load the settings module pointed to by the enviro...
is used the first time we need any settings at al...
previously configured the settings manually.
"""
settings_module = os.environ.get(ENVIRONMENT_VARI...
if not settings_module:
desc = ("setting %s" % name) if name else "se...
raise ImproperlyConfigured(
"Requested %s, but settings are not confi...
"You must either define the environment v...
"or call settings.configure() before acce...
% (desc, ENVIRONMENT_VARIABLE))
self._wrapped = Settings(settings_module)
}}
説明の都合上メソッドの順番を入れ替えましたが、LazyObject...
INSTALLED_APPSという属性を取ろうとすると__getattr__が呼ば...
普通の条件分岐っぽい処理を例外処理でやってるのに違和感を...
というわけで例外が送信されて、managementの方に戻ってきて...
#code(Python){{
def configure(self, default_settings=global_settings,...
"""
Called to manually configure the settings. The 'd...
parameter sets where to retrieve any unspecified ...
argument must support attribute access (__getattr...
"""
if self._wrapped is not empty:
raise RuntimeError('Settings already configur...
holder = UserSettingsHolder(default_settings)
for name, value in options.items():
setattr(holder, name, value)
self._wrapped = holder
@property
def configured(self):
"""
Returns True if the settings have already been co...
"""
return self._wrapped is not empty
}}
settings要らないって言ってるのだからデフォルト値も要らな...
**ManagementUtility.execute続き [#cef8ec55]
settingsの初期化が終わるとdjango.setupが呼ばれていますが...
残りはコマンドラインで指定されたコマンドに応じた分岐です。
#code(Python){{
if subcommand == 'help':
if '--commands' in args:
sys.stdout.write(self.main_help_text(comm...
elif len(options.args) < 1:
sys.stdout.write(self.main_help_text() + ...
else:
self.fetch_command(options.args[0]).print...
# Special-cases: We want 'django-admin --version'...
# 'django-admin --help' to work, for backwards co...
elif subcommand == 'version' or self.argv[1:] == ...
sys.stdout.write(django.get_version() + '\n')
elif self.argv[1:] in (['--help'], ['-h']):
sys.stdout.write(self.main_help_text() + '\n')
else:
self.fetch_command(subcommand).run_from_argv(...
}}
というわけでfetch_commandに続く。
**fetch_command [#y38c95bb]
#code(Python){{
def fetch_command(self, subcommand):
"""
Tries to fetch the given subcommand, printing a m...
appropriate command called from the command line ...
"django-admin" or "manage.py") if it can't be fou...
"""
# Get commands outside of try block to prevent sw...
commands = get_commands()
try:
app_name = commands[subcommand]
except KeyError:
# 省略
if isinstance(app_name, BaseCommand):
# If the command is already loaded, use it di...
klass = app_name
else:
klass = load_command_class(app_name, subcomma...
return klass
}}
まずはget_commandsへ。なお、get_commandsはManagementUtili...
#code(Python){{
def get_commands():
"""
Returns a dictionary mapping command names to their c...
This works by looking for a management.commands packa...
in each installed application -- if a commands packag...
in that package are registered.
Core commands are always included. If a settings modu...
specified, user-defined commands will also be included.
The dictionary is in the format {command_name: app_na...
pairs from this dictionary can then be used in calls to
load_command_class(app_name, command_name)
If a specific version of a command must be loaded (e....
startapp command), the instantiated module can be pla...
dictionary in place of the application name.
The dictionary is cached on the first call and reused...
calls.
"""
commands = {name: 'django.core' for name in find_comm...
if not settings.configured:
return commands
for app_config in reversed(list(apps.get_app_configs(...
path = os.path.join(app_config.path, 'management')
commands.update({name: app_config.name for name i...
return commands
}}
__path__はパッケージの__init__.pyがあるディレクトリが入っ...
#code(Python){{
def find_commands(management_dir):
"""
Given a path to a management directory, returns a lis...
names that are available.
Returns an empty list if no commands are defined.
"""
command_dir = os.path.join(management_dir, 'commands')
return [name for _, name, is_pkg in pkgutil.iter_modu...
if not is_pkg and not name.startswith('_')]
}}
パッケージのディレクトリ、つまり、django/core/management...
#code(Python){{
{'startproject': 'django.core'}
}}
みたいな辞書ができるわけですね。
fetch_commandに戻る。ここまでで見てきてapp_nameに入ってい...
#code(Python){{
def load_command_class(app_name, name):
"""
Given a command name and an application name, returns...
class instance. All errors raised by the import process
(ImportError, AttributeError) are allowed to propagate.
"""
module = import_module('%s.management.commands.%s' % ...
return module.Command()
}}
まあ説明は不要ですね(笑)
*django/core/management/commands/startproject.py [#s4b985...
さて、というわけでようやくstartprojectコマンドを実行する...
run_from_argv
create_parser
add_arguments
execute
handle
という順番に実行され、サブクラスはadd_argumentsをオーバー...
#code(Python){{
def run_from_argv(self, argv):
"""
Set up any environment changes requested (e.g., P...
and Django settings), then run this command. If the
command raises a ``CommandError``, intercept it a...
to stderr. If the ``--traceback`` option is prese...
``Exception`` is not ``CommandError``, raise it.
"""
self._called_from_command_line = True
parser = self.create_parser(argv[0], argv[1])
options = parser.parse_args(argv[2:])
cmd_options = vars(options)
# Move positional args out of options to mimic le...
args = cmd_options.pop('args', ())
handle_default_options(options)
try:
self.execute(*args, **cmd_options)
except Exception as e:
# 省略
finally:
connections.close_all()
}}
parserはargparse.ArgumentParser(を少し拡張したクラス)で...
**TemplateCommand.add_arguments [#l030f611]
上で示したように、create_parserはadd_argumentsを呼び出し...
#code(Python){{
def add_arguments(self, parser):
parser.add_argument('name', help='Name of the app...
parser.add_argument('directory', nargs='?', help=...
parser.add_argument('--template', help='The path ...
parser.add_argument(
'--extension', '-e', dest='extensions',
action='append', default=['py'],
help='The file extension(s) to render (defaul...
'Separate multiple extensions with comma...
'-e multiple times.'
)
parser.add_argument(
'--name', '-n', dest='files',
action='append', default=[],
help='The file name(s) to render. Separate mu...
'with commas, or use -n multiple times.'
)
}}
というわけで、
$ django-admin startproject mysite
とした場合、nameに'mysite'、directoryとtemplateにNoneが入...
**startproject.Command.handle [#ad9bc505]
executeはシステムチェックとかが行われていますが今回はコマ...
というわけで、startprojectモジュールのhandleにやってきま...
#code(Python){{
def handle(self, **options):
project_name, target = options.pop('name'), optio...
self.validate_name(project_name, "project")
# Check that the project_name cannot be imported.
try:
import_module(project_name)
except ImportError:
pass
else:
raise CommandError(
"%r conflicts with the name of an existin...
"cannot be used as a project name. Please...
)
# Create a random SECRET_KEY to put it in the mai...
options['secret_key'] = get_random_secret_key()
super(Command, self).handle('project', project_na...
}}
validate_nameはプロジェクト名として指定された名前がPython...
処理のメインはスーパークラス(TemplateCommand)のhandleに...
**TemplateCommand.handle [#yf0ed21c]
TemplateCommandの方のhandle、まずは前半(関係ないところは...
#code(Python){{
def handle(self, app_or_project, name, target=None, *...
self.app_or_project = app_or_project
self.paths_to_remove = []
self.verbosity = options['verbosity']
self.validate_name(name, app_or_project)
# if some directory is given, make sure it's nice...
if target is None:
top_dir = path.join(os.getcwd(), name)
try:
os.makedirs(top_dir)
except OSError as e:
# 省略
else:
# 省略
extensions = tuple(handle_extensions(options['ext...
base_name = '%s_name' % app_or_project
base_subdir = '%s_template' % app_or_project
base_directory = '%s_directory' % app_or_project
camel_case_name = 'camel_case_%s_name' % app_or_p...
camel_case_value = ''.join(x for x in name.title(...
context = Context(dict(options, **{
base_name: name,
base_directory: top_dir,
camel_case_name: camel_case_value,
'docs_version': get_docs_version(),
'django_version': django.__version__,
'unicode_literals': '' if six.PY3 else 'from ...
}), autoescape=False)
}}
Contextはdjango.templateのクラスです。
中盤、
#code(Python){{
template_dir = self.handle_template(options['temp...
base_subdir)
prefix_length = len(template_dir) + 1
for root, dirs, files in os.walk(template_dir):
path_rest = root[prefix_length:]
relative_dir = path_rest.replace(base_name, n...
if relative_dir:
target_dir = path.join(top_dir, relative_...
if not path.exists(target_dir):
os.mkdir(target_dir)
}}
handle_template、
#code(Python){{
def handle_template(self, template, subdir):
"""
Determines where the app or project templates are.
Use django.__path__[0] as the default because we ...
know into which directory Django has been install...
"""
if template is None:
return path.join(django.__path__[0], 'conf', ...
else:
# 省略
}}
というわけで、django/conf/project_templateにあるファイル...
で、handleの中盤に話を戻すと、テンプレートディレクトリと...
後半、
#code(Python){{
for filename in files:
old_path = path.join(root, filename)
new_path = path.join(top_dir, relative_dir,
filename.replace(bas...
for old_suffix, new_suffix in self.rewrit...
if new_path.endswith(old_suffix):
new_path = new_path[:-len(old_suf...
break # Only rewrite once
# Only render the Python files, as we don...
# accidentally render Django templates fi...
with open(old_path, 'rb') as template_file:
content = template_file.read()
if new_path.endswith(extensions) or filen...
content = content.decode('utf-8')
template = Engine().from_string(conte...
content = template.render(context)
content = content.encode('utf-8')
with open(new_path, 'wb') as new_file:
new_file.write(content)
try:
shutil.copymode(old_path, new_path)
self.make_writeable(new_path)
except OSError:
# 省略
}}
テンプレートの中身に踏み込むのはまた今度。ともかくこれで...
*おわりに [#c55d33d0]
ということでDjangoのとっかかり、startprojectの処理を見て...
なお、startappについてはmanage.pyを使う、プロジェクトのse...
ページ名: