Skip to content

Commit

Permalink
Fixed #14162 - Dumpdata needs an option to use the base manager inste…
Browse files Browse the repository at this point in the history
…ad of the default manager

Thanks to PaulM for suggestion and patch.



git-svn-id: http://code.djangoproject.com/svn/django/trunk@13669 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
spookylukey committed Aug 30, 2010
1 parent f9d051d commit 5deb3e5
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 5 deletions.
11 changes: 9 additions & 2 deletions django/core/management/commands/dumpdata.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ class Command(BaseCommand):
help='An appname or appname.ModelName to exclude (use multiple --exclude to exclude multiple apps/models).'), help='An appname or appname.ModelName to exclude (use multiple --exclude to exclude multiple apps/models).'),
make_option('-n', '--natural', action='store_true', dest='use_natural_keys', default=False, make_option('-n', '--natural', action='store_true', dest='use_natural_keys', default=False,
help='Use natural keys if they are available.'), help='Use natural keys if they are available.'),
make_option('-a', '--all', action='store_true', dest='use_base_manager', default=False,
help="Use Django's base manager to dump all models stored in the database, including those that would otherwise be filtered or modified by a custom manager."),
) )
help = ("Output the contents of the database as a fixture of the given " help = ("Output the contents of the database as a fixture of the given "
"format (using each model's default manager).") "format (using each model's default manager unless --all is "
"specified).")
args = '[appname appname.ModelName ...]' args = '[appname appname.ModelName ...]'


def handle(self, *app_labels, **options): def handle(self, *app_labels, **options):
Expand All @@ -34,6 +37,7 @@ def handle(self, *app_labels, **options):
excludes = options.get('exclude',[]) excludes = options.get('exclude',[])
show_traceback = options.get('traceback', False) show_traceback = options.get('traceback', False)
use_natural_keys = options.get('use_natural_keys', False) use_natural_keys = options.get('use_natural_keys', False)
use_base_manager = options.get('use_base_manager', False)


excluded_apps = set() excluded_apps = set()
excluded_models = set() excluded_models = set()
Expand Down Expand Up @@ -100,7 +104,10 @@ def handle(self, *app_labels, **options):
if model in excluded_models: if model in excluded_models:
continue continue
if not model._meta.proxy and router.allow_syncdb(using, model): if not model._meta.proxy and router.allow_syncdb(using, model):
objects.extend(model._default_manager.using(using).all()) if use_base_manager:
objects.extend(model._base_manager.using(using).all())
else:
objects.extend(model._default_manager.using(using).all())


try: try:
return serializers.serialize(format, objects, indent=indent, return serializers.serialize(format, objects, indent=indent,
Expand Down
7 changes: 6 additions & 1 deletion docs/ref/django-admin.txt
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -208,6 +208,12 @@ records to dump. If you're using a :ref:`custom manager <custom-managers>` as
the default manager and it filters some of the available records, not all of the the default manager and it filters some of the available records, not all of the
objects will be dumped. objects will be dumped.


.. versionadded:: 1.3

The :djadminopt:`--all` option may be provided to specify that
``dumpdata`` should use Django's base manager, dumping records which
might otherwise be filtered or modified by a custom manager.

.. django-admin-option:: --format <fmt> .. django-admin-option:: --format <fmt>


By default, ``dumpdata`` will format its output in JSON, but you can use the By default, ``dumpdata`` will format its output in JSON, but you can use the
Expand Down Expand Up @@ -271,7 +277,6 @@ prompts.
The :djadminopt:`--database` option may be used to specify the database The :djadminopt:`--database` option may be used to specify the database
to flush. to flush.



inspectdb inspectdb
--------- ---------


Expand Down
8 changes: 8 additions & 0 deletions tests/modeltests/fixtures/models.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ class Meta:
def natural_key(self): def natural_key(self):
return (self.name,) return (self.name,)


class SpyManager(PersonManager):
def get_query_set(self):
return super(SpyManager, self).get_query_set().filter(cover_blown=False)

class Spy(Person):
objects = SpyManager()
cover_blown = models.BooleanField(default=False)

class Visa(models.Model): class Visa(models.Model):
person = models.ForeignKey(Person) person = models.ForeignKey(Person)
permissions = models.ManyToManyField(Permission, blank=True) permissions = models.ManyToManyField(Permission, blank=True)
Expand Down
16 changes: 14 additions & 2 deletions tests/modeltests/fixtures/tests.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from django.core import management from django.core import management
from django.db import DEFAULT_DB_ALIAS from django.db import DEFAULT_DB_ALIAS


from models import Article, Blog, Book, Category, Person, Tag, Visa from models import Article, Blog, Book, Category, Person, Spy, Tag, Visa


class TestCaseFixtureLoadingTests(TestCase): class TestCaseFixtureLoadingTests(TestCase):
fixtures = ['fixture1.json', 'fixture2.json'] fixtures = ['fixture1.json', 'fixture2.json']
Expand All @@ -24,12 +24,13 @@ def testClassFixtures(self):
class FixtureLoadingTests(TestCase): class FixtureLoadingTests(TestCase):


def _dumpdata_assert(self, args, output, format='json', natural_keys=False, def _dumpdata_assert(self, args, output, format='json', natural_keys=False,
exclude_list=[]): use_base_manager=False, exclude_list=[]):
new_io = StringIO.StringIO() new_io = StringIO.StringIO()
management.call_command('dumpdata', *args, **{'format':format, management.call_command('dumpdata', *args, **{'format':format,
'stdout':new_io, 'stdout':new_io,
'stderr':new_io, 'stderr':new_io,
'use_natural_keys':natural_keys, 'use_natural_keys':natural_keys,
'use_base_manager':use_base_manager,
'exclude': exclude_list}) 'exclude': exclude_list})
command_output = new_io.getvalue().strip() command_output = new_io.getvalue().strip()
self.assertEqual(command_output, output) self.assertEqual(command_output, output)
Expand Down Expand Up @@ -197,6 +198,17 @@ def test_dumpdata_with_excludes(self):
'', '',
exclude_list=['fixtures.FooModel']) exclude_list=['fixtures.FooModel'])


def test_dumpdata_with_filtering_manager(self):
Spy(name='Paul').save()
Spy(name='Alex', cover_blown=True).save()
self.assertQuerysetEqual(Spy.objects.all(),
['<Spy: Paul>'])
# Use the default manager
self._dumpdata_assert(['fixtures.Spy'],'[{"pk": 1, "model": "fixtures.spy", "fields": {"cover_blown": false}}]')
# Dump using Django's base manager. Should return all objects,
# even those normally filtered by the manager
self._dumpdata_assert(['fixtures.Spy'], '[{"pk": 2, "model": "fixtures.spy", "fields": {"cover_blown": true}}, {"pk": 1, "model": "fixtures.spy", "fields": {"cover_blown": false}}]', use_base_manager=True)

def test_compress_format_loading(self): def test_compress_format_loading(self):
# Load fixture 4 (compressed), using format specification # Load fixture 4 (compressed), using format specification
management.call_command('loaddata', 'fixture4.json', verbosity=0, commit=False) management.call_command('loaddata', 'fixture4.json', verbosity=0, commit=False)
Expand Down

0 comments on commit 5deb3e5

Please sign in to comment.