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.
This commit is contained in:
Konrad Świat 2014-10-30 18:38:47 +01:00 committed by Tim Graham
parent e548d08f24
commit 934a16dc93
3 changed files with 61 additions and 3 deletions

View File

@ -9,6 +9,7 @@ import zipfile
from django.apps import apps from django.apps import apps
from django.conf import settings from django.conf import settings
from django.core import serializers from django.core import serializers
from django.core.exceptions import ImproperlyConfigured
from django.core.management.base import BaseCommand, CommandError from django.core.management.base import BaseCommand, CommandError
from django.core.management.color import no_style from django.core.management.color import no_style
from django.db import (connections, router, transaction, DEFAULT_DB_ALIAS, from django.db import (connections, router, transaction, DEFAULT_DB_ALIAS,
@ -238,13 +239,23 @@ class Command(BaseCommand):
current directory. current directory.
""" """
dirs = [] dirs = []
fixture_dirs = settings.FIXTURE_DIRS
if len(fixture_dirs) != len(set(fixture_dirs)):
raise ImproperlyConfigured("settings.FIXTURE_DIRS contains duplicates.")
for app_config in apps.get_app_configs(): for app_config in apps.get_app_configs():
if self.app_label and app_config.label != self.app_label: app_label = app_config.label
continue
app_dir = os.path.join(app_config.path, 'fixtures') app_dir = os.path.join(app_config.path, 'fixtures')
if app_dir in fixture_dirs:
raise ImproperlyConfigured(
"'%s' is a default fixture directory for the '%s' app "
"and cannot be listed in settings.FIXTURE_DIRS." % (app_dir, app_label)
)
if self.app_label and app_label != self.app_label:
continue
if os.path.isdir(app_dir): if os.path.isdir(app_dir):
dirs.append(app_dir) dirs.append(app_dir)
dirs.extend(list(settings.FIXTURE_DIRS)) dirs.extend(list(fixture_dirs))
dirs.append('') dirs.append('')
dirs = [upath(os.path.abspath(os.path.realpath(d))) for d in dirs] dirs = [upath(os.path.abspath(os.path.realpath(d))) for d in dirs]
return dirs return dirs

View File

@ -284,6 +284,10 @@ Management Commands
* The :djadminopt:`--name` option for :djadmin:`makemigrations` allows you to * The :djadminopt:`--name` option for :djadmin:`makemigrations` allows you to
to give the migration(s) a custom name instead of a generated one. to give the migration(s) a custom name instead of a generated one.
* The :djadmin:`loaddata` command now prevents repeated fixture loading. If
:setting:`FIXTURE_DIRS` contains duplicates or a default fixture directory
path (``app_name/fixtures``), an exception is raised.
Migrations Migrations
^^^^^^^^^^ ^^^^^^^^^^

View File

@ -8,6 +8,7 @@ import re
import warnings import warnings
from django.core import serializers from django.core import serializers
from django.core.exceptions import ImproperlyConfigured
from django.core.serializers.base import DeserializationError from django.core.serializers.base import DeserializationError
from django.core import management from django.core import management
from django.core.management.base import CommandError from django.core.management.base import CommandError
@ -486,6 +487,48 @@ class TestFixtures(TestCase):
verbosity=0, verbosity=0,
) )
@override_settings(FIXTURE_DIRS=[os.path.join(_cur_dir, 'fixtures_1'),
os.path.join(_cur_dir, 'fixtures_1')])
def test_fixture_dirs_with_duplicates(self):
"""
settings.FIXTURE_DIRS cannot contain duplicates in order to avoid
repeated fixture loading.
"""
self.assertRaisesMessage(
ImproperlyConfigured,
"settings.FIXTURE_DIRS contains duplicates.",
management.call_command,
'loaddata',
'absolute.json',
verbosity=0,
)
@override_settings(FIXTURE_DIRS=[os.path.join(_cur_dir, 'fixtures')])
def test_fixture_dirs_with_default_fixture_path(self):
"""
settings.FIXTURE_DIRS cannot contain a default fixtures directory
for application (app/fixtures) in order to avoid repeated fixture loading.
"""
self.assertRaisesMessage(
ImproperlyConfigured,
"'%s' is a default fixture directory for the '%s' app "
"and cannot be listed in settings.FIXTURE_DIRS."
% (os.path.join(_cur_dir, 'fixtures'), 'fixtures_regress'),
management.call_command,
'loaddata',
'absolute.json',
verbosity=0,
)
@override_settings(FIXTURE_DIRS=[os.path.join(_cur_dir, 'fixtures_1'),
os.path.join(_cur_dir, 'fixtures_2')])
def test_loaddata_with_valid_fixture_dirs(self):
management.call_command(
'loaddata',
'absolute.json',
verbosity=0,
)
class NaturalKeyFixtureTests(TestCase): class NaturalKeyFixtureTests(TestCase):