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 support 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 filer.models.filemodels.File
.
# 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, filer.admin.clipboardadmin.ClipboardAdmin.ajax_upload()
loops over the different models 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:
@classmethod
def matches_file_type(cls, iname, ifile, mime_type):
video_types = ['application/vnd.dvb.ait', 'video/x-sgi-movie', 'video/mp4', 'video/mpeg',
'video/x-msvideo', 'video/x-ms-wmv', 'video/ogg', 'video/webm', 'video/quicktime']
return mime_type in video_types
Note
The signature of this classmethod changed in version 2.0.
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 filer.models.filemodels.File
class we’ve inherited from has an icons()
property, from 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, 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:
# 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:
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¶
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:
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/how_to/custom_plugins.html#overview will provide an explanation.
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 appropriate information for your new file type.
In that case you will need to override the template, and in the Video
model:
# 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.
Overriding the Directory Listing Search¶
By default, filer will search against name
for Folders
and name
, description
, and
original_filename
for Files
, in
addition to searching against the owner. If you are using auth.User
as
your User model, filer will search against the username
, first_name
,
last_name
, email
fields. If you are using a custom User model, filer
will search against all fields that are CharFields except for the password
field. You can override this behavior by subclassing the
filer.admin.folderadmin.FolderAdmin
class and overriding the
owner_search_fields
property.
# in an admin.py file
from django.contrib import admin
from filer.admin import FolderAdmin
from filer.models import Folder
class MyFolderAdmin(FolderAdmin):
owner_search_fields = ['field1', 'field2']
admin.site.unregister(Folder)
admin.site.register(Folder, FolderAdmin)
You can also override the search behavior for Folders
.
Just override search_fields
by subclassing
the filer.admin.folderadmin.FolderAdmin
. It works as described in
Django’s docs. E.g.:
# in an admin.py file
class MyFolderAdmin(FolderAdmin):
search_fields = ['=field1', '^field2']
admin.site.unregister(Folder)
admin.site.register(Folder, MyFolderAdmin)
Providing custom Image model¶
As the Image
model is special, a different way to implement custom Image model is required, which uses the Django
swappable models interface.
Defining the model¶
First a custom model must be defined; it should inherit from BaseImage, the basic abstract class:
from filer.models.abstract.BaseImage
class CustomImage(BaseImage):
my_field = models.CharField(max_length=10)
class Meta(BaseImage.Meta):
# You must define a meta with en explicit app_label
app_label = 'myapp'
default_manager_name = 'objects'
The model can be defined in any installed application declared after django-filer
.
BaseImage
defines the following fields (plus the basic fields defined in File
):
default_alt_text
default_caption
subject_location
you may add whatever fields you need, just like any other model.
..warning: app_label
in Meta
must be explicitly defined.
Customize the admin¶
If you added fields in your custom Image model, you have to customize the admin too:
from django.contrib import admin
from filer.admin.imageadmin import ImageAdmin
Image = load_model(filer_settings.FILER_IMAGE_MODEL)
class CustomImageAdmin(ImageAdmin):
# your custom code
pass
# Using build_fieldsets allows to easily integrate common field in the admin
# Don't define fieldsets in the ModelAdmin above and add the custom fields
# to the ``extra_main_fields`` or ``extra_fieldsets`` as shown below
CustomImageAdmin.fieldsets = CustomImageAdmin.build_fieldsets(
extra_main_fields=('default_alt_text', 'default_caption', 'my_field'...),
extra_fieldsets=(
('Subject Location', {
'fields': ('subject_location',),
'classes': ('collapse',),
}),
)
)
# Unregister the default admin
admin.site.unregister(Image)
# Register your own
admin.site.register(Image, CustomImageAdmin)
Swap the Image model¶
Set FILER_IMAGE_MODEL
to the path of your custom model:
FILER_IMAGE_MODEL = 'myapp.CustomImage'