Ticket #7159: loaddata-delete.diff

File loaddata-delete.diff, 5.4 KB (added by Graham King <graham@…>, 7 years ago)

The patch

  • django/core/management/commands/loaddata.py

     
    1414        make_option('--verbosity', action='store', dest='verbosity', default='1',
    1515            type='choice', choices=['0', '1', '2'],
    1616            help='Verbosity level; 0=minimal output, 1=normal output, 2=all output'),
     17        make_option('--delete', action='store_true', dest='delete', default=False,
     18            help='Deletes any items in the database which are not in the fixture'),
    1719    )
    1820    help = 'Installs the named fixture(s) in the database.'
    1921    args = "fixture [fixture ...]"
    2022
     23    def remove_objects_not_in(self, objects_to_keep, verbosity):
     24        """
     25        Deletes all the objects in the database that are not in objects_to_keep.
     26        - objects_to_keep: A map where the keys are classes, and the values are a
     27         set of the objects of that class we should keep.
     28        """
     29        for class_ in objects_to_keep.keys():
     30       
     31            current = class_.objects.all()
     32            current_ids = set( [x.id for x in current] )
     33            keep_ids = set( [x.id for x in objects_to_keep[class_]] )
     34
     35            remove_these_ones = current_ids.difference(keep_ids)
     36            if remove_these_ones:
     37               
     38                for obj in current:
     39                    if obj.id in remove_these_ones:
     40                        obj.delete()
     41                        if verbosity >= 2:
     42                            print "Deleted object: "+ unicode(obj)
     43                               
     44            if verbosity > 0 and remove_these_ones:
     45                num_deleted = len(remove_these_ones)
     46                if num_deleted > 1:
     47                    type_deleted = unicode(class_._meta.verbose_name_plural)
     48                else:
     49                    type_deleted = unicode(class_._meta.verbose_name)
     50
     51                print "Deleted "+ str(num_deleted) +" "+ type_deleted
     52   
    2153    def handle(self, *fixture_labels, **options):
    2254        from django.db.models import get_apps
    2355        from django.core import serializers
     
    2860
    2961        verbosity = int(options.get('verbosity', 1))
    3062        show_traceback = options.get('traceback', False)
    31 
     63        is_delete = options.get('delete', False)
     64       
    3265        # Keep a count of the installed objects and fixtures
    3366        fixture_count = 0
    3467        object_count = 0
     
    97130                                print "Installing %s fixture '%s' from %s." % \
    98131                                    (format, fixture_name, humanize(fixture_dir))
    99132                            try:
     133                               
     134                                objects_to_keep = {}
     135                               
    100136                                objects = serializers.deserialize(format, fixture)
    101137                                for obj in objects:
    102138                                    object_count += 1
    103                                     models.add(obj.object.__class__)
     139                                   
     140                                    class_ = obj.object.__class__
     141                                    if not class_ in objects_to_keep:
     142                                        objects_to_keep[class_] = set()
     143                                    objects_to_keep[class_].add(obj.object)
     144                                   
     145                                    models.add(class_)
    104146                                    obj.save()
     147                               
     148                                if is_delete:
     149                                    self.remove_objects_not_in(objects_to_keep, verbosity)
     150
    105151                                label_found = True
    106152                            except Exception, e:
    107153                                fixture.close()
  • tests/modeltests/fixtures/models.py

     
    5454# object list is unaffected
    5555>>> Article.objects.all()
    5656[<Article: XML identified as leading cause of cancer>, <Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker on TV is great!>, <Article: Python program becomes self aware>]
     57
     58# Delete two existing objects
     59>>> management.call_command('loaddata', 'fixture4.json', verbosity=0, delete=True)
     60>>> Article.objects.all()
     61[<Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker on TV is great!>]
    5762"""}
    5863
    5964# Database flushing does not work on MySQL with the default storage engine
  • docs/django-admin.txt

     
    321321
    322322    django-admin.py loaddata --verbosity=2
    323323
     324**New in Django development version**
     325--delete
     326~~~~~~~~
     327
     328Deletes any objects in the database which are not in the fixtures. If you run ``loaddata``
     329with ``--delete``, after the operation the database will exactly match the contents
     330of the fixtures.
     331If you do not specify ``--delete`` new objects only present in the fixture will be created in
     332the database, objects present in both will be updated, but no data will be removed from
     333the database.
     334
    324335reset <appname appname ...>
    325336---------------------------
    326337
Back to Top