Django

Code

Changeset 9527

Show
Ignore:
Timestamp:
11/24/08 14:42:09 (2 months ago)
Author:
jacob
Message:

Fixed #4924: added support for loading compressed fixtures. Thanks to Lars Yencken and Jeremy Dunck.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/AUTHORS

    r9416 r9527  
    426426    wojtek 
    427427    Jason Yan <tailofthesun@gmail.com> 
     428    Lars Yencken <lars.yencken@gmail.com> 
    428429    ye7cakf02@sneakemail.com 
    429430    ymasuda@ethercube.com 
  • django/trunk/django/core/management/commands/loaddata.py

    r9357 r9527  
    44import sys 
    55import os 
     6import bz2, gzip, zipfile 
    67 
    78try: 
     
    5253            transaction.managed(True) 
    5354 
     55        class SingleZipReader(zipfile.ZipFile): 
     56            def __init__(self, *args, **kwargs): 
     57                zipfile.ZipFile.__init__(self, *args, **kwargs) 
     58                if settings.DEBUG: 
     59                    assert len(self.namelist()) == 1, "Zip-compressed fixtures must contain only one file." 
     60            def read(self): 
     61                return zipfile.ZipFile.read(self, self.namelist()[0]) 
     62 
     63        compression_types = { 
     64            None:   file, 
     65            'bz2':  bz2.BZ2File, 
     66            'gz':   gzip.GzipFile, 
     67            'zip':  SingleZipReader 
     68        } 
     69 
    5470        app_fixtures = [os.path.join(os.path.dirname(app.__file__), 'fixtures') for app in get_apps()] 
    5571        for fixture_label in fixture_labels: 
    5672            parts = fixture_label.split('.') 
     73 
     74            if len(parts) > 1 and parts[-1] in compression_types: 
     75                compression_formats = [parts[-1]] 
     76                parts = parts[:-1] 
     77            else: 
     78                compression_formats = compression_types.keys() 
     79 
    5780            if len(parts) == 1: 
    58                 fixture_name = fixture_label 
     81                fixture_name = parts[0] 
    5982                formats = serializers.get_public_serializer_formats() 
    6083            else: 
     
    87110                label_found = False 
    88111                for format in formats: 
    89                     serializer = serializers.get_serializer(format) 
    90                     if verbosity > 1: 
    91                         print "Trying %s for %s fixture '%s'..." % \ 
    92                             (humanize(fixture_dir), format, fixture_name) 
    93                     try: 
    94                         full_path = os.path.join(fixture_dir, '.'.join([fixture_name, format])) 
    95                         fixture = open(full_path, 'r') 
    96                         if label_found: 
    97                             fixture.close() 
    98                             print self.style.ERROR("Multiple fixtures named '%s' in %s. Aborting." % 
    99                                 (fixture_name, humanize(fixture_dir))) 
    100                             transaction.rollback() 
    101                             transaction.leave_transaction_management() 
    102                             return 
    103                         else: 
    104                             fixture_count += 1 
    105                             objects_in_fixture = 0 
    106                             if verbosity > 0: 
    107                                 print "Installing %s fixture '%s' from %s." % \ 
    108                                     (format, fixture_name, humanize(fixture_dir)) 
    109                             try: 
    110                                 objects = serializers.deserialize(format, fixture) 
    111                                 for obj in objects: 
    112                                     objects_in_fixture += 1 
    113                                     models.add(obj.object.__class__) 
    114                                     obj.save() 
    115                                 object_count += objects_in_fixture 
    116                                 label_found = True 
    117                             except (SystemExit, KeyboardInterrupt): 
    118                                 raise 
    119                             except Exception: 
    120                                 import traceback 
     112                    for compression_format in compression_formats: 
     113                        if compression_format:  
     114                            file_name = '.'.join([fixture_name, format,  
     115                                                  compression_format]) 
     116                        else:  
     117                            file_name = '.'.join([fixture_name, format]) 
     118                     
     119                        if verbosity > 1: 
     120                            print "Trying %s for %s fixture '%s'..." % \ 
     121                                (humanize(fixture_dir), file_name, fixture_name) 
     122                        full_path = os.path.join(fixture_dir, file_name) 
     123                        open_method = compression_types[compression_format]                                 
     124                        try:  
     125                            fixture = open_method(full_path, 'r') 
     126                            if label_found: 
    121127                                fixture.close() 
    122                                 transaction.rollback() 
    123                                 transaction.leave_transaction_management() 
    124                                 if show_traceback: 
    125                                     import traceback 
    126                                     traceback.print_exc() 
    127                                 else: 
    128                                     sys.stderr.write( 
    129                                         self.style.ERROR("Problem installing fixture '%s': %s\n" % 
    130                                              (full_path, traceback.format_exc()))) 
    131                                 return 
    132                             fixture.close() 
    133  
    134                             # If the fixture we loaded contains 0 objects, assume that an 
    135                             # error was encountered during fixture loading. 
    136                             if objects_in_fixture == 0: 
    137                                 sys.stderr.write( 
    138                                     self.style.ERROR("No fixture data found for '%s'. (File format may be invalid.)" % 
    139                                         (fixture_name))) 
     128                                print self.style.ERROR("Multiple fixtures named '%s' in %s. Aborting." % 
     129                                    (fixture_name, humanize(fixture_dir))) 
    140130                                transaction.rollback() 
    141131                                transaction.leave_transaction_management() 
    142132                                return 
    143                     except: 
    144                         if verbosity > 1: 
    145                             print "No %s fixture '%s' in %s." % \ 
    146                                 (format, fixture_name, humanize(fixture_dir)) 
     133                            else: 
     134                                fixture_count += 1 
     135                                if verbosity > 0: 
     136                                    print "Installing %s fixture '%s' from %s." % \ 
     137                                        (format, fixture_name, humanize(fixture_dir)) 
     138                                try: 
     139                                    objects = serializers.deserialize(format, fixture) 
     140                                    for obj in objects: 
     141                                        object_count += 1 
     142                                        models.add(obj.object.__class__) 
     143                                        obj.save() 
     144                                    label_found = True 
     145                                except (SystemExit, KeyboardInterrupt): 
     146                                    raise 
     147                                except Exception: 
     148                                    import traceback 
     149                                    fixture.close() 
     150                                    transaction.rollback() 
     151                                    transaction.leave_transaction_management() 
     152                                    if show_traceback: 
     153                                        import traceback 
     154                                        traceback.print_exc() 
     155                                    else: 
     156                                        sys.stderr.write( 
     157                                            self.style.ERROR("Problem installing fixture '%s': %s\n" % 
     158                                                 (full_path, traceback.format_exc()))) 
     159                                    return 
     160                                fixture.close() 
     161                        except Exception, e: 
     162                            if verbosity > 1: 
     163                                print "No %s fixture '%s' in %s." % \ 
     164                                    (format, fixture_name, humanize(fixture_dir)) 
     165                                print e 
     166                                transaction.rollback() 
     167                                transaction.leave_transaction_management() 
     168                                return 
    147169 
    148170        # If we found even one object in a fixture, we need to reset the 
  • django/trunk/docs/ref/django-admin.txt

    r9454 r9527  
    291291Searches for and loads the contents of the named fixture into the database. 
    292292 
     293What's a "fixture"? 
     294~~~~~~~~~~~~~~~~~~~ 
     295 
    293296A *fixture* is a collection of files that contain the serialized contents of 
    294297the database. Each fixture has a unique name, and the files that comprise the 
     
    310313 
    311314would only load JSON fixtures called ``mydata``. The fixture extension 
    312 must correspond to the registered name of a serializer (e.g., ``json`` or 
    313 ``xml``). 
    314  
    315 If you omit the extension, Django will search all available fixture types 
     315must correspond to the registered name of a 
     316:ref:`serializer <serialization-formats>` (e.g., ``json`` or ``xml``). 
     317 
     318If you omit the extensions, Django will search all available fixture types 
    316319for a matching fixture. For example:: 
    317320 
     
    320323would look for any fixture of any fixture type called ``mydata``. If a fixture 
    321324directory contained ``mydata.json``, that fixture would be loaded 
    322 as a JSON fixture. However, if two fixtures with the same name but different 
    323 fixture type are discovered (for example, if ``mydata.json`` and 
    324 ``mydata.xml`` were found in the same fixture directory), fixture 
    325 installation will be aborted, and any data installed in the call to 
    326 ``loaddata`` will be removed from the database. 
     325as a JSON fixture. 
    327326 
    328327The fixtures that are named can include directory components. These 
     
    342341 
    343342The ``dumpdata`` command can be used to generate input for ``loaddata``. 
     343 
     344Compressed fixtures 
     345~~~~~~~~~~~~~~~~~~~ 
     346 
     347Fixtures may be compressed in ``zip``, ``gz``, or ``bz2`` format. For example:: 
     348 
     349    django-admin.py loaddata mydata.json 
     350 
     351would look for any of ``mydata.json``, ``mydata.json.zip``, 
     352``mydata.json.gz``, or ``mydata.json.bz2``.  The first file contained within a 
     353zip-compressed archive is used. 
     354 
     355Note that if two fixtures with the same name but different 
     356fixture type are discovered (for example, if ``mydata.json`` and 
     357``mydata.xml.gz`` were found in the same fixture directory), fixture 
     358installation will be aborted, and any data installed in the call to 
     359``loaddata`` will be removed from the database. 
    344360 
    345361.. admonition:: MySQL and Fixtures 
  • django/trunk/tests/modeltests/fixtures/models.py

    r8325 r9527  
    7777Multiple fixtures named 'fixture2' in '...fixtures'. Aborting. 
    7878 
     79# object list is unaffected 
    7980>>> Article.objects.all() 
    8081[<Article: Time to reform copyright>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>] 
     
    8384>>> management.call_command('dumpdata', 'fixtures', format='json') 
    8485[{"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16 12:00:00"}}, {"pk": 1, "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}] 
     86 
     87# Load fixture 4 (compressed), using format discovery 
     88>>> management.call_command('loaddata', 'fixture4', verbosity=0) 
     89>>> Article.objects.all() 
     90[<Article: Django pets kitten>, <Article: Time to reform copyright>, <Article: Poker has no place on ESPN>, <Article: Python program becomes self aware>] 
     91 
     92>>> management.call_command('flush', verbosity=0, interactive=False) 
     93 
     94# Load fixture 4 (compressed), using format specification 
     95>>> management.call_command('loaddata', 'fixture4.json', verbosity=0) 
     96>>> Article.objects.all() 
     97[<Article: Django pets kitten>, <Article: Python program becomes self aware>] 
     98 
     99>>> management.call_command('flush', verbosity=0, interactive=False) 
     100 
     101# Load fixture 5 (compressed), using format *and* compression specification 
     102>>> management.call_command('loaddata', 'fixture5.json.zip', verbosity=0) 
     103>>> Article.objects.all() 
     104[<Article: WoW subscribers now outnumber readers>, <Article: Python program becomes self aware>] 
     105 
     106>>> management.call_command('flush', verbosity=0, interactive=False) 
     107 
     108# Load fixture 5 (compressed), only compression specification 
     109>>> management.call_command('loaddata', 'fixture5.zip', verbosity=0) 
     110>>> Article.objects.all() 
     111[<Article: WoW subscribers now outnumber readers>, <Article: Python program becomes self aware>] 
     112 
     113>>> management.call_command('flush', verbosity=0, interactive=False) 
     114 
     115# Try to load fixture 5 using format and compression discovery; this will fail 
     116# because there are two fixture5's in the fixtures directory 
     117>>> management.call_command('loaddata', 'fixture5', verbosity=0) # doctest: +ELLIPSIS 
     118Multiple fixtures named 'fixture5' in '...fixtures'. Aborting. 
    85119""" 
    86120