2
0
Эх сурвалжийг харах

Fixed #8918 -- Made FileField.upload_to optional.

Thanks leahculver for the suggestion and dc and vajrasky for work
on the patch.
Tim Graham 11 жил өмнө
parent
commit
945e033a69

+ 0 - 2
django/core/management/validation.py

@@ -120,8 +120,6 @@ def get_validation_errors(outfile, app=None):
                 if decimalp_ok and mdigits_ok:
                     if decimal_places > max_digits:
                         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):
                 try:
                     from django.utils.image import Image

+ 3 - 4
docs/faq/usage.txt

@@ -45,10 +45,9 @@ Using a :class:`~django.db.models.FileField` or an
    account.
 
 #. Add the :class:`~django.db.models.FileField` or
-   :class:`~django.db.models.ImageField` to your model, making sure to
-   define the :attr:`~django.db.models.FileField.upload_to` option to tell
-   Django to which subdirectory of :setting:`MEDIA_ROOT` it should upload
-   files.
+   :class:`~django.db.models.ImageField` to your model, defining the
+   :attr:`~django.db.models.FileField.upload_to` option to specify a
+   subdirectory of :setting:`MEDIA_ROOT` to use for uploaded files.
 
 #. 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

+ 11 - 9
docs/ref/models/fields.txt

@@ -542,7 +542,7 @@ A :class:`CharField` that checks that the value is a valid email address.
 ``FileField``
 -------------
 
-.. class:: FileField(upload_to=None, [max_length=100, **options])
+.. class:: FileField([upload_to=None, max_length=100, **options])
 
 A file-upload field.
 
@@ -550,10 +550,14 @@ A file-upload field.
     The ``primary_key`` and ``unique`` arguments are not supported, and will
     raise a ``TypeError`` if used.
 
-Has one **required** argument:
+Has two optional arguments:
 
 .. 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`
     setting to determine the value of the
     :attr:`~django.db.models.fields.files.FieldFile.url` attribute.
@@ -586,11 +590,9 @@ Has one **required** argument:
                             when determining the final destination path.
     ======================  ===============================================
 
-Also has one optional argument:
-
 .. 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.
 
 The default form widget for this field is a :class:`~django.forms.FileInput`.
@@ -604,9 +606,9 @@ takes a few steps:
    :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.
 
-2. Add the :class:`FileField` or :class:`ImageField` to your model, making
-   sure to define the :attr:`~FileField.upload_to` option to tell Django
-   to which subdirectory of :setting:`MEDIA_ROOT` it should upload files.
+2. Add the :class:`FileField` or :class:`ImageField` to your model, defining
+   the :attr:`~FileField.upload_to` option to specify a subdirectory of
+   :setting:`MEDIA_ROOT` to use for uploaded files.
 
 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
@@ -807,7 +809,7 @@ The default form widget for this field is a :class:`~django.forms.TextInput`.
 ``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
 validates that the uploaded object is a valid image.

+ 4 - 0
docs/releases/1.7.txt

@@ -246,6 +246,10 @@ File Uploads
   the file system permissions of directories created during file upload, like
   :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
 ^^^^^
 

+ 1 - 0
tests/files/models.py

@@ -28,3 +28,4 @@ class Storage(models.Model):
     custom = models.FileField(storage=temp_storage, upload_to=custom_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')
+    empty = models.FileField(storage=temp_storage)

+ 6 - 0
tests/files/tests.py

@@ -106,6 +106,12 @@ class FileStorageTests(TestCase):
         obj4.random.save("random_file", ContentFile("random content"))
         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):
         # Create sample file
         temp_storage.save('tests/example.txt', ContentFile('some content'))

+ 0 - 2
tests/invalid_models/invalid_models/models.py

@@ -19,7 +19,6 @@ class FieldErrors(models.Model):
     decimalfield3 = models.DecimalField(max_digits="bad", decimal_places="bad")
     decimalfield4 = models.DecimalField(max_digits=9, decimal_places=10)
     decimalfield5 = models.DecimalField(max_digits=10, decimal_places=10)
-    filefield = models.FileField()
     choices = models.CharField(max_length=10, choices='bad')
     choices2 = models.CharField(max_length=10, choices=[(1, 2, 3), (1, 2, 3)])
     index = models.CharField(max_length=10, db_index='bad')
@@ -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 "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: "filefield": FileFields require an "upload_to" attribute.
 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).