diff --git a/django/core/management/commands/startapp.py b/django/core/management/commands/startapp.py
index 5581331..692ad09 100644
a
|
b
|
class Command(TemplateCommand):
|
9 | 9 | "directory.") |
10 | 10 | |
11 | 11 | def handle(self, app_name=None, target=None, **options): |
12 | | if app_name is None: |
13 | | raise CommandError("you must provide an app name") |
| 12 | self.validate_name(app_name, "app") |
14 | 13 | |
15 | 14 | # Check that the app_name cannot be imported. |
16 | 15 | try: |
diff --git a/django/core/management/commands/startproject.py b/django/core/management/commands/startproject.py
index a1a9b33..b143e6c 100644
a
|
b
|
class Command(TemplateCommand):
|
10 | 10 | "given directory.") |
11 | 11 | |
12 | 12 | def handle(self, project_name=None, target=None, *args, **options): |
13 | | if project_name is None: |
14 | | raise CommandError("you must provide a project name") |
| 13 | self.validate_name(project_name, "project") |
15 | 14 | |
16 | 15 | # Check that the project_name cannot be imported. |
17 | 16 | try: |
diff --git a/django/core/management/templates.py b/django/core/management/templates.py
index d34a0de..e75befc 100644
a
|
b
|
class TemplateCommand(BaseCommand):
|
64 | 64 | # The supported URL schemes |
65 | 65 | url_schemes = ['http', 'https', 'ftp'] |
66 | 66 | |
| 67 | |
67 | 68 | def handle(self, app_or_project, name, target=None, **options): |
68 | 69 | self.app_or_project = app_or_project |
69 | 70 | self.paths_to_remove = [] |
70 | 71 | self.verbosity = int(options.get('verbosity')) |
71 | 72 | |
72 | | # If it's not a valid directory name. |
73 | | if not re.search(r'^[_a-zA-Z]\w*$', name): |
74 | | # Provide a smart error message, depending on the error. |
75 | | if not re.search(r'^[_a-zA-Z]', name): |
76 | | message = ('make sure the name begins ' |
77 | | 'with a letter or underscore') |
78 | | else: |
79 | | message = 'use only numbers, letters and underscores' |
80 | | raise CommandError("%r is not a valid %s name. Please %s." % |
81 | | (name, app_or_project, message)) |
| 73 | self.validate_name(name, app_or_project) |
82 | 74 | |
83 | 75 | # if some directory is given, make sure it's nicely expanded |
84 | 76 | if target is None: |
… |
… |
class TemplateCommand(BaseCommand):
|
211 | 203 | raise CommandError("couldn't handle %s template %s." % |
212 | 204 | (self.app_or_project, template)) |
213 | 205 | |
| 206 | def validate_name(self, name, app_or_project): |
| 207 | if name is None: |
| 208 | raise CommandError("you must provide %s %s name" % ("an" if app_or_project == "app" else "a", app_or_project)) |
| 209 | # If it's not a valid directory name. |
| 210 | if not re.search(r'^[_a-zA-Z]\w*$', name): |
| 211 | # Provide a smart error message, depending on the error. |
| 212 | if not re.search(r'^[_a-zA-Z]', name): |
| 213 | message = ('make sure the name begins ' |
| 214 | 'with a letter or underscore') |
| 215 | else: |
| 216 | message = 'use only numbers, letters and underscores' |
| 217 | raise CommandError("%r is not a valid %s name. Please %s." % |
| 218 | (name, app_or_project, message)) |
| 219 | |
214 | 220 | def download(self, url): |
215 | 221 | """ |
216 | 222 | Downloads the given URL and returns the file name. |
diff --git a/tests/regressiontests/admin_scripts/tests.py b/tests/regressiontests/admin_scripts/tests.py
index 6f524be..a9a9728 100644
a
|
b
|
class StartProject(LiveServerTestCase, AdminScriptTestCase):
|
1428 | 1428 | |
1429 | 1429 | args = ['startproject', '7testproject'] |
1430 | 1430 | testproject_dir = os.path.join(test_dir, '7testproject') |
| 1431 | self.addCleanup(cleanup, testproject_dir) |
1431 | 1432 | |
1432 | 1433 | out, err = self.run_django_admin(args) |
1433 | | self.addCleanup(cleanup, testproject_dir) |
1434 | 1434 | self.assertOutput(err, "Error: '7testproject' is not a valid project name. Please make sure the name begins with a letter or underscore.") |
1435 | 1435 | self.assertFalse(os.path.exists(testproject_dir)) |
1436 | 1436 | |
| 1437 | def test_path_as_project_name(self): |
| 1438 | "Make sure the startproject management command validates a project name" |
| 1439 | |
| 1440 | def cleanup(p): |
| 1441 | if os.path.exists(p): |
| 1442 | shutil.rmtree(p) |
| 1443 | |
| 1444 | args = ['startproject', '../testproject'] |
| 1445 | testproject_dir = os.path.join(test_dir, '../testproject') |
| 1446 | self.addCleanup(cleanup, testproject_dir) |
| 1447 | |
| 1448 | out, err = self.run_django_admin(args) |
| 1449 | self.assertOutput(err, "Error: '../testproject' is not a valid project name. Please make sure the name begins with a letter or underscore.") |
| 1450 | self.assertFalse(os.path.exists(testproject_dir)) |
| 1451 | |
1437 | 1452 | def test_simple_project_different_directory(self): |
1438 | 1453 | "Make sure the startproject management command creates a project in a specific directory" |
1439 | 1454 | args = ['startproject', 'testproject', 'othertestproject'] |