1
0
mirror of https://github.com/django/django.git synced 2025-07-22 10:39:13 +00:00

Fixed #18296 -- Created missing custom target directory for startproject and startapp.

This commit is contained in:
Bruno Alla 2025-04-27 12:01:24 +02:00 committed by Sarah Boyce
parent 3babda775d
commit bc21bc4282
5 changed files with 92 additions and 30 deletions

View File

@ -46,7 +46,9 @@ class TemplateCommand(BaseCommand):
def add_arguments(self, parser):
parser.add_argument("name", help="Name of the application or project.")
parser.add_argument(
"directory", nargs="?", help="Optional destination directory"
"directory",
nargs="?",
help="Optional destination directory, this will be created if needed.",
)
parser.add_argument(
"--template", help="The path or URL to load the template from."
@ -105,10 +107,10 @@ class TemplateCommand(BaseCommand):
if app_or_project == "app":
self.validate_name(os.path.basename(top_dir), "directory")
if not os.path.exists(top_dir):
raise CommandError(
"Destination directory '%s' does not "
"exist, please create it first." % top_dir
)
try:
os.makedirs(top_dir)
except OSError as e:
raise CommandError(e)
# Find formatters, which are external executables, before input
# from the templates can sneak into the path.

View File

@ -45,21 +45,16 @@ including database configuration, Django-specific options and
application-specific settings.
From the command line, ``cd`` into a directory where you'd like to store your
code and create a new directory named ``djangotutorial``. (This directory name
doesn't matter to Django; you can rename it to anything you like.)
.. console::
$ mkdir djangotutorial
Then, run the following command to bootstrap a new Django project:
code and run the following command to bootstrap a new Django project:
.. console::
$ django-admin startproject mysite djangotutorial
This will create a project called ``mysite`` inside the ``djangotutorial``
directory. If it didn't work, see :ref:`troubleshooting-django-admin`.
This will create a directory ``djangotutorial`` with a project called
``mysite`` inside. The directory name doesn't matter to Django; you can rename
it to anything you like. If it didn't work, see
:ref:`troubleshooting-django-admin`.
.. note::

View File

@ -1266,9 +1266,13 @@ By default, :source:`the new directory <django/conf/app_template>` contains a
``models.py`` file and other app template files. If only the app name is given,
the app directory will be created in the current working directory.
If the optional destination is provided, Django will use that existing
directory rather than creating a new one. You can use '.' to denote the current
working directory.
If the optional destination is provided, Django will use that name instead. If
the directory with the given name doesn't exist, it will be created. You can
use '.' to denote the current working directory.
.. versionchanged:: 6.0
Automatic creation of the destination directory was added.
For example:
@ -1378,9 +1382,14 @@ If only the project name is given, both the project directory and project
package will be named ``<projectname>`` and the project directory
will be created in the current working directory.
If the optional destination is provided, Django will use that existing
directory as the project directory, and create ``manage.py`` and the project
package within it. Use '.' to denote the current working directory.
If the optional destination is provided, Django will use that name as the
project directory, and create ``manage.py`` and the project package within it.
If the directory with the given name doesn't exist, it will be created. Use '.'
to denote the current working directory.
.. versionchanged:: 6.0
Automatic creation of the destination directory was added.
For example:

View File

@ -170,7 +170,8 @@ Logging
Management Commands
~~~~~~~~~~~~~~~~~~~
* ...
* The :djadmin:`startproject` and :djadmin:`startapp` commands now create the
custom target directory if it doesn't exist.
Migrations
~~~~~~~~~~

View File

@ -2843,8 +2843,7 @@ class StartProject(LiveServerTestCase, AdminScriptTestCase):
def test_custom_project_destination_missing(self):
"""
Make sure an exception is raised when the provided
destination directory doesn't exist
Create the directory when the provided destination directory doesn't exist.
"""
template_path = os.path.join(custom_templates_dir, "project_template")
args = [
@ -2857,12 +2856,8 @@ class StartProject(LiveServerTestCase, AdminScriptTestCase):
testproject_dir = os.path.join(self.test_dir, "project_dir2")
out, err = self.run_django_admin(args)
self.assertNoOutput(out)
self.assertOutput(
err,
"Destination directory '%s' does not exist, please create it first."
% testproject_dir,
)
self.assertFalse(os.path.exists(testproject_dir))
self.assertNoOutput(err)
self.assertTrue(os.path.exists(testproject_dir))
def test_custom_project_template_with_non_ascii_templates(self):
"""
@ -3099,6 +3094,66 @@ class StartApp(AdminScriptTestCase):
content,
)
def test_creates_directory_when_custom_app_destination_missing(self):
args = [
"startapp",
"my_app",
"my_app",
]
testapp_dir = os.path.join(self.test_dir, "my_app")
out, err = self.run_django_admin(args)
self.assertNoOutput(out)
self.assertNoOutput(err)
self.assertTrue(os.path.exists(testapp_dir))
def test_custom_app_destination_missing_with_nested_subdirectory(self):
args = [
"startapp",
"my_app",
"apps/my_app",
]
testapp_dir = os.path.join(self.test_dir, "apps", "my_app")
out, err = self.run_django_admin(args)
self.assertNoOutput(out)
self.assertNoOutput(err)
self.assertTrue(os.path.exists(testapp_dir))
def test_custom_name_with_app_within_other_app(self):
parent_app_dir = os.path.join(self.test_dir, "parent")
self.run_django_admin(["startapp", "parent"])
self.assertTrue(os.path.exists(parent_app_dir))
nested_args = ["startapp", "child", "parent/child"]
child_app_dir = os.path.join(self.test_dir, "parent", "child")
out, err = self.run_django_admin(nested_args)
self.assertNoOutput(out)
self.assertNoOutput(err)
self.assertTrue(os.path.exists(child_app_dir))
@unittest.skipIf(
sys.platform == "win32",
"Windows only partially supports umasks and chmod.",
)
def test_custom_app_directory_creation_error_handling(self):
"""The error is displayed to the user in case of OSError."""
args = [
"startapp",
"my_app",
"project_dir/my_app",
]
# Create a read-only parent directory.
os.makedirs(
os.path.join(self.test_dir, "project_dir"), exist_ok=True, mode=0o200
)
testapp_dir = os.path.join(self.test_dir, "project_dir", "my_app")
out, err = self.run_django_admin(args)
self.assertNoOutput(out)
self.assertOutput(
err,
"Permission denied",
)
self.assertFalse(os.path.exists(testapp_dir))
class DiffSettings(AdminScriptTestCase):
"""Tests for diffsettings management command."""