from django.db.models import get_apps, get_models from django.db.models.fields.related import * from django.conf import global_settings from django.contrib.contenttypes import generic from django.utils.datastructures import SortedDict from django_evolution import is_multi_db if is_multi_db(): from django.db import router ATTRIBUTE_DEFAULTS = { # Common to all fields 'primary_key': False, 'max_length' : None, 'unique' : False, 'null' : False, 'db_index' : False, 'db_column' : None, 'db_tablespace' : global_settings.DEFAULT_TABLESPACE, 'rel': None, # Decimal Field 'max_digits' : None, 'decimal_places' : None, # ManyToManyField 'db_table': None } # r7790 modified the unique attribute of the meta model to be # a property that combined an underlying _unique attribute with # the primary key attribute. We need the underlying property, # but we don't want to affect old signatures (plus the # underscore is ugly :-). ATTRIBUTE_ALIASES = { 'unique': '_unique' } def create_field_sig(field): field_sig = { 'field_type': field.__class__, } for attrib in ATTRIBUTE_DEFAULTS.keys(): alias = ATTRIBUTE_ALIASES.get(attrib, attrib) if hasattr(field,alias): value = getattr(field,alias) if isinstance(field, ForeignKey): if attrib == 'db_index': default = True else: default = ATTRIBUTE_DEFAULTS[attrib] else: default = ATTRIBUTE_DEFAULTS[attrib] # only store non-default values if default != value: field_sig[attrib] = value rel = field_sig.pop('rel', None) if rel: field_sig['related_model'] = '.'.join([rel.to._meta.app_label, rel.to._meta.object_name]) return field_sig def create_model_sig(model): model_sig = { 'meta': { 'unique_together': model._meta.unique_together, 'db_tablespace': model._meta.db_tablespace, 'db_table': model._meta.db_table, 'pk_column': model._meta.pk.column, }, 'fields': {}, } for field in model._meta.local_fields + model._meta.local_many_to_many: # Special case - don't generate a signature for generic relations if not isinstance(field, generic.GenericRelation): model_sig['fields'][field.name] = create_field_sig(field) return model_sig def create_app_sig(app, database): """ Creates a dictionary representation of the models in a given app. Only those attributes that are interesting from a schema-evolution perspective are included. """ app_sig = SortedDict() for model in get_models(app): # only include those who want to be syncdb if not is_multi_db() or router.allow_syncdb(database, model): app_sig[model._meta.object_name] = create_model_sig(model) return app_sig def create_project_sig(database): """ Create a dictionary representation of the apps in a given project. """ proj_sig = { '__version__': 1, } for app in get_apps(): proj_sig[app.__name__.split('.')[-2]] = create_app_sig(app, database) return proj_sig