Kaydet (Commit) 945e033a authored tarafından Tim Graham's avatar Tim Graham

Fixed #8918 -- Made FileField.upload_to optional.

Thanks leahculver for the suggestion and dc and vajrasky for work
on the patch.
üst b67ab75e
...@@ -120,8 +120,6 @@ def get_validation_errors(outfile, app=None): ...@@ -120,8 +120,6 @@ def get_validation_errors(outfile, app=None):
if decimalp_ok and mdigits_ok: if decimalp_ok and mdigits_ok:
if decimal_places > max_digits: if decimal_places > max_digits:
e.add(opts, invalid_values_msg % f.name) e.add(opts, invalid_values_msg % f.name)
if isinstance(f, models.FileField) and not f.upload_to:
e.add(opts, '"%s": FileFields require an "upload_to" attribute.' % f.name)
if isinstance(f, models.ImageField): if isinstance(f, models.ImageField):
try: try:
from django.utils.image import Image from django.utils.image import Image
......
...@@ -45,10 +45,9 @@ Using a :class:`~django.db.models.FileField` or an ...@@ -45,10 +45,9 @@ Using a :class:`~django.db.models.FileField` or an
account. account.
#. Add the :class:`~django.db.models.FileField` or #. Add the :class:`~django.db.models.FileField` or
:class:`~django.db.models.ImageField` to your model, making sure to :class:`~django.db.models.ImageField` to your model, defining the
define the :attr:`~django.db.models.FileField.upload_to` option to tell :attr:`~django.db.models.FileField.upload_to` option to specify a
Django to which subdirectory of :setting:`MEDIA_ROOT` it should upload subdirectory of :setting:`MEDIA_ROOT` to use for uploaded files.
files.
#. All that will be stored in your database is a path to the file #. All that will be stored in your database is a path to the file
(relative to :setting:`MEDIA_ROOT`). You'll most likely want to use the (relative to :setting:`MEDIA_ROOT`). You'll most likely want to use the
......
...@@ -542,7 +542,7 @@ A :class:`CharField` that checks that the value is a valid email address. ...@@ -542,7 +542,7 @@ A :class:`CharField` that checks that the value is a valid email address.
``FileField`` ``FileField``
------------- -------------
.. class:: FileField(upload_to=None, [max_length=100, **options]) .. class:: FileField([upload_to=None, max_length=100, **options])
A file-upload field. A file-upload field.
...@@ -550,10 +550,14 @@ A file-upload field. ...@@ -550,10 +550,14 @@ A file-upload field.
The ``primary_key`` and ``unique`` arguments are not supported, and will The ``primary_key`` and ``unique`` arguments are not supported, and will
raise a ``TypeError`` if used. raise a ``TypeError`` if used.
Has one **required** argument: Has two optional arguments:
.. attribute:: FileField.upload_to .. attribute:: FileField.upload_to
.. versionchanged:: 1.7
``upload_to`` was required in older versions of Django.
A local filesystem path that will be appended to your :setting:`MEDIA_ROOT` A local filesystem path that will be appended to your :setting:`MEDIA_ROOT`
setting to determine the value of the setting to determine the value of the
:attr:`~django.db.models.fields.files.FieldFile.url` attribute. :attr:`~django.db.models.fields.files.FieldFile.url` attribute.
...@@ -586,11 +590,9 @@ Has one **required** argument: ...@@ -586,11 +590,9 @@ Has one **required** argument:
when determining the final destination path. when determining the final destination path.
====================== =============================================== ====================== ===============================================
Also has one optional argument:
.. attribute:: FileField.storage .. attribute:: FileField.storage
Optional. A storage object, which handles the storage and retrieval of your A storage object, which handles the storage and retrieval of your
files. See :doc:`/topics/files` for details on how to provide this object. files. See :doc:`/topics/files` for details on how to provide this object.
The default form widget for this field is a :class:`~django.forms.FileInput`. The default form widget for this field is a :class:`~django.forms.FileInput`.
...@@ -604,9 +606,9 @@ takes a few steps: ...@@ -604,9 +606,9 @@ takes a few steps:
:setting:`MEDIA_URL` as the base public URL of that directory. Make sure :setting:`MEDIA_URL` as the base public URL of that directory. Make sure
that this directory is writable by the Web server's user account. that this directory is writable by the Web server's user account.
2. Add the :class:`FileField` or :class:`ImageField` to your model, making 2. Add the :class:`FileField` or :class:`ImageField` to your model, defining
sure to define the :attr:`~FileField.upload_to` option to tell Django the :attr:`~FileField.upload_to` option to specify a subdirectory of
to which subdirectory of :setting:`MEDIA_ROOT` it should upload files. :setting:`MEDIA_ROOT` to use for uploaded files.
3. All that will be stored in your database is a path to the file 3. All that will be stored in your database is a path to the file
(relative to :setting:`MEDIA_ROOT`). You'll most likely want to use the (relative to :setting:`MEDIA_ROOT`). You'll most likely want to use the
...@@ -807,7 +809,7 @@ The default form widget for this field is a :class:`~django.forms.TextInput`. ...@@ -807,7 +809,7 @@ The default form widget for this field is a :class:`~django.forms.TextInput`.
``ImageField`` ``ImageField``
-------------- --------------
.. class:: ImageField(upload_to=None, [height_field=None, width_field=None, max_length=100, **options]) .. class:: ImageField([upload_to=None, height_field=None, width_field=None, max_length=100, **options])
Inherits all attributes and methods from :class:`FileField`, but also Inherits all attributes and methods from :class:`FileField`, but also
validates that the uploaded object is a valid image. validates that the uploaded object is a valid image.
......
...@@ -246,6 +246,10 @@ File Uploads ...@@ -246,6 +246,10 @@ File Uploads
the file system permissions of directories created during file upload, like the file system permissions of directories created during file upload, like
:setting:`FILE_UPLOAD_PERMISSIONS` does for the files themselves. :setting:`FILE_UPLOAD_PERMISSIONS` does for the files themselves.
* The :attr:`FileField.upload_to <django.db.models.FileField.upload_to>`
attribute is now optional. If it is omitted or given ``None`` or an empty
string, a subdirectory won't be used for storing the uploaded files.
Forms Forms
^^^^^ ^^^^^
......
...@@ -28,3 +28,4 @@ class Storage(models.Model): ...@@ -28,3 +28,4 @@ class Storage(models.Model):
custom = models.FileField(storage=temp_storage, upload_to=custom_upload_to) custom = models.FileField(storage=temp_storage, upload_to=custom_upload_to)
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)
...@@ -106,6 +106,12 @@ class FileStorageTests(TestCase): ...@@ -106,6 +106,12 @@ class FileStorageTests(TestCase):
obj4.random.save("random_file", ContentFile("random content")) obj4.random.save("random_file", ContentFile("random content"))
self.assertTrue(obj4.random.name.endswith("/random_file")) self.assertTrue(obj4.random.name.endswith("/random_file"))
# upload_to can be empty, meaning it does not use subdirectory.
obj5 = Storage()
obj5.empty.save('django_test.txt', ContentFile('more content'))
self.assertEqual(obj5.empty.name, "./django_test.txt")
self.assertEqual(obj5.empty.read(), b"more content")
def test_file_object(self): def test_file_object(self):
# Create sample file # Create sample file
temp_storage.save('tests/example.txt', ContentFile('some content')) temp_storage.save('tests/example.txt', ContentFile('some content'))
......
...@@ -19,7 +19,6 @@ class FieldErrors(models.Model): ...@@ -19,7 +19,6 @@ class FieldErrors(models.Model):
decimalfield3 = models.DecimalField(max_digits="bad", decimal_places="bad") decimalfield3 = models.DecimalField(max_digits="bad", decimal_places="bad")
decimalfield4 = models.DecimalField(max_digits=9, decimal_places=10) decimalfield4 = models.DecimalField(max_digits=9, decimal_places=10)
decimalfield5 = models.DecimalField(max_digits=10, decimal_places=10) decimalfield5 = models.DecimalField(max_digits=10, decimal_places=10)
filefield = models.FileField()
choices = models.CharField(max_length=10, choices='bad') choices = models.CharField(max_length=10, choices='bad')
choices2 = models.CharField(max_length=10, choices=[(1, 2, 3), (1, 2, 3)]) choices2 = models.CharField(max_length=10, choices=[(1, 2, 3), (1, 2, 3)])
index = models.CharField(max_length=10, db_index='bad') index = models.CharField(max_length=10, db_index='bad')
...@@ -424,7 +423,6 @@ invalid_models.fielderrors: "decimalfield2": DecimalFields require a "max_digits ...@@ -424,7 +423,6 @@ invalid_models.fielderrors: "decimalfield2": DecimalFields require a "max_digits
invalid_models.fielderrors: "decimalfield3": DecimalFields require a "decimal_places" attribute that is a non-negative integer. invalid_models.fielderrors: "decimalfield3": DecimalFields require a "decimal_places" attribute that is a non-negative integer.
invalid_models.fielderrors: "decimalfield3": DecimalFields require a "max_digits" attribute that is a positive integer. invalid_models.fielderrors: "decimalfield3": DecimalFields require a "max_digits" attribute that is a positive integer.
invalid_models.fielderrors: "decimalfield4": DecimalFields require a "max_digits" attribute value that is greater than or equal to the value of the "decimal_places" attribute. invalid_models.fielderrors: "decimalfield4": DecimalFields require a "max_digits" attribute value that is greater than or equal to the value of the "decimal_places" attribute.
invalid_models.fielderrors: "filefield": FileFields require an "upload_to" attribute.
invalid_models.fielderrors: "choices": "choices" should be iterable (e.g., a tuple or list). invalid_models.fielderrors: "choices": "choices" should be iterable (e.g., a tuple or list).
invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-item iterables (e.g. list of 2 item tuples). invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-item iterables (e.g. list of 2 item tuples).
invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-item iterables (e.g. list of 2 item tuples). invalid_models.fielderrors: "choices2": "choices" should be a sequence of two-item iterables (e.g. list of 2 item tuples).
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment