david / semanticdjango (http://semanticdjango.org/)

fork of django-trunk

The right time for a semantic contrib, that's my pony.

Clone this repository (size: 23.1 MB): HTTPS / SSH
$ hg clone http://code.welldev.org/semanticdjango
commit 6477: 397c8c6c2959
parent 6476: ce1bfac55ea2
branch: default
Fixed #10044: You can now assign directly to file fields (`instance.filefield = somefile`). Thanks, Marty Alchin.
jacob
19 months ago

Changed (Δ1.6 KB):

raw changeset »

django/core/files/base.py (2 lines added, 0 lines removed)

django/db/models/fields/files.py (26 lines added, 7 lines removed)

tests/modeltests/files/models.py (18 lines added, 0 lines removed)

Up to file-list django/core/files/base.py:

@@ -32,6 +32,8 @@ class File(object):
32
32
        return self.size
33
33
34
34
    def _get_name(self):
35
        if not hasattr(self, '_name'):
36
            raise ValueError("This operation requires the file to have a name.")
35
37
        return self._name
36
38
    name = property(_get_name)
37
39

Up to file-list django/db/models/fields/files.py:

1
import copy
1
2
import datetime
2
3
import os
3
4
@@ -21,6 +22,7 @@ class FieldFile(File):
21
22
        self.storage = field.storage
22
23
        self._name = name or u''
23
24
        self._closed = False
25
        self._committed = True
24
26
25
27
    def __eq__(self, other):
26
28
        # Older code may be expecting FileField values to be simple strings.
@@ -79,6 +81,7 @@ class FieldFile(File):
79
81
80
82
        # Update the filesize cache
81
83
        self._size = len(content)
84
        self._committed = True
82
85
83
86
        # Save the object because it has changed, unless save is False
84
87
        if save:
@@ -100,6 +103,7 @@ class FieldFile(File):
100
103
        # Delete the filesize cache
101
104
        if hasattr(self, '_size'):
102
105
            del self._size
106
        self._committed = False
103
107
104
108
        if save:
105
109
            self.instance.save()
@@ -110,7 +114,7 @@ class FieldFile(File):
110
114
        # it's attached to in order to work properly, but the only necessary
111
115
        # data to be pickled is the file's name itself. Everything else will
112
116
        # be restored later, by FileDescriptor below.
113
        return {'_name': self.name, '_closed': False}
117
        return {'_name': self.name, '_closed': False, '_committed': True}
114
118
115
119
class FileDescriptor(object):
116
120
    def __init__(self, field):
@@ -120,10 +124,21 @@ class FileDescriptor(object):
120
124
        if instance is None:
121
125
            raise AttributeError, "%s can only be accessed from %s instances." % (self.field.name(self.owner.__name__))
122
126
        file = instance.__dict__[self.field.name]
123
        if not isinstance(file, FieldFile):
127
        if isinstance(file, basestring) or file is None:
124
128
            # Create a new instance of FieldFile, based on a given file name
125
129
            instance.__dict__[self.field.name] = self.field.attr_class(instance, self.field, file)
126
        elif not hasattr(file, 'field'):
130
        elif isinstance(file, File) and not isinstance(file, FieldFile):
131
            # Other types of files may be assigned as well, but they need to
132
            # have the FieldFile interface added to them
133
            file_copy = copy.copy(file)
134
            file_copy.__class__ = type(file.__class__.__name__, 
135
                                       (file.__class__, FieldFile), {})
136
            file_copy.instance = instance
137
            file_copy.field = self.field
138
            file_copy.storage = self.field.storage
139
            file_copy._committed = False
140
            instance.__dict__[self.field.name] = file_copy
141
        elif isinstance(file, FieldFile) and not hasattr(file, 'field'):
127
142
            # The FieldFile was pickled, so some attributes need to be reset.
128
143
            file.instance = instance
129
144
            file.field = self.field
@@ -164,6 +179,14 @@ class FileField(Field):
164
179
            return None
165
180
        return unicode(value)
166
181
182
    def pre_save(self, model_instance, add):
183
        "Returns field's value just before saving."
184
        file = super(FileField, self).pre_save(model_instance, add)
185
        if file and not file._committed:
186
            # Commit the file to storage prior to saving the model
187
            file.save(file.name, file, save=False)
188
        return file
189
167
190
    def contribute_to_class(self, cls, name):
168
191
        super(FileField, self).contribute_to_class(cls, name)
169
192
        setattr(cls, self.name, FileDescriptor(self))
@@ -190,10 +213,6 @@ class FileField(Field):
190
213
    def generate_filename(self, instance, filename):
191
214
        return os.path.join(self.get_directory_name(), self.get_filename(filename))
192
215
193
    def save_form_data(self, instance, data):
194
        if data and isinstance(data, UploadedFile):
195
            getattr(instance, self.name).save(data.name, data, save=False)
196
197
216
    def formfield(self, **kwargs):
198
217
        defaults = {'form_class': forms.FileField}
199
218
        # If a file has been provided previously, then the form doesn't require

Up to file-list tests/modeltests/files/models.py:

@@ -9,6 +9,7 @@ import shutil
9
9
import tempfile
10
10
from django.db import models
11
11
from django.core.files.base import ContentFile
12
from django.core.files.uploadedfile import SimpleUploadedFile
12
13
from django.core.files.storage import FileSystemStorage
13
14
from django.core.cache import cache
14
15
@@ -54,6 +55,23 @@ 7
54
55
>>> obj1.normal.read()
55
56
'content'
56
57
58
# File objects can be assigned to FileField attributes,  but shouldn't get
59
# committed until the model it's attached to is saved.
60
61
>>> obj1.normal = SimpleUploadedFile('assignment.txt', 'content')
62
>>> dirs, files = temp_storage.listdir('tests')
63
>>> dirs
64
[]
65
>>> files.sort()
66
>>> files
67
[u'default.txt', u'django_test.txt']
68
69
>>> obj1.save()
70
>>> dirs, files = temp_storage.listdir('tests')
71
>>> files.sort()
72
>>> files
73
[u'assignment.txt', u'default.txt', u'django_test.txt']
74
57
75
# Files can be read in a little at a time, if necessary.
58
76
59
77
>>> obj1.normal.open()