Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoengine FileField saving to disk?

Mongoengine stores FileField and ImageField to GridFS. What's the easiest approach to replicate the functionality of the original File/Image Field?

EDIT:

So this is the class I have in place at the moment. I'm able to load files and save them to disk, Mongo holds the path to the file in database.

I'm falling over on "to_python" as I believe it needs to create an object of the proxy_class but I can't see how, if all I'm getting is a path to the file (as the value passed in).

import os
import datetime

from mongoengine.python_support import str_types
from django.db.models.fields.files import FieldFile
from django.core.files.base import File
from django.core.files.storage import default_storage
from mongoengine.base import BaseField
from mongoengine.connection import get_db, DEFAULT_CONNECTION_NAME
from django.utils.encoding import force_text
#from django.utils.encoding import force_str


class DJFileField(BaseField):

    proxy_class = FieldFile

    def __init__(self,
                 db_alias=DEFAULT_CONNECTION_NAME, 
                 name=None,
                 upload_to='',
                 storage=None,
                 **kwargs):

        self.db_alias = db_alias
        self.storage = storage or default_storage
        self.upload_to = upload_to

        if callable(upload_to):
            self.generate_filename = upload_to

        super(DJFileField, self).__init__(**kwargs)


    def __get__(self, instance, owner):
        # Lots of information on whats going on here can be found
        # on Django's FieldFile implementation, go over to GitHub to
        # read it.
        file = instance._data.get(self.name)

        if isinstance(file, str_types) or file is None:
            attr = self.proxy_class(instance, self, file)
            instance._data[self.name] = attr

        elif isinstance(file, File) and not isinstance(file, FieldFile):
            file_copy = self.proxy_class(instance, self, file.name)
            file_copy.file = file
            file_copy._committed = False
            instance._data[self.name] = file_copy

        elif isinstance(file, FieldFile) and not hasattr(file, 'field'):
            file.instance = instance
            file.field = self
            file.storage = self.storage

        # That was fun, wasn't it?
        return instance._data[self.name]


    def __set__(self, instance, value):
        instance._data[self.name] = value

    # The 3 methods below get used by the FieldFile proxy_object
    def get_directory_name(self):
        return os.path.normpath(force_text(datetime.datetime.now().strftime(self.upload_to)))

    def get_filename(self, filename):
        return os.path.normpath(self.storage.get_valid_name(os.path.basename(filename)))

    def generate_filename(self, instance, filename):
        return os.path.join(self.get_directory_name(), self.get_filename(filename))


    def to_mongo(self, value):
    # Store the path in MongoDB
    # I also used this bit to actually save the file to disk.
    # The value I'm getting here is a FileFiled and it all looks
    # pretty good at this stage even though I'm not 100% sure
    # of what's going on.

        import ipdb; ipdb.set_trace()

        if not value._committed and value is not None:
            value.save(value.name, value)
            return value.path

        return value.path    


    def to_python(self, value):
        # Now this is the real problem, value is the path that got saved
        # in mongo. No idea how to return a FileField obj from here.
        # self.instance and instance throw errors.
like image 773
holografix Avatar asked Apr 07 '13 13:04

holografix


1 Answers

I think it would be a good addition - maybe called LocalFileField to make it more framework agnostic and if you provided tests and docs it would make a great addition to https://github.com/MongoEngine/extras-mongoengine

The only reason I'm not sold on having it in core - is if you are running a replicaset the file would still only be stored on one node.

like image 159
Ross Avatar answered Oct 11 '22 04:10

Ross