Fixed #26144 -- Warned when dumping proxy model without concrete parent.

This commit is contained in:
Yoong Kang Lim 2016-01-27 22:15:38 +11:00 committed by Tim Graham
parent 04de436932
commit 0edb8a146f
4 changed files with 56 additions and 2 deletions

View File

@ -1,3 +1,5 @@
import inspect
import warnings
from collections import OrderedDict from collections import OrderedDict
from django.apps import apps from django.apps import apps
@ -6,6 +8,10 @@ from django.core.management.base import BaseCommand, CommandError
from django.db import DEFAULT_DB_ALIAS, router from django.db import DEFAULT_DB_ALIAS, router
class ProxyModelWarning(Warning):
pass
class Command(BaseCommand): class Command(BaseCommand):
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 unless --all is " "format (using each model's default manager unless --all is "
@ -132,9 +138,15 @@ class Command(BaseCommand):
Collate the objects to be serialized. If count_only is True, just Collate the objects to be serialized. If count_only is True, just
count the number of objects to be serialized. count the number of objects to be serialized.
""" """
for model in serializers.sort_dependencies(app_list.items()): models = serializers.sort_dependencies(app_list.items())
for model in models:
if model in excluded_models: if model in excluded_models:
continue continue
if model._meta.proxy and inspect.getmro(model)[1] not in models:
warnings.warn(
"%s is a proxy model and won't be serialized." % model._meta.label,
category=ProxyModelWarning,
)
if not model._meta.proxy and router.allow_migrate_model(using, model): if not model._meta.proxy and router.allow_migrate_model(using, model):
if use_base_manager: if use_base_manager:
objects = model._base_manager objects = model._base_manager

View File

@ -245,6 +245,9 @@ Management Commands
* The new :option:`shell --command` option lets you run a command as Django and * The new :option:`shell --command` option lets you run a command as Django and
exit, instead of opening the interactive shell. exit, instead of opening the interactive shell.
* Added a warning to :djadmin:`dumpdata` if a proxy model is specified (which
results in no output) without its concrete parent.
Migrations Migrations
~~~~~~~~~~ ~~~~~~~~~~

View File

@ -92,6 +92,11 @@ class Spy(Person):
cover_blown = models.BooleanField(default=False) cover_blown = models.BooleanField(default=False)
class ProxySpy(Spy):
class Meta:
proxy = True
@python_2_unicode_compatible @python_2_unicode_compatible
class Visa(models.Model): class Visa(models.Model):
person = models.ForeignKey(Person, models.CASCADE) person = models.ForeignKey(Person, models.CASCADE)

View File

@ -4,12 +4,14 @@ import os
import sys import sys
import tempfile import tempfile
import unittest import unittest
import warnings
from django.apps import apps from django.apps import apps
from django.contrib.sites.models import Site from django.contrib.sites.models import Site
from django.core import management from django.core import management
from django.core.files.temp import NamedTemporaryFile from django.core.files.temp import NamedTemporaryFile
from django.core.management import CommandError from django.core.management import CommandError
from django.core.management.commands.dumpdata import ProxyModelWarning
from django.core.serializers.base import ProgressBar from django.core.serializers.base import ProgressBar
from django.db import IntegrityError, connection from django.db import IntegrityError, connection
from django.test import ( from django.test import (
@ -18,7 +20,7 @@ from django.test import (
from django.utils import six from django.utils import six
from django.utils.encoding import force_text from django.utils.encoding import force_text
from .models import Article, Spy, Tag, Visa from .models import Article, ProxySpy, Spy, Tag, Visa
class TestCaseFixtureLoadingTests(TestCase): class TestCaseFixtureLoadingTests(TestCase):
@ -476,6 +478,38 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase):
management.call_command('dumpdata', 'fixtures', **options) management.call_command('dumpdata', 'fixtures', **options)
self.assertEqual(new_io.getvalue(), '') self.assertEqual(new_io.getvalue(), '')
def test_dumpdata_proxy_without_concrete(self):
"""
A warning is displayed if a proxy model is dumped without its concrete
parent.
"""
ProxySpy.objects.create(name='Paul')
with warnings.catch_warnings(record=True) as warning_list:
warnings.simplefilter('always')
self._dumpdata_assert(['fixtures.ProxySpy'], '[]')
warning = warning_list.pop()
self.assertEqual(warning.category, ProxyModelWarning)
self.assertEqual(
str(warning.message),
"fixtures.ProxySpy is a proxy model and won't be serialized."
)
def test_dumpdata_proxy_with_concrete(self):
"""
A warning isn't displayed if a proxy model is dumped with its concrete
parent.
"""
spy = ProxySpy.objects.create(name='Paul')
with warnings.catch_warnings(record=True) as warning_list:
warnings.simplefilter('always')
self._dumpdata_assert(
['fixtures.ProxySpy', 'fixtures.Spy'],
'[{"pk": %d, "model": "fixtures.spy", "fields": {"cover_blown": false}}]' % spy.pk
)
self.assertEqual(len(warning_list), 0)
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) management.call_command('loaddata', 'fixture4.json', verbosity=0)