Skip to content

Commit 934a16d

Browse files
kswiattimgraham
authored andcommitted
Fixed #23468 -- Added checks for duplicate fixtures directories in loaddata.
If settings.FIXTURE_DIRS contains duplicates or a default fixture directory (app_name/fixtures), ImproperlyConfigured is raised. Thanks to Berker Peksag and Tim Graham for review.
1 parent e548d08 commit 934a16d

File tree

3 files changed

+61
-3
lines changed

3 files changed

+61
-3
lines changed

django/core/management/commands/loaddata.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from django.apps import apps
1010
from django.conf import settings
1111
from django.core import serializers
12+
from django.core.exceptions import ImproperlyConfigured
1213
from django.core.management.base import BaseCommand, CommandError
1314
from django.core.management.color import no_style
1415
from django.db import (connections, router, transaction, DEFAULT_DB_ALIAS,
@@ -238,13 +239,23 @@ def fixture_dirs(self):
238239
current directory.
239240
"""
240241
dirs = []
242+
fixture_dirs = settings.FIXTURE_DIRS
243+
if len(fixture_dirs) != len(set(fixture_dirs)):
244+
raise ImproperlyConfigured("settings.FIXTURE_DIRS contains duplicates.")
241245
for app_config in apps.get_app_configs():
242-
if self.app_label and app_config.label != self.app_label:
243-
continue
246+
app_label = app_config.label
244247
app_dir = os.path.join(app_config.path, 'fixtures')
248+
if app_dir in fixture_dirs:
249+
raise ImproperlyConfigured(
250+
"'%s' is a default fixture directory for the '%s' app "
251+
"and cannot be listed in settings.FIXTURE_DIRS." % (app_dir, app_label)
252+
)
253+
254+
if self.app_label and app_label != self.app_label:
255+
continue
245256
if os.path.isdir(app_dir):
246257
dirs.append(app_dir)
247-
dirs.extend(list(settings.FIXTURE_DIRS))
258+
dirs.extend(list(fixture_dirs))
248259
dirs.append('')
249260
dirs = [upath(os.path.abspath(os.path.realpath(d))) for d in dirs]
250261
return dirs

docs/releases/1.8.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,10 @@ Management Commands
284284
* The :djadminopt:`--name` option for :djadmin:`makemigrations` allows you to
285285
to give the migration(s) a custom name instead of a generated one.
286286

287+
* The :djadmin:`loaddata` command now prevents repeated fixture loading. If
288+
:setting:`FIXTURE_DIRS` contains duplicates or a default fixture directory
289+
path (``app_name/fixtures``), an exception is raised.
290+
287291
Migrations
288292
^^^^^^^^^^
289293

tests/fixtures_regress/tests.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import warnings
99

1010
from django.core import serializers
11+
from django.core.exceptions import ImproperlyConfigured
1112
from django.core.serializers.base import DeserializationError
1213
from django.core import management
1314
from django.core.management.base import CommandError
@@ -486,6 +487,48 @@ def test_ticket_22421(self):
486487
verbosity=0,
487488
)
488489

490+
@override_settings(FIXTURE_DIRS=[os.path.join(_cur_dir, 'fixtures_1'),
491+
os.path.join(_cur_dir, 'fixtures_1')])
492+
def test_fixture_dirs_with_duplicates(self):
493+
"""
494+
settings.FIXTURE_DIRS cannot contain duplicates in order to avoid
495+
repeated fixture loading.
496+
"""
497+
self.assertRaisesMessage(
498+
ImproperlyConfigured,
499+
"settings.FIXTURE_DIRS contains duplicates.",
500+
management.call_command,
501+
'loaddata',
502+
'absolute.json',
503+
verbosity=0,
504+
)
505+
506+
@override_settings(FIXTURE_DIRS=[os.path.join(_cur_dir, 'fixtures')])
507+
def test_fixture_dirs_with_default_fixture_path(self):
508+
"""
509+
settings.FIXTURE_DIRS cannot contain a default fixtures directory
510+
for application (app/fixtures) in order to avoid repeated fixture loading.
511+
"""
512+
self.assertRaisesMessage(
513+
ImproperlyConfigured,
514+
"'%s' is a default fixture directory for the '%s' app "
515+
"and cannot be listed in settings.FIXTURE_DIRS."
516+
% (os.path.join(_cur_dir, 'fixtures'), 'fixtures_regress'),
517+
management.call_command,
518+
'loaddata',
519+
'absolute.json',
520+
verbosity=0,
521+
)
522+
523+
@override_settings(FIXTURE_DIRS=[os.path.join(_cur_dir, 'fixtures_1'),
524+
os.path.join(_cur_dir, 'fixtures_2')])
525+
def test_loaddata_with_valid_fixture_dirs(self):
526+
management.call_command(
527+
'loaddata',
528+
'absolute.json',
529+
verbosity=0,
530+
)
531+
489532

490533
class NaturalKeyFixtureTests(TestCase):
491534

0 commit comments

Comments
 (0)