Commit ae2a7da8 authored by Berker Peksag's avatar Berker Peksag Committed by Tim Graham
Browse files

Fixed #20468 -- Added loaddata --exclude option.

Thanks Alex Morozov for the initial patch.
parent 21130ce1
Loading
Loading
Loading
Loading
+2 −15
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ from collections import OrderedDict
from django.apps import apps
from django.core import serializers
from django.core.management.base import BaseCommand, CommandError
from django.core.management.utils import parse_apps_and_model_labels
from django.db import DEFAULT_DB_ALIAS, router


@@ -81,21 +82,7 @@ class Command(BaseCommand):
        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 as e:
                    raise CommandError(str(e))
                excluded_apps.add(app_config)
        excluded_models, excluded_apps = parse_apps_and_model_labels(excludes)

        if len(app_labels) == 0:
            if primary_keys:
+9 −1
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@ from django.core import serializers
from django.core.exceptions import ImproperlyConfigured
from django.core.management.base import BaseCommand, CommandError
from django.core.management.color import no_style
from django.core.management.utils import parse_apps_and_model_labels
from django.db import (
    DEFAULT_DB_ALIAS, DatabaseError, IntegrityError, connections, router,
    transaction,
@@ -52,13 +53,17 @@ class Command(BaseCommand):
            help='Ignores entries in the serialized data for fields that do not '
                 'currently exist on the model.',
        )
        parser.add_argument(
            '-e', '--exclude', dest='exclude', action='append', default=[],
            help='An app_label or app_label.ModelName to exclude. Can be used multiple times.',
        )

    def handle(self, *fixture_labels, **options):

        self.ignore = options['ignore']
        self.using = options['database']
        self.app_label = options['app_label']
        self.verbosity = options['verbosity']
        self.excluded_models, self.excluded_apps = parse_apps_and_model_labels(options['exclude'])

        with transaction.atomic(using=self.using):
            self.loaddata(fixture_labels)
@@ -160,6 +165,9 @@ class Command(BaseCommand):

                for obj in objects:
                    objects_in_fixture += 1
                    if (obj.object._meta.app_config in self.excluded_apps or
                            type(obj.object) in self.excluded_models):
                        continue
                    if router.allow_migrate_model(self.using, obj.object.__class__):
                        loaded_objects_in_fixture += 1
                        self.models.add(obj.object.__class__)
+28 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ import os
import sys
from subprocess import PIPE, Popen

from django.apps import apps as installed_apps
from django.utils import six
from django.utils.crypto import get_random_string
from django.utils.encoding import DEFAULT_LOCALE_ENCODING, force_text
@@ -84,3 +85,30 @@ def get_random_secret_key():
    """
    chars = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)'
    return get_random_string(50, chars)


def parse_apps_and_model_labels(labels):
    """
    Parse a list of "app_label.ModelName" or "app_label" strings into actual
    objects and return a two-element tuple:
        (set of model classes, set of app_configs).
    Raise a CommandError if some specified models or apps don't exist.
    """
    apps = set()
    models = set()

    for label in labels:
        if '.' in label:
            try:
                model = installed_apps.get_model(label)
            except LookupError:
                raise CommandError('Unknown model: %s' % label)
            models.add(model)
        else:
            try:
                app_config = installed_apps.get_app_config(label)
            except LookupError as e:
                raise CommandError(str(e))
            apps.add(app_config)

    return models, apps
+8 −0
Original line number Diff line number Diff line
@@ -416,6 +416,14 @@ originally generated.

Specifies a single app to look for fixtures in rather than looking in all apps.

.. django-admin-option:: --exclude EXCLUDE, -e EXCLUDE

.. versionadded:: 1.11

Excludes loading the fixtures from the given applications and/or models (in the
form of ``app_label`` or ``app_label.ModelName``). Use the option multiple
times to exclude more than one app or model.

What's a "fixture"?
~~~~~~~~~~~~~~~~~~~

+2 −1
Original line number Diff line number Diff line
@@ -169,7 +169,8 @@ Internationalization
Management Commands
~~~~~~~~~~~~~~~~~~~

* ...
* The new :option:`loaddata --exclude` option allows excluding models and apps
  while loading data from fixtures.

Migrations
~~~~~~~~~~
Loading