Ejemplo n.º 1
0
    def contribute_to_class(self, cls, *args, **kwargs):
        super().contribute_to_class(cls, *args, **kwargs)

        # Add any necessary unique_together index to the model
        if self.unique_for_fields and self.unique_db_constraint:
            # Alter only original_attr to fake being a declared unique_together
            # Cannot modify cls._meta.unique_together as it breaks state consistency for migrations
            ut = set((self.unique_together, )).union(
                normalize_together(
                    cls._meta.original_attrs.get('unique_together')))
            cls._meta.original_attrs['unique_together'] = ut
Ejemplo n.º 2
0
 def __init__(self, name, unique_together):
     unique_together = normalize_together(unique_together)
     self.unique_together = set(tuple(cons) for cons in unique_together)
     super(AlterUniqueTogether, self).__init__(name)
Ejemplo n.º 3
0
    def from_model(cls, model, exclude_rels=False):
        """
        Feed me a model, get a ModelState representing it out.
        """
        # Deconstruct the fields
        fields = []
        for field in model._meta.local_fields:
            if getattr(field, "rel", None) and exclude_rels:
                continue
            if isinstance(field, OrderWrt):
                continue
            name, path, args, kwargs = field.deconstruct()
            field_class = import_string(path)
            try:
                fields.append((name, field_class(*args, **kwargs)))
            except TypeError as e:
                raise TypeError("Couldn't reconstruct field %s on %s.%s: %s" % (
                    name,
                    model._meta.app_label,
                    model._meta.object_name,
                    e,
                ))
        if not exclude_rels:
            for field in model._meta.local_many_to_many:
                name, path, args, kwargs = field.deconstruct()
                field_class = import_string(path)
                try:
                    fields.append((name, field_class(*args, **kwargs)))
                except TypeError as e:
                    raise TypeError("Couldn't reconstruct m2m field %s on %s: %s" % (
                        name,
                        model._meta.object_name,
                        e,
                    ))
        # Extract the options
        options = {}
        for name in DEFAULT_NAMES:
            # Ignore some special options
            if name in ["apps", "app_label"]:
                continue
            elif name in model._meta.original_attrs:
                if name == "unique_together":
                    ut = model._meta.original_attrs["unique_together"]
                    options[name] = set(normalize_together(ut))
                elif name == "index_together":
                    it = model._meta.original_attrs["index_together"]
                    options[name] = set(normalize_together(it))
                else:
                    options[name] = model._meta.original_attrs[name]
        # If we're ignoring relationships, remove all field-listing model
        # options (that option basically just means "make a stub model")
        if exclude_rels:
            for key in ["unique_together", "index_together", "order_with_respect_to"]:
                if key in options:
                    del options[key]

        def flatten_bases(model):
            bases = []
            for base in model.__bases__:
                if hasattr(base, "_meta") and base._meta.abstract:
                    bases.extend(flatten_bases(base))
                else:
                    bases.append(base)
            return bases

        # We can't rely on __mro__ directly because we only want to flatten
        # abstract models and not the whole tree. However by recursing on
        # __bases__ we may end up with duplicates and ordering issues, we
        # therefore discard any duplicates and reorder the bases according
        # to their index in the MRO.
        flattened_bases = sorted(set(flatten_bases(model)), key=lambda x: model.__mro__.index(x))

        # Make our record
        bases = tuple(
            (
                "%s.%s" % (base._meta.app_label, base._meta.model_name)
                if hasattr(base, "_meta") else
                base
            )
            for base in flattened_bases
        )
        # Ensure at least one base inherits from models.Model
        if not any((isinstance(base, six.string_types) or issubclass(base, models.Model)) for base in bases):
            bases = (models.Model,)
        return cls(
            model._meta.app_label,
            model._meta.object_name,
            fields,
            options,
            bases,
        )
Ejemplo n.º 4
0
    def from_model(cls, model, exclude_rels=False):
        """
        Feed me a model, get a ModelState representing it out.
        """
        # Deconstruct the fields
        fields = []
        for field in model._meta.local_fields:
            if getattr(field, "rel", None) and exclude_rels:
                continue
            if isinstance(field, OrderWrt):
                continue
            name, path, args, kwargs = field.deconstruct()
            field_class = import_string(path)
            try:
                fields.append((name, field_class(*args, **kwargs)))
            except TypeError as e:
                raise TypeError("Couldn't reconstruct field %s on %s.%s: %s" %
                                (
                                    name,
                                    model._meta.app_label,
                                    model._meta.object_name,
                                    e,
                                ))
        if not exclude_rels:
            for field in model._meta.local_many_to_many:
                name, path, args, kwargs = field.deconstruct()
                field_class = import_string(path)
                try:
                    fields.append((name, field_class(*args, **kwargs)))
                except TypeError as e:
                    raise TypeError(
                        "Couldn't reconstruct m2m field %s on %s: %s" % (
                            name,
                            model._meta.object_name,
                            e,
                        ))
        # Extract the options
        options = {}
        for name in DEFAULT_NAMES:
            # Ignore some special options
            if name in ["apps", "app_label"]:
                continue
            elif name in model._meta.original_attrs:
                if name == "unique_together":
                    ut = model._meta.original_attrs["unique_together"]
                    options[name] = set(normalize_together(ut))
                elif name == "index_together":
                    it = model._meta.original_attrs["index_together"]
                    options[name] = set(normalize_together(it))
                else:
                    options[name] = model._meta.original_attrs[name]
        # If we're ignoring relationships, remove all field-listing model
        # options (that option basically just means "make a stub model")
        if exclude_rels:
            for key in [
                    "unique_together", "index_together",
                    "order_with_respect_to"
            ]:
                if key in options:
                    del options[key]

        def flatten_bases(model):
            bases = []
            for base in model.__bases__:
                if hasattr(base, "_meta") and base._meta.abstract:
                    bases.extend(flatten_bases(base))
                else:
                    bases.append(base)
            return bases

        # We can't rely on __mro__ directly because we only want to flatten
        # abstract models and not the whole tree. However by recursing on
        # __bases__ we may end up with duplicates and ordering issues, we
        # therefore discard any duplicates and reorder the bases according
        # to their index in the MRO.
        flattened_bases = sorted(set(flatten_bases(model)),
                                 key=lambda x: model.__mro__.index(x))

        # Make our record
        bases = tuple(
            ("%s.%s" %
             (base._meta.app_label,
              base._meta.model_name) if hasattr(base, "_meta") else base)
            for base in flattened_bases)
        # Ensure at least one base inherits from models.Model
        if not any((isinstance(base, six.string_types)
                    or issubclass(base, models.Model)) for base in bases):
            bases = (models.Model, )
        return cls(
            model._meta.app_label,
            model._meta.object_name,
            fields,
            options,
            bases,
        )
Ejemplo n.º 5
0
 def __init__(self, name, index_together):
     index_together = normalize_together(index_together)
     self.index_together = set(tuple(cons) for cons in index_together)
     super(AlterIndexTogether, self).__init__(name)
Ejemplo n.º 6
0
 def __init__(self, name, index_together):
     self.name = name
     index_together = normalize_together(index_together)
     self.index_together = set(tuple(cons) for cons in index_together)
Ejemplo n.º 7
0
 def __init__(self, name, index_together):
     index_together = normalize_together(index_together)
     self.index_together = {tuple(cons) for cons in index_together}
     super().__init__(name)
Ejemplo n.º 8
0
 def __init__(self, name, index_together):
     index_together = normalize_together(index_together)
     self.index_together = {tuple(cons) for cons in index_together}
     super().__init__(name)
Ejemplo n.º 9
0
 def __init__(self, name, index_together):
     self.name = name
     index_together = normalize_together(index_together)
     # need None rather than an empty set to prevent infinite migrations
     # after removing unique_together from a model
     self.index_together = set(tuple(cons) for cons in index_together) or None
Ejemplo n.º 10
0
 def __init__(self, name, unique_together):
     unique_together = normalize_together(unique_together)
     self.unique_together = {tuple(cons) for cons in unique_together}
     super().__init__(name)
Ejemplo n.º 11
0
from __future__ import unicode_literals
Ejemplo n.º 12
0
from __future__ import unicode_literals
Ejemplo n.º 13
0
 def __init__(self, name, index_together):
     self.name = name
     index_together = normalize_together(index_together)
     # need None rather than an empty set to prevent infinite migrations
     # after removing unique_together from a model
     self.index_together = set(tuple(cons) for cons in index_together) or None
Ejemplo n.º 14
0
 def __init__(self, name, index_together):
     index_together = normalize_together(index_together)
     self.index_together = set(tuple(cons) for cons in index_together)
     super(AlterIndexTogether, self).__init__(name)
Ejemplo n.º 15
0
 def __init__(self, name, option_value):
     if option_value:
         option_value = set(normalize_together(option_value))
     setattr(self, self.option_name, option_value)
     super().__init__(name)
Ejemplo n.º 16
0
 def __init__(self, name, unique_together):
     unique_together = normalize_together(unique_together)
     self.unique_together = {tuple(cons) for cons in unique_together}
     super().__init__(name)
Ejemplo n.º 17
0
 def from_model(cls, model):
     """
     Feed me a model, get a ModelState representing it out.
     """
     # Deconstruct the fields
     fields = []
     for field in model._meta.local_fields:
         name, path, args, kwargs = field.deconstruct()
         field_class = import_string(path)
         try:
             fields.append((name, field_class(*args, **kwargs)))
         except TypeError as e:
             raise TypeError("Couldn't reconstruct field %s on %s.%s: %s" % (
                 name,
                 model._meta.app_label,
                 model._meta.object_name,
                 e,
             ))
     for field in model._meta.local_many_to_many:
         name, path, args, kwargs = field.deconstruct()
         field_class = import_string(path)
         try:
             fields.append((name, field_class(*args, **kwargs)))
         except TypeError as e:
             raise TypeError("Couldn't reconstruct m2m field %s on %s: %s" % (
                 name,
                 model._meta.object_name,
                 e,
             ))
     # Extract the options
     options = {}
     for name in DEFAULT_NAMES:
         # Ignore some special options
         if name in ["apps", "app_label"]:
             continue
         elif name in model._meta.original_attrs:
             if name == "unique_together":
                 ut = model._meta.original_attrs["unique_together"]
                 options[name] = set(normalize_together(ut))
             elif name == "index_together":
                 it = model._meta.original_attrs["index_together"]
                 options[name] = set(normalize_together(it))
             else:
                 options[name] = model._meta.original_attrs[name]
     # Make our record
     bases = tuple(
         (
             "%s.%s" % (base._meta.app_label, base._meta.model_name)
             if hasattr(base, "_meta") else
             base
         )
         for base in model.__bases__
         if (not hasattr(base, "_meta") or not base._meta.abstract)
     )
     # Ensure at least one base inherits from models.Model
     if not any((isinstance(base, six.string_types) or issubclass(base, models.Model)) for base in bases):
         bases = (models.Model, )
     return cls(
         model._meta.app_label,
         model._meta.object_name,
         fields,
         options,
         bases,
     )
Ejemplo n.º 18
0
 def __init__(self, name, unique_together):
     unique_together = normalize_together(unique_together)
     self.unique_together = set(tuple(cons) for cons in unique_together)
     super(AlterUniqueTogether, self).__init__(name)
Ejemplo n.º 19
0
    def from_model(cls, model, exclude_rels=False):
        """
        Feed me a model, get a ModelState representing it out.
        """
        # Deconstruct the fields
        fields = []
        for field in model._meta.local_fields:
            if getattr(field, "remote_field", None) and exclude_rels:
                continue
            if isinstance(field, OrderWrt):
                continue
            name = force_text(field.name, strings_only=True)
            try:
                fields.append((name, field.clone()))
            except TypeError as e:
                raise TypeError("Couldn't reconstruct field %s on %s: %s" % (
                    name,
                    model._meta.label,
                    e,
                ))
        if not exclude_rels:
            for field in model._meta.local_many_to_many:
                name = force_text(field.name, strings_only=True)
                try:
                    fields.append((name, field.clone()))
                except TypeError as e:
                    raise TypeError("Couldn't reconstruct m2m field %s on %s: %s" % (
                        name,
                        model._meta.object_name,
                        e,
                    ))
        # Extract the options
        options = {}
        for name in DEFAULT_NAMES:
            # Ignore some special options
            if name in ["apps", "app_label"]:
                continue
            elif name in model._meta.original_attrs:
                if name == "unique_together":
                    ut = model._meta.original_attrs["unique_together"]
                    options[name] = set(normalize_together(ut))
                elif name == "index_together":
                    it = model._meta.original_attrs["index_together"]
                    options[name] = set(normalize_together(it))
                else:
                    options[name] = model._meta.original_attrs[name]
        # Force-convert all options to text_type (#23226)
        options = cls.force_text_recursive(options)
        # If we're ignoring relationships, remove all field-listing model
        # options (that option basically just means "make a stub model")
        if exclude_rels:
            for key in ["unique_together", "index_together", "order_with_respect_to"]:
                if key in options:
                    del options[key]
        # Private fields are ignored, so remove options that refer to them.
        elif options.get('order_with_respect_to') in {field.name for field in model._meta.private_fields}:
            del options['order_with_respect_to']

        def flatten_bases(model):
            bases = []
            for base in model.__bases__:
                if hasattr(base, "_meta") and base._meta.abstract:
                    bases.extend(flatten_bases(base))
                else:
                    bases.append(base)
            return bases

        # We can't rely on __mro__ directly because we only want to flatten
        # abstract models and not the whole tree. However by recursing on
        # __bases__ we may end up with duplicates and ordering issues, we
        # therefore discard any duplicates and reorder the bases according
        # to their index in the MRO.
        flattened_bases = sorted(set(flatten_bases(model)), key=lambda x: model.__mro__.index(x))

        # Make our record
        bases = tuple(
            (
                base._meta.label_lower
                if hasattr(base, "_meta") else
                base
            )
            for base in flattened_bases
        )
        # Ensure at least one base inherits from models.Model
        if not any((isinstance(base, six.string_types) or issubclass(base, models.Model)) for base in bases):
            bases = (models.Model,)

        managers = []
        manager_names = set()
        default_manager_shim = None
        for manager in model._meta.managers:
            manager_name = force_text(manager.name)
            if manager_name in manager_names:
                # Skip overridden managers.
                continue
            elif manager.use_in_migrations:
                # Copy managers usable in migrations.
                new_manager = copy.copy(manager)
                new_manager._set_creation_counter()
            elif manager is model._base_manager or manager is model._default_manager:
                # Shim custom managers used as default and base managers.
                new_manager = models.Manager()
                new_manager.model = manager.model
                new_manager.name = manager.name
                if manager is model._default_manager:
                    default_manager_shim = new_manager
            else:
                continue
            manager_names.add(manager_name)
            managers.append((manager_name, new_manager))

        # Ignore a shimmed default manager called objects if it's the only one.
        if managers == [('objects', default_manager_shim)]:
            managers = []

        # Construct the new ModelState
        return cls(
            model._meta.app_label,
            model._meta.object_name,
            fields,
            options,
            bases,
            managers,
        )
Ejemplo n.º 20
0
 def __init__(self, name, unique_together):
     self.name = name
     unique_together = normalize_together(unique_together)
     self.unique_together = set(tuple(cons) for cons in unique_together)
Ejemplo n.º 21
0
    def from_model(cls, model, exclude_rels=False):
        """
        Feed me a model, get a ModelState representing it out.
        """
        # Deconstruct the fields
        fields = []
        for field in model._meta.local_fields:
            if getattr(field, "remote_field", None) and exclude_rels:
                continue
            if isinstance(field, OrderWrt):
                continue
            name, path, args, kwargs = field.deconstruct()
            field_class = import_string(path)
            try:
                fields.append((name, field_class(*args, **kwargs)))
            except TypeError as e:
                raise TypeError("Couldn't reconstruct field %s on %s.%s: %s" % (
                    name,
                    model._meta.app_label,
                    model._meta.object_name,
                    e,
                ))
        if not exclude_rels:
            for field in model._meta.local_many_to_many:
                name, path, args, kwargs = field.deconstruct()
                field_class = import_string(path)
                try:
                    fields.append((name, field_class(*args, **kwargs)))
                except TypeError as e:
                    raise TypeError("Couldn't reconstruct m2m field %s on %s: %s" % (
                        name,
                        model._meta.object_name,
                        e,
                    ))
        # Extract the options
        options = {}
        for name in DEFAULT_NAMES:
            # Ignore some special options
            if name in ["apps", "app_label"]:
                continue
            elif name in model._meta.original_attrs:
                if name == "unique_together":
                    ut = model._meta.original_attrs["unique_together"]
                    options[name] = set(normalize_together(ut))
                elif name == "index_together":
                    it = model._meta.original_attrs["index_together"]
                    options[name] = set(normalize_together(it))
                else:
                    options[name] = model._meta.original_attrs[name]
        # Force-convert all options to text_type (#23226)
        options = cls.force_text_recursive(options)
        # If we're ignoring relationships, remove all field-listing model
        # options (that option basically just means "make a stub model")
        if exclude_rels:
            for key in ["unique_together", "index_together", "order_with_respect_to"]:
                if key in options:
                    del options[key]

        def flatten_bases(model):
            bases = []
            for base in model.__bases__:
                if hasattr(base, "_meta") and base._meta.abstract:
                    bases.extend(flatten_bases(base))
                else:
                    bases.append(base)
            return bases

        # We can't rely on __mro__ directly because we only want to flatten
        # abstract models and not the whole tree. However by recursing on
        # __bases__ we may end up with duplicates and ordering issues, we
        # therefore discard any duplicates and reorder the bases according
        # to their index in the MRO.
        flattened_bases = sorted(set(flatten_bases(model)), key=lambda x: model.__mro__.index(x))

        # Make our record
        bases = tuple(
            (
                "%s.%s" % (base._meta.app_label, base._meta.model_name)
                if hasattr(base, "_meta") else
                base
            )
            for base in flattened_bases
        )
        # Ensure at least one base inherits from models.Model
        if not any((isinstance(base, six.string_types) or issubclass(base, models.Model)) for base in bases):
            bases = (models.Model,)

        # Constructs all managers on the model
        managers = {}

        def reconstruct_manager(mgr):
            as_manager, manager_path, qs_path, args, kwargs = mgr.deconstruct()
            if as_manager:
                qs_class = import_string(qs_path)
                instance = qs_class.as_manager()
            else:
                manager_class = import_string(manager_path)
                instance = manager_class(*args, **kwargs)
            # We rely on the ordering of the creation_counter of the original
            # instance
            managers[mgr.name] = (mgr.creation_counter, instance)

        if hasattr(model, "_default_manager"):
            default_manager_name = model._default_manager.name
            # Make sure the default manager is always the first
            if model._default_manager.use_in_migrations:
                reconstruct_manager(model._default_manager)
            else:
                # Force this manager to be the first and thus default
                managers[default_manager_name] = (0, models.Manager())
            # Sort all managers by their creation counter
            for _, manager, _ in sorted(model._meta.managers):
                if manager.name == "_base_manager" or not manager.use_in_migrations:
                    continue
                reconstruct_manager(manager)
            # Sort all managers by their creation counter but take only name and
            # instance for further processing
            managers = [
                (name, instance) for name, (cc, instance) in
                sorted(managers.items(), key=lambda v: v[1])
            ]
            if managers == [(default_manager_name, models.Manager())]:
                managers = []
        else:
            managers = []

        # Construct the new ModelState
        return cls(
            model._meta.app_label,
            model._meta.object_name,
            fields,
            options,
            bases,
            managers,
        )
Ejemplo n.º 22
0
 def __init__(self, name, option_value):
     if option_value:
         option_value = set(normalize_together(option_value))
     setattr(self, self.option_name, option_value)
     super().__init__(name)
Ejemplo n.º 23
0
 def __init__(self, name, unique_together):
     self.name = name
     unique_together = normalize_together(unique_together)
     self.unique_together = set(tuple(cons) for cons in unique_together)
Ejemplo n.º 24
0
    def from_model(cls, model, exclude_rels=False):
        """
        Feed me a model, get a ModelState representing it out.
        """
        # Deconstruct the fields
        fields = []
        for field in model._meta.local_fields:
            if getattr(field, "remote_field", None) and exclude_rels:
                continue
            if isinstance(field, OrderWrt):
                continue
            name, path, args, kwargs = field.deconstruct()
            field_class = import_string(path)
            try:
                fields.append((name, field_class(*args, **kwargs)))
            except TypeError as e:
                raise TypeError("Couldn't reconstruct field %s on %s: %s" % (
                    name,
                    model._meta.label,
                    e,
                ))
        if not exclude_rels:
            for field in model._meta.local_many_to_many:
                name, path, args, kwargs = field.deconstruct()
                field_class = import_string(path)
                try:
                    fields.append((name, field_class(*args, **kwargs)))
                except TypeError as e:
                    raise TypeError("Couldn't reconstruct m2m field %s on %s: %s" % (
                        name,
                        model._meta.object_name,
                        e,
                    ))
        # Extract the options
        options = {}
        for name in DEFAULT_NAMES:
            # Ignore some special options
            if name in ["apps", "app_label"]:
                continue
            elif name in model._meta.original_attrs:
                if name == "unique_together":
                    ut = model._meta.original_attrs["unique_together"]
                    options[name] = set(normalize_together(ut))
                elif name == "index_together":
                    it = model._meta.original_attrs["index_together"]
                    options[name] = set(normalize_together(it))
                else:
                    options[name] = model._meta.original_attrs[name]
        # Force-convert all options to text_type (#23226)
        options = cls.force_text_recursive(options)
        # If we're ignoring relationships, remove all field-listing model
        # options (that option basically just means "make a stub model")
        if exclude_rels:
            for key in ["unique_together", "index_together", "order_with_respect_to"]:
                if key in options:
                    del options[key]

        def flatten_bases(model):
            bases = []
            for base in model.__bases__:
                if hasattr(base, "_meta") and base._meta.abstract:
                    bases.extend(flatten_bases(base))
                else:
                    bases.append(base)
            return bases

        # We can't rely on __mro__ directly because we only want to flatten
        # abstract models and not the whole tree. However by recursing on
        # __bases__ we may end up with duplicates and ordering issues, we
        # therefore discard any duplicates and reorder the bases according
        # to their index in the MRO.
        flattened_bases = sorted(set(flatten_bases(model)), key=lambda x: model.__mro__.index(x))

        # Make our record
        bases = tuple(
            (
                base._meta.label_lower
                if hasattr(base, "_meta") else
                base
            )
            for base in flattened_bases
        )
        # Ensure at least one base inherits from models.Model
        if not any((isinstance(base, six.string_types) or issubclass(base, models.Model)) for base in bases):
            bases = (models.Model,)

        # Constructs all managers on the model
        managers_mapping = {}

        def reconstruct_manager(mgr):
            as_manager, manager_path, qs_path, args, kwargs = mgr.deconstruct()
            if as_manager:
                qs_class = import_string(qs_path)
                instance = qs_class.as_manager()
            else:
                manager_class = import_string(manager_path)
                instance = manager_class(*args, **kwargs)
            # We rely on the ordering of the creation_counter of the original
            # instance
            name = force_text(mgr.name)
            managers_mapping[name] = (mgr.creation_counter, instance)

        if hasattr(model, "_default_manager"):
            default_manager_name = force_text(model._default_manager.name)
            # Make sure the default manager is always the first
            if model._default_manager.use_in_migrations:
                reconstruct_manager(model._default_manager)
            else:
                # Force this manager to be the first and thus default
                managers_mapping[default_manager_name] = (0, models.Manager())
            # Sort all managers by their creation counter
            for _, manager, _ in sorted(model._meta.managers):
                if manager.name == "_base_manager" or not manager.use_in_migrations:
                    continue
                reconstruct_manager(manager)
            # Sort all managers by their creation counter but take only name and
            # instance for further processing
            managers = [
                (name, instance) for name, (cc, instance) in
                sorted(managers_mapping.items(), key=lambda v: v[1])
            ]
            if managers == [(default_manager_name, models.Manager())]:
                managers = []
        else:
            managers = []

        # Construct the new ModelState
        return cls(
            model._meta.app_label,
            model._meta.object_name,
            fields,
            options,
            bases,
            managers,
        )
Ejemplo n.º 25
0
 def __init__(self, name, index_together):
     self.name = name
     index_together = normalize_together(index_together)
     self.index_together = set(tuple(cons) for cons in index_together)
Ejemplo n.º 26
0
    def from_model(cls, model, exclude_rels=False):
        """Given a model, return a ModelState representing it."""
        # Deconstruct the fields
        fields = []
        for field in model._meta.local_fields:
            if getattr(field, "remote_field", None) and exclude_rels:
                continue
            if isinstance(field, OrderWrt):
                continue
            name = field.name
            try:
                fields.append((name, field.clone()))
            except TypeError as e:
                raise TypeError("Couldn't reconstruct field %s on %s: %s" % (
                    name,
                    model._meta.label,
                    e,
                ))
        if not exclude_rels:
            for field in model._meta.local_many_to_many:
                name = field.name
                try:
                    fields.append((name, field.clone()))
                except TypeError as e:
                    raise TypeError(
                        "Couldn't reconstruct m2m field %s on %s: %s" % (
                            name,
                            model._meta.object_name,
                            e,
                        ))
        # Extract the options
        options = {}
        for name in DEFAULT_NAMES:
            # Ignore some special options
            if name in ["apps", "app_label"]:
                continue
            elif name in model._meta.original_attrs:
                if name == "unique_together":
                    ut = model._meta.original_attrs["unique_together"]
                    options[name] = set(normalize_together(ut))
                elif name == "index_together":
                    it = model._meta.original_attrs["index_together"]
                    options[name] = set(normalize_together(it))
                elif name == "indexes":
                    indexes = [idx.clone() for idx in model._meta.indexes]
                    for index in indexes:
                        if not index.name:
                            index.set_name_with_model(model)
                    options['indexes'] = indexes
                else:
                    options[name] = model._meta.original_attrs[name]
        # If we're ignoring relationships, remove all field-listing model
        # options (that option basically just means "make a stub model")
        if exclude_rels:
            for key in [
                    "unique_together", "index_together",
                    "order_with_respect_to"
            ]:
                if key in options:
                    del options[key]
        # Private fields are ignored, so remove options that refer to them.
        elif options.get('order_with_respect_to') in {
                field.name
                for field in model._meta.private_fields
        }:
            del options['order_with_respect_to']

        def flatten_bases(model):
            bases = []
            for base in model.__bases__:
                if hasattr(base, "_meta") and base._meta.abstract:
                    bases.extend(flatten_bases(base))
                else:
                    bases.append(base)
            return bases

        # We can't rely on __mro__ directly because we only want to flatten
        # abstract models and not the whole tree. However by recursing on
        # __bases__ we may end up with duplicates and ordering issues, we
        # therefore discard any duplicates and reorder the bases according
        # to their index in the MRO.
        flattened_bases = sorted(set(flatten_bases(model)),
                                 key=lambda x: model.__mro__.index(x))

        # Make our record
        bases = tuple(
            (base._meta.label_lower if hasattr(base, "_meta") else base)
            for base in flattened_bases)
        # Ensure at least one base inherits from models.Model
        if not any((isinstance(base, str) or issubclass(base, models.Model))
                   for base in bases):
            bases = (models.Model, )

        managers = []
        manager_names = set()
        default_manager_shim = None
        for manager in model._meta.managers:
            if manager.name in manager_names:
                # Skip overridden managers.
                continue
            elif manager.use_in_migrations:
                # Copy managers usable in migrations.
                new_manager = copy.copy(manager)
                new_manager._set_creation_counter()
            elif manager is model._base_manager or manager is model._default_manager:
                # Shim custom managers used as default and base managers.
                new_manager = models.Manager()
                new_manager.model = manager.model
                new_manager.name = manager.name
                if manager is model._default_manager:
                    default_manager_shim = new_manager
            else:
                continue
            manager_names.add(manager.name)
            managers.append((manager.name, new_manager))

        # Ignore a shimmed default manager called objects if it's the only one.
        if managers == [('objects', default_manager_shim)]:
            managers = []

        # Construct the new ModelState
        return cls(
            model._meta.app_label,
            model._meta.object_name,
            fields,
            options,
            bases,
            managers,
        )
Ejemplo n.º 27
0
 def from_model(cls, model):
     """
     Feed me a model, get a ModelState representing it out.
     """
     # Deconstruct the fields
     fields = []
     for field in model._meta.local_fields:
         name, path, args, kwargs = field.deconstruct()
         field_class = import_string(path)
         try:
             fields.append((name, field_class(*args, **kwargs)))
         except TypeError as e:
             raise TypeError("Couldn't reconstruct field %s on %s.%s: %s" %
                             (
                                 name,
                                 model._meta.app_label,
                                 model._meta.object_name,
                                 e,
                             ))
     for field in model._meta.local_many_to_many:
         name, path, args, kwargs = field.deconstruct()
         field_class = import_string(path)
         try:
             fields.append((name, field_class(*args, **kwargs)))
         except TypeError as e:
             raise TypeError("Couldn't reconstruct m2m field %s on %s: %s" %
                             (
                                 name,
                                 model._meta.object_name,
                                 e,
                             ))
     # Extract the options
     options = {}
     for name in DEFAULT_NAMES:
         # Ignore some special options
         if name in ["apps", "app_label"]:
             continue
         elif name in model._meta.original_attrs:
             if name == "unique_together":
                 ut = model._meta.original_attrs["unique_together"]
                 options[name] = set(normalize_together(ut))
             elif name == "index_together":
                 it = model._meta.original_attrs["index_together"]
                 options[name] = set(normalize_together(it))
             else:
                 options[name] = model._meta.original_attrs[name]
     # Make our record
     bases = tuple(
         ("%s.%s" %
          (base._meta.app_label,
           base._meta.model_name) if hasattr(base, "_meta") else base)
         for base in model.__bases__
         if (not hasattr(base, "_meta") or not base._meta.abstract))
     # Ensure at least one base inherits from models.Model
     if not any((isinstance(base, six.string_types)
                 or issubclass(base, models.Model)) for base in bases):
         bases = (models.Model, )
     return cls(
         model._meta.app_label,
         model._meta.object_name,
         fields,
         options,
         bases,
     )