Storing files

In OIOIOI we need some mechanism to exchange files with external judging machines. We use Filetracker for it. It’s our custom module and lives in the Git repository in lib/filetracker.

Filetracker in Django

Most of the Django files docs still apply. The only difference is that we use our custom model field and storage manager, as specified in settngs.py:

DEFAULT_FILE_STORAGE = 'oioioi.filetracker.storage.FiletrackerStorage'

To store a field in a model, use code like this:

from django.db import models
from oioioi.filetracker.fields import FileField

class TestFileModel(models.Model):
    file_field = FileField(upload_to='some/folder')

Frequently you don’t want all files from a single field occupy a single folder. No one wants all input files for all tasks to be in a single folder. Therefore in practice you usually pass a filename generator as upload_to. You may do it like this:

from djang.utils.text import get_valid_filename
import os.path

def make_test_filename(instance, filename):
    # instance will be an instance of Test
    # filename will be the name of the file uploaded by the user
    #   or passed programatically to instance.input_file.save()
    return 'problems/%d/%s' % (instance.problem.id,
            get_valid_filename(os.path.basename(filename)))

class Test(models.Model):
    problem = models.ForeignKey('Problem', on_delete=models.CASCADE)
    input_file = FileField(upload_to=make_test_filename)

To store an existing file, write something like this:

from django.core.files import File
my_model.file_field = File(open('/etc/passwd', 'rb'), name='myfile.txt')
# or: my_model.file_field.save('myfile.txt', File(open('/etc/passwd', 'rb')))

To store a string variable:

from django.core.files import ContentFile
my_model.file_field = ContentFile('content of file', name='myfile.txt')
# or: my_model.file_field.save('myfile.txt', ContentFile('content of file'))

To assign a file, which is already in Filetracker:

from oioioi.filetracker.utils import filetracker_to_django_file
my_model.file_field = filetracker_to_django_file('/path/in/filetracker/to/myfile.txt')

Note

This is assignment, so any output of upload_to will be ignored.

oioioi.filetracker.utils.filetracker_to_django_file(filetracker_path, storage=None)[source]

Returns a File representing an existing Filetracker file (usable only for assigning to a FileField)

oioioi.filetracker.utils.django_to_filetracker_path(django_file)[source]

Returns the filetracker path of a django.core.files.File.

Accessing Filetracker client

To obtain the Filetracker client class instance, use oioioi.filetracker.client.get_client(). Our Django Filetracker storage backend uses this function as well.

oioioi.filetracker.client.get_client()[source]

Constructs a Filetracker client.

Needs a FILETRACKER_CLIENT_FACTORY entry in settings.py, which should contain a dotted name of a function which returns a filetracker.client.Client instance. A good candidate is remote_storage_factory().

The constructed client is cached.

oioioi.filetracker.client.remote_storage_factory()[source]

A filetracker factory which creates a client that uses the remote server at settings.FILETRACKER_URL and a folder settings.FILETRACKER_CACHE_ROOT as a cache directory.

Indeed, in settings.py you will find:

FILETRACKER_CLIENT_FACTORY = 'oioioi.filetracker.client.remote_storage_factory'

Testing with files

Database fixtures allow to store database entities ready for use in tests. Our FileField is tweaked to also serialize its content, and deserialize automatically when fixtures are loaded.