You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

dumpdata.py 8.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. import warnings
  2. from collections import OrderedDict
  3. from django.apps import apps
  4. from django.core import serializers
  5. from django.core.management.base import BaseCommand, CommandError
  6. from django.core.management.utils import parse_apps_and_model_labels
  7. from django.db import DEFAULT_DB_ALIAS, router
  8. class ProxyModelWarning(Warning):
  9. pass
  10. class Command(BaseCommand):
  11. help = (
  12. "Output the contents of the database as a fixture of the given format "
  13. "(using each model's default manager unless --all is specified)."
  14. )
  15. def add_arguments(self, parser):
  16. parser.add_argument(
  17. 'args', metavar='app_label[.ModelName]', nargs='*',
  18. help='Restricts dumped data to the specified app_label or app_label.ModelName.',
  19. )
  20. parser.add_argument(
  21. '--format', default='json',
  22. help='Specifies the output serialization format for fixtures.',
  23. )
  24. parser.add_argument(
  25. '--indent', type=int,
  26. help='Specifies the indent level to use when pretty-printing output.',
  27. )
  28. parser.add_argument(
  29. '--database',
  30. default=DEFAULT_DB_ALIAS,
  31. help='Nominates a specific database to dump fixtures from. '
  32. 'Defaults to the "default" database.',
  33. )
  34. parser.add_argument(
  35. '-e', '--exclude', action='append', default=[],
  36. help='An app_label or app_label.ModelName to exclude '
  37. '(use multiple --exclude to exclude multiple apps/models).',
  38. )
  39. parser.add_argument(
  40. '--natural-foreign', action='store_true', dest='use_natural_foreign_keys',
  41. help='Use natural foreign keys if they are available.',
  42. )
  43. parser.add_argument(
  44. '--natural-primary', action='store_true', dest='use_natural_primary_keys',
  45. help='Use natural primary keys if they are available.',
  46. )
  47. parser.add_argument(
  48. '-a', '--all', action='store_true', dest='use_base_manager',
  49. help="Use Django's base manager to dump all models stored in the database, "
  50. "including those that would otherwise be filtered or modified by a custom manager.",
  51. )
  52. parser.add_argument(
  53. '--pks', dest='primary_keys',
  54. help="Only dump objects with given primary keys. Accepts a comma-separated "
  55. "list of keys. This option only works when you specify one model.",
  56. )
  57. parser.add_argument(
  58. '-o', '--output',
  59. help='Specifies file to which the output is written.'
  60. )
  61. def handle(self, *app_labels, **options):
  62. format = options['format']
  63. indent = options['indent']
  64. using = options['database']
  65. excludes = options['exclude']
  66. output = options['output']
  67. show_traceback = options['traceback']
  68. use_natural_foreign_keys = options['use_natural_foreign_keys']
  69. use_natural_primary_keys = options['use_natural_primary_keys']
  70. use_base_manager = options['use_base_manager']
  71. pks = options['primary_keys']
  72. if pks:
  73. primary_keys = [pk.strip() for pk in pks.split(',')]
  74. else:
  75. primary_keys = []
  76. excluded_models, excluded_apps = parse_apps_and_model_labels(excludes)
  77. if not app_labels:
  78. if primary_keys:
  79. raise CommandError("You can only use --pks option with one model")
  80. app_list = OrderedDict.fromkeys(
  81. app_config for app_config in apps.get_app_configs()
  82. if app_config.models_module is not None and app_config not in excluded_apps
  83. )
  84. else:
  85. if len(app_labels) > 1 and primary_keys:
  86. raise CommandError("You can only use --pks option with one model")
  87. app_list = OrderedDict()
  88. for label in app_labels:
  89. try:
  90. app_label, model_label = label.split('.')
  91. try:
  92. app_config = apps.get_app_config(app_label)
  93. except LookupError as e:
  94. raise CommandError(str(e))
  95. if app_config.models_module is None or app_config in excluded_apps:
  96. continue
  97. try:
  98. model = app_config.get_model(model_label)
  99. except LookupError:
  100. raise CommandError("Unknown model: %s.%s" % (app_label, model_label))
  101. app_list_value = app_list.setdefault(app_config, [])
  102. # We may have previously seen a "all-models" request for
  103. # this app (no model qualifier was given). In this case
  104. # there is no need adding specific models to the list.
  105. if app_list_value is not None:
  106. if model not in app_list_value:
  107. app_list_value.append(model)
  108. except ValueError:
  109. if primary_keys:
  110. raise CommandError("You can only use --pks option with one model")
  111. # This is just an app - no model qualifier
  112. app_label = label
  113. try:
  114. app_config = apps.get_app_config(app_label)
  115. except LookupError as e:
  116. raise CommandError(str(e))
  117. if app_config.models_module is None or app_config in excluded_apps:
  118. continue
  119. app_list[app_config] = None
  120. # Check that the serialization format exists; this is a shortcut to
  121. # avoid collating all the objects and _then_ failing.
  122. if format not in serializers.get_public_serializer_formats():
  123. try:
  124. serializers.get_serializer(format)
  125. except serializers.SerializerDoesNotExist:
  126. pass
  127. raise CommandError("Unknown serialization format: %s" % format)
  128. def get_objects(count_only=False):
  129. """
  130. Collate the objects to be serialized. If count_only is True, just
  131. count the number of objects to be serialized.
  132. """
  133. models = serializers.sort_dependencies(app_list.items())
  134. for model in models:
  135. if model in excluded_models:
  136. continue
  137. if model._meta.proxy and model._meta.proxy_for_model not in models:
  138. warnings.warn(
  139. "%s is a proxy model and won't be serialized." % model._meta.label,
  140. category=ProxyModelWarning,
  141. )
  142. if not model._meta.proxy and router.allow_migrate_model(using, model):
  143. if use_base_manager:
  144. objects = model._base_manager
  145. else:
  146. objects = model._default_manager
  147. queryset = objects.using(using).order_by(model._meta.pk.name)
  148. if primary_keys:
  149. queryset = queryset.filter(pk__in=primary_keys)
  150. if count_only:
  151. yield queryset.order_by().count()
  152. else:
  153. yield from queryset.iterator()
  154. try:
  155. self.stdout.ending = None
  156. progress_output = None
  157. object_count = 0
  158. # If dumpdata is outputting to stdout, there is no way to display progress
  159. if output and self.stdout.isatty() and options['verbosity'] > 0:
  160. progress_output = self.stdout
  161. object_count = sum(get_objects(count_only=True))
  162. stream = open(output, 'w') if output else None
  163. try:
  164. serializers.serialize(
  165. format, get_objects(), indent=indent,
  166. use_natural_foreign_keys=use_natural_foreign_keys,
  167. use_natural_primary_keys=use_natural_primary_keys,
  168. stream=stream or self.stdout, progress_output=progress_output,
  169. object_count=object_count,
  170. )
  171. finally:
  172. if stream:
  173. stream.close()
  174. except Exception as e:
  175. if show_traceback:
  176. raise
  177. raise CommandError("Unable to serialize database: %s" % e)