Fixed #27188 -- Allowed using unique=True with FileField.

Thanks Tim Graham for the initial patch.
This commit is contained in:
Michael Scott 2016-09-20 22:31:23 +01:00 committed by Tim Graham
parent 625cd5bcb3
commit ec9ed07488
7 changed files with 23 additions and 34 deletions

View File

@ -230,7 +230,6 @@ class FileField(Field):
def __init__(self, verbose_name=None, name=None, upload_to='', storage=None, **kwargs): def __init__(self, verbose_name=None, name=None, upload_to='', storage=None, **kwargs):
self._primary_key_set_explicitly = 'primary_key' in kwargs self._primary_key_set_explicitly = 'primary_key' in kwargs
self._unique_set_explicitly = 'unique' in kwargs
self.storage = storage or default_storage self.storage = storage or default_storage
self.upload_to = upload_to self.upload_to = upload_to
@ -240,22 +239,9 @@ class FileField(Field):
def check(self, **kwargs): def check(self, **kwargs):
errors = super(FileField, self).check(**kwargs) errors = super(FileField, self).check(**kwargs)
errors.extend(self._check_unique())
errors.extend(self._check_primary_key()) errors.extend(self._check_primary_key())
return errors return errors
def _check_unique(self):
if self._unique_set_explicitly:
return [
checks.Error(
"'unique' is not a valid argument for a %s." % self.__class__.__name__,
obj=self,
id='fields.E200',
)
]
else:
return []
def _check_primary_key(self): def _check_primary_key(self):
if self._primary_key_set_explicitly: if self._primary_key_set_explicitly:
return [ return [

View File

@ -183,6 +183,7 @@ File Fields
~~~~~~~~~~~ ~~~~~~~~~~~
* **fields.E200**: ``unique`` is not a valid argument for a ``FileField``. * **fields.E200**: ``unique`` is not a valid argument for a ``FileField``.
*This check is removed in Django 1.11*.
* **fields.E201**: ``primary_key`` is not a valid argument for a ``FileField``. * **fields.E201**: ``primary_key`` is not a valid argument for a ``FileField``.
* **fields.E210**: Cannot use ``ImageField`` because Pillow is not installed. * **fields.E210**: Cannot use ``ImageField`` because Pillow is not installed.

View File

@ -306,12 +306,16 @@ you try to save a model with a duplicate value in a :attr:`~Field.unique`
field, a :exc:`django.db.IntegrityError` will be raised by the model's field, a :exc:`django.db.IntegrityError` will be raised by the model's
:meth:`~django.db.models.Model.save` method. :meth:`~django.db.models.Model.save` method.
This option is valid on all field types except :class:`ManyToManyField`, This option is valid on all field types except :class:`ManyToManyField` and
:class:`OneToOneField`, and :class:`FileField`. :class:`OneToOneField`.
Note that when ``unique`` is ``True``, you don't need to specify Note that when ``unique`` is ``True``, you don't need to specify
:attr:`~Field.db_index`, because ``unique`` implies the creation of an index. :attr:`~Field.db_index`, because ``unique`` implies the creation of an index.
.. versionchanged:: 1.11
In older versions, ``unique=True`` can't be used on :class:`FileField`.
``unique_for_date`` ``unique_for_date``
------------------- -------------------
@ -628,8 +632,8 @@ uses :class:`~django.core.validators.EmailValidator` to validate the input.
A file-upload field. A file-upload field.
.. note:: .. note::
The ``primary_key`` and ``unique`` arguments are not supported, and will The ``primary_key`` argument isn't supported and will raise a an error if
raise a ``TypeError`` if used. used.
Has two optional arguments: Has two optional arguments:

View File

@ -312,6 +312,9 @@ Models
* Added support for query expressions on lookups that take multiple arguments, * Added support for query expressions on lookups that take multiple arguments,
such as ``range``. such as ``range``.
* You can now use the ``unique=True`` option with
:class:`~django.db.models.FileField`.
Requests and Responses Requests and Responses
~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~

View File

@ -440,21 +440,6 @@ class FileFieldTests(SimpleTestCase):
expected = [] expected = []
self.assertEqual(errors, expected) self.assertEqual(errors, expected)
def test_unique(self):
class Model(models.Model):
field = models.FileField(unique=False, upload_to='somewhere')
field = Model._meta.get_field('field')
errors = field.check()
expected = [
Error(
"'unique' is not a valid argument for a FileField.",
obj=field,
id='fields.E200',
)
]
self.assertEqual(errors, expected)
def test_primary_key(self): def test_primary_key(self):
class Model(models.Model): class Model(models.Model):
field = models.FileField(primary_key=False, upload_to='somewhere') field = models.FileField(primary_key=False, upload_to='somewhere')

View File

@ -216,7 +216,7 @@ class DataModel(models.Model):
class Document(models.Model): class Document(models.Model):
myfile = models.FileField(upload_to='unused') myfile = models.FileField(upload_to='unused', unique=True)
############################################################################### ###############################################################################
# ImageField # ImageField

View File

@ -4,6 +4,7 @@ import unittest
from django.core.files import temp from django.core.files import temp
from django.core.files.uploadedfile import TemporaryUploadedFile from django.core.files.uploadedfile import TemporaryUploadedFile
from django.db.utils import IntegrityError
from django.test import TestCase, override_settings from django.test import TestCase, override_settings
from .models import Document from .models import Document
@ -61,6 +62,15 @@ class FileFieldTests(TestCase):
Document.objects.create(myfile='something.txt') Document.objects.create(myfile='something.txt')
self.assertEqual(Document.objects.defer('myfile')[0].myfile, 'something.txt') self.assertEqual(Document.objects.defer('myfile')[0].myfile, 'something.txt')
def test_unique_when_same_filename(self):
"""
A FileField with unique=True shouldn't allow two instances with the
same name to be saved.
"""
Document.objects.create(myfile='something.txt')
with self.assertRaises(IntegrityError):
Document.objects.create(myfile='something.txt')
@unittest.skipIf(sys.platform.startswith('win'), "Windows doesn't support moving open files.") @unittest.skipIf(sys.platform.startswith('win'), "Windows doesn't support moving open files.")
# The file's source and destination must be on the same filesystem. # The file's source and destination must be on the same filesystem.
@override_settings(MEDIA_ROOT=temp.gettempdir()) @override_settings(MEDIA_ROOT=temp.gettempdir())