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.
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 |
|
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 |
|
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() |
