Ticket #20485: 20485-prewalk-fixtures-dirs.diff

File 20485-prewalk-fixtures-dirs.diff, 8.2 KB (added by Aymeric Augustin, 7 years ago)
  • django/core/management/commands/loaddata.py

    diff --git a/django/core/management/commands/loaddata.py b/django/core/management/commands/loaddata.py
    index ab9f746..cb4a61b 100644
    a b from django.core.management.base import BaseCommand, CommandError 
    1212from django.core.management.color import no_style
    1313from django.db import (connections, router, transaction, DEFAULT_DB_ALIAS,
    1414      IntegrityError, DatabaseError)
    15 from django.db.models import get_apps
     15from django.db.models import get_app_paths
    1616from django.utils.encoding import force_text
     17from django.utils.functional import cached_property
    1718from django.utils._os import upath
     19from django.utils import six
    1820from itertools import product
    1921
    2022try:
    class Command(BaseCommand): 
    6971        self.fixture_object_count = 0
    7072        self.models = set()
    7173
    72         class SingleZipReader(zipfile.ZipFile):
    73             def __init__(self, *args, **kwargs):
    74                 zipfile.ZipFile.__init__(self, *args, **kwargs)
    75                 if settings.DEBUG:
    76                     assert len(self.namelist()) == 1, "Zip-compressed fixtures must contain only one file."
    77             def read(self):
    78                 return zipfile.ZipFile.read(self, self.namelist()[0])
    79 
    8074        self.compression_types = {
    8175            None:   open,
    8276            'gz':   gzip.GzipFile,
    class Command(BaseCommand): 
    8579        if has_bz2:
    8680            self.compression_types['bz2'] = bz2.BZ2File
    8781
    88         app_module_paths = []
    89         for app in get_apps():
    90             if hasattr(app, '__path__'):
    91                 # It's a 'models/' subpackage
    92                 for path in app.__path__:
    93                     app_module_paths.append(upath(path))
    94             else:
    95                 # It's a models.py module
    96                 app_module_paths.append(upath(app.__file__))
    97 
    98         app_fixtures = [os.path.join(os.path.dirname(path), 'fixtures') for path in app_module_paths]
    99 
    10082        with connection.constraint_checks_disabled():
    10183            for fixture_label in fixture_labels:
    102                 self.load_label(fixture_label, app_fixtures)
     84                self.load_label(fixture_label)
    10385
    10486        # Since we disabled constraint checks, we must manually check for
    10587        # any invalid keys that might have been added
    class Command(BaseCommand): 
    130112                self.stdout.write("Installed %d object(s) (of %d) from %d fixture(s)" % (
    131113                    self.loaded_object_count, self.fixture_object_count, self.fixture_count))
    132114
    133     def load_label(self, fixture_label, app_fixtures):
     115    def load_label(self, fixture_label):
    134116
    135117        parts = fixture_label.split('.')
    136118
    class Command(BaseCommand): 
    159141                    (fixture_name, format))
    160142
    161143        if os.path.isabs(fixture_name):
    162             fixture_dirs = [fixture_name]
     144            dirs_candidates = {'': [fixture_name]}
    163145        else:
    164             fixture_dirs = app_fixtures + list(settings.FIXTURE_DIRS) + ['']
     146            dirs_candidates = self.fixture_files_cache
    165147
    166148        label_found = False
    167         for fixture_dir in fixture_dirs:
    168             found = self.process_dir(fixture_dir, fixture_name,
     149        for fixture_dir, candidates in six.iteritems(dirs_candidates):
     150            found = self.process_dir(fixture_dir, candidates, fixture_name,
    169151                compression_formats, formats)
    170152            label_found = label_found or found
    171153
    172154        if fixture_name != 'initial_data' and not label_found:
    173155            warnings.warn("No fixture named '%s' found." % fixture_name)
    174156
    175     def process_dir(self, fixture_dir, fixture_name, compression_formats,
    176                     serialization_formats):
     157    def process_dir(self, fixture_dir, candidates, fixture_name,
     158                compression_formats, serialization_formats):
    177159
    178160        humanize = lambda dirname: "'%s'" % dirname if dirname else 'absolute path'
    179161
    class Command(BaseCommand): 
    193175            if self.verbosity >= 3:
    194176                self.stdout.write("Trying %s for %s fixture '%s'..." % \
    195177                    (humanize(fixture_dir), file_name, fixture_name))
     178            if file_name not in candidates:
     179                continue
    196180            full_path = os.path.join(fixture_dir, file_name)
    197181            open_method = self.compression_types[compression_format]
    198182            try:
    class Command(BaseCommand): 
    250234                            (fixture_name))
    251235
    252236        return label_found
     237
     238    @cached_property
     239    def fixture_files_cache(self):
     240        """
     241        Return a dict mapping fixture directories to a list of their files.
     242
     243        Fixtures directories includes the 'fixtures' subdirectories of
     244        installed application and the directories in FIXTURE_DIRS.
     245
     246        File paths are relative to the fixture directory containing them.
     247        """
     248        dirs = []
     249        for path in get_app_paths():
     250            d = os.path.join(os.path.dirname(path), 'fixtures')
     251            if os.path.isdir(d):
     252                dirs.append(d)
     253        dirs.extend(list(settings.FIXTURE_DIRS))
     254        dirs = [os.path.abspath(os.path.realpath(d)) for d in dirs]
     255
     256        cache = {}
     257        for d in dirs:
     258            files = []
     259            for dirpath, dirnames, filenames in os.walk(d):
     260                dirpath = os.path.relpath(dirpath, d)
     261                if dirpath == '.':
     262                    dirpath = ''
     263                for filename in filenames:
     264                    files.append(os.path.join(dirpath, filename))
     265            cache[d] = files
     266
     267        return cache
     268
     269
     270class SingleZipReader(zipfile.ZipFile):
     271
     272    def __init__(self, *args, **kwargs):
     273        zipfile.ZipFile.__init__(self, *args, **kwargs)
     274        if len(self.namelist()) != 1:
     275            raise ValueError("Zip-compressed fixtures must contain one file.")
     276
     277    def read(self):
     278        return zipfile.ZipFile.read(self, self.namelist()[0])
  • django/db/models/__init__.py

    diff --git a/django/db/models/__init__.py b/django/db/models/__init__.py
    index 5f17229..3eac216 100644
    a b  
    11from functools import wraps
    22
    33from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
    4 from django.db.models.loading import get_apps, get_app, get_models, get_model, register_models
     4from django.db.models.loading import get_apps, get_app_paths, get_app, get_models, get_model, register_models
    55from django.db.models.query import Q
    66from django.db.models.expressions import F
    77from django.db.models.manager import Manager
  • django/db/models/loading.py

    diff --git a/django/db/models/loading.py b/django/db/models/loading.py
    index c027105..4372873 100644
    a b class AppCache(object): 
    130130        return self.loaded
    131131
    132132    def get_apps(self):
    133         "Returns a list of all installed modules that contain models."
     133        """
     134        Returns a list of all installed modules that contain models.
     135        """
    134136        self._populate()
    135137
    136138        # Ensure the returned list is always in the same order (with new apps
    class AppCache(object): 
    140142        apps.sort()
    141143        return [elt[1] for elt in apps]
    142144
     145    def get_app_paths(self):
     146        """
     147        Returns a list of paths to all installed apps.
     148
     149        Useful for discovering files at conventional locations inside apps
     150        (static files, templates, etc.)
     151        """
     152        self._populate()
     153
     154        app_paths = []
     155        for app in self.get_apps():
     156            if hasattr(app, '__path__'):        # models/__init__.py package
     157                app_paths.extend([upath(path) for path in app.__path__])
     158            else:                               # models.py module
     159                app_paths.append(upath(app.__file__))
     160        return app_paths
     161
    143162    def get_app(self, app_label, emptyOK=False):
    144163        """
    145164        Returns the module containing the models for the given app_label. If
    cache = AppCache() 
    260279# These methods were always module level, so are kept that way for backwards
    261280# compatibility.
    262281get_apps = cache.get_apps
     282get_app_paths = cache.get_app_paths
    263283get_app = cache.get_app
    264284get_app_errors = cache.get_app_errors
    265285get_models = cache.get_models
Back to Top