+def create_tag_model(model):
+ name = model.__name__ + 'Tag'
+
+ class Meta(Tag.Meta):
+ app_label = model._meta.app_label
+
+ if hasattr(model, 'TagMeta'):
+ for attr, value in model.TagMeta.__dict__.items():
+ setattr(Meta, attr, value)
+
+ attrs = {
+ '__module__': model.__module__,
+ 'Meta': Meta,
+ }
+ return type(name, (Tag,), attrs)
+
+
+def create_change_model(model):
+ name = model.__name__ + 'Change'
+ repo = GzipFileSystemStorage(location=model.REPO_PATH)
+
+ class Meta(Change.Meta):
+ app_label = model._meta.app_label
+
+ attrs = {
+ '__module__': model.__module__,
+ 'tree': models.ForeignKey(model, related_name='change_set', verbose_name=_('document')),
+ 'tags': models.ManyToManyField(model.tag_model, verbose_name=_('tags'), related_name='change_set'),
+ 'data': models.FileField(_('data'), upload_to=data_upload_to, storage=repo),
+ 'Meta': Meta,
+ }
+ return type(name, (Change,), attrs)
+
+
+class DocumentMeta(ModelBase):
+ "Metaclass for Document models."
+ def __new__(cls, name, bases, attrs):
+
+ model = super(DocumentMeta, cls).__new__(cls, name, bases, attrs)
+ if not model._meta.abstract:
+ # create a real Tag object and `stage' fk
+ model.tag_model = create_tag_model(model)
+ models.ForeignKey(model.tag_model, verbose_name=_('stage'),
+ null=True, blank=True).contribute_to_class(model, 'stage')
+
+ # create real Change model and `head' fk
+ model.change_model = create_change_model(model)
+
+ models.ForeignKey(model.change_model,