import warnings from collections import OrderedDict from django.apps import apps from django.core.management.base import BaseCommand, CommandError from django.core import serializers from django.db import router, DEFAULT_DB_ALIAS from django.utils.deprecation import RemovedInDjango19Warning class Command(BaseCommand): help = ("Output the contents of the database as a fixture of the given " "format (using each model's default manager unless --all is " "specified).") def add_arguments(self, parser): parser.add_argument('args', metavar='app_label[.ModelName]', nargs='*', help='Restricts dumped data to the specified app_label or app_label.ModelName.') parser.add_argument('--format', default='json', dest='format', help='Specifies the output serialization format for fixtures.') parser.add_argument('--indent', default=None, dest='indent', type=int, help='Specifies the indent level to use when pretty-printing output.') parser.add_argument('--database', action='store', dest='database', default=DEFAULT_DB_ALIAS, help='Nominates a specific database to dump fixtures from. ' 'Defaults to the "default" database.') parser.add_argument('-e', '--exclude', dest='exclude', action='append', default=[], help='An app_label or app_label.ModelName to exclude ' '(use multiple --exclude to exclude multiple apps/models).') parser.add_argument('-n', '--natural', action='store_true', dest='use_natural_keys', default=False, help='Use natural keys if they are available (deprecated: use --natural-foreign instead).') parser.add_argument('--natural-foreign', action='store_true', dest='use_natural_foreign_keys', default=False, help='Use natural foreign keys if they are available.') parser.add_argument('--natural-primary', action='store_true', dest='use_natural_primary_keys', default=False, help='Use natural primary keys if they are available.') parser.add_argument('-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.") parser.add_argument('--pks', dest='primary_keys', help="Only dump objects with given primary keys. " "Accepts a comma separated list of keys. " "This option will only work when you specify one model.") parser.add_argument('-o', '--output', default=None, dest='output', help='Specifies file to which the output is written.') def handle(self, *app_labels, **options): format = options.get('format') indent = options.get('indent') using = options.get('database') excludes = options.get('exclude') output = options.get('output') show_traceback = options.get('traceback') use_natural_keys = options.get('use_natural_keys') if use_natural_keys: warnings.warn("``--natural`` is deprecated; use ``--natural-foreign`` instead.", RemovedInDjango19Warning) use_natural_foreign_keys = options.get('use_natural_foreign_keys') or use_natural_keys use_natural_primary_keys = options.get('use_natural_primary_keys') use_base_manager = options.get('use_base_manager') pks = options.get('primary_keys') if pks: primary_keys = pks.split(',') else: primary_keys = [] excluded_apps = set() excluded_models = set() for exclude in excludes: if '.' in exclude: try: model = apps.get_model(exclude) except LookupError: raise CommandError('Unknown model in excludes: %s' % exclude) excluded_models.add(model) else: try: app_config = apps.get_app_config(exclude) except LookupError: raise CommandError('Unknown app in excludes: %s' % exclude) excluded_apps.add(app_config) if len(app_labels) == 0: if primary_keys: raise CommandError("You can only use --pks option with one model") app_list = OrderedDict((app_config, None) for app_config in apps.get_app_configs() if app_config.models_module is not None and app_config not in excluded_apps) else: if len(app_labels) > 1 and primary_keys: raise CommandError("You can only use --pks option with one model") app_list = OrderedDict() for label in app_labels: try: app_label, model_label = label.split('.') try: app_config = apps.get_app_config(app_label) except LookupError: raise CommandError("Unknown application: %s" % app_label) if app_config.models_module is None or app_config in excluded_apps: continue try: model = app_config.get_model(model_label) except LookupError: raise CommandError("Unknown model: %s.%s" % (app_label, model_label)) app_list_value = app_list.setdefault(app_config, []) # We may have previously seen a "all-models" request for # this app (no model qualifier was given). In this case # there is no need adding specific models to the list. if app_list_value is not None: if model not in app_list_value: app_list_value.append(model) except ValueError: if primary_keys: raise CommandError("You can only use --pks option with one model") # This is just an app - no model qualifier app_label = label try: app_config = apps.get_app_config(app_label) except LookupError: raise CommandError("Unknown application: %s" % app_label) if app_config.models_module is None or app_config in excluded_apps: continue app_list[app_config] = None # Check that the serialization format exists; this is a shortcut to # avoid collating all the objects and _then_ failing. if format not in serializers.get_public_serializer_formats(): try: serializers.get_serializer(format) except serializers.SerializerDoesNotExist: pass raise CommandError("Unknown serialization format: %s" % format) def get_objects(): # Collate the objects to be serialized. for model in serializers.sort_dependencies(app_list.items()): if model in excluded_models: continue if not model._meta.proxy and router.allow_migrate(using, model): if use_base_manager: objects = model._base_manager else: objects = model._default_manager queryset = objects.using(using).order_by(model._meta.pk.name) if primary_keys: queryset = queryset.filter(pk__in=primary_keys) for obj in queryset.iterator(): yield obj try: self.stdout.ending = None stream = open(output, 'w') if output else None try: serializers.serialize(format, get_objects(), indent=indent, use_natural_foreign_keys=use_natural_foreign_keys, use_natural_primary_keys=use_natural_primary_keys, stream=stream or self.stdout) finally: if stream: stream.close() except Exception as e: if show_traceback: raise raise CommandError("Unable to serialize database: %s" % e)