.. _extending_filer: Extending Django Filer ====================== Django Filer ships with support for image files, and generic files (everything that's not an image). So what if you wanted to add support for a particular kind of file thats's not already included? It's easy to extend it to do this, without needing to touch the Filer's code at all (and no-one wants to have to maintain fork if they can avoid it). So for example, you might want to be able to manage video files. You could of course simply store and file them as generic file types, but that might not be enough - perhaps your own application needs to know that certain files are in fact video files, so that it can treat them appropriately (process them, allow only them to be selected in certain widgets, and so on). In this example we will create suport for video files. The model --------- The very basics ............... In your own application, you need to create a Video model. This model has to inherit from :py:class:`filer.models.filemodels.File`. .. code-block:: python # import the File class to inherit from from filer.models.filemodels import File # we'll need to refer to filer settings from filer import settings as filer_settings class Video(File): pass # for now... When a file is uploaded, :py:meth:`filer.admin.clipboardadmin.ClipboardAdmin.ajax_upload` loops over the different classes in ``filer.settings.FILER_FILE_MODELS`` and calls its ``matches_file_type()`` to see if the file matches a known filename extension. When a match is found, the filer will create an instance of that class for the file. So let's add a ``matches_file_type()`` method to the ``Video`` model: .. code-block:: python @classmethod def matches_file_type(cls, iname, ifile, request): # the extensions we'll recognise for this file type filename_extensions = ['.dv', '.mov', '.mp4', '.avi', '.wmv',] ext = os.path.splitext(iname)[1].lower() return ext in filename_extensions Now you can upload files of those types into the Filer. For each one you upload an instance of your ``Video`` class will be created. Icons ..... At the moment, the files you upload will have the Filer's generic file icon - not very appropriate or helpful for video. What you need to do is add a suitable ``_icon`` attribute to the class. The :py:class:`filer.models.filemodels.File` class we've inherited from has an ``icons()`` property, from :py:class:`filer.models.mixins.IconsMixin`. This checks for the ``_icon`` attribute; if it finds one, it uses it to build URLs for the icons in various different sizes. If ``_icons`` is ``video``, a typical result might be ``/static/filer/icons/video_48x48.png``. Of course, you can also create an ``icons()`` property specific to your new model. For example, :py:class:`filer.models.imagemodels.Image` does that, so that it can create thumbnail icons for each file rather than a single icon for all of that type. In our ``Video`` model the simple case will do: .. code-block:: python # the icon it will use _icon = "video" And in fact, the Filer *already* has an icon that matches this - if there were not already a set of video icons in the Filer's static assets, we'd have to provide them - see ``filer/static/icons`` for examples. The admin --------- Now we need to register our new model with the admin. Again, the very simplest case: .. code-block:: python from django.contrib import admin from filer.admin.fileadmin import FileAdmin from models import Video admin.site.register(Video, FileAdmin) # use the standard FileAdmin ... but of course if your model had particular fields of its own (as for example the ``Image`` model has a ``subject_location`` field) you would create your own ModelAdmin class for it, along with a form, special widgets and whatever else you needed. Using your new file type ------------------------ You've now done enough to be able to get hold of files of your new kind in the admin (wherever the admin uses a ``FilerFileField``) but to make it really useful we need to to a little more. For example, it might be useful to have: * its own field type to get hold of it in some other model * a special form for the field * a widget for selecting it in the admin * ... and so on How you use it will be up to you, but a fairly typical use case would be in a django CMS plugin, and that is the example that will be followed here. Create a custom field for your file type ---------------------------------------- .. code-block:: python from filer.fields.file import FilerFileField class FilerVideoField(FilerFileField): default_model_class = Video Of course you could also create an admin widget and admin form, but it's not necessary at this stage - the ones generic files use will do just fine. Create some other model that uses it ------------------------------------ Here, it's going to be a django CMS plugin: .. code-block:: python from cms.models import CMSPlugin class VideoPluginEditor(CMSPlugin): video = FilerVideoField() # you'd probably want some other fields in practice... You'll have to provide an admin class for your model; in this case, the admin will be provided as part of the django CMS plugin architecture. .. note:: If you are not already familiar with the django CMS plugin architecture, http://docs.django-cms.org/en/latest/extending_cms/custom_plugins.html#overview will provide an explanation. .. code-block:: python from cms.plugin_base import CMSPluginBase from models import VideoPluginEditor class VideoPluginPublisher(CMSPluginBase): model = VideoPluginEditor render_template = "video/video.html" text_enabled = True admin_preview = False def icon_src(self, instance): return "/static/plugin_icons/video.png" def render(self, context, instance, placeholder): context.update({ 'video':instance, 'placeholder':placeholder, }) return context plugin_pool.register_plugin(VideoPluginPublisher) ... and now, assuming you have created a suitable ``video/video.html``, you've got a working plugin that will make use of your new Filer file type. Other things you could add -------------------------- Admin templating ................ ``filer/templates/templates/admin/filer/folder`` lists the individual items in each folder. It checks ``item.file_type`` to determine how to display those items and what to display for them. You might want to extend this, so that the list includes the apprpriate information for your new file type. In that case you will need to override the template, and in the ``Video`` model: .. code-block:: python # declare the file_type for the list template file_type = 'Video' Note that if you do this, you *will* need to override the template - otherwise your items will fail to display in the folder lists.