Ejemplo n.º 1
0
def field_dependencies(field, checked_models=None):
    checked_models = checked_models or set()
    depends = set()
    arg_defs, kwarg_defs = modelsinspector.matching_details(field)
    for attrname, options in arg_defs + kwarg_defs.values():
        if options.get("ignore_if_auto_through", False) and auto_through(field):
            continue
        if options.get("is_value", False):
            value = attrname
        elif attrname == 'rel.through' and hasattr(getattr(field, 'rel', None), 'through_model'):
            # Hack for django 1.1 and below, where the through model is stored
            # in rel.through_model while rel.through stores only the model name.
            value = field.rel.through_model
        else:
            try:
                value = get_attribute(field, attrname)
            except AttributeError:
                if options.get("ignore_missing", False):
                    continue
                raise
        if isinstance(value, Model):
            value = value.__class__
        if not isinstance(value, ModelBase):
            continue
        if getattr(value._meta, "proxy", False):
            value = value._meta.proxy_for_model
        if value in checked_models:
            continue
        checked_models.add(value)
        depends.add(value)
        depends.update(model_dependencies(value, checked_models))

    return depends
Ejemplo n.º 2
0
def field_dependencies(field, checked_models=None):
    checked_models = checked_models or set()
    depends = set()
    arg_defs, kwarg_defs = modelsinspector.matching_details(field)
    for attrname, options in arg_defs + kwarg_defs.values():
        if options.get("ignore_if_auto_through",
                       False) and auto_through(field):
            continue
        if options.get("is_value", False):
            value = attrname
        elif attrname == 'rel.through' and hasattr(getattr(field, 'rel', None),
                                                   'through_model'):
            # Hack for django 1.1 and below, where the through model is stored
            # in rel.through_model while rel.through stores only the model name.
            value = field.rel.through_model
        else:
            try:
                value = get_attribute(field, attrname)
            except AttributeError:
                if options.get("ignore_missing", False):
                    continue
                raise
        if isinstance(value, Model):
            value = value.__class__
        if not isinstance(value, ModelBase):
            continue
        if getattr(value._meta, "proxy", False):
            value = value._meta.proxy_for_model
        if value in checked_models:
            continue
        checked_models.add(value)
        depends.add(value)
        depends.update(model_dependencies(value, checked_models))

    return depends
Ejemplo n.º 3
0
def get_value(field, descriptor):
    """
    Gets an attribute value from a Field instance and formats it.
    """
    attrname, options = descriptor
    # If the options say it's not a attribute name but a real value, use that.
    if options.get('is_value', False):
        value = attrname
    else:
        try:
            value = get_attribute(field, attrname)
        except AttributeError:
            if options.get("ignore_missing", False):
                raise IsDefault
            else:
                raise

    # Lazy-eval functions get eval'd.
    if isinstance(value, Promise):
        value = text_type(value)
    # If the value is the same as the default, omit it for clarity
    if "default" in options and value == options['default']:
        raise IsDefault
    # If there's an ignore_if, use it
    if "ignore_if" in options:
        if get_attribute(field, options['ignore_if']):
            raise IsDefault
    # If there's an ignore_if_auto_through which is True, use it
    if options.get("ignore_if_auto_through", False):
        if auto_through(field):
            raise IsDefault
    # Some default values need to be gotten from an attribute too.
    if "default_attr" in options:
        default_value = get_attribute(field, options['default_attr'])
        if value == default_value:
            raise IsDefault
    # Some are made from a formatting string and several attrs (e.g. db_table)
    if "default_attr_concat" in options:
        format, attrs = options['default_attr_concat'][0], options[
            'default_attr_concat'][1:]
        default_value = format % tuple(
            map(lambda x: get_attribute(field, x), attrs))
        if value == default_value:
            raise IsDefault
    # Clean and return the value
    return value_clean(value, options)
Ejemplo n.º 4
0
def get_value(field, descriptor):
    """
    Gets an attribute value from a Field instance and formats it.
    """
    attrname, options = descriptor
    # If the options say it's not a attribute name but a real value, use that.
    if options.get('is_value', False):
        value = attrname
    else:
        try:
            value = get_attribute(field, attrname)
        except AttributeError:
            if options.get("ignore_missing", False):
                raise IsDefault
            else:
                raise
            
    # Lazy-eval functions get eval'd.
    if isinstance(value, Promise):
        value = unicode(value)
    # If the value is the same as the default, omit it for clarity
    if "default" in options and value == options['default']:
        raise IsDefault
    # If there's an ignore_if, use it
    if "ignore_if" in options:
        if get_attribute(field, options['ignore_if']):
            raise IsDefault
    # If there's an ignore_if_auto_through which is True, use it
    if options.get("ignore_if_auto_through", False):
        if auto_through(field):
            raise IsDefault
    # Some default values need to be gotten from an attribute too.
    if "default_attr" in options:
        default_value = get_attribute(field, options['default_attr'])
        if value == default_value:
            raise IsDefault
    # Some are made from a formatting string and several attrs (e.g. db_table)
    if "default_attr_concat" in options:
        format, attrs = options['default_attr_concat'][0], options['default_attr_concat'][1:]
        default_value = format % tuple(map(lambda x: get_attribute(field, x), attrs))
        if value == default_value:
            raise IsDefault
    # Clean and return the value
    return value_clean(value, options)
Ejemplo n.º 5
0
def get_value(field, descriptor):
    """
    Gets an attribute value from a Field instance and formats it.
    """
    attrname, options = descriptor
    # If the options say it's not a attribute name but a real value, use that.
    if options.get('is_value', False):
        value = attrname
    else:
        try:
            value = get_attribute(field, attrname)
        except AttributeError:
            if options.get("ignore_missing", False):
                raise IsDefault
            else:
                raise
    # Lazy-eval functions get eval'd.
    if isinstance(value, Promise):
        value = unicode(value)
    # If the value is the same as the default, omit it for clarity
    if "default" in options and value == options['default']:
        raise IsDefault
    # If there's an ignore_if, use it
    if "ignore_if" in options:
        if get_attribute(field, options['ignore_if']):
            raise IsDefault
    # If there's an ignore_if_auto_through which is True, use it
    if options.get("ignore_if_auto_through", False):
        if auto_through(field):
            raise IsDefault
    # Some default values need to be gotten from an attribute too.
    if "default_attr" in options:
        default_value = get_attribute(field, options['default_attr'])
        if value == default_value:
            raise IsDefault
    # Some are made from a formatting string and several attrs (e.g. db_table)
    if "default_attr_concat" in options:
        format, attrs = options['default_attr_concat'][0], options['default_attr_concat'][1:]
        default_value = format % tuple(map(lambda x: get_attribute(field, x), attrs))
        if value == default_value:
            raise IsDefault
    # Callables get called.
    if callable(value) and not isinstance(value, ModelBase):
        # Datetime.datetime.now is special, as we can access it from the eval
        # context (and because it changes all the time; people will file bugs otherwise).
        if value == datetime.datetime.now:
            return "datetime.datetime.now"
        if value == datetime.datetime.utcnow:
            return "datetime.datetime.utcnow"
        if value == datetime.date.today:
            return "datetime.date.today"
        # All other callables get called.
        value = value()
    # Models get their own special repr()
    if isinstance(value, ModelBase):
        # If it's a proxy model, follow it back to its non-proxy parent
        if getattr(value._meta, "proxy", False):
            value = value._meta.proxy_for_model
        return "orm['%s.%s']" % (value._meta.app_label, value._meta.object_name)
    # As do model instances
    if isinstance(value, Model):
        if options.get("ignore_dynamics", False):
            raise IsDefault
        return "orm['%s.%s'].objects.get(pk=%r)" % (value.__class__._meta.app_label, value.__class__._meta.object_name, value.pk)
    # Make sure Decimal is converted down into a string
    if isinstance(value, decimal.Decimal):
        value = str(value)
    # datetime_safe has an improper repr value
    if isinstance(value, datetime_safe.datetime):
        value = datetime.datetime(*value.utctimetuple()[:7])
    if isinstance(value, datetime_safe.date):
        value = datetime.date(*value.timetuple()[:3])
    # Now, apply the converter func if there is one
    if "converter" in options:
        value = options['converter'](value)
    # Return the final value
    return repr(value)
Ejemplo n.º 6
0
    def get_changes(self):
        """
        Returns the difference between the old and new sets of models as a 5-tuple:
        added_models, deleted_models, added_fields, deleted_fields, changed_fields
        """

        deleted_models = set()

        # See if anything's vanished
        for key in self.old_defs:
            if key not in self.new_defs:
                # We shouldn't delete it if it was managed=False
                old_fields, old_meta, old_m2ms = self.split_model_def(
                    self.old_orm[key], self.old_defs[key])
                if old_meta.get("managed", "True") != "False":
                    # Alright, delete it.
                    yield ("DeleteModel", {
                        "model": self.old_orm[key],
                        "model_def": old_fields,
                    })
                    # Also make sure we delete any M2Ms it had.
                    for fieldname in old_m2ms:
                        # Only delete its stuff if it wasn't a through=.
                        field = self.old_orm[key + ":" + fieldname]
                        if auto_through(field):
                            yield ("DeleteM2M", {
                                "model": self.old_orm[key],
                                "field": field
                            })
                    # And any unique constraints it had
                    unique_together = eval(
                        old_meta.get("unique_together", "[]"))
                    if unique_together:
                        # If it's only a single tuple, make it into the longer one
                        if isinstance(unique_together[0], basestring):
                            unique_together = [unique_together]
                        # For each combination, make an action for it
                        for fields in unique_together:
                            yield ("DeleteUnique", {
                                "model":
                                self.old_orm[key],
                                "fields": [
                                    self.old_orm[key]._meta.get_field_by_name(
                                        x)[0] for x in fields
                                ],
                            })
                # We always add it in here so we ignore it later
                deleted_models.add(key)

        # Or appeared
        for key in self.new_defs:
            if key not in self.old_defs:
                # We shouldn't add it if it's managed=False
                new_fields, new_meta, new_m2ms = self.split_model_def(
                    self.current_model_from_key(key), self.new_defs[key])
                if new_meta.get("managed", "True") != "False":
                    yield ("AddModel", {
                        "model": self.current_model_from_key(key),
                        "model_def": new_fields,
                    })
                    # Also make sure we add any M2Ms it has.
                    for fieldname in new_m2ms:
                        # Only create its stuff if it wasn't a through=.
                        field = self.current_field_from_key(key, fieldname)
                        if auto_through(field):
                            yield ("AddM2M", {
                                "model": self.current_model_from_key(key),
                                "field": field
                            })
                    # And any unique constraints it has
                    unique_together = eval(
                        new_meta.get("unique_together", "[]"))
                    if unique_together:
                        # If it's only a single tuple, make it into the longer one
                        if isinstance(unique_together[0], basestring):
                            unique_together = [unique_together]
                        # For each combination, make an action for it
                        for fields in unique_together:
                            yield ("AddUnique", {
                                "model":
                                self.current_model_from_key(key),
                                "fields": [
                                    self.current_model_from_key(
                                        key)._meta.get_field_by_name(x)[0]
                                    for x in fields
                                ],
                            })

        # Now, for every model that's stayed the same, check its fields.
        for key in self.old_defs:
            if key not in deleted_models:

                old_fields, old_meta, old_m2ms = self.split_model_def(
                    self.old_orm[key], self.old_defs[key])
                new_fields, new_meta, new_m2ms = self.split_model_def(
                    self.current_model_from_key(key), self.new_defs[key])

                # Find fields that have vanished.
                for fieldname in old_fields:
                    if fieldname not in new_fields:
                        # Don't do it for any fields we're ignoring
                        field = self.old_orm[key + ":" + fieldname]
                        field_allowed = True
                        for field_type in self.IGNORED_FIELD_TYPES:
                            if isinstance(field, field_type):
                                field_allowed = False
                        if field_allowed:
                            # Looks alright.
                            yield ("DeleteField", {
                                "model": self.old_orm[key],
                                "field": field,
                                "field_def": old_fields[fieldname],
                            })

                # And ones that have appeared
                for fieldname in new_fields:
                    if fieldname not in old_fields:
                        # Don't do it for any fields we're ignoring
                        field = self.current_field_from_key(key, fieldname)
                        field_allowed = True
                        for field_type in self.IGNORED_FIELD_TYPES:
                            if isinstance(field, field_type):
                                field_allowed = False
                        if field_allowed:
                            # Looks alright.
                            yield ("AddField", {
                                "model": self.current_model_from_key(key),
                                "field": field,
                                "field_def": new_fields[fieldname],
                            })

                # Find M2Ms that have vanished
                for fieldname in old_m2ms:
                    if fieldname not in new_m2ms:
                        # Only delete its stuff if it wasn't a through=.
                        field = self.old_orm[key + ":" + fieldname]
                        if auto_through(field):
                            yield ("DeleteM2M", {
                                "model": self.old_orm[key],
                                "field": field
                            })

                # Find M2Ms that have appeared
                for fieldname in new_m2ms:
                    if fieldname not in old_m2ms:
                        # Only create its stuff if it wasn't a through=.
                        field = self.current_field_from_key(key, fieldname)
                        if auto_through(field):
                            yield ("AddM2M", {
                                "model": self.current_model_from_key(key),
                                "field": field
                            })

                # For the ones that exist in both models, see if they were changed
                for fieldname in set(old_fields).intersection(set(new_fields)):
                    # Non-index changes
                    if self.different_attributes(
                            remove_useless_attributes(old_fields[fieldname],
                                                      True, True),
                            remove_useless_attributes(new_fields[fieldname],
                                                      True, True)):
                        yield ("ChangeField", {
                            "model":
                            self.current_model_from_key(key),
                            "old_field":
                            self.old_orm[key + ":" + fieldname],
                            "new_field":
                            self.current_field_from_key(key, fieldname),
                            "old_def":
                            old_fields[fieldname],
                            "new_def":
                            new_fields[fieldname],
                        })
                    # Index changes
                    old_field = self.old_orm[key + ":" + fieldname]
                    new_field = self.current_field_from_key(key, fieldname)
                    if not old_field.db_index and new_field.db_index:
                        # They've added an index.
                        yield ("AddIndex", {
                            "model": self.current_model_from_key(key),
                            "fields": [new_field],
                        })
                    if old_field.db_index and not new_field.db_index:
                        # They've removed an index.
                        yield ("DeleteIndex", {
                            "model": self.old_orm[key],
                            "fields": [old_field],
                        })
                    # See if their uniques have changed
                    if old_field.unique != new_field.unique:
                        # Make sure we look at the one explicitly given to see what happened
                        if new_field.unique:
                            yield ("AddUnique", {
                                "model": self.current_model_from_key(key),
                                "fields": [new_field],
                            })
                        else:
                            yield ("DeleteUnique", {
                                "model": self.old_orm[key],
                                "fields": [old_field],
                            })

                # See if there's any M2Ms that have changed.
                for fieldname in set(old_m2ms).intersection(set(new_m2ms)):
                    old_field = self.old_orm[key + ":" + fieldname]
                    new_field = self.current_field_from_key(key, fieldname)
                    # Have they _added_ a through= ?
                    if auto_through(old_field) and not auto_through(new_field):
                        yield ("DeleteM2M", {
                            "model": self.old_orm[key],
                            "field": old_field
                        })
                    # Have they _removed_ a through= ?
                    if not auto_through(old_field) and auto_through(new_field):
                        yield ("AddM2M", {
                            "model": self.current_model_from_key(key),
                            "field": new_field
                        })

                ## See if the unique_togethers have changed
                # First, normalise them into lists of sets.
                old_unique_together = eval(
                    old_meta.get("unique_together", "[]"))
                new_unique_together = eval(
                    new_meta.get("unique_together", "[]"))
                if old_unique_together and isinstance(old_unique_together[0],
                                                      basestring):
                    old_unique_together = [old_unique_together]
                if new_unique_together and isinstance(new_unique_together[0],
                                                      basestring):
                    new_unique_together = [new_unique_together]
                old_unique_together = map(set, old_unique_together)
                new_unique_together = map(set, new_unique_together)
                # See if any appeared or disappeared
                for item in old_unique_together:
                    if item not in new_unique_together:
                        yield ("DeleteUnique", {
                            "model":
                            self.old_orm[key],
                            "fields":
                            [self.old_orm[key + ":" + x] for x in item],
                        })
                for item in new_unique_together:
                    if item not in old_unique_together:
                        yield ("AddUnique", {
                            "model":
                            self.current_model_from_key(key),
                            "fields": [
                                self.current_field_from_key(key, x)
                                for x in item
                            ],
                        })
Ejemplo n.º 7
0
 def get_changes(self):
     """
     Returns the difference between the old and new sets of models as a 5-tuple:
     added_models, deleted_models, added_fields, deleted_fields, changed_fields
     """
     
     deleted_models = set()
     
     # See if anything's vanished
     for key in self.old_defs:
         if key not in self.new_defs:
             # We shouldn't delete it if it was managed=False
             old_fields, old_meta, old_m2ms = self.split_model_def(self.old_orm[key], self.old_defs[key])
             if old_meta.get("managed", "True") != "False":
                 # Alright, delete it.
                 yield ("DeleteModel", {
                     "model": self.old_orm[key], 
                     "model_def": old_fields,
                 })
                 # Also make sure we delete any M2Ms it had.
                 for fieldname in old_m2ms:
                     # Only delete its stuff if it wasn't a through=.
                     field = self.old_orm[key + ":" + fieldname]
                     if auto_through(field):
                         yield ("DeleteM2M", {"model": self.old_orm[key], "field": field})
                 # And any index/uniqueness constraints it had
                 for attr, operation in (("unique_together", "DeleteUnique"), ("index_together", "DeleteIndex")):
                     together = eval(old_meta.get(attr, "[]"))
                     if together:
                         # If it's only a single tuple, make it into the longer one
                         if isinstance(together[0], string_types):
                             together = [together]
                         # For each combination, make an action for it
                         for fields in together:
                             yield (operation, {
                                 "model": self.old_orm[key],
                                 "fields": [self.old_orm[key]._meta.get_field_by_name(x)[0] for x in fields],
                             })
             # We always add it in here so we ignore it later
             deleted_models.add(key)
     
     # Or appeared
     for key in self.new_defs:
         if key not in self.old_defs:
             # We shouldn't add it if it's managed=False
             new_fields, new_meta, new_m2ms = self.split_model_def(self.current_model_from_key(key), self.new_defs[key])
             if new_meta.get("managed", "True") != "False":
                 yield ("AddModel", {
                     "model": self.current_model_from_key(key), 
                     "model_def": new_fields,
                 })
                 # Also make sure we add any M2Ms it has.
                 for fieldname in new_m2ms:
                     # Only create its stuff if it wasn't a through=.
                     field = self.current_field_from_key(key, fieldname)
                     if auto_through(field):
                         yield ("AddM2M", {"model": self.current_model_from_key(key), "field": field})
                 # And any index/uniqueness constraints it has
                 for attr, operation in (("unique_together", "AddUnique"), ("index_together", "AddIndex")):
                     together = eval(new_meta.get(attr, "[]"))
                     if together:
                         # If it's only a single tuple, make it into the longer one
                         if isinstance(together[0], string_types):
                             together = [together]
                         # For each combination, make an action for it
                         for fields in together:
                             yield (operation, {
                                 "model": self.current_model_from_key(key),
                                 "fields": [self.current_model_from_key(key)._meta.get_field_by_name(x)[0] for x in fields],
                             })
     
     # Now, for every model that's stayed the same, check its fields.
     for key in self.old_defs:
         if key not in deleted_models:
             
             old_fields, old_meta, old_m2ms = self.split_model_def(self.old_orm[key], self.old_defs[key])
             new_fields, new_meta, new_m2ms = self.split_model_def(self.current_model_from_key(key), self.new_defs[key])
             
             # Do nothing for models which are now not managed.
             if new_meta.get("managed", "True") == "False":
                 continue
             
             # Find fields that have vanished.
             for fieldname in old_fields:
                 if fieldname not in new_fields:
                     # Don't do it for any fields we're ignoring
                     field = self.old_orm[key + ":" + fieldname]
                     field_allowed = True
                     for field_type in self.IGNORED_FIELD_TYPES:
                         if isinstance(field, field_type):
                             field_allowed = False
                     if field_allowed:
                         # Looks alright.
                         yield ("DeleteField", {
                             "model": self.old_orm[key],
                             "field": field,
                             "field_def": old_fields[fieldname],
                         })
             
             # And ones that have appeared
             for fieldname in new_fields:
                 if fieldname not in old_fields:
                     # Don't do it for any fields we're ignoring
                     field = self.current_field_from_key(key, fieldname)
                     field_allowed = True
                     for field_type in self.IGNORED_FIELD_TYPES:
                         if isinstance(field, field_type):
                             field_allowed = False
                     if field_allowed:
                         # Looks alright.
                         yield ("AddField", {
                             "model": self.current_model_from_key(key),
                             "field": field,
                             "field_def": new_fields[fieldname],
                         })
             
             # Find M2Ms that have vanished
             for fieldname in old_m2ms:
                 if fieldname not in new_m2ms:
                     # Only delete its stuff if it wasn't a through=.
                     field = self.old_orm[key + ":" + fieldname]
                     if auto_through(field):
                         yield ("DeleteM2M", {"model": self.old_orm[key], "field": field})
             
             # Find M2Ms that have appeared
             for fieldname in new_m2ms:
                 if fieldname not in old_m2ms:
                     # Only create its stuff if it wasn't a through=.
                     field = self.current_field_from_key(key, fieldname)
                     if auto_through(field):
                         yield ("AddM2M", {"model": self.current_model_from_key(key), "field": field})
             
             # For the ones that exist in both models, see if they were changed
             for fieldname in set(old_fields).intersection(set(new_fields)):
                 # Non-index changes
                 if self.different_attributes(
                  remove_useless_attributes(old_fields[fieldname], True, True),
                  remove_useless_attributes(new_fields[fieldname], True, True)):
                     yield ("ChangeField", {
                         "model": self.current_model_from_key(key),
                         "old_field": self.old_orm[key + ":" + fieldname],
                         "new_field": self.current_field_from_key(key, fieldname),
                         "old_def": old_fields[fieldname],
                         "new_def": new_fields[fieldname],
                     })
                 # Index changes
                 old_field = self.old_orm[key + ":" + fieldname]
                 new_field = self.current_field_from_key(key, fieldname)
                 if not old_field.db_index and new_field.db_index:
                     # They've added an index.
                     yield ("AddIndex", {
                         "model": self.current_model_from_key(key),
                         "fields": [new_field],
                     })
                 if old_field.db_index and not new_field.db_index:
                     # They've removed an index.
                     yield ("DeleteIndex", {
                         "model": self.old_orm[key],
                         "fields": [old_field],
                     })
                 # See if their uniques have changed
                 if old_field.unique != new_field.unique:
                     # Make sure we look at the one explicitly given to see what happened
                     if new_field.unique:
                         yield ("AddUnique", {
                             "model": self.current_model_from_key(key),
                             "fields": [new_field],
                         })
                     else:
                         yield ("DeleteUnique", {
                             "model": self.old_orm[key],
                             "fields": [old_field],
                         })
             
             # See if there's any M2Ms that have changed.
             for fieldname in set(old_m2ms).intersection(set(new_m2ms)):
                 old_field = self.old_orm[key + ":" + fieldname]
                 new_field = self.current_field_from_key(key, fieldname)
                 # Have they _added_ a through= ?
                 if auto_through(old_field) and not auto_through(new_field):
                     yield ("DeleteM2M", {"model": self.old_orm[key], "field": old_field})
                 # Have they _removed_ a through= ?
                 if not auto_through(old_field) and auto_through(new_field):
                     yield ("AddM2M", {"model": self.current_model_from_key(key), "field": new_field})
             
             ## See if the {index,unique}_togethers have changed
             for attr, add_operation, del_operation in (("unique_together", "AddUnique", "DeleteUnique"), ("index_together", "AddIndex", "DeleteIndex")):
                 # First, normalise them into lists of sets.
                 old_together = eval(old_meta.get(attr, "[]"))
                 new_together = eval(new_meta.get(attr, "[]"))
                 if old_together and isinstance(old_together[0], string_types):
                     old_together = [old_together]
                 if new_together and isinstance(new_together[0], string_types):
                     new_together = [new_together]
                 old_together = frozenset(tuple(o) for o in old_together)
                 new_together = frozenset(tuple(n) for n in new_together)
                 # See if any appeared or disappeared
                 disappeared = old_together.difference(new_together)
                 appeared = new_together.difference(old_together)
                 for item in disappeared:
                     yield (del_operation, {
                         "model": self.old_orm[key],
                         "fields": [self.old_orm[key + ":" + x] for x in item],
                     })
                 for item in appeared:
                     yield (add_operation, {
                         "model": self.current_model_from_key(key),
                         "fields": [self.current_field_from_key(key, x) for x in item],
                     })
Ejemplo n.º 8
0
def get_value(field, descriptor):
    """
    Gets an attribute value from a Field instance and formats it.
    """
    attrname, options = descriptor
    # If the options say it's not a attribute name but a real value, use that.
    if options.get('is_value', False):
        value = attrname
    else:
        value = get_attribute(field, attrname)
    # Lazy-eval functions get eval'd.
    if isinstance(value, Promise):
        value = unicode(value)
    # If the value is the same as the default, omit it for clarity
    if "default" in options and value == options['default']:
        raise IsDefault
    # If there's an ignore_if, use it
    if "ignore_if" in options:
        if get_attribute(field, options['ignore_if']):
            raise IsDefault
    # If there's an ignore_if_auto_through which is True, use it
    if options.get("ignore_if_auto_through", False):
        if auto_through(field):
            raise IsDefault
    # Some default values need to be gotten from an attribute too.
    if "default_attr" in options:
        default_value = get_attribute(field, options['default_attr'])
        if value == default_value:
            raise IsDefault
    # Some are made from a formatting string and several attrs (e.g. db_table)
    if "default_attr_concat" in options:
        format, attrs = options['default_attr_concat'][0], options['default_attr_concat'][1:]
        default_value = format % tuple(map(lambda x: get_attribute(field, x), attrs))
        if value == default_value:
            raise IsDefault
    # Callables get called.
    if callable(value) and not isinstance(value, ModelBase):
        # Datetime.datetime.now is special, as we can access it from the eval
        # context (and because it changes all the time; people will file bugs otherwise).
        if value == datetime.datetime.now:
            return "datetime.datetime.now"
        if value == datetime.datetime.utcnow:
            return "datetime.datetime.utcnow"
        if value == datetime.date.today:
            return "datetime.date.today"
        # All other callables get called.
        value = value()
    # Models get their own special repr()
    if isinstance(value, ModelBase):
        # If it's a proxy model, follow it back to its non-proxy parent
        if getattr(value._meta, "proxy", False):
            value = value._meta.proxy_for_model
        return "orm['%s.%s']" % (value._meta.app_label, value._meta.object_name)
    # As do model instances
    if isinstance(value, Model):
        return "orm['%s.%s'].objects.get(pk=%r)" % (value.__class__._meta.app_label, value.__class__._meta.object_name, value.pk)
    # Make sure Decimal is converted down into a string
    if isinstance(value, decimal.Decimal):
        value = str(value)
    # Now, apply the converter func if there is one
    if "converter" in options:
        value = options['converter'](value)
    # Return the final value
    return repr(value)
Ejemplo n.º 9
0
    def get_changes(self):
        """
        Returns the difference between the old and new sets of models as a 5-tuple:
        added_models, deleted_models, added_fields, deleted_fields, changed_fields
        """

        deleted_models = set()

        # See if anything's vanished
        for key in self.old_defs:
            if key not in self.new_defs:
                # We shouldn't delete it if it was managed=False
                if self.old_defs[key].get("Meta", {}).get("managed", "True") != "False":
                    # Alright, delete it.
                    yield (
                        "DeleteModel",
                        {
                            "model": self.old_orm[key],
                            "model_def": self.split_model_def(self.old_orm[key], self.old_defs[key])[0],
                        },
                    )
                # We always add it in here so we ignore it later
                deleted_models.add(key)

        # Or appeared
        for key in self.new_defs:
            if key not in self.old_defs:
                # We shouldn't add it if it's managed=False
                if self.new_defs[key].get("Meta", {}).get("managed", "True") != "False":
                    yield (
                        "AddModel",
                        {
                            "model": self.current_model_from_key(key),
                            "model_def": self.split_model_def(self.current_model_from_key(key), self.new_defs[key])[0],
                        },
                    )

        # Now, for every model that's stayed the same, check its fields.
        for key in self.old_defs:
            if key not in deleted_models:

                still_there = set()

                old_fields, old_meta, old_m2ms = self.split_model_def(self.old_orm[key], self.old_defs[key])
                new_fields, new_meta, new_m2ms = self.split_model_def(
                    self.current_model_from_key(key), self.new_defs[key]
                )

                # Find fields that have vanished.
                for fieldname in old_fields:
                    if fieldname not in new_fields:
                        yield (
                            "DeleteField",
                            {
                                "model": self.old_orm[key],
                                "field": self.old_orm[key + ":" + fieldname],
                                "field_def": old_fields[fieldname],
                            },
                        )

                # And ones that have appeared
                for fieldname in new_fields:
                    if fieldname not in old_fields:
                        yield (
                            "AddField",
                            {
                                "model": self.current_model_from_key(key),
                                "field": self.current_field_from_key(key, fieldname),
                                "field_def": new_fields[fieldname],
                            },
                        )

                # Find M2Ms that have vanished
                for fieldname in old_m2ms:
                    if fieldname not in new_m2ms:
                        # Only delete its stuff if it wasn't a through=.
                        field = self.old_orm[key + ":" + fieldname]
                        if auto_through(field):
                            yield ("DeleteM2M", {"model": self.old_orm[key], "field": field})

                # Find M2Ms that have appeared
                for fieldname in new_m2ms:
                    if fieldname not in old_m2ms:
                        # Only create its stuff if it wasn't a through=.
                        field = self.current_field_from_key(key, fieldname)
                        if auto_through(field):
                            yield ("AddM2M", {"model": self.current_model_from_key(key), "field": field})

                # For the ones that exist in both models, see if they were changed
                for fieldname in set(old_fields).intersection(set(new_fields)):
                    if self.different_attributes(
                        remove_useless_attributes(old_fields[fieldname], True),
                        remove_useless_attributes(new_fields[fieldname], True),
                    ):
                        yield (
                            "ChangeField",
                            {
                                "model": self.current_model_from_key(key),
                                "old_field": self.old_orm[key + ":" + fieldname],
                                "new_field": self.current_field_from_key(key, fieldname),
                                "old_def": old_fields[fieldname],
                                "new_def": new_fields[fieldname],
                            },
                        )
                    # See if their uniques have changed
                    old_field = self.old_orm[key + ":" + fieldname]
                    new_field = self.current_field_from_key(key, fieldname)
                    if old_field.unique != new_field.unique:
                        # Make sure we look at the one explicitly given to see what happened
                        if new_field.unique:
                            yield (
                                "AddUnique",
                                {
                                    "model": self.current_model_from_key(key),
                                    "fields": [self.current_field_from_key(key, fieldname)],
                                },
                            )
                        else:
                            yield (
                                "DeleteUnique",
                                {"model": self.old_orm[key], "fields": [self.old_orm[key + ":" + fieldname]]},
                            )

                # See if there's any M2Ms that have changed.
                for fieldname in set(old_m2ms).intersection(set(new_m2ms)):
                    old_field = self.old_orm[key + ":" + fieldname]
                    new_field = self.current_field_from_key(key, fieldname)
                    # Have they _added_ a through= ?
                    if auto_through(old_field) and not auto_through(new_field):
                        yield ("DeleteM2M", {"model": self.old_orm[key], "field": old_field})
                    # Have they _removed_ a through= ?
                    if not auto_through(old_field) and auto_through(new_field):
                        yield ("AddM2M", {"model": self.current_model_from_key(key), "field": new_field})

                ## See if the unique_togethers have changed
                # First, normalise them into lists of sets.
                old_unique_together = eval(old_meta.get("unique_together", "[]"))
                new_unique_together = eval(new_meta.get("unique_together", "[]"))
                if old_unique_together and isinstance(old_unique_together[0], basestring):
                    old_unique_together = [old_unique_together]
                if new_unique_together and isinstance(new_unique_together[0], basestring):
                    new_unique_together = [new_unique_together]
                old_unique_together = map(set, old_unique_together)
                new_unique_together = map(set, new_unique_together)
                # See if any appeared or disappeared
                for item in old_unique_together:
                    if item not in new_unique_together:
                        yield (
                            "DeleteUnique",
                            {"model": self.old_orm[key], "fields": [self.old_orm[key + ":" + x] for x in item]},
                        )
                for item in new_unique_together:
                    if item not in old_unique_together:
                        yield (
                            "AddUnique",
                            {
                                "model": self.current_model_from_key(key),
                                "fields": [self.current_field_from_key(key, x) for x in item],
                            },
                        )
Ejemplo n.º 10
0
 def get_changes(self):
     """
     Returns the difference between the old and new sets of models as a 5-tuple:
     added_models, deleted_models, added_fields, deleted_fields, changed_fields
     """
     
     deleted_models = set()
     
     # See if anything's vanished
     for key in self.old_defs:
         if key not in self.new_defs:
             # We shouldn't delete it if it was managed=False
             if self.old_defs[key].get("Meta", {}).get("managed", "True") != "False":
                 # Alright, delete it.
                 yield ("DeleteModel", {
                     "model": self.old_orm[key], 
                     "model_def": self.split_model_def(self.old_orm[key], self.old_defs[key])[0],
                 })
             # We always add it in here so we ignore it later
             deleted_models.add(key)
     
     # Or appeared
     for key in self.new_defs:
         if key not in self.old_defs:
             # We shouldn't add it if it's managed=False
             if self.new_defs[key].get("Meta", {}).get("managed", "True") != "False":
                 yield ("AddModel", {
                     "model": self.current_model_from_key(key), 
                     "model_def": self.split_model_def(self.current_model_from_key(key), self.new_defs[key])[0],
                 })
     
     # Now, for every model that's stayed the same, check its fields.
     for key in self.old_defs:
         if key not in deleted_models:
             
             still_there = set()
             
             old_fields, old_meta, old_m2ms = self.split_model_def(self.old_orm[key], self.old_defs[key])
             new_fields, new_meta, new_m2ms = self.split_model_def(self.current_model_from_key(key), self.new_defs[key])
             
             # Find fields that have vanished.
             for fieldname in old_fields:
                 if fieldname not in new_fields:
                     yield ("DeleteField", {"model": self.old_orm[key], "field": self.old_orm[key + ":" + fieldname], "field_def": old_fields[fieldname]})
             
             # And ones that have appeared
             for fieldname in new_fields:
                 if fieldname not in old_fields:
                     yield ("AddField", {"model": self.current_model_from_key(key), "field": self.current_field_from_key(key, fieldname), "field_def": new_fields[fieldname]})
             
             # Find M2Ms that have vanished
             for fieldname in old_m2ms:
                 if fieldname not in new_m2ms:
                     # Only delete its stuff if it wasn't a through=.
                     field = self.old_orm[key + ":" + fieldname]
                     if auto_through(field):
                         yield ("DeleteM2M", {"model": self.old_orm[key], "field": field})
             
             # Find M2Ms that have appeared
             for fieldname in new_m2ms:
                 if fieldname not in old_m2ms:
                     # Only create its stuff if it wasn't a through=.
                     field = self.current_field_from_key(key, fieldname)
                     if auto_through(field):
                         yield ("AddM2M", {"model": self.current_model_from_key(key), "field": field})
             
             # For the ones that exist in both models, see if they were changed
             for fieldname in set(old_fields).intersection(set(new_fields)):
                 if self.different_attributes(
                  remove_useless_attributes(old_fields[fieldname], True),
                  remove_useless_attributes(new_fields[fieldname], True)):
                     yield ("ChangeField", {
                         "model": self.current_model_from_key(key),
                         "old_field": self.old_orm[key + ":" + fieldname],
                         "new_field": self.current_field_from_key(key, fieldname),
                         "old_def": old_fields[fieldname],
                         "new_def": new_fields[fieldname],
                     })
                 # See if their uniques have changed
                 old_field = self.old_orm[key + ":" + fieldname]
                 new_field = self.current_field_from_key(key, fieldname)
                 if old_field.unique != new_field.unique:
                     # Make sure we look at the one explicitly given to see what happened
                     if new_field.unique:
                         yield ("AddUnique", {
                             "model": self.current_model_from_key(key),
                             "fields": [self.current_field_from_key(key, fieldname)],
                         })
                     else:
                         yield ("DeleteUnique", {
                             "model": self.old_orm[key],
                             "fields": [self.old_orm[key + ":" + fieldname]],
                         })
             
             # See if there's any M2Ms that have changed.
             for fieldname in set(old_m2ms).intersection(set(new_m2ms)):
                 old_field = self.old_orm[key + ":" + fieldname]
                 new_field = self.current_field_from_key(key, fieldname)
                 # Have they _added_ a through= ?
                 if auto_through(old_field) and not auto_through(new_field):
                     yield ("DeleteM2M", {"model": self.old_orm[key], "field": old_field})
                 # Have they _removed_ a through= ?
                 if not auto_through(old_field) and auto_through(new_field):
                     yield ("AddM2M", {"model": self.current_model_from_key(key), "field": new_field})
             
             ## See if the unique_togethers have changed
             # First, normalise them into lists of sets.
             old_unique_together = eval(old_meta.get("unique_together", "[]"))
             new_unique_together = eval(new_meta.get("unique_together", "[]"))
             if old_unique_together and isinstance(old_unique_together[0], basestring):
                 old_unique_together = [old_unique_together]
             if new_unique_together and isinstance(new_unique_together[0], basestring):
                 new_unique_together = [new_unique_together]
             old_unique_together = map(set, old_unique_together)
             new_unique_together = map(set, new_unique_together)
             # See if any appeared or disappeared
             for item in old_unique_together:
                 if item not in new_unique_together:
                     yield ("DeleteUnique", {
                         "model": self.old_orm[key],
                         "fields": [self.old_orm[key + ":" + x] for x in item],
                     })
             for item in new_unique_together:
                 if item not in old_unique_together:
                     yield ("AddUnique", {
                         "model": self.current_model_from_key(key),
                         "fields": [self.current_field_from_key(key, x) for x in item],
                     })