south.creator.freezer: 126 total statements, 0.0% covered

Generated: Wed 2013-03-13 10:33 CET

Source file: /media/Envs/Envs/filer-gallery/lib/python2.7/site-packages/south/creator/freezer.py

Stats: 0 executed, 119 missed, 7 excluded, 64 ignored

  1. """
  2. Handles freezing of models into FakeORMs.
  3. """
  4. import sys
  5. from django.db import models
  6. from django.db.models.base import ModelBase, Model
  7. from django.contrib.contenttypes.generic import GenericRelation
  8. from south.orm import FakeORM
  9. from south.utils import get_attribute, auto_through
  10. from south import modelsinspector
  11. def freeze_apps(apps):
  12. """
  13. Takes a list of app labels, and returns a string of their frozen form.
  14. """
  15. if isinstance(apps, basestring):
  16. apps = [apps]
  17. frozen_models = set()
  18. # For each app, add in all its models
  19. for app in apps:
  20. for model in models.get_models(models.get_app(app)):
  21. # Only add if it's not abstract or proxy
  22. if not model._meta.abstract and not getattr(model._meta, "proxy", False):
  23. frozen_models.add(model)
  24. # Now, add all the dependencies
  25. for model in list(frozen_models):
  26. frozen_models.update(model_dependencies(model))
  27. # Serialise!
  28. model_defs = {}
  29. model_classes = {}
  30. for model in frozen_models:
  31. model_defs[model_key(model)] = prep_for_freeze(model)
  32. model_classes[model_key(model)] = model
  33. # Check for any custom fields that failed to freeze.
  34. missing_fields = False
  35. for key, fields in model_defs.items():
  36. for field_name, value in fields.items():
  37. if value is None:
  38. missing_fields = True
  39. model_class = model_classes[key]
  40. field_class = model_class._meta.get_field_by_name(field_name)[0]
  41. print " ! Cannot freeze field '%s.%s'" % (key, field_name)
  42. print " ! (this field has class %s.%s)" % (field_class.__class__.__module__, field_class.__class__.__name__)
  43. if missing_fields:
  44. print ""
  45. print " ! South cannot introspect some fields; this is probably because they are custom"
  46. print " ! fields. If they worked in 0.6 or below, this is because we have removed the"
  47. print " ! models parser (it often broke things)."
  48. print " ! To fix this, read http://south.aeracode.org/wiki/MyFieldsDontWork"
  49. sys.exit(1)
  50. return model_defs
  51. def freeze_apps_to_string(apps):
  52. return pprint_frozen_models(freeze_apps(apps))
  53. ###
  54. def model_key(model):
  55. "For a given model, return 'appname.modelname'."
  56. return "%s.%s" % (model._meta.app_label, model._meta.object_name.lower())
  57. def prep_for_freeze(model):
  58. """
  59. Takes a model and returns the ready-to-serialise dict (all you need
  60. to do is just pretty-print it).
  61. """
  62. fields = modelsinspector.get_model_fields(model, m2m=True)
  63. # Remove useless attributes (like 'choices')
  64. for name, field in fields.items():
  65. fields[name] = remove_useless_attributes(field)
  66. # See if there's a Meta
  67. fields['Meta'] = remove_useless_meta(modelsinspector.get_model_meta(model))
  68. # Add in our own special items to track the object name and managed
  69. fields['Meta']['object_name'] = model._meta.object_name # Special: not eval'able.
  70. if not getattr(model._meta, "managed", True):
  71. fields['Meta']['managed'] = repr(model._meta.managed)
  72. return fields
  73. ### Dependency resolvers
  74. def model_dependencies(model, checked_models=None):
  75. """
  76. Returns a set of models this one depends on to be defined; things like
  77. OneToOneFields as ID, ForeignKeys everywhere, etc.
  78. """
  79. depends = set()
  80. checked_models = checked_models or set()
  81. # Get deps for each field
  82. for field in model._meta.fields + model._meta.many_to_many:
  83. depends.update(field_dependencies(field, checked_models))
  84. # Add in any non-abstract bases
  85. for base in model.__bases__:
  86. if issubclass(base, models.Model) and hasattr(base, '_meta') and not base._meta.abstract:
  87. depends.add(base)
  88. # Now recurse
  89. new_to_check = depends - checked_models
  90. while new_to_check:
  91. checked_model = new_to_check.pop()
  92. if checked_model == model or checked_model in checked_models:
  93. continue
  94. checked_models.add(checked_model)
  95. deps = model_dependencies(checked_model, checked_models)
  96. # Loop through dependencies...
  97. for dep in deps:
  98. # If the new dep is not already checked, add to the queue
  99. if (dep not in depends) and (dep not in new_to_check) and (dep not in checked_models):
  100. new_to_check.add(dep)
  101. depends.add(dep)
  102. return depends
  103. def field_dependencies(field, checked_models=None):
  104. checked_models = checked_models or set()
  105. depends = set()
  106. arg_defs, kwarg_defs = modelsinspector.matching_details(field)
  107. for attrname, options in arg_defs + kwarg_defs.values():
  108. if options.get("ignore_if_auto_through", False) and auto_through(field):
  109. continue
  110. if options.get("is_value", False):
  111. value = attrname
  112. elif attrname == 'rel.through' and hasattr(getattr(field, 'rel', None), 'through_model'):
  113. # Hack for django 1.1 and below, where the through model is stored
  114. # in rel.through_model while rel.through stores only the model name.
  115. value = field.rel.through_model
  116. else:
  117. try:
  118. value = get_attribute(field, attrname)
  119. except AttributeError:
  120. if options.get("ignore_missing", False):
  121. continue
  122. raise
  123. if isinstance(value, Model):
  124. value = value.__class__
  125. if not isinstance(value, ModelBase):
  126. continue
  127. if getattr(value._meta, "proxy", False):
  128. value = value._meta.proxy_for_model
  129. if value in checked_models:
  130. continue
  131. checked_models.add(value)
  132. depends.add(value)
  133. depends.update(model_dependencies(value, checked_models))
  134. return depends
  135. ### Prettyprinters
  136. def pprint_frozen_models(models):
  137. return "{\n %s\n }" % ",\n ".join([
  138. "%r: %s" % (name, pprint_fields(fields))
  139. for name, fields in sorted(models.items())
  140. ])
  141. def pprint_fields(fields):
  142. return "{\n %s\n }" % ",\n ".join([
  143. "%r: %r" % (name, defn)
  144. for name, defn in sorted(fields.items())
  145. ])
  146. ### Output sanitisers
  147. USELESS_KEYWORDS = ["choices", "help_text", "verbose_name"]
  148. USELESS_DB_KEYWORDS = ["related_name", "default", "blank"] # Important for ORM, not for DB.
  149. INDEX_KEYWORDS = ["db_index"]
  150. def remove_useless_attributes(field, db=False, indexes=False):
  151. "Removes useless (for database) attributes from the field's defn."
  152. # Work out what to remove, and remove it.
  153. keywords = USELESS_KEYWORDS[:]
  154. if db:
  155. keywords += USELESS_DB_KEYWORDS[:]
  156. if indexes:
  157. keywords += INDEX_KEYWORDS[:]
  158. if field:
  159. for name in keywords:
  160. if name in field[2]:
  161. del field[2][name]
  162. return field
  163. USELESS_META = ["verbose_name", "verbose_name_plural"]
  164. def remove_useless_meta(meta):
  165. "Removes useless (for database) attributes from the table's meta."
  166. if meta:
  167. for name in USELESS_META:
  168. if name in meta:
  169. del meta[name]
  170. return meta