diff --git a/django/core/management/templates.py b/django/core/management/templates.py index 299b36b6df..0e9adfeb09 100644 --- a/django/core/management/templates.py +++ b/django/core/management/templates.py @@ -58,10 +58,11 @@ class TemplateCommand(BaseCommand): def handle(self, app_or_project, name, target=None, **options): self.app_or_project = app_or_project + self.a_or_an = 'an' if app_or_project == 'app' else 'a' self.paths_to_remove = [] self.verbosity = options['verbosity'] - self.validate_name(name, app_or_project) + self.validate_name(name) # if some directory is given, make sure it's nicely expanded if target is None: @@ -139,10 +140,12 @@ class TemplateCommand(BaseCommand): break # Only rewrite once if 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) + raise CommandError( + "%s already exists. Overlaying %s %s into an existing " + "directory won't replace conflicting files." % ( + new_path, self.a_or_an, app_or_project, + ) + ) # Only render the Python files, as we don't want to # accidentally render Django templates files @@ -202,12 +205,11 @@ class TemplateCommand(BaseCommand): raise CommandError("couldn't handle %s template %s." % (self.app_or_project, template)) - def validate_name(self, name, app_or_project): - a_or_an = 'an' if app_or_project == 'app' else 'a' + def validate_name(self, name): if name is None: raise CommandError('you must provide {an} {app} name'.format( - an=a_or_an, - app=app_or_project, + an=self.a_or_an, + app=self.app_or_project, )) # Check it's a valid directory name. if not name.isidentifier(): @@ -215,7 +217,7 @@ class TemplateCommand(BaseCommand): "'{name}' is not a valid {app} name. Please make sure the " "name is a valid identifier.".format( name=name, - app=app_or_project, + app=self.app_or_project, ) ) # Check it cannot be imported. @@ -229,8 +231,8 @@ class TemplateCommand(BaseCommand): "module and cannot be used as {an} {app} name. Please try " "another name.".format( name=name, - an=a_or_an, - app=app_or_project, + an=self.a_or_an, + app=self.app_or_project, ) ) diff --git a/tests/admin_scripts/tests.py b/tests/admin_scripts/tests.py index 32233cf258..f6fb42b1aa 100644 --- a/tests/admin_scripts/tests.py +++ b/tests/admin_scripts/tests.py @@ -1938,7 +1938,11 @@ class StartProject(LiveServerTestCase, AdminScriptTestCase): # running again.. out, err = self.run_django_admin(args) self.assertNoOutput(out) - self.assertOutput(err, "already exists") + self.assertOutput( + err, + "already exists. Overlaying a project into an existing directory " + "won't replace conflicting files." + ) def test_custom_project_template(self): "Make sure the startproject management command is able to use a different project template" @@ -2128,6 +2132,15 @@ class StartApp(AdminScriptTestCase): ) self.assertFalse(os.path.exists(testproject_dir)) + def test_overlaying_app(self): + self.run_django_admin(['startapp', 'app1']) + out, err = self.run_django_admin(['startapp', 'app2', 'app1']) + self.assertOutput( + err, + "already exists. Overlaying an app into an existing directory " + "won't replace conflicting files." + ) + class DiffSettings(AdminScriptTestCase): """Tests for diffsettings management command."""