Show
Ignore:
Timestamp:
02/27/07 09:59:46 (3 years ago)
Author:
akaihola
Message:

dbpickle now handles foreign keys correctly.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • trunk/dbpickle/dbpickle.py

    r28 r75  
    2828for migrating from one database engine to another. 
    2929 
     30This version handles ForeignKeys which refer to the related model's 
     31primary key.  ManyToMany and OneToOne relations are not supported. 
     32 
    3033Let's suppose your project is using PostgreSQL and the database has 
    3134been populated using the app. 
     
    5255import cPickle 
    5356import logging 
     57from django.db import models 
    5458 
    5559def dump(filepath): 
    56     from django.db import models 
     60    """ 
     61    Pickle all Django objects from the database and save them into the given file. 
     62    """ 
    5763    data = {} 
    5864    for model in models.get_models(): 
    5965        meta = model._meta 
    6066        app, model_name = meta.app_label, meta.module_name 
    61         objects = list(model.objects.all()) 
    62         logging.info('dumping model %s.%s (%d objects)' % (app, model_name, len(objects))) 
    63         data[app, model_name] = objects 
     67        for obj in model.objects.all(): 
     68            logging.info('dumping %s.%s %s' % (app, model_name, obj)) 
     69            data[app, model_name, obj._get_pk_val()] = obj 
    6470    cPickle.dump(data, file(filepath, 'w')) 
     71 
    6572 
    6673@transaction.commit_on_success 
    6774def load(filepath): 
     75    """ 
     76    Unpickle Django objects from the given file and save them into the 
     77    database. 
     78    """ 
     79     
     80    # unpickle objects from file 
    6881    data = cPickle.load(file(filepath)) 
    69     for (app, model), objects in data.items(): 
    70         logging.info('loading model %s.%s' % (app, model)) 
    71         for obj in objects: 
    72             logging.debug(str(obj)) 
     82 
     83    # delete objects from all models to be loaded 
     84    models = set(obj.__class__ for obj in data.itervalues()) 
     85    for model in models: 
     86        for obj in model._default_manager.all(): 
     87            obj.delete() 
     88 
     89    # load all objects 
     90    while data: 
     91        key, obj = data.popitem() 
     92        load_recursive(data, obj) 
     93 
     94 
     95def load_recursive(data, obj): 
     96    """ 
     97    Save the given object into the database.  If the object has 
     98    ForeignKey relations to other objects, first make sure they are 
     99    already saved (and repeat recursively). 
     100    """ 
     101     
     102    for field in obj._meta.fields: 
     103        if isinstance(field, models.ForeignKey): 
     104            related_app = field.rel.to._meta.app_label 
     105            related_model = field.rel.to._meta.module_name 
     106            related_pk_val = getattr(obj, field.name+'_id') 
    73107            try: 
    74                 obj.save() 
    75             except Exception, e: 
    76                 logging.error('%s while saving %s.%s %s' % (e, app, model, str(obj))) 
     108                related_obj = data.pop((related_app, 
     109                                        related_model, 
     110                                        related_pk_val)) 
     111                load_recursive(data, related_obj) 
     112            except KeyError: 
     113                logging.debug('probably loaded already: ' 
     114                              '%(related_app)s.%(related_model)s ' 
     115                              '%(related_pk_val)s' % locals()) 
     116    logging.info('loading %s' % obj) 
     117    try: 
     118        obj.save() 
     119    except Exception, e: 
     120        logging.error('%s while saving %s' % (e, obj)) 
     121 
    77122 
    78123if __name__ == '__main__':