Package: example.blobattype
IntroductionThe purpose of this example package is to demonstrate how to migrate custom
AT-based content types that use FileFields to useplone.app.blobbased blobs.Migrating your own AT-based content types.In order to migrate your own content types to use blobs you need to perform
the following steps:Use a schema extender to replace the FileField(s) of your content type with
BlobField(s). For detailed information on how to do so please look into thearchetypes.schemaextenderdocumentation. In
essence this breaks down to:Creating anextensionfield:class ExtensionBlobField(ExtensionField, BlobField):
    """ derivative of blobfield for extending schemas """Extending your content type to use the blob fields. So for instance if your
content type ExampleATType has two fields, namelyafileandsecondfileyou need to register an extender looking like:class ExampleATTypeExtender(object):
    adapts(IExampleATType)
    implements(ISchemaExtender)

    fields = [
        ExtensionBlobField('afile',
            widget=atapi.FileWidget(
                label=_(u"A file"),
                description=_(u"Some file"),
            ),
            required=True,
            validators=('isNonEmptyFile'),
        ),
        ExtensionBlobField('secondfile',
            widget=atapi.FileWidget(
                label=_(u"Some other file"),
                description=_(u"Some other file"),
            ),
            required=True,
            validators=('isNonEmptyFile'),
        ),
    ]

    def __init__(self, context):
        self.context = context

    def getFields(self):
        return self.fieldsIf you want to be able to still use your content type withoutplone.app.blobon instances that do not support blobs yet, you will find
it convenient to register the adapter with a conditional such as:<adapter
    zcml:condition="installed plone.app.blob"
    factory=".exampleattype.ExampleATTypeExtender" />This way, if plone.app.blob is not installed your original FileField(s) will
be used.Writing a migrator. We useProducts.contentmigrationto do so, and for
the example above the migrator would like this:class ExampleATTypeMigrator(BaseInlineMigrator):
    """ example migrator """

    src_portal_type = 'ExampleATType'
    src_meta_type = 'ExampleATType'
    dst_portal_type = 'ExampleATType'
    dst_meta_type = 'ExampleATType'

    fields_map = {
        'afile': None,
        'secondfile': None,
    }

    def migrate_data(self):
        f = self.obj.getField('afile').get(self.obj)
        self.obj.getField('afile').getMutator(self.obj)(f)
        f = self.obj.getField('secondfile').get(self.obj)
        self.obj.getField('secondfile').getMutator(self.obj)(f)

    def last_migrate_reindex(self):
        self.obj.reindexObject()You will also need to provide awalkeriterating over your objects, in
this case:def migrateExampleATTypes(context):
    portal = getToolByName(context, 'portal_url').getPortalObject()
    migrator = ExampleATTypeMigrator
    walker = CustomQueryWalker(portal, migrator, full_transaction=True)
    savepoint(optimistic=True)
    walker.go()
    return walker.getOutput()You can now callmigrateExampleATTypesfrom a view or a script to convert
your objects.Changelog1.0 UnreleasedInitial version
[ggozad]