diff --git a/django/core/files/storage.py b/django/core/files/storage.py
index bf30a78..3fb2a2f 100644
|
a
|
b
|
|
| 1 | 1 | import os |
| 2 | 2 | import errno |
| 3 | 3 | import urlparse |
| | 4 | import itertools |
| 4 | 5 | |
| 5 | 6 | from django.conf import settings |
| 6 | 7 | from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation |
| … |
… |
class Storage(object):
|
| 63 | 64 | Returns a filename that's free on the target storage system, and |
| 64 | 65 | available for new content to be written to. |
| 65 | 66 | """ |
| 66 | | # If the filename already exists, keep adding an underscore to the name |
| 67 | | # of the file until the filename doesn't exist. |
| 68 | | while self.exists(name): |
| | 67 | # If the filename already exists, add a number to the filename |
| | 68 | # until an available name is found. |
| | 69 | if self.exists(name): |
| | 70 | # Build a filename template out of the (existing) name |
| 69 | 71 | try: |
| 70 | 72 | dot_index = name.rindex('.') |
| 71 | 73 | except ValueError: # filename has no dot |
| 72 | | name += '_' |
| | 74 | template = "%s_%%d" % (name,) |
| 73 | 75 | else: |
| 74 | | name = name[:dot_index] + '_' + name[dot_index:] |
| | 76 | template = "%s_%%d%s" % (name[:dot_index], name[dot_index:],) |
| | 77 | # Iterate indefinitely until a filename is found. |
| | 78 | count = itertools.count(1) |
| | 79 | while self.exists(name): |
| | 80 | name = template % count.next() |
| 75 | 81 | return name |
| 76 | 82 | |
| 77 | 83 | def path(self, name): |
diff --git a/tests/modeltests/files/models.py b/tests/modeltests/files/models.py
index ba3eb99..182eab7 100644
|
a
|
b
|
ValueError: The 'normal' attribute has no file associated with it.
|
| 93 | 93 | >>> obj2 = Storage() |
| 94 | 94 | >>> obj2.normal.save('django_test.txt', ContentFile('more content')) |
| 95 | 95 | >>> obj2.normal |
| 96 | | <FieldFile: tests/django_test_.txt> |
| | 96 | <FieldFile: tests/django_test_1.txt> |
| 97 | 97 | >>> obj2.normal.size |
| 98 | 98 | 12 |
| 99 | 99 | |
| … |
… |
ValueError: The 'normal' attribute has no file associated with it.
|
| 102 | 102 | >>> cache.set('obj1', obj1) |
| 103 | 103 | >>> cache.set('obj2', obj2) |
| 104 | 104 | >>> cache.get('obj2').normal |
| 105 | | <FieldFile: tests/django_test_.txt> |
| | 105 | <FieldFile: tests/django_test_1.txt> |
| 106 | 106 | |
| 107 | 107 | # Deleting an object deletes the file it uses, if there are no other objects |
| 108 | 108 | # still using that file. |
| … |
… |
ValueError: The 'normal' attribute has no file associated with it.
|
| 110 | 110 | >>> obj2.delete() |
| 111 | 111 | >>> obj2.normal.save('django_test.txt', ContentFile('more content')) |
| 112 | 112 | >>> obj2.normal |
| 113 | | <FieldFile: tests/django_test_.txt> |
| | 113 | <FieldFile: tests/django_test_1.txt> |
| 114 | 114 | |
| 115 | 115 | # Default values allow an object to access a single file. |
| 116 | 116 | |
diff --git a/tests/regressiontests/file_storage/tests.py b/tests/regressiontests/file_storage/tests.py
index 6b219f0..bb1f3eb 100644
|
a
|
b
|
class FileSaveRaceConditionTest(TestCase):
|
| 121 | 121 | name = self.save_file('conflict') |
| 122 | 122 | self.thread.join() |
| 123 | 123 | self.assert_(self.storage.exists('conflict')) |
| 124 | | self.assert_(self.storage.exists('conflict_')) |
| | 124 | self.assert_(self.storage.exists('conflict_1')) |
| 125 | 125 | self.storage.delete('conflict') |
| 126 | | self.storage.delete('conflict_') |
| | 126 | self.storage.delete('conflict_1') |
| 127 | 127 | |
| 128 | 128 | class FileStoragePermissions(TestCase): |
| 129 | 129 | def setUp(self): |