src/ldt/ldt/apps.py
author ymh <ymh.work@gmail.com>
Thu, 10 Sep 2015 12:06:33 +0200
changeset 1429 bb5fc6324484
parent 1420 0637048db5d4
permissions -rw-r--r--
Increment version
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
1420
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
     1
# -*- coding: utf-8 -*-
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
     2
'''
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
     3
Created on Sep 1, 2015
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
     4
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
     5
@author: ymh
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
     6
'''
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
     7
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
     8
from django.apps import AppConfig
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
     9
from django.core.files.base import File
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    10
from django.db.models.fields.files import FieldFile
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    11
from django.db.models.fields.files import FileDescriptor
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    12
import six
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    13
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    14
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    15
def ldt_get(self, instance=None, owner=None):
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    16
    if instance is None:
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    17
        raise AttributeError(
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    18
            "The '%s' attribute can only be accessed from %s instances."
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    19
            % (self.field.name, owner.__name__))
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    20
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    21
    # This is slightly complicated, so worth an explanation.
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    22
    # instance.file`needs to ultimately return some instance of `File`,
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    23
    # probably a subclass. Additionally, this returned object needs to have
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    24
    # the FieldFile API so that users can easily do things like
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    25
    # instance.file.path and have that delegated to the file storage engine.
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    26
    # Easy enough if we're strict about assignment in __set__, but if you
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    27
    # peek below you can see that we're not. So depending on the current
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    28
    # value of the field we have to dynamically construct some sort of
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    29
    # "thing" to return.
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    30
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    31
    # The instance dict contains whatever was originally assigned
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    32
    # in __set__.
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    33
    file = instance.__dict__[self.field.name]  # @ReservedAssignment
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    34
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    35
    # If this value is callable (certainly because the field was defined
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    36
    # with a callable default), we execute the function and assign the
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    37
    # result to the value
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    38
    if six.callable(file):
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    39
        file = file()  # @ReservedAssignment
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    40
        if isinstance(file, FieldFile) and not hasattr(file, 'field'):
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    41
            instance.__dict__[self.field.name] = file
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    42
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    43
    # If this value is a string (instance.file = "path/to/file") or None
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    44
    # then we simply wrap it with the appropriate attribute class according
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    45
    # to the file field. [This is FieldFile for FileFields and
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    46
    # ImageFieldFile for ImageFields; it's also conceivable that user
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    47
    # subclasses might also want to subclass the attribute class]. This
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    48
    # object understands how to convert a path to a file, and also how to
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    49
    # handle None.
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    50
    if isinstance(file, six.string_types) or file is None:
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    51
        attr = self.field.attr_class(instance, self.field, file)
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    52
        instance.__dict__[self.field.name] = attr
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    53
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    54
    # Other types of files may be assigned as well, but they need to have
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    55
    # the FieldFile interface added to them. Thus, we wrap any other type of
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    56
    # File inside a FieldFile (well, the field's attr_class, which is
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    57
    # usually FieldFile).
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    58
    elif isinstance(file, File) and not isinstance(file, FieldFile):
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    59
        file_copy = self.field.attr_class(instance, self.field, file.name)
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    60
        file_copy.file = file
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    61
        file_copy._committed = False
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    62
        instance.__dict__[self.field.name] = file_copy
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    63
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    64
    # Finally, because of the (some would say boneheaded) way pickle works,
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    65
    # the underlying FieldFile might not actually itself have an associated
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    66
    # file. So we need to reset the details of the FieldFile in those cases.
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    67
    elif isinstance(file, FieldFile) and not hasattr(file, 'field'):
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    68
        file.instance = instance
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    69
        file.field = self.field
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    70
        file.storage = self.field.storage
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    71
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    72
    # That was fun, wasn't it?
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    73
    return instance.__dict__[self.field.name]
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    74
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    75
class LdtAppConfig(AppConfig):
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    76
    '''
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    77
    App config to monkey patch django.db.models.fields.files.FileDescriptor.__get__ (cf django bug #24823 https://code.djangoproject.com/ticket/24823)
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    78
    '''
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    79
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    80
    name = 'ldt'
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    81
    verbose_name = 'LDT Platform'
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    82
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    83
    def ready(self):
0637048db5d4 Add a monkey patch to "
ymh <ymh.work@gmail.com>
parents:
diff changeset
    84
        FileDescriptor.__get__ = ldt_get