Opened 10 years ago
Closed 10 years ago
#26469 closed Bug (duplicate)
FieldFile.open() does not properly set mode when opening file
| Reported by: | Nathan Osman | Owned by: | nobody |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 1.9 |
| Severity: | Normal | Keywords: | |
| Cc: | Triage Stage: | Unreviewed | |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Consider the following model definition:
class Thing(models.Model):
file = models.FileField(upload_to="things")
Let's suppose I have an existing model instance and I want to open the file for writing:
t = Thing.objects.get(pk=1)
t.file.open('wb')
t.file.write(data)
This raises an unexpected exception:
IOError: File not open for writing
Here's the source code for FieldFile.open():
def open(self, mode='rb'):
self._require_file()
self.file.open(mode)
The second line in the body accesses self.file - a property which is defined as follows:
def _get_file(self):
self._require_file()
if not hasattr(self, '_file') or self._file is None:
self._file = self.storage.open(self.name, 'rb')
return self._file
# ...
file = property(_get_file, ...
If self._file is None (which is the case in my example above), the storage backend is then instructed to open the file with mode 'rb' instead of the mode that was originally passed to FieldFile.open(). The newly opened File instance is returned and control resumes in FieldFile.open() which invokes the open() method on the File instance.
Here are the first few lines of File.open():
def open(self, mode=None):
if not self.closed:
self.seek(0)
elif self.name and os.path.exists(self.name):
self.file = open(self.name, mode or self.mode)
# ...
Since the file is already open, not self.closed evaluates to True and the file remains open in read-only mode. It is not possible to write to the file.
Duplicate of #26398. This should be fixed in master.