Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
D
django
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
django
Commits
a7c256cb
Kaydet (Commit)
a7c256cb
authored
Eki 15, 2014
tarafından
Pavel Shpilev
Kaydeden (comit)
Tim Graham
Ock 12, 2015
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
Fixed #9893 -- Allowed using a field's max_length in the Storage.
üst
b5c1a85b
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
194 additions
and
21 deletions
+194
-21
storage.py
django/core/files/storage.py
+37
-7
files.py
django/db/models/fields/files.py
+16
-1
custom-file-storage.txt
docs/howto/custom-file-storage.txt
+13
-7
deprecation.txt
docs/internals/deprecation.txt
+4
-0
storage.txt
docs/ref/files/storage.txt
+18
-2
1.8.txt
docs/releases/1.8.txt
+20
-1
models.py
tests/file_storage/models.py
+19
-0
tests.py
tests/file_storage/tests.py
+67
-3
No files found.
django/core/files/storage.py
Dosyayı görüntüle @
a7c256cb
import
os
import
errno
from
datetime
import
datetime
from
datetime
import
datetime
import
errno
from
inspect
import
getargspec
import
os
import
warnings
from
django.conf
import
settings
from
django.conf
import
settings
from
django.core.exceptions
import
SuspiciousFileOperation
from
django.core.files
import
locks
,
File
from
django.core.files
import
locks
,
File
from
django.core.files.move
import
file_move_safe
from
django.core.files.move
import
file_move_safe
from
django.utils.crypto
import
get_random_string
from
django.utils.crypto
import
get_random_string
...
@@ -13,6 +16,7 @@ from django.utils.six.moves.urllib.parse import urljoin
...
@@ -13,6 +16,7 @@ from django.utils.six.moves.urllib.parse import urljoin
from
django.utils.text
import
get_valid_filename
from
django.utils.text
import
get_valid_filename
from
django.utils._os
import
safe_join
,
abspathu
from
django.utils._os
import
safe_join
,
abspathu
from
django.utils.deconstruct
import
deconstructible
from
django.utils.deconstruct
import
deconstructible
from
django.utils.deprecation
import
RemovedInDjango20Warning
__all__
=
(
'Storage'
,
'FileSystemStorage'
,
'DefaultStorage'
,
'default_storage'
)
__all__
=
(
'Storage'
,
'FileSystemStorage'
,
'DefaultStorage'
,
'default_storage'
)
...
@@ -33,7 +37,7 @@ class Storage(object):
...
@@ -33,7 +37,7 @@ class Storage(object):
"""
"""
return
self
.
_open
(
name
,
mode
)
return
self
.
_open
(
name
,
mode
)
def
save
(
self
,
name
,
content
):
def
save
(
self
,
name
,
content
,
max_length
=
None
):
"""
"""
Saves new content to the file specified by name. The content should be
Saves new content to the file specified by name. The content should be
a proper File object or any python file-like object, ready to be read
a proper File object or any python file-like object, ready to be read
...
@@ -46,7 +50,18 @@ class Storage(object):
...
@@ -46,7 +50,18 @@ class Storage(object):
if
not
hasattr
(
content
,
'chunks'
):
if
not
hasattr
(
content
,
'chunks'
):
content
=
File
(
content
)
content
=
File
(
content
)
name
=
self
.
get_available_name
(
name
)
args
,
varargs
,
varkw
,
defaults
=
getargspec
(
self
.
get_available_name
)
if
'max_length'
in
args
:
name
=
self
.
get_available_name
(
name
,
max_length
=
max_length
)
else
:
warnings
.
warn
(
'Backwards compatibility for storage backends without '
'support for the `max_length` argument in '
'Storage.get_available_name() will be removed in Django 2.0.'
,
RemovedInDjango20Warning
,
stacklevel
=
2
)
name
=
self
.
get_available_name
(
name
)
name
=
self
.
_save
(
name
,
content
)
name
=
self
.
_save
(
name
,
content
)
# Store filenames with forward slashes, even on Windows
# Store filenames with forward slashes, even on Windows
...
@@ -61,7 +76,7 @@ class Storage(object):
...
@@ -61,7 +76,7 @@ class Storage(object):
"""
"""
return
get_valid_filename
(
name
)
return
get_valid_filename
(
name
)
def
get_available_name
(
self
,
name
):
def
get_available_name
(
self
,
name
,
max_length
=
None
):
"""
"""
Returns a filename that's free on the target storage system, and
Returns a filename that's free on the target storage system, and
available for new content to be written to.
available for new content to be written to.
...
@@ -71,10 +86,25 @@ class Storage(object):
...
@@ -71,10 +86,25 @@ class Storage(object):
# If the filename already exists, add an underscore and a random 7
# If the filename already exists, add an underscore and a random 7
# character alphanumeric string (before the file extension, if one
# character alphanumeric string (before the file extension, if one
# exists) to the filename until the generated filename doesn't exist.
# exists) to the filename until the generated filename doesn't exist.
while
self
.
exists
(
name
):
# Truncate original name if required, so the new filename does not
# exceed the max_length.
while
self
.
exists
(
name
)
or
(
max_length
and
len
(
name
)
>
max_length
):
# file_ext includes the dot.
# file_ext includes the dot.
name
=
os
.
path
.
join
(
dir_name
,
"
%
s_
%
s
%
s"
%
(
file_root
,
get_random_string
(
7
),
file_ext
))
name
=
os
.
path
.
join
(
dir_name
,
"
%
s_
%
s
%
s"
%
(
file_root
,
get_random_string
(
7
),
file_ext
))
if
max_length
is
None
:
continue
# Truncate file_root if max_length exceeded.
truncation
=
len
(
name
)
-
max_length
if
truncation
>
0
:
file_root
=
file_root
[:
-
truncation
]
# Entire file_root was truncated in attempt to find an available filename.
if
not
file_root
:
raise
SuspiciousFileOperation
(
'Storage can not find an available filename for "
%
s". '
'Please make sure that the corresponding file field '
'allows sufficient "max_length".'
%
name
)
name
=
os
.
path
.
join
(
dir_name
,
"
%
s_
%
s
%
s"
%
(
file_root
,
get_random_string
(
7
),
file_ext
))
return
name
return
name
def
path
(
self
,
name
):
def
path
(
self
,
name
):
...
...
django/db/models/fields/files.py
Dosyayı görüntüle @
a7c256cb
import
datetime
import
datetime
from
inspect
import
getargspec
import
os
import
os
import
warnings
from
django
import
forms
from
django
import
forms
from
django.db.models.fields
import
Field
from
django.db.models.fields
import
Field
...
@@ -11,6 +13,7 @@ from django.db.models import signals
...
@@ -11,6 +13,7 @@ from django.db.models import signals
from
django.utils.encoding
import
force_str
,
force_text
from
django.utils.encoding
import
force_str
,
force_text
from
django.utils
import
six
from
django.utils
import
six
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.deprecation
import
RemovedInDjango20Warning
class
FieldFile
(
File
):
class
FieldFile
(
File
):
...
@@ -85,7 +88,19 @@ class FieldFile(File):
...
@@ -85,7 +88,19 @@ class FieldFile(File):
def
save
(
self
,
name
,
content
,
save
=
True
):
def
save
(
self
,
name
,
content
,
save
=
True
):
name
=
self
.
field
.
generate_filename
(
self
.
instance
,
name
)
name
=
self
.
field
.
generate_filename
(
self
.
instance
,
name
)
self
.
name
=
self
.
storage
.
save
(
name
,
content
)
args
,
varargs
,
varkw
,
defaults
=
getargspec
(
self
.
storage
.
save
)
if
'max_length'
in
args
:
self
.
name
=
self
.
storage
.
save
(
name
,
content
,
max_length
=
self
.
field
.
max_length
)
else
:
warnings
.
warn
(
'Backwards compatibility for storage backends without '
'support for the `max_length` argument in '
'Storage.save() will be removed in Django 2.0.'
,
RemovedInDjango20Warning
,
stacklevel
=
2
)
self
.
name
=
self
.
storage
.
save
(
name
,
content
)
setattr
(
self
.
instance
,
self
.
field
.
name
,
self
.
name
)
setattr
(
self
.
instance
,
self
.
field
.
name
,
self
.
name
)
# Update the filesize cache
# Update the filesize cache
...
...
docs/howto/custom-file-storage.txt
Dosyayı görüntüle @
a7c256cb
...
@@ -50,7 +50,7 @@ typically have to be overridden:
...
@@ -50,7 +50,7 @@ typically have to be overridden:
* :meth:`Storage.size`
* :meth:`Storage.size`
* :meth:`Storage.url`
* :meth:`Storage.url`
Note however that not all these methods are required and may be deliberately
Note however that not all these methods are required and may be deliberately
omitted. As it happens, it is possible to leave each method unimplemented and
omitted. As it happens, it is possible to leave each method unimplemented and
still have a working Storage.
still have a working Storage.
...
@@ -87,7 +87,6 @@ instead).
...
@@ -87,7 +87,6 @@ instead).
.. method:: get_valid_name(name)
.. method:: get_valid_name(name)
Returns a filename suitable for use with the underlying storage system. The
Returns a filename suitable for use with the underlying storage system. The
``name`` argument passed to this method is the original filename sent to the
``name`` argument passed to this method is the original filename sent to the
server, after having any path information removed. Override this to customize
server, after having any path information removed. Override this to customize
...
@@ -96,21 +95,28 @@ how non-standard characters are converted to safe filenames.
...
@@ -96,21 +95,28 @@ how non-standard characters are converted to safe filenames.
The code provided on ``Storage`` retains only alpha-numeric characters, periods
The code provided on ``Storage`` retains only alpha-numeric characters, periods
and underscores from the original filename, removing everything else.
and underscores from the original filename, removing everything else.
.. method:: get_available_name(name)
.. method:: get_available_name(name
, max_length=None
)
Returns a filename that is available in the storage mechanism, possibly taking
Returns a filename that is available in the storage mechanism, possibly taking
the provided filename into account. The ``name`` argument passed to this method
the provided filename into account. The ``name`` argument passed to this method
will have already cleaned to a filename valid for the storage system, according
will have already cleaned to a filename valid for the storage system, according
to the ``get_valid_name()`` method described above.
to the ``get_valid_name()`` method described above.
.. versionchanged:: 1.7
The length of the filename will not exceed ``max_length``, if provided. If a
free unique filename cannot be found, a :exc:`SuspiciousFileOperation
<django.core.exceptions.SuspiciousOperation>` exception is raised.
If a file with ``name`` already exists, an underscore plus a random 7 character
alphanumeric string is appended to the filename before the extension.
If a file with ``name`` already exists, an underscore plus a random 7
.. versionchanged:: 1.7
character alphanumeric string is appended to the filename before the
extension.
Previously, an underscore followed by a number (e.g. ``"_1"``, ``"_2"``,
Previously, an underscore followed by a number (e.g. ``"_1"``, ``"_2"``,
etc.) was appended to the filename until an available name in the destination
etc.) was appended to the filename until an available name in the destination
directory was found. A malicious user could exploit this deterministic
directory was found. A malicious user could exploit this deterministic
algorithm to create a denial-of-service attack. This change was also made
algorithm to create a denial-of-service attack. This change was also made
in Django 1.6.6, 1.5.9, and 1.4.14.
in Django 1.6.6, 1.5.9, and 1.4.14.
.. versionchanged:: 1.8
The ``max_length`` argument was added.
docs/internals/deprecation.txt
Dosyayı görüntüle @
a7c256cb
...
@@ -143,6 +143,10 @@ details on these changes.
...
@@ -143,6 +143,10 @@ details on these changes.
* Support for the ``=`` comparison operator in the ``if`` template tag will be
* Support for the ``=`` comparison operator in the ``if`` template tag will be
removed.
removed.
* The backwards compatibility shims to allow ``Storage.get_available_name()``
and ``Storage.save()`` to be defined without a ``max_length`` argument will
be removed.
.. _deprecation-removed-in-1.9:
.. _deprecation-removed-in-1.9:
1.9
1.9
...
...
docs/ref/files/storage.txt
Dosyayı görüntüle @
a7c256cb
...
@@ -114,12 +114,17 @@ The Storage Class
...
@@ -114,12 +114,17 @@ The Storage Class
in the storage system, or ``False`` if the name is available for a new
in the storage system, or ``False`` if the name is available for a new
file.
file.
.. method:: get_available_name(name)
.. method:: get_available_name(name
, max_length=None
)
Returns a filename based on the ``name`` parameter that's free and
Returns a filename based on the ``name`` parameter that's free and
available for new content to be written to on the target storage
available for new content to be written to on the target storage
system.
system.
The length of the filename will not exceed ``max_length``, if provided.
If a free unique filename cannot be found, a
:exc:`SuspiciousFileOperation
<django.core.exceptions.SuspiciousOperation>` exception will be raised.
If a file with ``name`` already exists, an underscore plus a random
If a file with ``name`` already exists, an underscore plus a random
7 character alphanumeric string is appended to the filename before
7 character alphanumeric string is appended to the filename before
the extension.
the extension.
...
@@ -133,6 +138,10 @@ The Storage Class
...
@@ -133,6 +138,10 @@ The Storage Class
attack. This change was also made in Django 1.6.6, 1.5.9, and
attack. This change was also made in Django 1.6.6, 1.5.9, and
1.4.14.
1.4.14.
.. versionchanged:: 1.8
The ``max_length`` argument was added.
.. method:: get_valid_name(name)
.. method:: get_valid_name(name)
Returns a filename based on the ``name`` parameter that's suitable
Returns a filename based on the ``name`` parameter that's suitable
...
@@ -165,17 +174,24 @@ The Storage Class
...
@@ -165,17 +174,24 @@ The Storage Class
standard ``open()``. For storage systems that aren't accessible from
standard ``open()``. For storage systems that aren't accessible from
the local filesystem, this will raise ``NotImplementedError`` instead.
the local filesystem, this will raise ``NotImplementedError`` instead.
.. method:: save(name, content)
.. method:: save(name, content
, max_length=None
)
Saves a new file using the storage system, preferably with the name
Saves a new file using the storage system, preferably with the name
specified. If there already exists a file with this name ``name``, the
specified. If there already exists a file with this name ``name``, the
storage system may modify the filename as necessary to get a unique
storage system may modify the filename as necessary to get a unique
name. The actual name of the stored file will be returned.
name. The actual name of the stored file will be returned.
The ``max_length`` argument is passed along to
:meth:`get_available_name`.
The ``content`` argument must be an instance of
The ``content`` argument must be an instance of
:class:`django.core.files.File` or of a subclass of
:class:`django.core.files.File` or of a subclass of
:class:`~django.core.files.File`.
:class:`~django.core.files.File`.
.. versionchanged:: 1.8
The ``max_length`` argument was added.
.. method:: size(name)
.. method:: size(name)
Returns the total size, in bytes, of the file referenced by ``name``.
Returns the total size, in bytes, of the file referenced by ``name``.
...
...
docs/releases/1.8.txt
Dosyayı görüntüle @
a7c256cb
...
@@ -317,7 +317,15 @@ Email
...
@@ -317,7 +317,15 @@ Email
File Storage
File Storage
^^^^^^^^^^^^
^^^^^^^^^^^^
* ...
* :meth:`Storage.get_available_name()
<django.core.files.storage.Storage.get_available_name>` and
:meth:`Storage.save() <django.core.files.storage.Storage.save>`
now take a ``max_length`` argument to implement storage-level maximum
filename length constraints. Filenames exceeding this argument will get
truncated. This prevents a database error when appending a unique suffix to a
long filename that already exists on the storage. See the :ref:`deprecation
note <storage-max-length-update>` about adding this argument to your custom
storage classes.
File Uploads
File Uploads
^^^^^^^^^^^^
^^^^^^^^^^^^
...
@@ -1432,6 +1440,17 @@ loader that inherits ``BaseLoader``, you must inherit ``Loader`` instead.
...
@@ -1432,6 +1440,17 @@ loader that inherits ``BaseLoader``, you must inherit ``Loader`` instead.
Private API ``django.test.utils.TestTemplateLoader`` is deprecated in favor of
Private API ``django.test.utils.TestTemplateLoader`` is deprecated in favor of
``django.template.loaders.locmem.Loader``.
``django.template.loaders.locmem.Loader``.
.. _storage-max-length-update:
Support for the ``max_length`` argument on custom ``Storage`` classes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``Storage`` subclasses should add ``max_length=None`` as a parameter to
:meth:`~django.core.files.storage.Storage.get_available_name` and/or
:meth:`~django.core.files.storage.Storage.save` if they override either method.
Support for storages that do not accept this argument will be removed in
Django 2.0.
``qn`` replaced by ``compiler``
``qn`` replaced by ``compiler``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
...
tests/file_storage/models.py
Dosyayı görüntüle @
a7c256cb
...
@@ -13,6 +13,19 @@ from django.db import models
...
@@ -13,6 +13,19 @@ from django.db import models
from
django.core.files.storage
import
FileSystemStorage
from
django.core.files.storage
import
FileSystemStorage
class
OldStyleFSStorage
(
FileSystemStorage
):
"""
Storage backend without support for the ``max_length`` argument in
``get_available_name()`` and ``save()``; for backward-compatibility and
deprecation testing.
"""
def
get_available_name
(
self
,
name
):
return
name
def
save
(
self
,
name
,
content
):
return
super
(
OldStyleFSStorage
,
self
)
.
save
(
name
,
content
)
temp_storage_location
=
tempfile
.
mkdtemp
(
dir
=
os
.
environ
[
'DJANGO_TEST_TEMP_DIR'
])
temp_storage_location
=
tempfile
.
mkdtemp
(
dir
=
os
.
environ
[
'DJANGO_TEST_TEMP_DIR'
])
temp_storage
=
FileSystemStorage
(
location
=
temp_storage_location
)
temp_storage
=
FileSystemStorage
(
location
=
temp_storage_location
)
...
@@ -31,3 +44,9 @@ class Storage(models.Model):
...
@@ -31,3 +44,9 @@ class Storage(models.Model):
random
=
models
.
FileField
(
storage
=
temp_storage
,
upload_to
=
random_upload_to
)
random
=
models
.
FileField
(
storage
=
temp_storage
,
upload_to
=
random_upload_to
)
default
=
models
.
FileField
(
storage
=
temp_storage
,
upload_to
=
'tests'
,
default
=
'tests/default.txt'
)
default
=
models
.
FileField
(
storage
=
temp_storage
,
upload_to
=
'tests'
,
default
=
'tests/default.txt'
)
empty
=
models
.
FileField
(
storage
=
temp_storage
)
empty
=
models
.
FileField
(
storage
=
temp_storage
)
limited_length
=
models
.
FileField
(
storage
=
temp_storage
,
upload_to
=
'tests'
,
max_length
=
20
)
extended_length
=
models
.
FileField
(
storage
=
temp_storage
,
upload_to
=
'tests'
,
max_length
=
300
)
old_style
=
models
.
FileField
(
storage
=
OldStyleFSStorage
(
location
=
temp_storage_location
),
upload_to
=
'tests'
,
)
tests/file_storage/tests.py
Dosyayı görüntüle @
a7c256cb
...
@@ -8,6 +8,7 @@ import sys
...
@@ -8,6 +8,7 @@ import sys
import
tempfile
import
tempfile
import
time
import
time
import
unittest
import
unittest
import
warnings
from
datetime
import
datetime
,
timedelta
from
datetime
import
datetime
,
timedelta
try
:
try
:
...
@@ -16,7 +17,7 @@ except ImportError:
...
@@ -16,7 +17,7 @@ except ImportError:
import
dummy_threading
as
threading
import
dummy_threading
as
threading
from
django.core.cache
import
cache
from
django.core.cache
import
cache
from
django.core.exceptions
import
SuspiciousOperation
from
django.core.exceptions
import
SuspiciousOperation
,
SuspiciousFileOperation
from
django.core.files.base
import
File
,
ContentFile
from
django.core.files.base
import
File
,
ContentFile
from
django.core.files.storage
import
FileSystemStorage
,
get_storage_class
from
django.core.files.storage
import
FileSystemStorage
,
get_storage_class
from
django.core.files.uploadedfile
import
(
InMemoryUploadedFile
,
SimpleUploadedFile
,
from
django.core.files.uploadedfile
import
(
InMemoryUploadedFile
,
SimpleUploadedFile
,
...
@@ -407,7 +408,7 @@ class FileStorageTests(unittest.TestCase):
...
@@ -407,7 +408,7 @@ class FileStorageTests(unittest.TestCase):
class
CustomStorage
(
FileSystemStorage
):
class
CustomStorage
(
FileSystemStorage
):
def
get_available_name
(
self
,
name
):
def
get_available_name
(
self
,
name
,
max_length
=
None
):
"""
"""
Append numbers to duplicate files rather than underscores, like Trac.
Append numbers to duplicate files rather than underscores, like Trac.
"""
"""
...
@@ -433,7 +434,7 @@ class CustomStorageTests(FileStorageTests):
...
@@ -433,7 +434,7 @@ class CustomStorageTests(FileStorageTests):
self
.
storage
.
delete
(
second
)
self
.
storage
.
delete
(
second
)
class
FileFieldStorageTests
(
unittest
.
TestCase
):
class
FileFieldStorageTests
(
Simple
TestCase
):
def
tearDown
(
self
):
def
tearDown
(
self
):
shutil
.
rmtree
(
temp_storage_location
)
shutil
.
rmtree
(
temp_storage_location
)
...
@@ -503,6 +504,69 @@ class FileFieldStorageTests(unittest.TestCase):
...
@@ -503,6 +504,69 @@ class FileFieldStorageTests(unittest.TestCase):
for
o
in
objs
:
for
o
in
objs
:
o
.
delete
()
o
.
delete
()
def
test_file_truncation
(
self
):
# Given the max_length is limited, when multiple files get uploaded
# under the same name, then the filename get truncated in order to fit
# in _(7 random chars). When most of the max_length is taken by
# dirname + extension and there are not enough characters in the
# filename to truncate, an exception should be raised.
objs
=
[
Storage
()
for
i
in
range
(
2
)]
filename
=
'filename.ext'
for
o
in
objs
:
o
.
limited_length
.
save
(
filename
,
ContentFile
(
'Same Content'
))
try
:
# Testing truncation.
names
=
[
o
.
limited_length
.
name
for
o
in
objs
]
self
.
assertEqual
(
names
[
0
],
'tests/
%
s'
%
filename
)
six
.
assertRegex
(
self
,
names
[
1
],
'tests/fi_
%
s.ext'
%
FILE_SUFFIX_REGEX
)
# Testing exception is raised when filename is too short to truncate.
filename
=
'short.longext'
objs
[
0
]
.
limited_length
.
save
(
filename
,
ContentFile
(
'Same Content'
))
self
.
assertRaisesMessage
(
SuspiciousFileOperation
,
'Storage can not find an available filename'
,
objs
[
1
]
.
limited_length
.
save
,
*
(
filename
,
ContentFile
(
'Same Content'
))
)
finally
:
for
o
in
objs
:
o
.
delete
()
def
test_extended_length_storage
(
self
):
# Testing FileField with max_length > 255. Most systems have filename
# length limitation of 255. Path takes extra chars.
filename
=
251
*
'a'
# 4 chars for extension.
obj
=
Storage
()
obj
.
extended_length
.
save
(
'
%
s.txt'
%
filename
,
ContentFile
(
'Same Content'
))
self
.
assertEqual
(
obj
.
extended_length
.
name
,
'tests/
%
s.txt'
%
filename
)
self
.
assertEqual
(
obj
.
extended_length
.
read
(),
b
'Same Content'
)
obj
.
extended_length
.
close
()
def
test_old_style_storage
(
self
):
# Testing backward-compatibility with old-style storage backends that
# don't take ``max_length`` parameter in ``get_available_name()``
# and save(). A deprecation warning should be raised.
obj
=
Storage
()
with
warnings
.
catch_warnings
(
record
=
True
)
as
warns
:
warnings
.
simplefilter
(
'always'
)
obj
.
old_style
.
save
(
'deprecated_storage_test.txt'
,
ContentFile
(
'Same Content'
))
self
.
assertEqual
(
len
(
warns
),
2
)
self
.
assertEqual
(
str
(
warns
[
0
]
.
message
),
'Backwards compatibility for storage backends without support for '
'the `max_length` argument in Storage.save() will be removed in '
'Django 2.0.'
)
self
.
assertEqual
(
str
(
warns
[
1
]
.
message
),
'Backwards compatibility for storage backends without support for '
'the `max_length` argument in Storage.get_available_name() will '
'be removed in Django 2.0.'
)
self
.
assertEqual
(
obj
.
old_style
.
name
,
'tests/deprecated_storage_test.txt'
)
self
.
assertEqual
(
obj
.
old_style
.
read
(),
b
'Same Content'
)
obj
.
old_style
.
close
()
def
test_filefield_default
(
self
):
def
test_filefield_default
(
self
):
# Default values allow an object to access a single file.
# Default values allow an object to access a single file.
temp_storage
.
save
(
'tests/default.txt'
,
ContentFile
(
'default content'
))
temp_storage
.
save
(
'tests/default.txt'
,
ContentFile
(
'default content'
))
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment