Ticket #11838: ticket11838-2.diff

File ticket11838-2.diff, 23.7 KB (added by Brandon Konkle, 14 years ago)
  • django/core/management/commands/loaddata.py

     
    66
    77from django.core.management.base import BaseCommand
    88from django.core.management.color import no_style
     9from django.core import serializers
     10from django.db import transaction
    911
    1012try:
    1113    set
     
    2426
    2527    def handle(self, *fixture_labels, **options):
    2628        from django.db.models import get_apps
    27         from django.core import serializers
    28         from django.db import connection, transaction
     29        from django.db import connection
    2930        from django.conf import settings
    3031
    3132        self.style = no_style()
    3233
    33         verbosity = int(options.get('verbosity', 1))
    34         show_traceback = options.get('traceback', False)
     34        self.verbosity = int(options.get('verbosity', 1))
     35        self.show_traceback = options.get('traceback', False)
    3536
    3637        # commit is a stealth option - it isn't really useful as
    3738        # a command line option, but it can be useful when invoking
     
    4344
    4445        # Keep a count of the installed objects and fixtures
    4546        fixture_count = 0
    46         object_count = 0
    47         models = set()
     47        self.object_count = 0
     48        self.models = set()
    4849
    49         humanize = lambda dirname: dirname and "'%s'" % dirname or 'absolute path'
     50        self.humanize = lambda dirname: dirname and "'%s'" % dirname or 'absolute path'
    5051
    5152        # Get a cursor (even though we don't need one yet). This has
    5253        # the side effect of initializing the test database (if
     
    8889
    8990            if len(parts) == 1:
    9091                fixture_name = parts[0]
     92                fixture_format = None
    9193                formats = serializers.get_public_serializer_formats()
    9294            else:
    9395                fixture_name, format = '.'.join(parts[:-1]), parts[-1]
    9496                if format in serializers.get_public_serializer_formats():
     97                    fixture_format = format
    9598                    formats = [format]
    9699                else:
    97100                    formats = []
    98101
    99102            if formats:
    100                 if verbosity > 1:
     103                if self.verbosity > 1:
    101104                    print "Loading '%s' fixtures..." % fixture_name
    102105            else:
    103106                sys.stderr.write(
     
    113116                fixture_dirs = app_fixtures + list(settings.FIXTURE_DIRS) + ['']
    114117
    115118            for fixture_dir in fixture_dirs:
    116                 if verbosity > 1:
    117                     print "Checking %s for fixtures..." % humanize(fixture_dir)
     119                if self.verbosity > 1:
     120                    print "Checking %s for fixtures..." % self.humanize(fixture_dir)
    118121
    119122                label_found = False
    120123                for format in formats:
     
    125128                        else:
    126129                            file_name = '.'.join([fixture_name, format])
    127130                   
    128                         if verbosity > 1:
     131                        if self.verbosity > 1:
    129132                            print "Trying %s for %s fixture '%s'..." % \
    130                                 (humanize(fixture_dir), file_name, fixture_name)
     133                                (self.humanize(fixture_dir), file_name, fixture_name)
    131134                        full_path = os.path.join(fixture_dir, file_name)
    132135                        open_method = compression_types[compression_format]                               
    133136                        try:
     
    135138                            if label_found:
    136139                                fixture.close()
    137140                                print self.style.ERROR("Multiple fixtures named '%s' in %s. Aborting." %
    138                                     (fixture_name, humanize(fixture_dir)))
     141                                    (fixture_name, self.humanize(fixture_dir)))
    139142                                transaction.rollback()
    140143                                transaction.leave_transaction_management()
    141144                                return
    142145                            else:
    143146                                fixture_count += 1
    144                                 objects_in_fixture = 0
    145                                 if verbosity > 0:
    146                                     print "Installing %s fixture '%s' from %s." % \
    147                                         (format, fixture_name, humanize(fixture_dir))
    148                                 try:
    149                                     objects = serializers.deserialize(format, fixture)
    150                                     for obj in objects:
    151                                         objects_in_fixture += 1
    152                                         models.add(obj.object.__class__)
    153                                         obj.save()
    154                                     object_count += objects_in_fixture
    155                                     label_found = True
    156                                 except (SystemExit, KeyboardInterrupt):
    157                                     raise
    158                                 except Exception:
    159                                     import traceback
    160                                     fixture.close()
    161                                     transaction.rollback()
    162                                     transaction.leave_transaction_management()
    163                                     if show_traceback:
    164                                         traceback.print_exc()
    165                                     else:
    166                                         sys.stderr.write(
    167                                             self.style.ERROR("Problem installing fixture '%s': %s\n" %
    168                                                  (full_path, ''.join(traceback.format_exception(sys.exc_type,
    169                                                      sys.exc_value, sys.exc_traceback)))))
     147                                label_found, error = self.install_fixture(format, fixture, fixture_name, fixture_dir, full_path)
     148                                if error:
    170149                                    return
    171                                 fixture.close()
    172 
    173                                 # If the fixture we loaded contains 0 objects, assume that an
    174                                 # error was encountered during fixture loading.
    175                                 if objects_in_fixture == 0:
    176                                     sys.stderr.write(
    177                                         self.style.ERROR("No fixture data found for '%s'. (File format may be invalid.)" %
    178                                             (fixture_name)))
    179                                     transaction.rollback()
    180                                     transaction.leave_transaction_management()
    181                                     return
    182 
    183150                        except Exception, e:
    184                             if verbosity > 1:
     151                            if self.verbosity > 1:
    185152                                print "No %s fixture '%s' in %s." % \
    186                                     (format, fixture_name, humanize(fixture_dir))
     153                                    (format, fixture_name, self.humanize(fixture_dir))
    187154
     155                # Check for a group of fixtures with the requested name
     156                if not fixture_format:
     157                    group_dir = os.path.join(fixture_dir, fixture_name)
     158                    if os.path.isdir(group_dir):
     159                        if label_found:
     160                            print self.style.ERROR("A fixture named '%s' and a fixture group named '%s' were both found in %s. Aborting." %
     161                                (fixture_name, fixture_name, self.humanize(fixture_dir)))
     162                            transaction.rollback()
     163                            transaction.leave_transaction_management()
     164                            return
     165                        else:
     166                            labels_found = []
     167                            if self.verbosity > 1:
     168                                print "Checking %s for a group of fixtures." % \
     169                                    self.humanize(group_dir)
     170                            for file_name in os.listdir(group_dir):
     171                                parts = file_name.split('.')
     172                   
     173                                if len(parts) > 2 and parts[-1] in compression_types:
     174                                    compression_format = parts[-1]
     175                                    parts = parts[:-1]
     176                                else:
     177                                    compression_format = None
     178                   
     179                                if len(parts) == 2:
     180                                    group_fixture_name, format = '.'.join(parts[:-1]), parts[-1]
     181                       
     182                                    if format in serializers.get_public_serializer_formats():
     183                                        full_path = os.path.join(group_dir, file_name)
     184                                        if self.verbosity > 1:
     185                                            print "Trying %s for %s fixture '%s'..." % \
     186                                                (self.humanize(group_dir), file_name,
     187                                                 fixture_name)
     188                                        open_method = compression_types[compression_format]
     189                                        try:
     190                                            fixture = open_method(full_path, 'r')
     191                                            if group_fixture_name in labels_found:
     192                                                fixture.close()
     193                                                print self.style.ERROR("Multiple fixtures named '%s' in %s. Aborting." %
     194                                                    (group_fixture_name, self.humanize(group_dir)))
     195                                                transaction.rollback()
     196                                                transaction.leave_transaction_management()
     197                                                return
     198                                            fixture_count += 1
     199                                            label_found, error = self.install_fixture(format, fixture, group_fixture_name, group_dir, full_path)
     200                                            if error:
     201                                                return
     202                                            if label_found:
     203                                                labels_found += [label_found]
     204                                        except Exception, e:
     205                                            if self.verbosity > 1:
     206                                                print "No %s fixture '%s' in %s." % \
     207                                                    (format, group_fixture_name, self.humanize(group_dir))
     208
    188209        # If we found even one object in a fixture, we need to reset the
    189210        # database sequences.
    190         if object_count > 0:
    191             sequence_sql = connection.ops.sequence_reset_sql(self.style, models)
     211        if self.object_count > 0:
     212            sequence_sql = connection.ops.sequence_reset_sql(self.style, self.models)
    192213            if sequence_sql:
    193                 if verbosity > 1:
     214                if self.verbosity > 1:
    194215                    print "Resetting sequences"
    195216                for line in sequence_sql:
    196217                    cursor.execute(line)
     
    199220            transaction.commit()
    200221            transaction.leave_transaction_management()
    201222
    202         if object_count == 0:
    203             if verbosity > 1:
     223        if self.object_count == 0:
     224            if self.verbosity > 1:
    204225                print "No fixtures found."
    205226        else:
    206             if verbosity > 0:
    207                 print "Installed %d object(s) from %d fixture(s)" % (object_count, fixture_count)
     227            if self.verbosity > 0:
     228                print "Installed %d object(s) from %d fixture(s)" % (self.object_count, fixture_count)
    208229
    209230        # Close the DB connection. This is required as a workaround for an
    210231        # edge case in MySQL: if the same connection is used to
     
    212233        # incorrect results. See Django #7572, MySQL #37735.
    213234        if commit:
    214235            connection.close()
     236
     237    def install_fixture(self, format, fixture, fixture_name, fixture_dir, full_path):
     238        """
     239        Installs the requested fixture.
     240       
     241        Returns:
     242            label_found - The name of the label found.
     243            error - Whether there was an error while installing the fixture
     244        """
     245        error = False
     246        label_found = False
     247        objects_in_fixture = 0
     248        if self.verbosity > 0:
     249            print "Installing %s fixture '%s' from %s." % \
     250                (format, fixture_name, self.humanize(fixture_dir))
     251        try:
     252            objects = serializers.deserialize(format, fixture)
     253            for obj in objects:
     254                objects_in_fixture += 1
     255                self.models.add(obj.object.__class__)
     256                obj.save()
     257            self.object_count += objects_in_fixture
     258            label_found = fixture_name
     259        except (SystemExit, KeyboardInterrupt):
     260            raise
     261        except Exception:
     262            import traceback
     263            fixture.close()
     264            transaction.rollback()
     265            transaction.leave_transaction_management()
     266            if self.show_traceback:
     267                traceback.print_exc()
     268            else:
     269                sys.stderr.write(
     270                    self.style.ERROR("Problem installing fixture '%s': %s\n" %
     271                         (full_path, ''.join(traceback.format_exception(sys.exc_type,
     272                             sys.exc_value, sys.exc_traceback)))))
     273            error = True
     274            return label_found, error
     275        fixture.close()
     276
     277        # If the fixture we loaded contains 0 objects, assume that an
     278        # error was encountered during fixture loading.
     279        if objects_in_fixture == 0:
     280            sys.stderr.write(
     281                self.style.ERROR("No fixture data found for '%s'. (File format may be invalid.)" %
     282                    (fixture_name)))
     283            transaction.rollback()
     284            transaction.leave_transaction_management()
     285            error = True
     286            return label_found, error
     287
     288        return label_found, error
  • tests/modeltests/fixtures/fixtures/group3/fixture1.json

     
     1[
     2    {
     3        "pk": "8",
     4        "model": "fixtures.article",
     5        "fields": {
     6            "headline": "Researchers use Python to produce the Ultimate Question of Life, the Universe, and Everything",
     7            "pub_date": "2009-12-06 11:00:00"
     8        }
     9    }
     10]
     11 No newline at end of file
  • tests/modeltests/fixtures/fixtures/group3/fixture2.json

     
     1[
     2    {
     3        "pk": 8,
     4        "model": "fixtures.category",
     5        "fields": {
     6            "description": "Latest catastrophic disasters",
     7            "title": "Catastrophic Disasters"
     8        }
     9    }
     10]
     11 No newline at end of file
  • tests/modeltests/fixtures/fixtures/group4/fixture2.json

     
     1[
     2    {
     3        "pk": 9,
     4        "model": "fixtures.category",
     5        "fields": {
     6            "description": "Amusing hypochondriac anecdotes",
     7            "title": "Hypochondriac Anecdotes"
     8        }
     9    }
     10]
     11 No newline at end of file
  • tests/modeltests/fixtures/fixtures/group1.json

    Cannot display: file marked as a binary type.
    svn:mime-type = application/octet-stream
    
    Property changes on: tests/modeltests/fixtures/fixtures/group4/fixture1.json.gz
    ___________________________________________________________________
    Added: svn:mime-type
       + application/octet-stream
    
     
     1[
     2    {
     3        "pk": "6",
     4        "model": "fixtures.article",
     5        "fields": {
     6            "headline": "Guido awarded Nobel Prize",
     7            "pub_date": "2009-12-06 11:00:00"
     8        }
     9    }
     10]
     11 No newline at end of file
  • tests/modeltests/fixtures/fixtures/group1/fixture1.json

     
     1[
     2    {
     3        "pk": "6",
     4        "model": "fixtures.article",
     5        "fields": {
     6            "headline": "This fixture should never be installed",
     7            "pub_date": "2009-12-06 11:00:00"
     8        }
     9    }
     10]
     11 No newline at end of file
  • tests/modeltests/fixtures/fixtures/group2/fixture1.json

     
     1[
     2    {
     3        "pk": "7",
     4        "model": "fixtures.article",
     5        "fields": {
     6            "headline": "This fixture will cause the transaction to be rolled back",
     7            "pub_date": "2009-12-06 11:00:00"
     8        }
     9    }
     10]
     11 No newline at end of file
  • tests/modeltests/fixtures/fixtures/group2/fixture1.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<django-objects version="1.0">
     3    <object pk="7" model="fixtures.article">
     4        <field type="CharField" name="headline">This fixture will load, but then be rolled back</field>
     5        <field type="DateTimeField" name="pub_date">2009-12-06 11:00:00</field>
     6    </object>
     7</django-objects>
     8 No newline at end of file
  • tests/modeltests/fixtures/models.py

     
    159159>>> management.call_command('loaddata', 'fixture5', verbosity=0) # doctest: +ELLIPSIS
    160160Multiple fixtures named 'fixture5' in '...fixtures'. Aborting.
    161161
     162# Try to load fixture group 1 using format discovery; this will fail because
     163# there is a fixture and a group both named 'group1' in the fixtures
     164# directory.
     165>>> management.call_command('loaddata', 'group1', verbosity=0) # doctest: +ELLIPSIS
     166A fixture named 'group1' and a fixture group named 'group1' were both found in '...fixtures'. Aborting.
     167
     168# Load the individual fixture group1 with the full filename; this will succeed
     169# because the format was explicitly specified. The group of fixtures
     170# will be ignored.
     171>>> management.call_command('loaddata', 'group1.json', verbosity=0)
     172>>> Article.objects.all()
     173[<Article: Guido awarded Nobel Prize>, <Article: Python program becomes self aware>]
     174
     175>>> management.call_command('flush', verbosity=0, interactive=False)
     176
     177# Try to load group 2; this will fail because there are two fixtures in the
     178# group named 'fixture1'.
     179>>> management.call_command('loaddata', 'group2', verbosity=0) # doctest: +ELLIPSIS
     180Multiple fixtures named 'fixture1' in '.../fixtures/group2'. Aborting.
     181
     182# Load group 3, which will successfully load 2 fixtures.
     183>>> management.call_command('loaddata', 'group3', verbosity=0)
     184>>> Article.objects.all()
     185[<Article: Researchers use Python to produce the Ultimate Question of Life, the Universe, and Everything>, <Article: Python program becomes self aware>]
     186>>> Category.objects.all()
     187[<Category: Catastrophic Disasters>]
     188
     189>>> management.call_command('flush', verbosity=0, interactive=False)
     190
     191# Load group 4, which includes 1 gzipped fixture and 1 plain text fixture.
     192>>> management.call_command('loaddata', 'group4', verbosity=0)
     193>>> Article.objects.all()
     194[<Article: Pinky successfully ponders what Brain is pondering, lab in uproar>, <Article: Python program becomes self aware>]
     195>>> Category.objects.all()
     196[<Category: Hypochondriac Anecdotes>]
    162197"""
    163198
    164199from django.test import TestCase
  • AUTHORS

     
    250250    Bruce Kroeze <http://coderseye.com/>
    251251    krzysiek.pawlik@silvermedia.pl
    252252    Joseph Kocherhans
     253    Brandon Konkle (bkonkle) <http://brandonkonkle.com/>
    253254    konrad@gwu.edu
    254255    knox <christobzr@gmail.com>
    255256    David Krauth
  • docs/howto/initial-data.txt

     
    8282but be careful: remember that the data will be refreshed *every time* you run
    8383:djadmin:`syncdb`. So don't use ``initial_data`` for data you'll want to edit.
    8484
     85.. versionadded:: 1.2
     86
     87This also works with fixture groups.  If you create a subdirectory called
     88``initial_data`` within a fixtures directory, then all fixture files in
     89that subdirectory will be loaded each time you run :djadmin:`syncdb`.
     90
    8591.. seealso::
    8692
    8793    Fixtures are also used by the :ref:`testing framework
  • docs/ref/django-admin.txt

     
    351351
    352352The ``dumpdata`` command can be used to generate input for ``loaddata``.
    353353
     354Fixture groups
     355~~~~~~~~~~~~~~
     356
     357.. versionadded:: 1.2
     358
     359Fixtures can also be grouped together into subdirectories under the
     360``fixtures`` directory.  The subdirectory can be referred to as a fixture, and
     361:djadmin:`loaddata` will try to load each file in the subdirectory as a fixture
     362file.
     363
     364For example, say you have an app called ``blog`` with two models, ``Entry`` and
     365``Category``. If you want to separate your entries into multiple fixture
     366files based on their category, you could create a subdirectory underneath your
     367``blog`` app's ``fixtures`` directory called ``entries``.  Within
     368``blog/fixtures/entries/`` you could create two fixture files, ``django.json``
     369and ``python.json``.
     370
     371In this case, you can refer to the fixture group ``entries`` to install both
     372fixtures at the same time.  :djadmin:`loaddata` will first try to find individual
     373fixtures matching the name requested, and if it doesn't find any it will then
     374try to look for a fixture group with that name. The command::
     375
     376    django-admin.py loaddata entries
     377
     378would first search for an individual fixture named ``entries``, and when it
     379didn't find one it would look for a subdirectory with that name under each
     380fixture directory.  When it found one, it would attempt to install each file
     381within the subdirectory as a fixture.  Both ``django.json`` and ``python.json``
     382would be loaded.
     383
     384If you wanted to install only one of the fixtures in the group, you could refer
     385to it specifically with the command::
     386
     387    django-admin.py loaddata entries/django.json
     388
     389and it would load just the ``django.json`` file.
     390
    354391Compressed fixtures
    355392~~~~~~~~~~~~~~~~~~~
    356393
Back to Top