diff --git a/AUTHORS b/AUTHORS index 4498cebf5e..b6c9141db9 100644 --- a/AUTHORS +++ b/AUTHORS @@ -276,6 +276,7 @@ answer newbie questions, and generally made Django that much better: sopel Leo Soto Wiliam Alves de Souza + Don Spaulding Bjørn Stabell Georgi Stanojevski Vasiliy Stavenko diff --git a/django/db/backends/ado_mssql/creation.py b/django/db/backends/ado_mssql/creation.py index 1411ca4d6a..d4ba8f2897 100644 --- a/django/db/backends/ado_mssql/creation.py +++ b/django/db/backends/ado_mssql/creation.py @@ -6,10 +6,10 @@ DATA_TYPES = { 'DateField': 'smalldatetime', 'DateTimeField': 'smalldatetime', 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', - 'FileField': 'varchar(100)', - 'FilePathField': 'varchar(100)', + 'FileField': 'varchar(%(max_length)s)', + 'FilePathField': 'varchar(%(max_length)s)', 'FloatField': 'double precision', - 'ImageField': 'varchar(100)', + 'ImageField': 'varchar(%(max_length)s)', 'IntegerField': 'int', 'IPAddressField': 'char(15)', 'NullBooleanField': 'bit', diff --git a/django/db/backends/mysql/creation.py b/django/db/backends/mysql/creation.py index b2b3992651..efb351c07e 100644 --- a/django/db/backends/mysql/creation.py +++ b/django/db/backends/mysql/creation.py @@ -10,10 +10,10 @@ DATA_TYPES = { 'DateField': 'date', 'DateTimeField': 'datetime', 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', - 'FileField': 'varchar(100)', - 'FilePathField': 'varchar(100)', + 'FileField': 'varchar(%(max_length)s)', + 'FilePathField': 'varchar(%(max_length)s)', 'FloatField': 'double precision', - 'ImageField': 'varchar(100)', + 'ImageField': 'varchar(%(max_length)s)', 'IntegerField': 'integer', 'IPAddressField': 'char(15)', 'NullBooleanField': 'bool', diff --git a/django/db/backends/mysql_old/creation.py b/django/db/backends/mysql_old/creation.py index b2b3992651..efb351c07e 100644 --- a/django/db/backends/mysql_old/creation.py +++ b/django/db/backends/mysql_old/creation.py @@ -10,10 +10,10 @@ DATA_TYPES = { 'DateField': 'date', 'DateTimeField': 'datetime', 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', - 'FileField': 'varchar(100)', - 'FilePathField': 'varchar(100)', + 'FileField': 'varchar(%(max_length)s)', + 'FilePathField': 'varchar(%(max_length)s)', 'FloatField': 'double precision', - 'ImageField': 'varchar(100)', + 'ImageField': 'varchar(%(max_length)s)', 'IntegerField': 'integer', 'IPAddressField': 'char(15)', 'NullBooleanField': 'bool', diff --git a/django/db/backends/oracle/creation.py b/django/db/backends/oracle/creation.py index d080b5d283..f4ada55ac6 100644 --- a/django/db/backends/oracle/creation.py +++ b/django/db/backends/oracle/creation.py @@ -13,10 +13,10 @@ DATA_TYPES = { 'DateField': 'DATE', 'DateTimeField': 'TIMESTAMP', 'DecimalField': 'NUMBER(%(max_digits)s, %(decimal_places)s)', - 'FileField': 'NVARCHAR2(100)', - 'FilePathField': 'NVARCHAR2(100)', + 'FileField': 'NVARCHAR2(%(max_length)s)', + 'FilePathField': 'NVARCHAR2(%(max_length)s)', 'FloatField': 'DOUBLE PRECISION', - 'ImageField': 'NVARCHAR2(100)', + 'ImageField': 'NVARCHAR2(%(max_length)s)', 'IntegerField': 'NUMBER(11)', 'IPAddressField': 'VARCHAR2(15)', 'NullBooleanField': 'NUMBER(1) CHECK ((%(column)s IN (0,1)) OR (%(column)s IS NULL))', @@ -28,7 +28,7 @@ DATA_TYPES = { 'SmallIntegerField': 'NUMBER(11)', 'TextField': 'NCLOB', 'TimeField': 'TIMESTAMP', - 'URLField': 'VARCHAR2(200)', + 'URLField': 'VARCHAR2(%(max_length)s)', 'USStateField': 'CHAR(2)', } diff --git a/django/db/backends/postgresql/creation.py b/django/db/backends/postgresql/creation.py index ceffea19e6..b3e374da27 100644 --- a/django/db/backends/postgresql/creation.py +++ b/django/db/backends/postgresql/creation.py @@ -10,10 +10,10 @@ DATA_TYPES = { 'DateField': 'date', 'DateTimeField': 'timestamp with time zone', 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', - 'FileField': 'varchar(100)', - 'FilePathField': 'varchar(100)', + 'FileField': 'varchar(%(max_length)s)', + 'FilePathField': 'varchar(%(max_length)s)', 'FloatField': 'double precision', - 'ImageField': 'varchar(100)', + 'ImageField': 'varchar(%(max_length)s)', 'IntegerField': 'integer', 'IPAddressField': 'inet', 'NullBooleanField': 'boolean', diff --git a/django/db/backends/sqlite3/creation.py b/django/db/backends/sqlite3/creation.py index eccb19a160..54b75f23be 100644 --- a/django/db/backends/sqlite3/creation.py +++ b/django/db/backends/sqlite3/creation.py @@ -9,10 +9,10 @@ DATA_TYPES = { 'DateField': 'date', 'DateTimeField': 'datetime', 'DecimalField': 'decimal', - 'FileField': 'varchar(100)', - 'FilePathField': 'varchar(100)', + 'FileField': 'varchar(%(max_length)s)', + 'FilePathField': 'varchar(%(max_length)s)', 'FloatField': 'real', - 'ImageField': 'varchar(100)', + 'ImageField': 'varchar(%(max_length)s)', 'IntegerField': 'integer', 'IPAddressField': 'char(15)', 'NullBooleanField': 'bool', diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 6df1e34288..65ef687a04 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -686,8 +686,7 @@ class DecimalField(Field): class EmailField(CharField): def __init__(self, *args, **kwargs): - if 'max_length' not in kwargs: - kwargs['max_length'] = 75 + kwargs['max_length'] = kwargs.get('max_length', 75) CharField.__init__(self, *args, **kwargs) def get_internal_type(self): @@ -707,6 +706,7 @@ class EmailField(CharField): class FileField(Field): def __init__(self, verbose_name=None, name=None, upload_to='', **kwargs): self.upload_to = upload_to + kwargs['max_length'] = kwargs.get('max_length', 100) Field.__init__(self, verbose_name, name, **kwargs) def get_db_prep_save(self, value): @@ -808,6 +808,7 @@ class FileField(Field): class FilePathField(Field): def __init__(self, verbose_name=None, name=None, path='', match=None, recursive=False, **kwargs): self.path, self.match, self.recursive = path, match, recursive + kwargs['max_length'] = kwargs.get('max_length', 100) Field.__init__(self, verbose_name, name, **kwargs) def get_manipulator_field_objs(self): diff --git a/django/oldforms/__init__.py b/django/oldforms/__init__.py index 93cfa1d8fa..9bb90416c4 100644 --- a/django/oldforms/__init__.py +++ b/django/oldforms/__init__.py @@ -447,7 +447,7 @@ class LargeTextField(TextField): self.field_name, self.rows, self.cols, escape(data)) class HiddenField(FormField): - def __init__(self, field_name, is_required=False, validator_list=None): + def __init__(self, field_name, is_required=False, validator_list=None, max_length=None): if validator_list is None: validator_list = [] self.field_name, self.is_required = field_name, is_required self.validator_list = validator_list[:] @@ -674,7 +674,7 @@ class CheckboxSelectMultipleField(SelectMultipleField): #################### class FileUploadField(FormField): - def __init__(self, field_name, is_required=False, validator_list=None): + def __init__(self, field_name, is_required=False, validator_list=None, max_length=None): if validator_list is None: validator_list = [] self.field_name, self.is_required = field_name, is_required self.validator_list = [self.isNonEmptyFile] + validator_list @@ -946,7 +946,7 @@ class IPAddressField(TextField): class FilePathField(SelectField): "A SelectField whose choices are the files in a given directory." - def __init__(self, field_name, path, match=None, recursive=False, is_required=False, validator_list=None): + def __init__(self, field_name, path, match=None, recursive=False, is_required=False, validator_list=None, max_length=None): import os from django.db.models import BLANK_CHOICE_DASH if match is not None: diff --git a/docs/model-api.txt b/docs/model-api.txt index adb9cfceb1..2f40abd3a9 100644 --- a/docs/model-api.txt +++ b/docs/model-api.txt @@ -293,6 +293,12 @@ visiting its URL on your site. Don't allow that. .. _`strftime formatting`: http://docs.python.org/lib/module-time.html#l2h-1941 +**New in development version:** + +By default, file fields are created as ``varchar(100)`` database fields. Like +other fields, you can change the maximum length using the ``max_length`` +argument. + ``FilePathField`` ~~~~~~~~~~~~~~~~~ @@ -330,6 +336,12 @@ not the full path. So, this example:: because the ``match`` applies to the base filename (``foo.gif`` and ``bar.gif``). +**New in development version:** + +By default, file fields are created as ``varchar(100)`` database fields. Like +other fields, you can change the maximum length using the ``max_length`` +argument. + ``FloatField`` ~~~~~~~~~~~~~~ @@ -361,6 +373,12 @@ Requires the `Python Imaging Library`_. .. _Python Imaging Library: http://www.pythonware.com/products/pil/ .. _elsewhere: ../db-api/#get-foo-height-and-get-foo-width +**New in development version:** + +By default, file fields are created as ``varchar(100)`` database fields. Like +other fields, you can change the maximum length using the ``max_length`` +argument. + ``IntegerField`` ~~~~~~~~~~~~~~~~ diff --git a/tests/regressiontests/max_lengths/__init__.py b/tests/regressiontests/max_lengths/__init__.py new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/tests/regressiontests/max_lengths/__init__.py @@ -0,0 +1 @@ + diff --git a/tests/regressiontests/max_lengths/models.py b/tests/regressiontests/max_lengths/models.py new file mode 100644 index 0000000000..b4c43a220d --- /dev/null +++ b/tests/regressiontests/max_lengths/models.py @@ -0,0 +1,13 @@ +from django.db import models + +class PersonWithDefaultMaxLengths(models.Model): + email = models.EmailField() + vcard = models.FileField(upload_to='/tmp') + homepage = models.URLField() + avatar = models.FilePathField() + +class PersonWithCustomMaxLengths(models.Model): + email = models.EmailField(max_length=384) + vcard = models.FileField(upload_to='/tmp', max_length=1024) + homepage = models.URLField(max_length=256) + avatar = models.FilePathField(max_length=512) diff --git a/tests/regressiontests/max_lengths/tests.py b/tests/regressiontests/max_lengths/tests.py new file mode 100644 index 0000000000..0ef407f573 --- /dev/null +++ b/tests/regressiontests/max_lengths/tests.py @@ -0,0 +1,36 @@ +from unittest import TestCase +from django.db import DatabaseError +from regressiontests.max_lengths.models import PersonWithDefaultMaxLengths, PersonWithCustomMaxLengths + +class MaxLengthArgumentsTests(TestCase): + + def verify_max_length(self, model,field,length): + self.assertEquals(model._meta.get_field(field).max_length,length) + + def test_default_max_lengths(self): + self.verify_max_length(PersonWithDefaultMaxLengths, 'email', 75) + self.verify_max_length(PersonWithDefaultMaxLengths, 'vcard', 100) + self.verify_max_length(PersonWithDefaultMaxLengths, 'homepage', 200) + self.verify_max_length(PersonWithDefaultMaxLengths, 'avatar', 100) + + def test_custom_maxlengths(self): + self.verify_max_length(PersonWithCustomMaxLengths, 'email', 384) + self.verify_max_length(PersonWithCustomMaxLengths, 'vcard', 1024) + self.verify_max_length(PersonWithCustomMaxLengths, 'homepage', 256) + self.verify_max_length(PersonWithCustomMaxLengths, 'avatar', 512) + +class MaxLengthORMTests(TestCase): + + def test_custom_max_lengths(self): + args = { + "email": "someone@example.com", + "vcard": "vcard", + "homepage": "http://example.com/", + "avatar": "me.jpg" + } + + for field in ("email", "vcard", "homepage", "avatar"): + new_args = args.copy() + new_args[field] = "X" * 250 # a value longer than any of the default fields could hold. + p = PersonWithCustomMaxLengths.objects.create(**new_args) + self.assertEqual(getattr(p, field), ("X" * 250)) \ No newline at end of file