Tutorial: Adding a new Media Type

Prerequisites

Here we’ll assume you have a working Tutorial: Quickstart setup.

Goals

Let’s say we want to add PDF file support in the gallery. We need:

  • to provide a new model class inheriting Element,
  • to provide an importer class able to handle new files for addition in the gallery,
  • to provide a template fragment for the display view (thumbnail view is provided for free by Element).

Create a new app

$ django-admin.py startapp my_media_pdf

Create the models

Then let’s edit my_media_pdf/models.py and implement our new model.

It will contain a file, a title, an author name, and a page count. We also provide a pretty printer and a thumbnail generator that uses ImageMagick’s convert tool:

from django.db import models

from mg.core.element.models import *

class Pdf(Element):
    author = models.CharField(max_length = 32)
    title = models.CharField(max_length = 64)
    file = models.FileField(upload_to = "pdf")
    page_count = models.IntegerField()

    def __unicode__(self):
        return "<Pdf: '%s'>"%self.title

    @property
    def spool_filename(self):
        from django.conf import settings
        import os.path
        return str(os.path.join(settings.MEDIA_ROOT, self.file.name))

    def thumbnail_new(self, thumb_size):
        from django.core.files.base import File
        import tempfile
        from subprocess import call

        t = Thumbnail(
            size = thumb_size,
            element = self)
        output = t.filename_gen()
        t.save()

        out = tempfile.NamedTemporaryFile(suffix = ".jpg", mode = "w+b")

        cmd = ['convert',
               '-colorspace', 'RGB',
               '-geometry', '%dx%d'%thumb_size.wh,
               self.spool_filename, out.name,
               ]

        call(cmd)

        out.seek(0)
        t.file.save(t.filename_gen(), File(out))

        return t

Element.register_type("pdf", Pdf)

This last line is extremely important, it tells the Element system that there is a new element type to handle.

Implement an Element importer

Now let’s implement a basic importer. Create file my_media_pdf/management/utils/importer.py (dont forget to create __init__.py in each parent directory). It will implement the importer protocol (see mg.core.element.utils.protocols.Importer):

from mg.core.element.utils import protocols
from my_media_pdf.models import Pdf
from django.contrib.auth.models import User
from django.core.files import File
import os
import os.path

class Importer(protocols.Importer):

    def do_import(self, filename, fd):
        """
        Must do the actual import and create an Element (or
        subinstance), the fd is an open file descriptor pointing to
        file data. We have no guarantee it is on the file system.
        """

        basename = os.path.basename(filename).lower()

        # Create a database entry
        elem = Pdf(
            name = basename[:-4],
            owner = User.objects.get(pk = 0),
            title = "Title of "+basename,
            author = "Author of "+basename,
            page_count = 42,
            )

        # Get an available name for the payload
        fn = elem.file.storage.get_available_name(
            elem.file.storage.get_valid_name(
            basename
            ))

        # Save the payload in media root
        elem.file.save(fn, File(fd), save = True)

        return elem

    def can_handle(self, path, type):
        """
        We only handle files with a pdf extension. This is a cheesy
        file detection, but will suffice for now. We can still fail
        in do_import() if we need to anyway.
        """
        if type != "f":
            return False
        return path.lower().endswith(".pdf")

Provide templates

Provide my_media_pdf/templates/my_media_pdf/pdf_view.html, for the elem_view templatetag:

<div class="elem-view pdf-view">
 <embed src="{{ object.file.url }}" width="800" height="600" />
</div>

Updating settings

settings.py

Add the following in INSTALLED_APPS:

"my_media_pdf",

Update the database:

user@host quickstart $ ./manage.py syncdb

We’re done !

That’s it, you successfully added your own model !

Now you can import your files with mg_import (see Importing Elements):

$ ./manage.py mg_import --files ~/files/*.pdf

And you can see the result running the server:

$ ./manage.py runserver

What’s next ?

You may want to:

  • improve the importer code to extract a real title and author name from the PDF file, with some third-party library like PyPDF
  • create another media app with your favourite datatype.