diff options
author | Derek Anderson <public@kered.org> | 2007-08-06 16:50:17 +0000 |
---|---|---|
committer | Derek Anderson <public@kered.org> | 2007-08-06 16:50:17 +0000 |
commit | 5aa017255827b2c06bd9a5f7f069828ef625da18 (patch) | |
tree | 22ec9db537e3eeda5c8e21dbfe35f252a97e375d | |
parent | 0af6ed0c4853e11086e277ba352d27db4c466c89 (diff) | |
download | django-5aa017255827b2c06bd9a5f7f069828ef625da18.tar.gz |
schema-evolution: update from HEAD (v5821)
git-svn-id: http://code.djangoproject.com/svn/django/branches/schema-evolution@5822 bcc190cf-cafb-0310-a4f2-bffc1f526a37
111 files changed, 1067 insertions, 486 deletions
@@ -45,6 +45,7 @@ answer newbie questions, and generally made Django that much better: Marty Alchin <gulopine@gamemusic.org> Daniel Alves Barbosa de Oliveira Vaz <danielvaz@gmail.com> AgarFu <heaven@croasanaso.sytes.net> + Derek Anderson <public@kered.org> Andreas andy@jadedplanet.net Fabrice Aneche <akh@nobugware.com> @@ -96,6 +97,7 @@ answer newbie questions, and generally made Django that much better: Maximillian Dornseif <md@hudora.de> Jeremy Dunck <http://dunck.us/> Andrew Durdin <adurdin@gmail.com> + dusk@woofle.net Andy Dustman <farcepest@gmail.com> Clint Ecker enlight diff --git a/django/contrib/admin/models.py b/django/contrib/admin/models.py index b5b779a3ac..ffa2740d5e 100644 --- a/django/contrib/admin/models.py +++ b/django/contrib/admin/models.py @@ -18,7 +18,7 @@ class LogEntry(models.Model): user = models.ForeignKey(User) content_type = models.ForeignKey(ContentType, blank=True, null=True) object_id = models.TextField(_('object id'), blank=True, null=True) - object_repr = models.CharField(_('object repr'), maxlength=200) + object_repr = models.CharField(_('object repr'), max_length=200) action_flag = models.PositiveSmallIntegerField(_('action flag')) change_message = models.TextField(_('change message'), blank=True) objects = LogEntryManager() diff --git a/django/contrib/admin/templatetags/admin_modify.py b/django/contrib/admin/templatetags/admin_modify.py index 9bc41c6450..5f29782903 100644 --- a/django/contrib/admin/templatetags/admin_modify.py +++ b/django/contrib/admin/templatetags/admin_modify.py @@ -192,7 +192,7 @@ def auto_populated_field_script(auto_pop_fields, change = False): t.append(u'document.getElementById("id_%s").onkeyup = function() {' \ ' var e = document.getElementById("id_%s");' \ ' if(!e._changed) { e.value = URLify(%s, %s);} }; ' % ( - f, field.name, add_values, field.maxlength)) + f, field.name, add_values, field.max_length)) return u''.join(t) auto_populated_field_script = register.simple_tag(auto_populated_field_script) diff --git a/django/contrib/admin/views/doc.py b/django/contrib/admin/views/doc.py index a21eb99f09..37caa0f43b 100644 --- a/django/contrib/admin/views/doc.py +++ b/django/contrib/admin/views/doc.py @@ -291,7 +291,7 @@ def get_return_data_type(func_name): DATA_TYPE_MAPPING = { 'AutoField' : _('Integer'), 'BooleanField' : _('Boolean (Either True or False)'), - 'CharField' : _('String (up to %(maxlength)s)'), + 'CharField' : _('String (up to %(max_length)s)'), 'CommaSeparatedIntegerField': _('Comma-separated integers'), 'DateField' : _('Date (without time)'), 'DateTimeField' : _('Date (with time)'), @@ -310,7 +310,7 @@ DATA_TYPE_MAPPING = { 'PhoneNumberField' : _('Phone number'), 'PositiveIntegerField' : _('Integer'), 'PositiveSmallIntegerField' : _('Integer'), - 'SlugField' : _('String (up to %(maxlength)s)'), + 'SlugField' : _('String (up to %(max_length)s)'), 'SmallIntegerField' : _('Integer'), 'TextField' : _('Text'), 'TimeField' : _('Time'), diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index 874b3559ee..cfbe9a1f95 100644 --- a/django/contrib/admin/views/main.py +++ b/django/contrib/admin/views/main.py @@ -673,7 +673,7 @@ class ChangeList(object): try: attr = getattr(lookup_opts.admin.manager.model, field_name) order_field = attr.admin_order_field - except IndexError: + except AttributeError: pass else: if not isinstance(f.rel, models.ManyToOneRel) or not f.null: diff --git a/django/contrib/auth/forms.py b/django/contrib/auth/forms.py index 2a68e94766..16ee0289a2 100644 --- a/django/contrib/auth/forms.py +++ b/django/contrib/auth/forms.py @@ -10,10 +10,10 @@ class UserCreationForm(oldforms.Manipulator): "A form that creates a user, with no privileges, from the given username and password." def __init__(self): self.fields = ( - oldforms.TextField(field_name='username', length=30, maxlength=30, is_required=True, + oldforms.TextField(field_name='username', length=30, max_length=30, is_required=True, validator_list=[validators.isAlphaNumeric, self.isValidUsername]), - oldforms.PasswordField(field_name='password1', length=30, maxlength=60, is_required=True), - oldforms.PasswordField(field_name='password2', length=30, maxlength=60, is_required=True, + oldforms.PasswordField(field_name='password1', length=30, max_length=60, is_required=True), + oldforms.PasswordField(field_name='password2', length=30, max_length=60, is_required=True, validator_list=[validators.AlwaysMatchesOtherField('password1', _("The two password fields didn't match."))]), ) @@ -42,9 +42,9 @@ class AuthenticationForm(oldforms.Manipulator): """ self.request = request self.fields = [ - oldforms.TextField(field_name="username", length=15, maxlength=30, is_required=True, + oldforms.TextField(field_name="username", length=15, max_length=30, is_required=True, validator_list=[self.isValidUser, self.hasCookiesEnabled]), - oldforms.PasswordField(field_name="password", length=15, maxlength=30, is_required=True), + oldforms.PasswordField(field_name="password", length=15, max_length=30, is_required=True), ] self.user_cache = None @@ -111,11 +111,11 @@ class PasswordChangeForm(oldforms.Manipulator): def __init__(self, user): self.user = user self.fields = ( - oldforms.PasswordField(field_name="old_password", length=30, maxlength=30, is_required=True, + oldforms.PasswordField(field_name="old_password", length=30, max_length=30, is_required=True, validator_list=[self.isValidOldPassword]), - oldforms.PasswordField(field_name="new_password1", length=30, maxlength=30, is_required=True, + oldforms.PasswordField(field_name="new_password1", length=30, max_length=30, is_required=True, validator_list=[validators.AlwaysMatchesOtherField('new_password2', _("The two 'new password' fields didn't match."))]), - oldforms.PasswordField(field_name="new_password2", length=30, maxlength=30, is_required=True), + oldforms.PasswordField(field_name="new_password2", length=30, max_length=30, is_required=True), ) def isValidOldPassword(self, new_data, all_data): @@ -133,8 +133,8 @@ class AdminPasswordChangeForm(oldforms.Manipulator): def __init__(self, user): self.user = user self.fields = ( - oldforms.PasswordField(field_name='password1', length=30, maxlength=60, is_required=True), - oldforms.PasswordField(field_name='password2', length=30, maxlength=60, is_required=True, + oldforms.PasswordField(field_name='password1', length=30, max_length=60, is_required=True), + oldforms.PasswordField(field_name='password2', length=30, max_length=60, is_required=True, validator_list=[validators.AlwaysMatchesOtherField('password1', _("The two password fields didn't match."))]), ) diff --git a/django/contrib/auth/models.py b/django/contrib/auth/models.py index 939b576273..a70227e448 100644 --- a/django/contrib/auth/models.py +++ b/django/contrib/auth/models.py @@ -50,9 +50,9 @@ class Permission(models.Model): Three basic permissions -- add, change and delete -- are automatically created for each Django model. """ - name = models.CharField(_('name'), maxlength=50) + name = models.CharField(_('name'), max_length=50) content_type = models.ForeignKey(ContentType) - codename = models.CharField(_('codename'), maxlength=100) + codename = models.CharField(_('codename'), max_length=100) class Meta: verbose_name = _('permission') @@ -70,7 +70,7 @@ class Group(models.Model): Beyond permissions, groups are a convenient way to categorize users to apply some label, or extended functionality, to them. For example, you could create a group 'Special users', and you could write code that would do special things to those users -- such as giving them access to a members-only portion of your site, or sending them members-only e-mail messages. """ - name = models.CharField(_('name'), maxlength=80, unique=True) + name = models.CharField(_('name'), max_length=80, unique=True) permissions = models.ManyToManyField(Permission, verbose_name=_('permissions'), blank=True, filter_interface=models.HORIZONTAL) class Meta: @@ -108,11 +108,11 @@ class User(models.Model): Username and password are required. Other fields are optional. """ - username = models.CharField(_('username'), maxlength=30, unique=True, validator_list=[validators.isAlphaNumeric], help_text=_("Required. 30 characters or fewer. Alphanumeric characters only (letters, digits and underscores).")) - first_name = models.CharField(_('first name'), maxlength=30, blank=True) - last_name = models.CharField(_('last name'), maxlength=30, blank=True) + username = models.CharField(_('username'), max_length=30, unique=True, validator_list=[validators.isAlphaNumeric], help_text=_("Required. 30 characters or fewer. Alphanumeric characters only (letters, digits and underscores).")) + first_name = models.CharField(_('first name'), max_length=30, blank=True) + last_name = models.CharField(_('last name'), max_length=30, blank=True) email = models.EmailField(_('e-mail address'), blank=True) - password = models.CharField(_('password'), maxlength=128, help_text=_("Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change password form</a>.")) + password = models.CharField(_('password'), max_length=128, help_text=_("Use '[algo]$[salt]$[hexdigest]' or use the <a href=\"password/\">change password form</a>.")) is_staff = models.BooleanField(_('staff status'), default=False, help_text=_("Designates whether the user can log into this admin site.")) is_active = models.BooleanField(_('active'), default=True, help_text=_("Designates whether this user can log into the Django admin. Unselect this instead of deleting accounts.")) is_superuser = models.BooleanField(_('superuser status'), default=False, help_text=_("Designates that this user has all permissions without explicitly assigning them.")) diff --git a/django/contrib/comments/models.py b/django/contrib/comments/models.py index e01937d5d8..5f2018881e 100644 --- a/django/contrib/comments/models.py +++ b/django/contrib/comments/models.py @@ -65,8 +65,8 @@ class Comment(models.Model): user = models.ForeignKey(User, raw_id_admin=True) content_type = models.ForeignKey(ContentType) object_id = models.IntegerField(_('object ID')) - headline = models.CharField(_('headline'), maxlength=255, blank=True) - comment = models.TextField(_('comment'), maxlength=3000) + headline = models.CharField(_('headline'), max_length=255, blank=True) + comment = models.TextField(_('comment'), max_length=3000) rating1 = models.PositiveSmallIntegerField(_('rating #1'), blank=True, null=True) rating2 = models.PositiveSmallIntegerField(_('rating #2'), blank=True, null=True) rating3 = models.PositiveSmallIntegerField(_('rating #3'), blank=True, null=True) @@ -164,8 +164,8 @@ class FreeComment(models.Model): # A FreeComment is a comment by a non-registered user. content_type = models.ForeignKey(ContentType) object_id = models.IntegerField(_('object ID')) - comment = models.TextField(_('comment'), maxlength=3000) - person_name = models.CharField(_("person's name"), maxlength=50) + comment = models.TextField(_('comment'), max_length=3000) + person_name = models.CharField(_("person's name"), max_length=50) submit_date = models.DateTimeField(_('date/time submitted'), auto_now_add=True) is_public = models.BooleanField(_('is public')) ip_address = models.IPAddressField(_('ip address')) diff --git a/django/contrib/comments/views/comments.py b/django/contrib/comments/views/comments.py index 435bfa6f73..f166fa118f 100644 --- a/django/contrib/comments/views/comments.py +++ b/django/contrib/comments/views/comments.py @@ -29,7 +29,7 @@ class PublicCommentManipulator(AuthenticationForm): else: return [] self.fields.extend([ - oldforms.LargeTextField(field_name="comment", maxlength=3000, is_required=True, + oldforms.LargeTextField(field_name="comment", max_length=3000, is_required=True, validator_list=[self.hasNoProfanities]), oldforms.RadioSelectField(field_name="rating1", choices=choices, is_required=ratings_required and num_rating_choices > 0, @@ -122,9 +122,9 @@ class PublicFreeCommentManipulator(oldforms.Manipulator): "Manipulator that handles public free (unregistered) comments" def __init__(self): self.fields = ( - oldforms.TextField(field_name="person_name", maxlength=50, is_required=True, + oldforms.TextField(field_name="person_name", max_length=50, is_required=True, validator_list=[self.hasNoProfanities]), - oldforms.LargeTextField(field_name="comment", maxlength=3000, is_required=True, + oldforms.LargeTextField(field_name="comment", max_length=3000, is_required=True, validator_list=[self.hasNoProfanities]), ) diff --git a/django/contrib/contenttypes/models.py b/django/contrib/contenttypes/models.py index a825b4f3dd..cda47a18aa 100644 --- a/django/contrib/contenttypes/models.py +++ b/django/contrib/contenttypes/models.py @@ -32,9 +32,9 @@ class ContentTypeManager(models.Manager): CONTENT_TYPE_CACHE = {} class ContentType(models.Model): - name = models.CharField(maxlength=100) - app_label = models.CharField(maxlength=100) - model = models.CharField(_('python model class name'), maxlength=100) + name = models.CharField(max_length=100) + app_label = models.CharField(max_length=100) + model = models.CharField(_('python model class name'), max_length=100) objects = ContentTypeManager() class Meta: verbose_name = _('content type') diff --git a/django/contrib/flatpages/models.py b/django/contrib/flatpages/models.py index c9e9090d7d..36327c80c3 100644 --- a/django/contrib/flatpages/models.py +++ b/django/contrib/flatpages/models.py @@ -4,12 +4,12 @@ from django.contrib.sites.models import Site from django.utils.translation import ugettext_lazy as _ class FlatPage(models.Model): - url = models.CharField(_('URL'), maxlength=100, validator_list=[validators.isAlphaNumericURL], db_index=True, + url = models.CharField(_('URL'), max_length=100, validator_list=[validators.isAlphaNumericURL], db_index=True, help_text=_("Example: '/about/contact/'. Make sure to have leading and trailing slashes.")) - title = models.CharField(_('title'), maxlength=200) + title = models.CharField(_('title'), max_length=200) content = models.TextField(_('content')) enable_comments = models.BooleanField(_('enable comments')) - template_name = models.CharField(_('template name'), maxlength=70, blank=True, + template_name = models.CharField(_('template name'), max_length=70, blank=True, help_text=_("Example: 'flatpages/contact_page.html'. If this isn't provided, the system will use 'flatpages/default.html'.")) registration_required = models.BooleanField(_('registration required'), help_text=_("If this is checked, only logged-in users will be able to view the page.")) sites = models.ManyToManyField(Site) diff --git a/django/contrib/redirects/models.py b/django/contrib/redirects/models.py index 6a3f5c9ff5..ac2e8d5bac 100644 --- a/django/contrib/redirects/models.py +++ b/django/contrib/redirects/models.py @@ -4,9 +4,9 @@ from django.utils.translation import ugettext_lazy as _ class Redirect(models.Model): site = models.ForeignKey(Site, radio_admin=models.VERTICAL) - old_path = models.CharField(_('redirect from'), maxlength=200, db_index=True, + old_path = models.CharField(_('redirect from'), max_length=200, db_index=True, help_text=_("This should be an absolute path, excluding the domain name. Example: '/events/search/'.")) - new_path = models.CharField(_('redirect to'), maxlength=200, blank=True, + new_path = models.CharField(_('redirect to'), max_length=200, blank=True, help_text=_("This can be either an absolute path (as above) or a full URL starting with 'http://'.")) class Meta: diff --git a/django/contrib/sessions/models.py b/django/contrib/sessions/models.py index d2df17284c..29adc6e30c 100644 --- a/django/contrib/sessions/models.py +++ b/django/contrib/sessions/models.py @@ -65,7 +65,7 @@ class Session(models.Model): the sessions documentation that is shipped with Django (also available on the Django website). """ - session_key = models.CharField(_('session key'), maxlength=40, primary_key=True) + session_key = models.CharField(_('session key'), max_length=40, primary_key=True) session_data = models.TextField(_('session data')) expire_date = models.DateTimeField(_('expire date')) objects = SessionManager() diff --git a/django/contrib/sites/models.py b/django/contrib/sites/models.py index 9dbe1f45f8..191d5d0a3e 100644 --- a/django/contrib/sites/models.py +++ b/django/contrib/sites/models.py @@ -12,8 +12,8 @@ class SiteManager(models.Manager): return self.get(pk=sid) class Site(models.Model): - domain = models.CharField(_('domain name'), maxlength=100) - name = models.CharField(_('display name'), maxlength=50) + domain = models.CharField(_('domain name'), max_length=100) + name = models.CharField(_('display name'), max_length=50) objects = SiteManager() class Meta: db_table = 'django_site' diff --git a/django/core/management.py b/django/core/management.py index e12f6da78f..af61b7e664 100644 --- a/django/core/management.py +++ b/django/core/management.py @@ -1064,9 +1064,9 @@ def inspectdb(): field_type, new_params = field_type extra_params.update(new_params) - # Add maxlength for all CharFields. + # Add max_length for all CharFields. if field_type == 'CharField' and row[3]: - extra_params['maxlength'] = row[3] + extra_params['max_length'] = row[3] if field_type == 'DecimalField': extra_params['max_digits'] = row[4] @@ -1141,8 +1141,8 @@ def get_validation_errors(outfile, app=None): for f in opts.fields: if f.name == 'id' and not f.primary_key and opts.pk.name == 'id': e.add(opts, '"%s": You can\'t use "id" as a field name, because each model automatically gets an "id" field if none of the fields have primary_key=True. You need to either remove/rename your "id" field or add primary_key=True to a field.' % f.name) - if isinstance(f, models.CharField) and f.maxlength in (None, 0): - e.add(opts, '"%s": CharFields require a "maxlength" attribute.' % f.name) + if isinstance(f, models.CharField) and f.max_length in (None, 0): + e.add(opts, '"%s": CharFields require a "max_length" attribute.' % f.name) if isinstance(f, models.DecimalField): if f.decimal_places is None: e.add(opts, '"%s": DecimalFields require a "decimal_places" attribute.' % f.name) @@ -1167,11 +1167,11 @@ def get_validation_errors(outfile, app=None): if f.db_index not in (None, True, False): e.add(opts, '"%s": "db_index" should be either None, True or False.' % f.name) - # Check that maxlength <= 255 if using older MySQL versions. + # Check that max_length <= 255 if using older MySQL versions. if settings.DATABASE_ENGINE == 'mysql': db_version = connection.get_server_version() - if db_version < (5, 0, 3) and isinstance(f, (models.CharField, models.CommaSeparatedIntegerField, models.SlugField)) and f.maxlength > 255: - e.add(opts, '"%s": %s cannot have a "maxlength" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s).' % (f.name, f.__class__.__name__, '.'.join([str(n) for n in db_version[:3]]))) + if db_version < (5, 0, 3) and isinstance(f, (models.CharField, models.CommaSeparatedIntegerField, models.SlugField)) and f.max_length > 255: + e.add(opts, '"%s": %s cannot have a "max_length" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %s).' % (f.name, f.__class__.__name__, '.'.join([str(n) for n in db_version[:3]]))) # Check to see if the related field will clash with any # existing fields, m2m fields, m2m related objects or related objects @@ -1406,7 +1406,7 @@ def createcachetable(tablename): from django.db import backend, connection, transaction, models fields = ( # "key" is a reserved word in MySQL, so use "cache_key" instead. - models.CharField(name='cache_key', maxlength=255, unique=True, primary_key=True), + models.CharField(name='cache_key', max_length=255, unique=True, primary_key=True), models.TextField(name='value'), models.DateTimeField(name='expires', db_index=True), ) @@ -1454,6 +1454,10 @@ def run_shell(use_plain=False): shell.mainloop() except ImportError: import code + # Set up a dictionary to serve as the environment for the shell, so + # that tab completion works on objects that are imported at runtime. + # See ticket 5082. + imported_objects = {} try: # Try activating rlcompleter, because it's handy. import readline except ImportError: @@ -1462,8 +1466,9 @@ def run_shell(use_plain=False): # We don't have to wrap the following import in a 'try', because # we already know 'readline' was imported successfully. import rlcompleter + readline.set_completer(rlcompleter.Completer(imported_objects).complete) readline.parse_and_bind("tab:complete") - code.interact() + code.interact(local=imported_objects) run_shell.args = '[--plain]' def dbshell(): @@ -1578,7 +1583,7 @@ def load_data(fixture_labels, verbosity=1): print "Installing %s fixture '%s' from %s." % \ (format, fixture_name, humanize(fixture_dir)) try: - objects = serializers.deserialize(format, fixture) + objects = serializers.deserialize(format, fixture) for obj in objects: count[0] += 1 models.add(obj.object.__class__) diff --git a/django/core/validators.py b/django/core/validators.py index ca436690a5..fde4f052cb 100644 --- a/django/core/validators.py +++ b/django/core/validators.py @@ -442,7 +442,7 @@ def isValidFloat(field_data, all_data): try: float(data) except ValueError: - raise ValidationError, ugettext("Please enter a valid floating point number.") + raise ValidationError, _("Please enter a valid floating point number.") class HasAllowableSize(object): """ diff --git a/django/db/backends/ado_mssql/creation.py b/django/db/backends/ado_mssql/creation.py index e7d612817c..1411ca4d6a 100644 --- a/django/db/backends/ado_mssql/creation.py +++ b/django/db/backends/ado_mssql/creation.py @@ -1,8 +1,8 @@ DATA_TYPES = { 'AutoField': 'int IDENTITY (1, 1)', 'BooleanField': 'bit', - 'CharField': 'varchar(%(maxlength)s)', - 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)', + 'CharField': 'varchar(%(max_length)s)', + 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 'DateField': 'smalldatetime', 'DateTimeField': 'smalldatetime', 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', @@ -17,7 +17,7 @@ DATA_TYPES = { 'PhoneNumberField': 'varchar(20)', 'PositiveIntegerField': 'int CONSTRAINT [CK_int_pos_%(column)s] CHECK ([%(column)s] > 0)', 'PositiveSmallIntegerField': 'smallint CONSTRAINT [CK_smallint_pos_%(column)s] CHECK ([%(column)s] > 0)', - 'SlugField': 'varchar(%(maxlength)s)', + 'SlugField': 'varchar(%(max_length)s)', 'SmallIntegerField': 'smallint', 'TextField': 'text', 'TimeField': 'time', diff --git a/django/db/backends/mysql/creation.py b/django/db/backends/mysql/creation.py index e4b5eaf2c8..b2b3992651 100644 --- a/django/db/backends/mysql/creation.py +++ b/django/db/backends/mysql/creation.py @@ -5,8 +5,8 @@ DATA_TYPES = { 'AutoField': 'integer AUTO_INCREMENT', 'BooleanField': 'bool', - 'CharField': 'varchar(%(maxlength)s)', - 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)', + 'CharField': 'varchar(%(max_length)s)', + 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 'DateField': 'date', 'DateTimeField': 'datetime', 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', @@ -21,7 +21,7 @@ DATA_TYPES = { 'PhoneNumberField': 'varchar(20)', 'PositiveIntegerField': 'integer UNSIGNED', 'PositiveSmallIntegerField': 'smallint UNSIGNED', - 'SlugField': 'varchar(%(maxlength)s)', + 'SlugField': 'varchar(%(max_length)s)', 'SmallIntegerField': 'smallint', 'TextField': 'longtext', 'TimeField': 'time', diff --git a/django/db/backends/mysql_old/creation.py b/django/db/backends/mysql_old/creation.py index e4b5eaf2c8..b2b3992651 100644 --- a/django/db/backends/mysql_old/creation.py +++ b/django/db/backends/mysql_old/creation.py @@ -5,8 +5,8 @@ DATA_TYPES = { 'AutoField': 'integer AUTO_INCREMENT', 'BooleanField': 'bool', - 'CharField': 'varchar(%(maxlength)s)', - 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)', + 'CharField': 'varchar(%(max_length)s)', + 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 'DateField': 'date', 'DateTimeField': 'datetime', 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', @@ -21,7 +21,7 @@ DATA_TYPES = { 'PhoneNumberField': 'varchar(20)', 'PositiveIntegerField': 'integer UNSIGNED', 'PositiveSmallIntegerField': 'smallint UNSIGNED', - 'SlugField': 'varchar(%(maxlength)s)', + 'SlugField': 'varchar(%(max_length)s)', 'SmallIntegerField': 'smallint', 'TextField': 'longtext', 'TimeField': 'time', diff --git a/django/db/backends/oracle/creation.py b/django/db/backends/oracle/creation.py index 420b98bd9e..af498fa9ff 100644 --- a/django/db/backends/oracle/creation.py +++ b/django/db/backends/oracle/creation.py @@ -8,8 +8,8 @@ from django.core import management DATA_TYPES = { 'AutoField': 'NUMBER(11)', 'BooleanField': 'NUMBER(1) CHECK (%(column)s IN (0,1))', - 'CharField': 'NVARCHAR2(%(maxlength)s)', - 'CommaSeparatedIntegerField': 'VARCHAR2(%(maxlength)s)', + 'CharField': 'NVARCHAR2(%(max_length)s)', + 'CommaSeparatedIntegerField': 'VARCHAR2(%(max_length)s)', 'DateField': 'DATE', 'DateTimeField': 'TIMESTAMP', 'DecimalField': 'NUMBER(%(max_digits)s, %(decimal_places)s)', diff --git a/django/db/backends/postgresql/creation.py b/django/db/backends/postgresql/creation.py index fde094de7f..ceffea19e6 100644 --- a/django/db/backends/postgresql/creation.py +++ b/django/db/backends/postgresql/creation.py @@ -5,8 +5,8 @@ DATA_TYPES = { 'AutoField': 'serial', 'BooleanField': 'boolean', - 'CharField': 'varchar(%(maxlength)s)', - 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)', + 'CharField': 'varchar(%(max_length)s)', + 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 'DateField': 'date', 'DateTimeField': 'timestamp with time zone', 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', @@ -21,7 +21,7 @@ DATA_TYPES = { 'PhoneNumberField': 'varchar(20)', 'PositiveIntegerField': 'integer CHECK ("%(column)s" >= 0)', 'PositiveSmallIntegerField': 'smallint CHECK ("%(column)s" >= 0)', - 'SlugField': 'varchar(%(maxlength)s)', + 'SlugField': 'varchar(%(max_length)s)', 'SmallIntegerField': 'smallint', 'TextField': 'text', 'TimeField': 'time', diff --git a/django/db/backends/sqlite3/creation.py b/django/db/backends/sqlite3/creation.py index ab7442252e..eccb19a160 100644 --- a/django/db/backends/sqlite3/creation.py +++ b/django/db/backends/sqlite3/creation.py @@ -4,8 +4,8 @@ DATA_TYPES = { 'AutoField': 'integer', 'BooleanField': 'bool', - 'CharField': 'varchar(%(maxlength)s)', - 'CommaSeparatedIntegerField': 'varchar(%(maxlength)s)', + 'CharField': 'varchar(%(max_length)s)', + 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 'DateField': 'date', 'DateTimeField': 'datetime', 'DecimalField': 'decimal', @@ -20,7 +20,7 @@ DATA_TYPES = { 'PhoneNumberField': 'varchar(20)', 'PositiveIntegerField': 'integer unsigned', 'PositiveSmallIntegerField': 'smallint unsigned', - 'SlugField': 'varchar(%(maxlength)s)', + 'SlugField': 'varchar(%(max_length)s)', 'SmallIntegerField': 'smallint', 'TextField': 'text', 'TimeField': 'time', diff --git a/django/db/backends/sqlite3/introspection.py b/django/db/backends/sqlite3/introspection.py index 8ab8773ddf..824d35dded 100644 --- a/django/db/backends/sqlite3/introspection.py +++ b/django/db/backends/sqlite3/introspection.py @@ -137,7 +137,7 @@ class FlexibleFieldLookupDict: import re m = re.search(r'^\s*(?:var)?char\s*\(\s*(\d+)\s*\)\s*$', key) if m: - return ('CharField', {'maxlength': int(m.group(1))}) + return ('CharField', {'max_length': int(m.group(1))}) raise KeyError DATA_TYPES_REVERSE = FlexibleFieldLookupDict() diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index ef360f284b..be88382482 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -11,6 +11,7 @@ from django.utils.itercompat import tee from django.utils.text import capfirst from django.utils.translation import ugettext_lazy, ugettext as _ from django.utils.encoding import smart_unicode, force_unicode, smart_str +from django.utils.maxlength import LegacyMaxlength import datetime, os, time try: import decimal @@ -63,6 +64,9 @@ def manipulator_validator_unique(f, opts, self, field_data, all_data): # getattr(obj, opts.pk.attname) class Field(object): + # Provide backwards compatibility for the maxlength attribute and + # argument for this class and all subclasses. + __metaclass__ = LegacyMaxlength # Designates whether empty strings fundamentally are allowed at the # database level. @@ -72,7 +76,7 @@ class Field(object): creation_counter = 0 def __init__(self, verbose_name=None, name=None, primary_key=False, - maxlength=None, unique=False, blank=False, null=False, db_index=False, + max_length=None, unique=False, blank=False, null=False, db_index=False, core=False, rel=None, default=NOT_PROVIDED, editable=True, serialize=True, prepopulate_from=None, unique_for_date=None, unique_for_month=None, unique_for_year=None, validator_list=None, choices=None, radio_admin=None, @@ -80,7 +84,7 @@ class Field(object): self.name = name self.verbose_name = verbose_name self.primary_key = primary_key - self.maxlength, self.unique = maxlength, unique + self.max_length, self.unique = max_length, unique self.blank, self.null = blank, null # Oracle treats the empty string ('') as null, so coerce the null # option whenever '' is a possible value. @@ -245,8 +249,8 @@ class Field(object): def prepare_field_objs_and_params(self, manipulator, name_prefix): params = {'validator_list': self.validator_list[:]} - if self.maxlength and not self.choices: # Don't give SelectFields a maxlength parameter. - params['maxlength'] = self.maxlength + if self.max_length and not self.choices: # Don't give SelectFields a max_length parameter. + params['max_length'] = self.max_length if self.choices: if self.radio_admin: @@ -377,6 +381,9 @@ class Field(object): return self._choices choices = property(_get_choices) + def save_form_data(self, instance, data): + setattr(instance, self.name, data) + def formfield(self, form_class=forms.CharField, **kwargs): "Returns a django.newforms.Field instance for this database Field." defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name), 'help_text': self.help_text} @@ -462,7 +469,7 @@ class CharField(Field): return smart_unicode(value) def formfield(self, **kwargs): - defaults = {'max_length': self.maxlength} + defaults = {'max_length': self.max_length} defaults.update(kwargs) return super(CharField, self).formfield(**defaults) @@ -671,7 +678,7 @@ class DecimalField(Field): class EmailField(CharField): def __init__(self, *args, **kwargs): - kwargs['maxlength'] = 75 + kwargs['max_length'] = 75 CharField.__init__(self, *args, **kwargs) def get_internal_type(self): @@ -693,6 +700,13 @@ class FileField(Field): self.upload_to = upload_to Field.__init__(self, verbose_name, name, **kwargs) + def get_db_prep_save(self, value): + "Returns field's value prepared for saving into a database." + # Need to convert UploadedFile objects provided via a form to unicode for database insertion + if value is None: + return None + return unicode(value) + def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True): field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow) if not self.blank: @@ -769,6 +783,19 @@ class FileField(Field): f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.basename(filename))) return os.path.normpath(f) + def save_form_data(self, instance, data): + if data: + getattr(instance, "save_%s_file" % self.name)(os.path.join(self.upload_to, data.filename), data.content, save=False) + + def formfield(self, **kwargs): + defaults = {'form_class': forms.FileField} + # If a file has been provided previously, then the form doesn't require + # that a new file is provided this time. + if 'initial' in kwargs: + defaults['required'] = False + defaults.update(kwargs) + return super(FileField, self).formfield(**defaults) + 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 @@ -817,6 +844,10 @@ class ImageField(FileField): setattr(new_object, self.height_field, getattr(original_object, self.height_field)) new_object.save() + def formfield(self, **kwargs): + defaults = {'form_class': forms.ImageField} + return super(ImageField, self).formfield(**defaults) + class IntegerField(Field): empty_strings_allowed = False def get_manipulator_field_objs(self): @@ -830,7 +861,7 @@ class IntegerField(Field): class IPAddressField(Field): empty_strings_allowed = False def __init__(self, *args, **kwargs): - kwargs['maxlength'] = 15 + kwargs['max_length'] = 15 Field.__init__(self, *args, **kwargs) def get_manipulator_field_objs(self): @@ -878,7 +909,7 @@ class PositiveSmallIntegerField(IntegerField): class SlugField(Field): def __init__(self, *args, **kwargs): - kwargs['maxlength'] = kwargs.get('maxlength', 50) + kwargs['max_length'] = kwargs.get('max_length', 50) kwargs.setdefault('validator_list', []).append(validators.isSlug) # Set db_index=True unless it's been set manually. if 'db_index' not in kwargs: @@ -964,7 +995,7 @@ class TimeField(Field): class URLField(CharField): def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs): - kwargs['maxlength'] = kwargs.get('maxlength', 200) + kwargs['max_length'] = kwargs.get('max_length', 200) if verify_exists: kwargs.setdefault('validator_list', []).append(validators.isExistingURL) self.verify_exists = verify_exists diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index c4284f04b1..d3603b0016 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -756,6 +756,9 @@ class ManyToManyField(RelatedField, Field): "Returns the value of this field in the given model instance." return getattr(obj, self.attname).all() + def save_form_data(self, instance, data): + setattr(instance, self.attname, data) + def formfield(self, **kwargs): defaults = {'form_class': forms.ModelMultipleChoiceField, 'queryset': self.rel.to._default_manager.all()} defaults.update(kwargs) diff --git a/django/newforms/extras/widgets.py b/django/newforms/extras/widgets.py index 724dcd9b50..96b1c7244d 100644 --- a/django/newforms/extras/widgets.py +++ b/django/newforms/extras/widgets.py @@ -53,7 +53,7 @@ class SelectDateWidget(Widget): return u'\n'.join(output) - def value_from_datadict(self, data, name): + def value_from_datadict(self, data, files, name): y, m, d = data.get(self.year_field % name), data.get(self.month_field % name), data.get(self.day_field % name) if y and m and d: return '%s-%s-%s' % (y, m, d) diff --git a/django/newforms/fields.py b/django/newforms/fields.py index 58b46ce2b8..e9f50ad4ec 100644 --- a/django/newforms/fields.py +++ b/django/newforms/fields.py @@ -7,10 +7,10 @@ import re import time from django.utils.translation import ugettext -from django.utils.encoding import smart_unicode +from django.utils.encoding import StrAndUnicode, smart_unicode from util import ErrorList, ValidationError -from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple +from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple try: from decimal import Decimal, DecimalException @@ -22,7 +22,7 @@ __all__ = ( 'DEFAULT_DATE_INPUT_FORMATS', 'DateField', 'DEFAULT_TIME_INPUT_FORMATS', 'TimeField', 'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField', - 'RegexField', 'EmailField', 'URLField', 'BooleanField', + 'RegexField', 'EmailField', 'FileField', 'ImageField', 'URLField', 'BooleanField', 'ChoiceField', 'NullBooleanField', 'MultipleChoiceField', 'ComboField', 'MultiValueField', 'FloatField', 'DecimalField', 'SplitDateTimeField', @@ -120,6 +120,7 @@ class CharField(Field): def widget_attrs(self, widget): if self.max_length is not None and isinstance(widget, (TextInput, PasswordInput)): + # The HTML attribute is maxlength, not max_length. return {'maxlength': str(self.max_length)} class IntegerField(Field): @@ -347,6 +348,55 @@ except ImportError: # It's OK if Django settings aren't configured. URL_VALIDATOR_USER_AGENT = 'Django (http://www.djangoproject.com/)' +class UploadedFile(StrAndUnicode): + "A wrapper for files uploaded in a FileField" + def __init__(self, filename, content): + self.filename = filename + self.content = content + + def __unicode__(self): + """ + The unicode representation is the filename, so that the pre-database-insertion + logic can use UploadedFile objects + """ + return self.filename + +class FileField(Field): + widget = FileInput + def __init__(self, *args, **kwargs): + super(FileField, self).__init__(*args, **kwargs) + + def clean(self, data): + super(FileField, self).clean(data) + if not self.required and data in EMPTY_VALUES: + return None + try: + f = UploadedFile(data['filename'], data['content']) + except TypeError: + raise ValidationError(ugettext(u"No file was submitted. Check the encoding type on the form.")) + except KeyError: + raise ValidationError(ugettext(u"No file was submitted.")) + if not f.content: + raise ValidationError(ugettext(u"The submitted file is empty.")) + return f + +class ImageField(FileField): + def clean(self, data): + """ + Checks that the file-upload field data contains a valid image (GIF, JPG, + PNG, possibly others -- whatever the Python Imaging Library supports). + """ + f = super(ImageField, self).clean(data) + if f is None: + return None + from PIL import Image + from cStringIO import StringIO + try: + Image.open(StringIO(f.content)) + except IOError: # Python Imaging Library doesn't recognize it as an image + raise ValidationError(ugettext(u"Upload a valid image. The file you uploaded was either not an image or a corrupted image.")) + return f + class URLField(RegexField): def __init__(self, max_length=None, min_length=None, verify_exists=False, validator_user_agent=URL_VALIDATOR_USER_AGENT, *args, **kwargs): diff --git a/django/newforms/forms.py b/django/newforms/forms.py index 5da85a69c4..906978c86f 100644 --- a/django/newforms/forms.py +++ b/django/newforms/forms.py @@ -57,9 +57,10 @@ class BaseForm(StrAndUnicode): # class is different than Form. See the comments by the Form class for more # information. Any improvements to the form API should be made to *this* # class, not to the Form class. - def __init__(self, data=None, auto_id='id_%s', prefix=None, initial=None): - self.is_bound = data is not None + def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, initial=None): + self.is_bound = data is not None or files is not None self.data = data or {} + self.files = files or {} self.auto_id = auto_id self.prefix = prefix self.initial = initial or {} @@ -88,7 +89,7 @@ class BaseForm(StrAndUnicode): return BoundField(self, field, name) def _get_errors(self): - "Returns an ErrorDict for self.data" + "Returns an ErrorDict for the data provided for the form" if self._errors is None: self.full_clean() return self._errors @@ -179,10 +180,10 @@ class BaseForm(StrAndUnicode): return self.cleaned_data = {} for name, field in self.fields.items(): - # value_from_datadict() gets the data from the dictionary. + # value_from_datadict() gets the data from the data dictionaries. # Each widget type knows how to retrieve its own data, because some # widgets split data over several HTML fields. - value = field.widget.value_from_datadict(self.data, self.add_prefix(name)) + value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name)) try: value = field.clean(value) self.cleaned_data[name] = value @@ -283,7 +284,7 @@ class BoundField(StrAndUnicode): """ Returns the data for this BoundField, or None if it wasn't given. """ - return self.field.widget.value_from_datadict(self.form.data, self.html_name) + return self.field.widget.value_from_datadict(self.form.data, self.form.files, self.html_name) data = property(_data) def label_tag(self, contents=None, attrs=None): diff --git a/django/newforms/models.py b/django/newforms/models.py index 56a08bc58e..247a0eea6b 100644 --- a/django/newforms/models.py +++ b/django/newforms/models.py @@ -34,18 +34,24 @@ def save_instance(form, instance, fields=None, fail_message='saved', commit=True continue if fields and f.name not in fields: continue - setattr(instance, f.name, cleaned_data[f.name]) - if commit: - instance.save() + f.save_form_data(instance, cleaned_data[f.name]) + # Wrap up the saving of m2m data as a function + def save_m2m(): + opts = instance.__class__._meta + cleaned_data = form.cleaned_data for f in opts.many_to_many: if fields and f.name not in fields: continue if f.name in cleaned_data: - setattr(instance, f.attname, cleaned_data[f.name]) - # GOTCHA: If many-to-many data is given and commit=False, the many-to-many - # data will be lost. This happens because a many-to-many options cannot be - # set on an object until after it's saved. Maybe we should raise an - # exception in that case. + f.save_form_data(instance, cleaned_data[f.name]) + if commit: + # If we are committing, save the instance and the m2m data immediately + instance.save() + save_m2m() + else: + # We're not committing. Add a method to the form to allow deferred + # saving of m2m data + form.save_m2m = save_m2m return instance def make_model_save(model, fields, fail_message): diff --git a/django/newforms/widgets.py b/django/newforms/widgets.py index e9b9b55470..f985124389 100644 --- a/django/newforms/widgets.py +++ b/django/newforms/widgets.py @@ -47,7 +47,7 @@ class Widget(object): attrs.update(extra_attrs) return attrs - def value_from_datadict(self, data, name): + def value_from_datadict(self, data, files, name): """ Given a dictionary of data and this widget's name, returns the value of this widget. Returns None if it's not provided. @@ -113,7 +113,7 @@ class MultipleHiddenInput(HiddenInput): final_attrs = self.build_attrs(attrs, type=self.input_type, name=name) return u'\n'.join([(u'<input%s />' % flatatt(dict(value=force_unicode(v), **final_attrs))) for v in value]) - def value_from_datadict(self, data, name): + def value_from_datadict(self, data, files, name): if isinstance(data, MultiValueDict): return data.getlist(name) return data.get(name, None) @@ -121,6 +121,13 @@ class MultipleHiddenInput(HiddenInput): class FileInput(Input): input_type = 'file' + def render(self, name, value, attrs=None): + return super(FileInput, self).render(name, None, attrs=attrs) + + def value_from_datadict(self, data, files, name): + "File widgets take data from FILES, not POST" + return files.get(name, None) + class Textarea(Widget): def __init__(self, attrs=None): # The 'rows' and 'cols' attributes are required for HTML correctness. @@ -188,7 +195,7 @@ class NullBooleanSelect(Select): value = u'1' return super(NullBooleanSelect, self).render(name, value, attrs, choices) - def value_from_datadict(self, data, name): + def value_from_datadict(self, data, files, name): value = data.get(name, None) return {u'2': True, u'3': False, True: True, False: False}.get(value, None) @@ -210,7 +217,7 @@ class SelectMultiple(Widget): output.append(u'</select>') return u'\n'.join(output) - def value_from_datadict(self, data, name): + def value_from_datadict(self, data, files, name): if isinstance(data, MultiValueDict): return data.getlist(name) return data.get(name, None) @@ -377,8 +384,8 @@ class MultiWidget(Widget): return id_ id_for_label = classmethod(id_for_label) - def value_from_datadict(self, data, name): - return [widget.value_from_datadict(data, name + '_%s' % i) for i, widget in enumerate(self.widgets)] + def value_from_datadict(self, data, files, name): + return [widget.value_from_datadict(data, files, name + '_%s' % i) for i, widget in enumerate(self.widgets)] def format_output(self, rendered_widgets): """ diff --git a/django/oldforms/__init__.py b/django/oldforms/__init__.py index a0f14cdcf2..b3d78f8919 100644 --- a/django/oldforms/__init__.py +++ b/django/oldforms/__init__.py @@ -4,6 +4,7 @@ from django.utils.html import escape from django.conf import settings from django.utils.translation import ugettext, ungettext from django.utils.encoding import smart_unicode, force_unicode +from django.utils.maxlength import LegacyMaxlength FORM_FIELD_ID_PREFIX = 'id_' @@ -302,6 +303,9 @@ class FormField(object): Subclasses should also implement a render(data) method, which is responsible for rending the form field in XHTML. """ + # Provide backwards compatibility for the maxlength attribute and + # argument for this class and all subclasses. + __metaclass__ = LegacyMaxlength def __str__(self): return unicode(self).encode('utf-8') @@ -390,19 +394,19 @@ class FormField(object): class TextField(FormField): input_type = "text" - def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=None, member_name=None): + def __init__(self, field_name, length=30, max_length=None, is_required=False, validator_list=None, member_name=None): if validator_list is None: validator_list = [] self.field_name = field_name - self.length, self.maxlength = length, maxlength + self.length, self.max_length = length, max_length self.is_required = is_required self.validator_list = [self.isValidLength, self.hasNoNewlines] + validator_list if member_name != None: self.member_name = member_name def isValidLength(self, data, form): - if data and self.maxlength and len(smart_unicode(data)) > self.maxlength: + if data and self.max_length and len(smart_unicode(data)) > self.max_length: raise validators.ValidationError, ungettext("Ensure your text is less than %s character.", - "Ensure your text is less than %s characters.", self.maxlength) % self.maxlength + "Ensure your text is less than %s characters.", self.max_length) % self.max_length def hasNoNewlines(self, data, form): if data and '\n' in data: @@ -411,12 +415,12 @@ class TextField(FormField): def render(self, data): if data is None: data = u'' - maxlength = u'' - if self.maxlength: - maxlength = u'maxlength="%s" ' % self.maxlength + max_length = u'' + if self.max_length: + max_length = u'maxlength="%s" ' % self.max_length return u'<input type="%s" id="%s" class="v%s%s" name="%s" size="%s" value="%s" %s/>' % \ (self.input_type, self.get_id(), self.__class__.__name__, self.is_required and u' required' or '', - self.field_name, self.length, escape(data), maxlength) + self.field_name, self.length, escape(data), max_length) def html2python(data): return data @@ -426,14 +430,14 @@ class PasswordField(TextField): input_type = "password" class LargeTextField(TextField): - def __init__(self, field_name, rows=10, cols=40, is_required=False, validator_list=None, maxlength=None): + def __init__(self, field_name, rows=10, cols=40, is_required=False, validator_list=None, max_length=None): if validator_list is None: validator_list = [] self.field_name = field_name self.rows, self.cols, self.is_required = rows, cols, is_required self.validator_list = validator_list[:] - if maxlength: + if max_length: self.validator_list.append(self.isValidLength) - self.maxlength = maxlength + self.max_length = max_length def render(self, data): if data is None: @@ -710,12 +714,12 @@ class ImageUploadField(FileUploadField): #################### class IntegerField(TextField): - def __init__(self, field_name, length=10, maxlength=None, is_required=False, validator_list=None, member_name=None): + def __init__(self, field_name, length=10, max_length=None, is_required=False, validator_list=None, member_name=None): if validator_list is None: validator_list = [] validator_list = [self.isInteger] + validator_list if member_name is not None: self.member_name = member_name - TextField.__init__(self, field_name, length, maxlength, is_required, validator_list) + TextField.__init__(self, field_name, length, max_length, is_required, validator_list) def isInteger(self, field_data, all_data): try: @@ -730,57 +734,57 @@ class IntegerField(TextField): html2python = staticmethod(html2python) class SmallIntegerField(IntegerField): - def __init__(self, field_name, length=5, maxlength=5, is_required=False, validator_list=None): + def __init__(self, field_name, length=5, max_length=5, is_required=False, validator_list=None): if validator_list is None: validator_list = [] validator_list = [self.isSmallInteger] + validator_list - IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list) + IntegerField.__init__(self, field_name, length, max_length, is_required, validator_list) def isSmallInteger(self, field_data, all_data): if not -32768 <= int(field_data) <= 32767: raise validators.CriticalValidationError, ugettext("Enter a whole number between -32,768 and 32,767.") class PositiveIntegerField(IntegerField): - def __init__(self, field_name, length=10, maxlength=None, is_required=False, validator_list=None): + def __init__(self, field_name, length=10, max_length=None, is_required=False, validator_list=None): if validator_list is None: validator_list = [] validator_list = [self.isPositive] + validator_list - IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list) + IntegerField.__init__(self, field_name, length, max_length, is_required, validator_list) def isPositive(self, field_data, all_data): if int(field_data) < 0: raise validators.CriticalValidationError, ugettext("Enter a positive number.") class PositiveSmallIntegerField(IntegerField): - def __init__(self, field_name, length=5, maxlength=None, is_required=False, validator_list=None): + def __init__(self, field_name, length=5, max_length=None, is_required=False, validator_list=None): if validator_list is None: validator_list = [] validator_list = [self.isPositiveSmall] + validator_list - IntegerField.__init__(self, field_name, length, maxlength, is_required, validator_list) + IntegerField.__init__(self, field_name, length, max_length, is_required, validator_list) def isPositiveSmall(self, field_data, all_data): if not 0 <= int(field_data) <= 32767: raise validators.CriticalValidationError, ugettext("Enter a whole number between 0 and 32,767.") class FloatField(TextField): - def __init__(self, field_name, is_required=False, validator_list=None): - if validator_list is None: validator_list = [] - validator_list = [validators.isValidFloat] + validator_list - TextField.__init__(self, field_name, is_required=is_required, validator_list=validator_list) - - def html2python(data): - if data == '' or data is None: - return None - return float(data) - html2python = staticmethod(html2python) - -class DecimalField(TextField): + def __init__(self, field_name, is_required=False, validator_list=None): + if validator_list is None: validator_list = [] + validator_list = [validators.isValidFloat] + validator_list + TextField.__init__(self, field_name, is_required=is_required, validator_list=validator_list) + + def html2python(data): + if data == '' or data is None: + return None + return float(data) + html2python = staticmethod(html2python) + +class DecimalField(TextField): def __init__(self, field_name, max_digits, decimal_places, is_required=False, validator_list=None): if validator_list is None: validator_list = [] self.max_digits, self.decimal_places = max_digits, decimal_places - validator_list = [self.isValidDecimal] + validator_list - # Initialise the TextField, making sure it's large enough to fit the number with a - sign and a decimal point. - super(DecimalField, self).__init__(field_name, max_digits+2, max_digits+2, is_required, validator_list) + validator_list = [self.isValidDecimal] + validator_list + # Initialise the TextField, making sure it's large enough to fit the number with a - sign and a decimal point. + super(DecimalField, self).__init__(field_name, max_digits+2, max_digits+2, is_required, validator_list) - def isValidDecimal(self, field_data, all_data): - v = validators.IsValidDecimal(self.max_digits, self.decimal_places) + def isValidDecimal(self, field_data, all_data): + v = validators.IsValidDecimal(self.max_digits, self.decimal_places) try: v(field_data, all_data) except validators.ValidationError, e: @@ -789,14 +793,14 @@ class DecimalField(TextField): def html2python(data): if data == '' or data is None: return None - try: - import decimal + try: + import decimal except ImportError: from django.utils import _decimal as decimal - try: - return decimal.Decimal(data) - except decimal.InvalidOperation, e: - raise ValueError, e + try: + return decimal.Decimal(data) + except decimal.InvalidOperation, e: + raise ValueError, e html2python = staticmethod(html2python) #################### @@ -806,10 +810,10 @@ class DecimalField(TextField): class DatetimeField(TextField): """A FormField that automatically converts its data to a datetime.datetime object. The data should be in the format YYYY-MM-DD HH:MM:SS.""" - def __init__(self, field_name, length=30, maxlength=None, is_required=False, validator_list=None): + def __init__(self, field_name, length=30, max_length=None, is_required=False, validator_list=None): if validator_list is None: validator_list = [] self.field_name = field_name - self.length, self.maxlength = length, maxlength + self.length, self.max_length = length, max_length self.is_required = is_required self.validator_list = [validators.isValidANSIDatetime] + validator_list @@ -836,7 +840,7 @@ class DateField(TextField): def __init__(self, field_name, is_required=False, validator_list=None): if validator_list is None: validator_list = [] validator_list = [self.isValidDate] + validator_list - TextField.__init__(self, field_name, length=10, maxlength=10, + TextField.__init__(self, field_name, length=10, max_length=10, is_required=is_required, validator_list=validator_list) def isValidDate(self, field_data, all_data): @@ -861,7 +865,7 @@ class TimeField(TextField): def __init__(self, field_name, is_required=False, validator_list=None): if validator_list is None: validator_list = [] validator_list = [self.isValidTime] + validator_list - TextField.__init__(self, field_name, length=8, maxlength=8, + TextField.__init__(self, field_name, length=8, max_length=8, is_required=is_required, validator_list=validator_list) def isValidTime(self, field_data, all_data): @@ -893,10 +897,10 @@ class TimeField(TextField): class EmailField(TextField): "A convenience FormField for validating e-mail addresses" - def __init__(self, field_name, length=50, maxlength=75, is_required=False, validator_list=None): + def __init__(self, field_name, length=50, max_length=75, is_required=False, validator_list=None): if validator_list is None: validator_list = [] validator_list = [self.isValidEmail] + validator_list - TextField.__init__(self, field_name, length, maxlength=maxlength, + TextField.__init__(self, field_name, length, max_length=max_length, is_required=is_required, validator_list=validator_list) def isValidEmail(self, field_data, all_data): @@ -907,10 +911,10 @@ class EmailField(TextField): class URLField(TextField): "A convenience FormField for validating URLs" - def __init__(self, field_name, length=50, maxlength=200, is_required=False, validator_list=None): + def __init__(self, field_name, length=50, max_length=200, is_required=False, validator_list=None): if validator_list is None: validator_list = [] validator_list = [self.isValidURL] + validator_list - TextField.__init__(self, field_name, length=length, maxlength=maxlength, + TextField.__init__(self, field_name, length=length, max_length=max_length, is_required=is_required, validator_list=validator_list) def isValidURL(self, field_data, all_data): @@ -920,10 +924,10 @@ class URLField(TextField): raise validators.CriticalValidationError, e.messages class IPAddressField(TextField): - def __init__(self, field_name, length=15, maxlength=15, is_required=False, validator_list=None): + def __init__(self, field_name, length=15, max_length=15, is_required=False, validator_list=None): if validator_list is None: validator_list = [] validator_list = [self.isValidIPAddress] + validator_list - TextField.__init__(self, field_name, length=length, maxlength=maxlength, + TextField.__init__(self, field_name, length=length, max_length=max_length, is_required=is_required, validator_list=validator_list) def isValidIPAddress(self, field_data, all_data): @@ -970,7 +974,7 @@ class PhoneNumberField(TextField): def __init__(self, field_name, is_required=False, validator_list=None): if validator_list is None: validator_list = [] validator_list = [self.isValidPhone] + validator_list - TextField.__init__(self, field_name, length=12, maxlength=12, + TextField.__init__(self, field_name, length=12, max_length=12, is_required=is_required, validator_list=validator_list) def isValidPhone(self, field_data, all_data): @@ -984,7 +988,7 @@ class USStateField(TextField): def __init__(self, field_name, is_required=False, validator_list=None): if validator_list is None: validator_list = [] validator_list = [self.isValidUSState] + validator_list - TextField.__init__(self, field_name, length=2, maxlength=2, + TextField.__init__(self, field_name, length=2, max_length=2, is_required=is_required, validator_list=validator_list) def isValidUSState(self, field_data, all_data): @@ -1001,10 +1005,10 @@ class USStateField(TextField): class CommaSeparatedIntegerField(TextField): "A convenience FormField for validating comma-separated integer fields" - def __init__(self, field_name, maxlength=None, is_required=False, validator_list=None): + def __init__(self, field_name, max_length=None, is_required=False, validator_list=None): if validator_list is None: validator_list = [] validator_list = [self.isCommaSeparatedIntegerList] + validator_list - TextField.__init__(self, field_name, length=20, maxlength=maxlength, + TextField.__init__(self, field_name, length=20, max_length=max_length, is_required=is_required, validator_list=validator_list) def isCommaSeparatedIntegerList(self, field_data, all_data): diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py index 7b3a261a5b..bd21212ff6 100644 --- a/django/template/defaulttags.py +++ b/django/template/defaulttags.py @@ -649,8 +649,8 @@ def do_if(parser, token): As you can see, the ``if`` tag can take an option ``{% else %}`` clause that will be displayed if the test fails. - ``if`` tags may use ``or`` or ``not`` to test a number of variables or to - negate a given variable:: + ``if`` tags may use ``or``, ``and`` or ``not`` to test a number of + variables or to negate a given variable:: {% if not athlete_list %} There are no athletes. @@ -660,19 +660,32 @@ def do_if(parser, token): There are some athletes or some coaches. {% endif %} + {% if athlete_list and coach_list %} + Both atheletes and coaches are available. + {% endif %} + {% if not athlete_list or coach_list %} There are no athletes, or there are some coaches. {% endif %} - For simplicity, ``if`` tags do not allow ``and`` clauses. Use nested ``if`` - tags instead:: + {% if athlete_list and not coach_list %} + There are some athletes and absolutely no coaches. + {% endif %} - {% if athlete_list %} - {% if coach_list %} - Number of athletes: {{ athlete_list|count }}. - Number of coaches: {{ coach_list|count }}. - {% endif %} + ``if`` tags do not allow ``and`` and ``or`` clauses with the same + tag, because the order of logic would be ambigous. For example, + this is invalid:: + + {% if athlete_list and coach_list or cheerleader_list %} + + If you need to combine and and or to do advanced logic, just use + nested if tags. For example: + + {% if athlete_list %} + {% if coach_list or cheerleader_list %} + We have athletes, and either coaches or cheerleaders! {% endif %} + {% endif %} """ bits = token.contents.split() del bits[0] diff --git a/django/utils/encoding.py b/django/utils/encoding.py index 7515d0c41b..2319496538 100644 --- a/django/utils/encoding.py +++ b/django/utils/encoding.py @@ -1,6 +1,5 @@ import types import urllib -from django.conf import settings from django.utils.functional import Promise class StrAndUnicode(object): diff --git a/django/utils/maxlength.py b/django/utils/maxlength.py new file mode 100644 index 0000000000..9216fe1c3a --- /dev/null +++ b/django/utils/maxlength.py @@ -0,0 +1,67 @@ +""" +Utilities for providing backwards compatibility for the maxlength argument, +which has been replaced by max_length, see ticket #2101. +""" + +from warnings import warn + +def get_maxlength(self): + return self.max_length + +def set_maxlength(self, value): + self.max_length = value + +def legacy_maxlength(max_length, maxlength): + """ + Consolidates max_length and maxlength, providing backwards compatibilty + for the legacy "maxlength" argument. + If one of max_length or maxlength is given, then that value is returned. + If both are given, a TypeError is raised. + If maxlength is used at all, a deprecation warning is issued. + """ + if maxlength is not None: + warn("maxlength is deprecated, use max_length instead.", + PendingDeprecationWarning, + stacklevel=3) + if max_length is not None: + raise TypeError("field can not take both the max_length" + " argument and the legacy maxlength argument.") + max_length = maxlength + return max_length + +def remove_maxlength(func): + """ + A decorator to be used on a class's __init__ that provides backwards + compatibilty for the legacy "maxlength" keyword argument, i.e. + name = models.CharField(maxlength=20) + It does this by changing the passed "maxlength" keyword argument + (if it exists) into a "max_length" keyword argument. + """ + def inner(self, *args, **kwargs): + max_length = kwargs.get('max_length', None) + # pop maxlength because we don't want this going to __init__. + maxlength = kwargs.pop('maxlength', None) + max_length = legacy_maxlength(max_length, maxlength) + # Only set the max_length keyword argument if we got a value back. + if max_length is not None: + kwargs['max_length'] = max_length + func(self, *args, **kwargs) + return inner + +# This metaclass is used in two places, and should be removed when legacy +# support for maxlength is dropped. +# * oldforms.FormField +# * db.models.fields.Field + +class LegacyMaxlength(type): + """ + Metaclass for providing backwards compatibility support for the + "maxlength" keyword argument. + """ + + def __init__(cls, name, bases, attrs): + super(LegacyMaxlength, cls).__init__(name, bases, attrs) + # Decorate the class's __init__ to remove any maxlength keyword. + cls.__init__ = remove_maxlength(cls.__init__) + # Support accessing and setting to the legacy maxlength attribute. + cls.maxlength = property(get_maxlength, set_maxlength) diff --git a/docs/add_ons.txt b/docs/add_ons.txt index ffc4f7420f..8682208970 100644 --- a/docs/add_ons.txt +++ b/docs/add_ons.txt @@ -214,7 +214,7 @@ A framework for generating syndication feeds, in RSS and Atom, quite easily. See the `syndication documentation`_. -.. _syndication documentation: ../syndication/ +.. _syndication documentation: ../syndication_feeds/ Other add-ons ============= diff --git a/docs/api_stability.txt b/docs/api_stability.txt index cfaffeac6b..5ccf104327 100644 --- a/docs/api_stability.txt +++ b/docs/api_stability.txt @@ -82,9 +82,6 @@ that 90% of Django can be considered forwards-compatible at this point. That said, these APIs should *not* be considered stable, and are likely to change: - - `Forms and validation`_ will most likely be completely rewritten to - deemphasize Manipulators in favor of validation-aware models. - - `Serialization`_ is under heavy development; changes are likely. - The `authentication`_ framework is changing to be far more flexible, and @@ -114,7 +111,7 @@ change: .. _sending email: ../email/ .. _sessions: ../sessions/ .. _settings: ../settings/ -.. _syndication: ../syndication/ +.. _syndication: ../syndication_feeds/ .. _template language: ../templates/ .. _transactions: ../transactions/ .. _url dispatch: ../url_dispatch/ diff --git a/docs/authentication.txt b/docs/authentication.txt index a05624db68..589e8c9f1b 100644 --- a/docs/authentication.txt +++ b/docs/authentication.txt @@ -234,7 +234,7 @@ the setting and checking of these values behind the scenes. Previous Django versions, such as 0.90, used simple MD5 hashes without password salts. For backwards compatibility, those are still supported; they'll be -converted automatically to the new style the first time ``check_password()`` +converted automatically to the new style the first time ``User.check_password()`` works correctly for a given user. Anonymous users diff --git a/docs/contributing.txt b/docs/contributing.txt index 9dbb865a58..faa4c113f1 100644 --- a/docs/contributing.txt +++ b/docs/contributing.txt @@ -340,14 +340,14 @@ Model style Do this:: class Person(models.Model): - first_name = models.CharField(maxlength=20) - last_name = models.CharField(maxlength=40) + first_name = models.CharField(max_length=20) + last_name = models.CharField(max_length=40) Don't do this:: class Person(models.Model): - FirstName = models.CharField(maxlength=20) - Last_Name = models.CharField(maxlength=40) + FirstName = models.CharField(max_length=20) + Last_Name = models.CharField(max_length=40) * The ``class Meta`` should appear *after* the fields are defined, with a single blank line separating the fields and the class definition. @@ -355,8 +355,8 @@ Model style Do this:: class Person(models.Model): - first_name = models.CharField(maxlength=20) - last_name = models.CharField(maxlength=40) + first_name = models.CharField(max_length=20) + last_name = models.CharField(max_length=40) class Meta: verbose_name_plural = 'people' @@ -364,8 +364,8 @@ Model style Don't do this:: class Person(models.Model): - first_name = models.CharField(maxlength=20) - last_name = models.CharField(maxlength=40) + first_name = models.CharField(max_length=20) + last_name = models.CharField(max_length=40) class Meta: verbose_name_plural = 'people' @@ -375,8 +375,8 @@ Model style class Meta: verbose_name_plural = 'people' - first_name = models.CharField(maxlength=20) - last_name = models.CharField(maxlength=40) + first_name = models.CharField(max_length=20) + last_name = models.CharField(max_length=40) * The order of model inner classes and standard methods should be as follows (noting that these are not all required): diff --git a/docs/databases.txt b/docs/databases.txt index b73f39843c..ed0cb61bc3 100644 --- a/docs/databases.txt +++ b/docs/databases.txt @@ -124,7 +124,7 @@ Several other MySQLdb connection options may be useful, such as ``ssl``, ``use_unicode``, ``init_command``, and ``sql_mode``. Consult the `MySQLdb documentation`_ for more details. -.. _settings documentation: http://www.djangoproject.com/documentation/settings/#database-engine +.. _settings documentation: ../settings/#database-engine .. _MySQL option file: http://dev.mysql.com/doc/refman/5.0/en/option-files.html .. _MySQLdb documentation: http://mysql-python.sourceforge.net/ diff --git a/docs/db-api.txt b/docs/db-api.txt index 975a166b6b..766a6ae519 100644 --- a/docs/db-api.txt +++ b/docs/db-api.txt @@ -12,14 +12,14 @@ Throughout this reference, we'll refer to the following models, which comprise a weblog application:: class Blog(models.Model): - name = models.CharField(maxlength=100) + name = models.CharField(max_length=100) tagline = models.TextField() def __unicode__(self): return self.name class Author(models.Model): - name = models.CharField(maxlength=50) + name = models.CharField(max_length=50) email = models.EmailField() def __unicode__(self): @@ -27,7 +27,7 @@ a weblog application:: class Entry(models.Model): blog = models.ForeignKey(Blog) - headline = models.CharField(maxlength=255) + headline = models.CharField(max_length=255) body_text = models.TextField() pub_date = models.DateTimeField() authors = models.ManyToManyField(Author) @@ -1503,7 +1503,7 @@ precede the definition of any keyword arguments. For example:: See the `OR lookups examples page`_ for more examples. -.. _OR lookups examples page: http://www.djangoproject.com/documentation/models/or_lookups/ +.. _OR lookups examples page: ../models/or_lookups/ Related objects =============== @@ -1806,8 +1806,8 @@ following model:: ('F', 'Female'), ) class Person(models.Model): - name = models.CharField(maxlength=20) - gender = models.CharField(maxlength=1, choices=GENDER_CHOICES) + name = models.CharField(max_length=20) + gender = models.CharField(max_length=1, choices=GENDER_CHOICES) ...each ``Person`` instance will have a ``get_gender_display()`` method. Example:: @@ -1834,7 +1834,7 @@ Note that in the case of identical date values, these methods will use the ID as a fallback check. This guarantees that no records are skipped or duplicated. For a full example, see the `lookup API sample model`_. -.. _lookup API sample model: http://www.djangoproject.com/documentation/models/lookup/ +.. _lookup API sample model: ../models/lookup/ get_FOO_filename() ------------------ diff --git a/docs/email.txt b/docs/email.txt index 50dafaf8df..97bdec0037 100644 --- a/docs/email.txt +++ b/docs/email.txt @@ -314,7 +314,7 @@ To send a text and HTML combination, you could write:: subject, from_email, to = 'hello', 'from@example.com', 'to@example.com' text_content = 'This is an important message.' - html_content = '<p>This is an <strong>important</strong> message.' + html_content = '<p>This is an <strong>important</strong> message.</p>' msg = EmailMultiAlternatives(subject, text_content, from_email, to) msg.attach_alternative(html_content, "text/html") msg.send() diff --git a/docs/faq.txt b/docs/faq.txt index 67ed8a49a5..844ea77809 100644 --- a/docs/faq.txt +++ b/docs/faq.txt @@ -42,7 +42,10 @@ Listen to his music. You'll like it. Django is pronounced **JANG**-oh. Rhymes with FANG-oh. The "D" is silent. +We've also recorded an `audio clip of the pronunciation`_. + .. _Django Reinhardt: http://en.wikipedia.org/wiki/Django_Reinhardt +.. _audio clip of the pronunciation: http://red-bean.com/~adrian/django_pronunciation.mp3 Is Django stable? ----------------- diff --git a/docs/forms.txt b/docs/forms.txt index 18d3d3fcbe..18d322a8eb 100644 --- a/docs/forms.txt +++ b/docs/forms.txt @@ -37,11 +37,11 @@ this document, we'll be working with the following model, a "place" object:: ) class Place(models.Model): - name = models.CharField(maxlength=100) - address = models.CharField(maxlength=100, blank=True) - city = models.CharField(maxlength=50, blank=True) + name = models.CharField(max_length=100) + address = models.CharField(max_length=100, blank=True) + city = models.CharField(max_length=50, blank=True) state = models.USStateField() - zip_code = models.CharField(maxlength=5, blank=True) + zip_code = models.CharField(max_length=5, blank=True) place_type = models.IntegerField(choices=PLACE_TYPES) class Admin: @@ -388,7 +388,7 @@ for a "contact" form on a website:: def __init__(self): self.fields = ( forms.EmailField(field_name="from", is_required=True), - forms.TextField(field_name="subject", length=30, maxlength=200, is_required=True), + forms.TextField(field_name="subject", length=30, max_length=200, is_required=True), forms.SelectField(field_name="urgency", choices=urgency_choices), forms.LargeTextField(field_name="contents", is_required=True), ) diff --git a/docs/model-api.txt b/docs/model-api.txt index 6a706c57cb..3b634de1d8 100644 --- a/docs/model-api.txt +++ b/docs/model-api.txt @@ -22,7 +22,7 @@ A companion to this document is the `official repository of model examples`_. ``tests/modeltests`` directory.) .. _Database API reference: ../db-api/ -.. _official repository of model examples: http://www.djangoproject.com/documentation/models/ +.. _official repository of model examples: ../models/ Quick example ============= @@ -33,8 +33,8 @@ This example model defines a ``Person``, which has a ``first_name`` and from django.db import models class Person(models.Model): - first_name = models.CharField(maxlength=30) - last_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) + last_name = models.CharField(max_length=30) ``first_name`` and ``last_name`` are *fields* of the model. Each field is specified as a class attribute, and each attribute maps to a database column. @@ -69,13 +69,13 @@ attributes. Example:: class Musician(models.Model): - first_name = models.CharField(maxlength=50) - last_name = models.CharField(maxlength=50) - instrument = models.CharField(maxlength=100) + first_name = models.CharField(max_length=50) + last_name = models.CharField(max_length=50) + instrument = models.CharField(max_length=100) class Album(models.Model): artist = models.ForeignKey(Musician) - name = models.CharField(maxlength=100) + name = models.CharField(max_length=100) release_date = models.DateField() num_stars = models.IntegerField() @@ -142,14 +142,18 @@ For large amounts of text, use ``TextField``. The admin represents this as an ``<input type="text">`` (a single-line input). -``CharField`` has an extra required argument, ``maxlength``, the maximum length -(in characters) of the field. The maxlength is enforced at the database level +``CharField`` has an extra required argument, ``max_length``, the maximum length +(in characters) of the field. The max_length is enforced at the database level and in Django's validation. -``CommaSeparatedIntegerField`` +Django veterans: Note that the argument is now called ``max_length`` to +provide consistency throughout Django. There is full legacy support for +the old ``maxlength`` argument, but ``max_length`` is prefered. + + ``CommaSeparatedIntegerField`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -A field of integers separated by commas. As in ``CharField``, the ``maxlength`` +A field of integers separated by commas. As in ``CharField``, the ``max_length`` argument is required. ``DateField`` @@ -217,7 +221,7 @@ The admin represents this as an ``<input type="text">`` (a single-line input). ~~~~~~~~~~~~~~ A ``CharField`` that checks that the value is a valid e-mail address. -This doesn't accept ``maxlength``; its ``maxlength`` is automatically set to +This doesn't accept ``max_length``; its ``max_length`` is automatically set to 75. ``FileField`` @@ -400,7 +404,7 @@ Like a ``PositiveIntegerField``, but only allows values under a certain containing only letters, numbers, underscores or hyphens. They're generally used in URLs. -Like a CharField, you can specify ``maxlength``. If ``maxlength`` is +Like a CharField, you can specify ``max_length``. If ``max_length`` is not specified, Django will use a default length of 50. Implies ``db_index=True``. @@ -447,9 +451,9 @@ and doesn't give a 404 response). The admin represents this as an ``<input type="text">`` (a single-line input). -``URLField`` takes an optional argument, ``maxlength``, the maximum length (in -characters) of the field. The maxlength is enforced at the database level and -in Django's validation. If you don't specify ``maxlength``, a default of 200 +``URLField`` takes an optional argument, ``max_length``, the maximum length (in +characters) of the field. The maximum length is enforced at the database level and +in Django's validation. If you don't specify ``max_length``, a default of 200 is used. ``USStateField`` @@ -536,7 +540,7 @@ The choices list can be defined either as part of your model class:: ('M', 'Male'), ('F', 'Female'), ) - gender = models.CharField(maxlength=1, choices=GENDER_CHOICES) + gender = models.CharField(max_length=1, choices=GENDER_CHOICES) or outside your model class altogether:: @@ -545,7 +549,7 @@ or outside your model class altogether:: ('F', 'Female'), ) class Foo(models.Model): - gender = models.CharField(maxlength=1, choices=GENDER_CHOICES) + gender = models.CharField(max_length=1, choices=GENDER_CHOICES) For each model field that has ``choices`` set, Django will add a method to retrieve the human-readable name for the field's current value. See @@ -620,6 +624,12 @@ Extra "help" text to be displayed under the field on the object's admin form. It's useful for documentation even if your object doesn't have an admin form. +Note that this value is *not* HTML-escaped when it's displayed in the admin +interface. This lets you include HTML in ``help_text`` if you so desire. For +example:: + + help_text="Please use the following format: <em>YYYY-MM-DD</em>." + ``primary_key`` ~~~~~~~~~~~~~~~ @@ -698,11 +708,11 @@ it using the field's attribute name, converting underscores to spaces. In this example, the verbose name is ``"Person's first name"``:: - first_name = models.CharField("Person's first name", maxlength=30) + first_name = models.CharField("Person's first name", max_length=30) In this example, the verbose name is ``"first name"``:: - first_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) ``ForeignKey``, ``ManyToManyField`` and ``OneToOneField`` require the first argument to be a model class, so use the ``verbose_name`` keyword argument:: @@ -775,7 +785,7 @@ You can, of course, call the field whatever you want. For example:: See the `Many-to-one relationship model example`_ for a full example. -.. _Many-to-one relationship model example: http://www.djangoproject.com/documentation/models/many_to_one/ +.. _Many-to-one relationship model example: ../models/many_to_one/ ``ForeignKey`` fields take a number of extra arguments for defining how the relationship should work. All are optional: @@ -902,7 +912,7 @@ set up above, the ``Pizza`` admin form would let users select the toppings. See the `Many-to-many relationship model example`_ for a full example. -.. _Many-to-many relationship model example: http://www.djangoproject.com/documentation/models/many_to_many/ +.. _Many-to-many relationship model example: ../models/many_to_many/ ``ManyToManyField`` objects take a number of extra arguments for defining how the relationship should work. All are optional: @@ -979,7 +989,7 @@ as a read-only field when you edit an object in the admin interface: See the `One-to-one relationship model example`_ for a full example. -.. _One-to-one relationship model example: http://www.djangoproject.com/documentation/models/one_to_one/ +.. _One-to-one relationship model example: ../models/one_to_one/ Custom field types ------------------ @@ -1027,8 +1037,8 @@ Once you have ``MytypeField``, you can use it in any model, just like any other ``Field`` type:: class Person(models.Model): - name = models.CharField(maxlength=80) - gender = models.CharField(maxlength=1) + name = models.CharField(max_length=80) + gender = models.CharField(max_length=1) something_else = MytypeField() If you aim to build a database-agnostic application, you should account for @@ -1074,12 +1084,12 @@ time -- i.e., when the class is instantiated. To do that, just implement # This is a much more flexible example. class BetterCharField(models.Field): - def __init__(self, maxlength, *args, **kwargs): - self.maxlength = maxlength + def __init__(self, max_length, *args, **kwargs): + self.max_length = max_length super(BetterCharField, self).__init__(*args, **kwargs) def db_type(self): - return 'char(%s)' % self.maxlength + return 'char(%s)' % self.max_length # In the model: class MyModel(models.Model): @@ -1096,7 +1106,7 @@ Meta options Give your model metadata by using an inner ``class Meta``, like so:: class Foo(models.Model): - bar = models.CharField(maxlength=30) + bar = models.CharField(max_length=30) class Meta: # ... @@ -1186,7 +1196,7 @@ See `Specifying ordering`_ for more examples. Note that, regardless of how many fields are in ``ordering``, the admin site uses only the first field. -.. _Specifying ordering: http://www.djangoproject.com/documentation/models/ordering/ +.. _Specifying ordering: ../models/ordering/ ``permissions`` --------------- @@ -1270,8 +1280,8 @@ If you want your model to be visible to Django's admin site, give your model an inner ``"class Admin"``, like so:: class Person(models.Model): - first_name = models.CharField(maxlength=30) - last_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) + last_name = models.CharField(max_length=30) class Admin: # Admin options go here @@ -1430,7 +1440,7 @@ A few special cases to note about ``list_display``: Here's a full example model:: class Person(models.Model): - name = models.CharField(maxlength=50) + name = models.CharField(max_length=50) birthday = models.DateField() class Admin: @@ -1447,9 +1457,9 @@ A few special cases to note about ``list_display``: Here's a full example model:: class Person(models.Model): - first_name = models.CharField(maxlength=50) - last_name = models.CharField(maxlength=50) - color_code = models.CharField(maxlength=6) + first_name = models.CharField(max_length=50) + last_name = models.CharField(max_length=50) + color_code = models.CharField(max_length=6) class Admin: list_display = ('first_name', 'last_name', 'colored_name') @@ -1465,7 +1475,7 @@ A few special cases to note about ``list_display``: Here's a full example model:: class Person(models.Model): - first_name = models.CharField(maxlength=50) + first_name = models.CharField(max_length=50) birthday = models.DateField() class Admin: @@ -1493,8 +1503,8 @@ A few special cases to note about ``list_display``: For example:: class Person(models.Model): - first_name = models.CharField(maxlength=50) - color_code = models.CharField(maxlength=6) + first_name = models.CharField(max_length=50) + color_code = models.CharField(max_length=6) class Admin: list_display = ('first_name', 'colored_first_name') @@ -1744,13 +1754,13 @@ returns a list of all ``OpinionPoll`` objects, each with an extra return result_list class OpinionPoll(models.Model): - question = models.CharField(maxlength=200) + question = models.CharField(max_length=200) poll_date = models.DateField() objects = PollManager() class Response(models.Model): poll = models.ForeignKey(Poll) - person_name = models.CharField(maxlength=50) + person_name = models.CharField(max_length=50) response = models.TextField() With this example, you'd use ``OpinionPoll.objects.with_counts()`` to return @@ -1766,8 +1776,8 @@ A ``Manager``'s base ``QuerySet`` returns all objects in the system. For example, using this model:: class Book(models.Model): - title = models.CharField(maxlength=100) - author = models.CharField(maxlength=50) + title = models.CharField(max_length=100) + author = models.CharField(max_length=50) ...the statement ``Book.objects.all()`` will return all books in the database. @@ -1785,8 +1795,8 @@ all objects, and one that returns only the books by Roald Dahl:: # Then hook it into the Book model explicitly. class Book(models.Model): - title = models.CharField(maxlength=100) - author = models.CharField(maxlength=50) + title = models.CharField(max_length=100) + author = models.CharField(max_length=50) objects = models.Manager() # The default manager. dahl_objects = DahlBookManager() # The Dahl-specific manager. @@ -1819,9 +1829,9 @@ For example:: return super(FemaleManager, self).get_query_set().filter(sex='F') class Person(models.Model): - first_name = models.CharField(maxlength=50) - last_name = models.CharField(maxlength=50) - sex = models.CharField(maxlength=1, choices=(('M', 'Male'), ('F', 'Female'))) + first_name = models.CharField(max_length=50) + last_name = models.CharField(max_length=50) + sex = models.CharField(max_length=1, choices=(('M', 'Male'), ('F', 'Female'))) people = models.Manager() men = MaleManager() women = FemaleManager() @@ -1851,11 +1861,11 @@ model. For example, this model has a few custom methods:: class Person(models.Model): - first_name = models.CharField(maxlength=50) - last_name = models.CharField(maxlength=50) + first_name = models.CharField(max_length=50) + last_name = models.CharField(max_length=50) birth_date = models.DateField() - address = models.CharField(maxlength=100) - city = models.CharField(maxlength=50) + address = models.CharField(max_length=100) + city = models.CharField(max_length=50) state = models.USStateField() # Yes, this is America-centric... def baby_boomer_status(self): @@ -1897,8 +1907,8 @@ Although this isn't required, it's strongly encouraged (see the description of For example:: class Person(models.Model): - first_name = models.CharField(maxlength=50) - last_name = models.CharField(maxlength=50) + first_name = models.CharField(max_length=50) + last_name = models.CharField(max_length=50) def __str__(self): # Note use of django.utils.encoding.smart_str() here because @@ -1915,8 +1925,8 @@ method for your model. The example in the previous section could be written more simply as:: class Person(models.Model): - first_name = models.CharField(maxlength=50) - last_name = models.CharField(maxlength=50) + first_name = models.CharField(max_length=50) + last_name = models.CharField(max_length=50) def __unicode__(self): return u'%s %s' % (self.first_name, self.last_name) @@ -1942,10 +1952,12 @@ Django uses this in its admin interface. If an object defines link that will jump you directly to the object's public view, according to ``get_absolute_url()``. -Also, a couple of other bits of Django, such as the syndication-feed framework, +Also, a couple of other bits of Django, such as the `syndication feed framework`_, use ``get_absolute_url()`` as a convenience to reward people who've defined the method. +.. syndication feed framework: ../syndication_feeds/ + It's good practice to use ``get_absolute_url()`` in templates, instead of hard-coding your objects' URLs. For example, this template code is bad:: @@ -2056,7 +2068,7 @@ A classic use-case for overriding the built-in methods is if you want something to happen whenever you save an object. For example:: class Blog(models.Model): - name = models.CharField(maxlength=100) + name = models.CharField(max_length=100) tagline = models.TextField() def save(self): @@ -2067,7 +2079,7 @@ to happen whenever you save an object. For example:: You can also prevent saving:: class Blog(models.Model): - name = models.CharField(maxlength=100) + name = models.CharField(max_length=100) tagline = models.TextField() def save(self): diff --git a/docs/newforms.txt b/docs/newforms.txt index a51317343f..4f63411875 100644 --- a/docs/newforms.txt +++ b/docs/newforms.txt @@ -641,7 +641,7 @@ the "Outputting forms as HTML" section above. The simplest way to display a form's HTML is to use the variable on its own, like this:: - <form method="post"> + <form method="post" action=""> <table>{{ form }}</table> <input type="submit" /> </form> @@ -653,7 +653,7 @@ class' ``__str__()`` method calls its ``as_table()`` method. The following is equivalent but a bit more explicit:: - <form method="post"> + <form method="post" action=""> <table>{{ form.as_table }}</table> <input type="submit" /> </form> @@ -675,7 +675,7 @@ individual fields for complete template control over the form's design. The easiest way is to iterate over the form's fields, with ``{% for field in form %}``. For example:: - <form method="post"> + <form method="post" action=""> <dl> {% for field in form %} <dt>{{ field.label }}</dt> @@ -696,7 +696,7 @@ Alternatively, you can arrange the form's fields explicitly, by name. Do that by accessing ``{{ form.fieldname }}``, where ``fieldname`` is the field's name. For example:: - <form method="post"> + <form method="post" action=""> <ul class="myformclass"> <li>{{ form.sender.label }} {{ form.sender }}</li> <li class="helptext">{{ form.sender.help_text }}</li> @@ -710,6 +710,49 @@ For example:: </ul> </form> +Binding uploaded files to a form +-------------------------------- + +**New in Django development version** + +Dealing with forms that have ``FileField`` and ``ImageField`` fields +is a little more complicated than a normal form. + +Firstly, in order to upload files, you'll need to make sure that your +``<form>`` element correctly defines the ``enctype`` as +``"multipart/form-data"``:: + + <form enctype="multipart/form-data" method="post" action="/foo/"> + +Secondly, when you use the form, you need to bind the file data. File +data is handled separately to normal form data, so when your form +contains a ``FileField`` and ``ImageField``, you will need to specify +a second argument when you bind your form. So if we extend our +ContactForm to include an ``ImageField`` called ``mugshot``, we +need to bind the file data containing the mugshot image:: + + # Bound form with an image field + >>> data = {'subject': 'hello', + ... 'message': 'Hi there', + ... 'sender': 'foo@example.com', + ... 'cc_myself': True} + >>> file_data = {'mugshot': {'filename':'face.jpg' + ... 'content': <file data>}} + >>> f = ContactFormWithMugshot(data, file_data) + +In practice, you will usually specify ``request.FILES`` as the source +of file data (just like you use ``request.POST`` as the source of +form data):: + + # Bound form with an image field, data from the request + >>> f = ContactFormWithMugshot(request.POST, request.FILES) + +Constructing an unbound form is the same as always -- just omit both +form data *and* file data: + + # Unbound form with a image field + >>> f = ContactFormWithMugshot() + Subclassing forms ----------------- @@ -1099,6 +1142,54 @@ Has two optional arguments for validation, ``max_length`` and ``min_length``. If provided, these arguments ensure that the string is at most or at least the given length. +``FileField`` +~~~~~~~~~~~~~ + +**New in Django development version** + + * Default widget: ``FileInput`` + * Empty value: ``None`` + * Normalizes to: An ``UploadedFile`` object that wraps the file content + and file name into a single object. + * Validates that non-empty file data has been bound to the form. + +An ``UploadedFile`` object has two attributes: + + ====================== ===================================================== + Argument Description + ====================== ===================================================== + ``filename`` The name of the file, provided by the uploading + client. + ``content`` The array of bytes comprising the file content. + ====================== ===================================================== + +The string representation of an ``UploadedFile`` is the same as the filename +attribute. + +When you use a ``FileField`` on a form, you must also remember to +`bind the file data to the form`_. + +.. _`bind the file data to the form`: `Binding uploaded files to a form`_ + +``ImageField`` +~~~~~~~~~~~~~~ + +**New in Django development version** + + * Default widget: ``FileInput`` + * Empty value: ``None`` + * Normalizes to: An ``UploadedFile`` object that wraps the file content + and file name into a single object. + * Validates that file data has been bound to the form, and that the + file is of an image format understood by PIL. + +Using an ImageField requires that the `Python Imaging Library`_ is installed. + +When you use a ``FileField`` on a form, you must also remember to +`bind the file data to the form`_. + +.. _Python Imaging Library: http://www.pythonware.com/products/pil/ + ``IntegerField`` ~~~~~~~~~~~~~~~~ @@ -1222,7 +1313,7 @@ Custom form and field validation Form validation happens when the data is cleaned. If you want to customise this process, there are various places you can change, each one serving a -different purpose. Thee types of cleaning methods are run during form +different purpose. Three types of cleaning methods are run during form processing. These are normally executed when you call the ``is_valid()`` method on a form. There are other things that can trigger cleaning and validation (accessing the ``errors`` attribute or calling ``full_clean()`` @@ -1372,17 +1463,17 @@ the full list of conversions: ``AutoField`` Not represented in the form ``BooleanField`` ``BooleanField`` ``CharField`` ``CharField`` with ``max_length`` set to - the model field's ``maxlength`` + the model field's ``max_length`` ``CommaSeparatedIntegerField`` ``CharField`` ``DateField`` ``DateField`` ``DateTimeField`` ``DateTimeField`` ``DecimalField`` ``DecimalField`` ``EmailField`` ``EmailField`` - ``FileField`` ``CharField`` + ``FileField`` ``FileField`` ``FilePathField`` ``CharField`` ``FloatField`` ``FloatField`` ``ForeignKey`` ``ModelChoiceField`` (see below) - ``ImageField`` ``CharField`` + ``ImageField`` ``ImageField`` ``IntegerField`` ``IntegerField`` ``IPAddressField`` ``CharField`` ``ManyToManyField`` ``ModelMultipleChoiceField`` (see @@ -1452,15 +1543,15 @@ Consider this set of models:: ) class Author(models.Model): - name = models.CharField(maxlength=100) - title = models.CharField(maxlength=3, choices=TITLE_CHOICES) + name = models.CharField(max_length=100) + title = models.CharField(max_length=3, choices=TITLE_CHOICES) birth_date = models.DateField(blank=True, null=True) def __unicode__(self): return self.name class Book(models.Model): - name = models.CharField(maxlength=100) + name = models.CharField(max_length=100) authors = models.ManyToManyField(Author) With these models, a call to ``form_for_model(Author)`` would return a ``Form`` @@ -1502,6 +1593,44 @@ the database. In this case, it's up to you to call ``save()`` on the resulting model instance. This is useful if you want to do custom processing on the object before saving it. ``commit`` is ``True`` by default. +Another side effect of using ``commit=False`` is seen when your model has +a many-to-many relation with another model. If your model has a many-to-many +relation and you specify ``commit=False`` when you save a form, Django cannot +immediately save the form data for the many-to-many relation. This is because +it isn't possible to save many-to-many data for an instance until the instance +exists in the database. + +To work around this problem, every time you save a form using ``commit=False``, +Django adds a ``save_m2m()`` method to the form created by ``form_for_model``. +After you've manually saved the instance produced by the form, you can invoke +``save_m2m()`` to save the many-to-many form data. For example:: + + # Create a form instance with POST data. + >>> f = AuthorForm(request.POST) + + # Create, but don't save the new author instance. + >>> new_author = f.save(commit=False) + + # Modify the author in some way. + >>> new_author.some_field = 'some_value' + + # Save the new instance. + >>> new_author.save() + + # Now, save the many-to-many data for the form. + >>> f.save_m2m() + +Calling ``save_m2m()`` is only required if you use ``save(commit=False)``. +When you use a simple ``save()`` on a form, all data -- including +many-to-many data -- is saved without the need for any additional method calls. +For example:: + + # Create a form instance with POST data. + >>> f = AuthorForm(request.POST) + + # Create and save the new author instance. There's no need to do anything else. + >>> new_author = f.save() + Using an alternate base class ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/overview.txt b/docs/overview.txt index 46211432cb..b0311cee96 100644 --- a/docs/overview.txt +++ b/docs/overview.txt @@ -25,14 +25,14 @@ far, it's been solving two years' worth of database-schema problems. Here's a quick example:: class Reporter(models.Model): - full_name = models.CharField(maxlength=70) + full_name = models.CharField(max_length=70) def __unicode__(self): return self.full_name class Article(models.Model): pub_date = models.DateTimeField() - headline = models.CharField(maxlength=200) + headline = models.CharField(max_length=200) article = models.TextField() reporter = models.ForeignKey(Reporter) @@ -134,7 +134,7 @@ your model classes:: class Article(models.Model): pub_date = models.DateTimeField() - headline = models.CharField(maxlength=200) + headline = models.CharField(max_length=200) article = models.TextField() reporter = models.ForeignKey(Reporter) class Admin: pass @@ -288,14 +288,16 @@ This has been only a quick overview of Django's functionality. Some more useful features: * A caching framework that integrates with memcached or other backends. - * A syndication framework that makes creating RSS and Atom feeds as easy as + * A `syndication framework`_ that makes creating RSS and Atom feeds as easy as writing a small Python class. * More sexy automatically-generated admin features -- this overview barely scratched the surface. +.. _syndication framework: ../syndication_feeds/ + The next obvious steps are for you to `download Django`_, read `the tutorial`_ and join `the community`_. Thanks for your interest! .. _download Django: http://www.djangoproject.com/download/ -.. _the tutorial: http://www.djangoproject.com/documentation/tutorial01/ +.. _the tutorial: ../tutorial01/ .. _the community: http://www.djangoproject.com/community/ diff --git a/docs/release_notes_0.95.txt b/docs/release_notes_0.95.txt index 3709cacf5a..f2ecbb66e6 100644 --- a/docs/release_notes_0.95.txt +++ b/docs/release_notes_0.95.txt @@ -114,7 +114,7 @@ there's a #django channel on irc.freenode.net that is regularly populated by Django users and developers from around the world. Friendly people are usually available at any hour of the day -- to help, or just to chat. -.. _online: http://www.djangoproject.com/documentation/ +.. _online: http://www.djangoproject.com/documentation/0.95/ .. _Django website: http://www.djangoproject.com/ .. _FAQ: http://www.djangoproject.com/documentation/faq/ .. _django-users: http://groups.google.com/group/django-users diff --git a/docs/request_response.txt b/docs/request_response.txt index 0b985d563b..a17a60ff17 100644 --- a/docs/request_response.txt +++ b/docs/request_response.txt @@ -297,7 +297,7 @@ In contrast to ``HttpRequest`` objects, which are created automatically by Django, ``HttpResponse`` objects are your responsibility. Each view you write is responsible for instantiating, populating and returning an ``HttpResponse``. -The ``HttpResponse`` class lives at ``django.http.HttpResponse``. +The ``HttpResponse`` class lives in the ``django.http`` module. Usage ----- diff --git a/docs/sitemaps.txt b/docs/sitemaps.txt index 550f448de1..1d4fba2626 100644 --- a/docs/sitemaps.txt +++ b/docs/sitemaps.txt @@ -21,7 +21,7 @@ you express this information in Python code. It works much like Django's `syndication framework`_. To create a sitemap, just write a ``Sitemap`` class and point to it in your URLconf_. -.. _syndication framework: ../syndication/ +.. _syndication framework: ../syndication_feeds/ .. _URLconf: ../url_dispatch/ Installation diff --git a/docs/sites.txt b/docs/sites.txt index e9982f745a..90a9d0f90f 100644 --- a/docs/sites.txt +++ b/docs/sites.txt @@ -46,7 +46,7 @@ that's represented by a ``ManyToManyField`` in the ``Article`` model:: from django.contrib.sites.models import Site class Article(models.Model): - headline = models.CharField(maxlength=200) + headline = models.CharField(max_length=200) # ... sites = models.ManyToManyField(Site) @@ -87,7 +87,7 @@ like this:: from django.contrib.sites.models import Site class Article(models.Model): - headline = models.CharField(maxlength=200) + headline = models.CharField(max_length=200) # ... site = models.ForeignKey(Site) @@ -229,7 +229,7 @@ Use ``CurrentSiteManager`` by adding it to your model explicitly. For example:: class Photo(models.Model): photo = models.FileField(upload_to='/home/photos') - photographer_name = models.CharField(maxlength=100) + photographer_name = models.CharField(max_length=100) pub_date = models.DateField() site = models.ForeignKey(Site) objects = models.Manager() @@ -257,7 +257,7 @@ this:: class Photo(models.Model): photo = models.FileField(upload_to='/home/photos') - photographer_name = models.CharField(maxlength=100) + photographer_name = models.CharField(max_length=100) pub_date = models.DateField() publish_on = models.ForeignKey(Site) objects = models.Manager() @@ -318,7 +318,7 @@ Here's how Django uses the sites framework: .. _redirects framework: ../redirects/ .. _flatpages framework: ../flatpages/ -.. _syndication framework: ../syndication/ +.. _syndication framework: ../syndication_feeds/ .. _authentication framework: ../authentication/ ``RequestSite`` objects diff --git a/docs/testing.txt b/docs/testing.txt index f4b78273ce..52285f5e8e 100644 --- a/docs/testing.txt +++ b/docs/testing.txt @@ -79,8 +79,8 @@ For example:: 'The cat says "meow"' """ - name = models.CharField(maxlength=20) - sound = models.CharField(maxlength=20) + name = models.CharField(max_length=20) + sound = models.CharField(max_length=20) def speak(self): return 'The %s says "%s"' % (self.name, self.sound) diff --git a/docs/tutorial01.txt b/docs/tutorial01.txt index 180e30292d..32480ca487 100644 --- a/docs/tutorial01.txt +++ b/docs/tutorial01.txt @@ -251,12 +251,12 @@ These concepts are represented by simple Python classes. Edit the from django.db import models class Poll(models.Model): - question = models.CharField(maxlength=200) + question = models.CharField(max_length=200) pub_date = models.DateTimeField('date published') class Choice(models.Model): poll = models.ForeignKey(Poll) - choice = models.CharField(maxlength=200) + choice = models.CharField(max_length=200) votes = models.IntegerField() The code is straightforward. Each model is represented by a class that @@ -279,7 +279,7 @@ name for ``Poll.pub_date``. For all other fields in this model, the field's machine-readable name will suffice as its human-readable name. Some ``Field`` classes have required elements. ``CharField``, for example, -requires that you give it a ``maxlength``. That's used not only in the database +requires that you give it a ``max_length``. That's used not only in the database schema, but in validation, as we'll soon see. Finally, note a relationship is defined, using ``models.ForeignKey``. That tells diff --git a/docs/tutorial02.txt b/docs/tutorial02.txt index 99f586b4a1..b820701d11 100644 --- a/docs/tutorial02.txt +++ b/docs/tutorial02.txt @@ -240,7 +240,7 @@ default, provide enough fields for 3 Choices." Then change the other fields in ``Choice`` to give them ``core=True``:: - choice = models.CharField(maxlength=200, core=True) + choice = models.CharField(max_length=200, core=True) votes = models.IntegerField(core=True) This tells Django: "When you edit a Choice on the Poll admin page, the 'choice' diff --git a/docs/tutorial03.txt b/docs/tutorial03.txt index bf85c27231..d49a417dcf 100644 --- a/docs/tutorial03.txt +++ b/docs/tutorial03.txt @@ -356,7 +356,8 @@ Use the template system ======================= Back to the ``detail()`` view for our poll application. Given the context -variable ``poll``, here's what the template might look like:: +variable ``poll``, here's what the "polls/detail.html" template might look +like:: <h1>{{ poll.question }}</h1> <ul> diff --git a/docs/tutorial04.txt b/docs/tutorial04.txt index cfd9a45a4b..553a76e9b1 100644 --- a/docs/tutorial04.txt +++ b/docs/tutorial04.txt @@ -8,8 +8,8 @@ application and will focus on simple form processing and cutting down our code. Write a simple form =================== -Let's update our poll detail template from the last tutorial, so that the -template contains an HTML ``<form>`` element:: +Let's update our poll detail template ("polls/detail.html") from the last +tutorial, so that the template contains an HTML ``<form>`` element:: <h1>{{ poll.question }}</h1> @@ -213,7 +213,7 @@ objects" and "display a detail page for a particular type of object." a way to refer to its URL later on (see `naming URL patterns`_ for more on named patterns). -.. _naming URL patterns: http://www.djangoproject.com/documentation/url_dispatch/#naming-url-patterns +.. _naming URL patterns: ../url_dispatch/#naming-url-patterns By default, the ``object_detail`` generic view uses a template called ``<app name>/<model name>_detail.html``. In our case, it'll use the template diff --git a/docs/url_dispatch.txt b/docs/url_dispatch.txt index 716686ff50..f9723a6a89 100644 --- a/docs/url_dispatch.txt +++ b/docs/url_dispatch.txt @@ -404,7 +404,7 @@ This technique is used in `generic views`_ and in the `syndication framework`_ to pass metadata and options to views. .. _generic views: ../generic_views/ -.. _syndication framework: ../syndication/ +.. _syndication framework: ../syndication_feeds/ .. admonition:: Dealing with conflicts diff --git a/tests/modeltests/basic/models.py b/tests/modeltests/basic/models.py index 81656cf2df..d2220320a0 100644 --- a/tests/modeltests/basic/models.py +++ b/tests/modeltests/basic/models.py @@ -8,7 +8,7 @@ This is a basic model with only two non-primary-key fields. from django.db import models class Article(models.Model): - headline = models.CharField(maxlength=100, default='Default headline') + headline = models.CharField(max_length=100, default='Default headline') pub_date = models.DateTimeField() class Meta: diff --git a/tests/modeltests/choices/models.py b/tests/modeltests/choices/models.py index cb1bd481cd..550e655e46 100644 --- a/tests/modeltests/choices/models.py +++ b/tests/modeltests/choices/models.py @@ -17,8 +17,8 @@ GENDER_CHOICES = ( ) class Person(models.Model): - name = models.CharField(maxlength=20) - gender = models.CharField(maxlength=1, choices=GENDER_CHOICES) + name = models.CharField(max_length=20) + gender = models.CharField(max_length=1, choices=GENDER_CHOICES) def __unicode__(self): return self.name diff --git a/tests/modeltests/custom_columns/models.py b/tests/modeltests/custom_columns/models.py index fb2487802c..e1d0bc6e94 100644 --- a/tests/modeltests/custom_columns/models.py +++ b/tests/modeltests/custom_columns/models.py @@ -18,8 +18,8 @@ ManyToMany field. This has no effect on the API for querying the database. from django.db import models class Author(models.Model): - first_name = models.CharField(maxlength=30, db_column='firstname') - last_name = models.CharField(maxlength=30, db_column='last') + first_name = models.CharField(max_length=30, db_column='firstname') + last_name = models.CharField(max_length=30, db_column='last') def __unicode__(self): return u'%s %s' % (self.first_name, self.last_name) @@ -29,7 +29,7 @@ class Author(models.Model): ordering = ('last_name','first_name') class Article(models.Model): - headline = models.CharField(maxlength=100) + headline = models.CharField(max_length=100) authors = models.ManyToManyField(Author, db_table='my_m2m_table') def __unicode__(self): diff --git a/tests/modeltests/custom_managers/models.py b/tests/modeltests/custom_managers/models.py index 0b9edc88b9..40bf77e273 100644 --- a/tests/modeltests/custom_managers/models.py +++ b/tests/modeltests/custom_managers/models.py @@ -18,8 +18,8 @@ class PersonManager(models.Manager): return self.filter(fun=True) class Person(models.Model): - first_name = models.CharField(maxlength=30) - last_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) + last_name = models.CharField(max_length=30) fun = models.BooleanField() objects = PersonManager() @@ -33,8 +33,8 @@ class PublishedBookManager(models.Manager): return super(PublishedBookManager, self).get_query_set().filter(is_published=True) class Book(models.Model): - title = models.CharField(maxlength=50) - author = models.CharField(maxlength=30) + title = models.CharField(max_length=50) + author = models.CharField(max_length=30) is_published = models.BooleanField() published_objects = PublishedBookManager() authors = models.ManyToManyField(Person, related_name='books') @@ -49,7 +49,7 @@ class FastCarManager(models.Manager): return super(FastCarManager, self).get_query_set().filter(top_speed__gt=150) class Car(models.Model): - name = models.CharField(maxlength=10) + name = models.CharField(max_length=10) mileage = models.IntegerField() top_speed = models.IntegerField(help_text="In miles per hour.") cars = models.Manager() diff --git a/tests/modeltests/custom_methods/models.py b/tests/modeltests/custom_methods/models.py index 5a6581805a..b0ca4131a5 100644 --- a/tests/modeltests/custom_methods/models.py +++ b/tests/modeltests/custom_methods/models.py @@ -8,7 +8,7 @@ from django.db import models import datetime class Article(models.Model): - headline = models.CharField(maxlength=100) + headline = models.CharField(max_length=100) pub_date = models.DateField() def __unicode__(self): diff --git a/tests/modeltests/custom_pk/models.py b/tests/modeltests/custom_pk/models.py index 276fecc371..53bbadbfd4 100644 --- a/tests/modeltests/custom_pk/models.py +++ b/tests/modeltests/custom_pk/models.py @@ -8,10 +8,10 @@ this behavior by explicitly adding ``primary_key=True`` to a field. from django.db import models class Employee(models.Model): - employee_code = models.CharField(maxlength=10, primary_key=True, + employee_code = models.CharField(max_length=10, primary_key=True, db_column = 'code') - first_name = models.CharField(maxlength=20) - last_name = models.CharField(maxlength=20) + first_name = models.CharField(max_length=20) + last_name = models.CharField(max_length=20) class Meta: ordering = ('last_name', 'first_name') @@ -19,7 +19,7 @@ class Employee(models.Model): return u"%s %s" % (self.first_name, self.last_name) class Business(models.Model): - name = models.CharField(maxlength=20, primary_key=True) + name = models.CharField(max_length=20, primary_key=True) employees = models.ManyToManyField(Employee) class Meta: verbose_name_plural = 'businesses' diff --git a/tests/modeltests/field_defaults/models.py b/tests/modeltests/field_defaults/models.py index 7eafa03798..23c4733b8f 100644 --- a/tests/modeltests/field_defaults/models.py +++ b/tests/modeltests/field_defaults/models.py @@ -13,7 +13,7 @@ from django.db import models from datetime import datetime class Article(models.Model): - headline = models.CharField(maxlength=100, default='Default headline') + headline = models.CharField(max_length=100, default='Default headline') pub_date = models.DateTimeField(default=datetime.now) def __unicode__(self): diff --git a/tests/modeltests/fixtures/models.py b/tests/modeltests/fixtures/models.py index c713aa723d..b59dc82884 100644 --- a/tests/modeltests/fixtures/models.py +++ b/tests/modeltests/fixtures/models.py @@ -11,7 +11,7 @@ FIXTURE_DIRS setting. from django.db import models class Article(models.Model): - headline = models.CharField(maxlength=100, default='Default headline') + headline = models.CharField(max_length=100, default='Default headline') pub_date = models.DateTimeField() def __unicode__(self): diff --git a/tests/modeltests/generic_relations/models.py b/tests/modeltests/generic_relations/models.py index d77a2ee43d..ce1d824ca8 100644 --- a/tests/modeltests/generic_relations/models.py +++ b/tests/modeltests/generic_relations/models.py @@ -28,8 +28,8 @@ class TaggedItem(models.Model): return self.tag class Animal(models.Model): - common_name = models.CharField(maxlength=150) - latin_name = models.CharField(maxlength=150) + common_name = models.CharField(max_length=150) + latin_name = models.CharField(max_length=150) tags = generic.GenericRelation(TaggedItem) @@ -37,7 +37,7 @@ class Animal(models.Model): return self.common_name class Vegetable(models.Model): - name = models.CharField(maxlength=150) + name = models.CharField(max_length=150) is_yucky = models.BooleanField(default=True) tags = generic.GenericRelation(TaggedItem) @@ -46,7 +46,7 @@ class Vegetable(models.Model): return self.name class Mineral(models.Model): - name = models.CharField(maxlength=150) + name = models.CharField(max_length=150) hardness = models.PositiveSmallIntegerField() # note the lack of an explicit GenericRelation here... diff --git a/tests/modeltests/get_latest/models.py b/tests/modeltests/get_latest/models.py index e54e5e32b7..099f1e28a6 100644 --- a/tests/modeltests/get_latest/models.py +++ b/tests/modeltests/get_latest/models.py @@ -11,7 +11,7 @@ into the future." from django.db import models class Article(models.Model): - headline = models.CharField(maxlength=100) + headline = models.CharField(max_length=100) pub_date = models.DateField() expire_date = models.DateField() class Meta: @@ -21,7 +21,7 @@ class Article(models.Model): return self.headline class Person(models.Model): - name = models.CharField(maxlength=30) + name = models.CharField(max_length=30) birthday = models.DateField() # Note that this model doesn't have "get_latest_by" set. diff --git a/tests/modeltests/get_object_or_404/models.py b/tests/modeltests/get_object_or_404/models.py index 573eaf2047..bd800317d3 100644 --- a/tests/modeltests/get_object_or_404/models.py +++ b/tests/modeltests/get_object_or_404/models.py @@ -15,7 +15,7 @@ from django.http import Http404 from django.shortcuts import get_object_or_404, get_list_or_404 class Author(models.Model): - name = models.CharField(maxlength=50) + name = models.CharField(max_length=50) def __unicode__(self): return self.name @@ -26,7 +26,7 @@ class ArticleManager(models.Manager): class Article(models.Model): authors = models.ManyToManyField(Author) - title = models.CharField(maxlength=50) + title = models.CharField(max_length=50) objects = models.Manager() by_a_sir = ArticleManager() diff --git a/tests/modeltests/get_or_create/models.py b/tests/modeltests/get_or_create/models.py index ed26daa852..9f025dc582 100644 --- a/tests/modeltests/get_or_create/models.py +++ b/tests/modeltests/get_or_create/models.py @@ -8,8 +8,8 @@ parameters. If an object isn't found, it creates one with the given parameters. from django.db import models class Person(models.Model): - first_name = models.CharField(maxlength=100) - last_name = models.CharField(maxlength=100) + first_name = models.CharField(max_length=100) + last_name = models.CharField(max_length=100) birthday = models.DateField() def __unicode__(self): diff --git a/tests/modeltests/invalid_models/models.py b/tests/modeltests/invalid_models/models.py index 90f2f54632..1afe660dd0 100644 --- a/tests/modeltests/invalid_models/models.py +++ b/tests/modeltests/invalid_models/models.py @@ -10,26 +10,26 @@ class FieldErrors(models.Model): charfield = models.CharField() decimalfield = models.DecimalField() filefield = models.FileField() - prepopulate = models.CharField(maxlength=10, prepopulate_from='bad') - choices = models.CharField(maxlength=10, choices='bad') - choices2 = models.CharField(maxlength=10, choices=[(1,2,3),(1,2,3)]) - index = models.CharField(maxlength=10, db_index='bad') + prepopulate = models.CharField(max_length=10, prepopulate_from='bad') + 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') class Target(models.Model): - tgt_safe = models.CharField(maxlength=10) - clash1 = models.CharField(maxlength=10) - clash2 = models.CharField(maxlength=10) + tgt_safe = models.CharField(max_length=10) + clash1 = models.CharField(max_length=10) + clash2 = models.CharField(max_length=10) - clash1_set = models.CharField(maxlength=10) + clash1_set = models.CharField(max_length=10) class Clash1(models.Model): - src_safe = models.CharField(maxlength=10, core=True) + src_safe = models.CharField(max_length=10, core=True) foreign = models.ForeignKey(Target) m2m = models.ManyToManyField(Target) class Clash2(models.Model): - src_safe = models.CharField(maxlength=10, core=True) + src_safe = models.CharField(max_length=10, core=True) foreign_1 = models.ForeignKey(Target, related_name='id') foreign_2 = models.ForeignKey(Target, related_name='src_safe') @@ -38,7 +38,7 @@ class Clash2(models.Model): m2m_2 = models.ManyToManyField(Target, related_name='src_safe') class Target2(models.Model): - clash3 = models.CharField(maxlength=10) + clash3 = models.CharField(max_length=10) foreign_tgt = models.ForeignKey(Target) clashforeign_set = models.ForeignKey(Target) @@ -46,7 +46,7 @@ class Target2(models.Model): clashm2m_set = models.ManyToManyField(Target) class Clash3(models.Model): - src_safe = models.CharField(maxlength=10, core=True) + src_safe = models.CharField(max_length=10, core=True) foreign_1 = models.ForeignKey(Target2, related_name='foreign_tgt') foreign_2 = models.ForeignKey(Target2, related_name='m2m_tgt') @@ -61,16 +61,16 @@ class ClashM2M(models.Model): m2m = models.ManyToManyField(Target2) class SelfClashForeign(models.Model): - src_safe = models.CharField(maxlength=10, core=True) - selfclashforeign = models.CharField(maxlength=10) + src_safe = models.CharField(max_length=10, core=True) + selfclashforeign = models.CharField(max_length=10) selfclashforeign_set = models.ForeignKey("SelfClashForeign") foreign_1 = models.ForeignKey("SelfClashForeign", related_name='id') foreign_2 = models.ForeignKey("SelfClashForeign", related_name='src_safe') class ValidM2M(models.Model): - src_safe = models.CharField(maxlength=10) - validm2m = models.CharField(maxlength=10) + src_safe = models.CharField(max_length=10) + validm2m = models.CharField(max_length=10) # M2M fields are symmetrical by default. Symmetrical M2M fields # on self don't require a related accessor, so many potential @@ -84,8 +84,8 @@ class ValidM2M(models.Model): m2m_4 = models.ManyToManyField('self') class SelfClashM2M(models.Model): - src_safe = models.CharField(maxlength=10) - selfclashm2m = models.CharField(maxlength=10) + src_safe = models.CharField(max_length=10) + selfclashm2m = models.CharField(max_length=10) # Non-symmetrical M2M fields _do_ have related accessors, so # there is potential for clashes. @@ -100,14 +100,14 @@ class SelfClashM2M(models.Model): class Model(models.Model): "But it's valid to call a model Model." year = models.PositiveIntegerField() #1960 - make = models.CharField(maxlength=10) #Aston Martin - name = models.CharField(maxlength=10) #DB 4 GT + make = models.CharField(max_length=10) #Aston Martin + name = models.CharField(max_length=10) #DB 4 GT class Car(models.Model): - colour = models.CharField(maxlength=5) + colour = models.CharField(max_length=5) model = models.ForeignKey(Model) -model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "maxlength" attribute. +model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "max_length" attribute. invalid_models.fielderrors: "decimalfield": DecimalFields require a "decimal_places" attribute. invalid_models.fielderrors: "decimalfield": DecimalFields require a "max_digits" attribute. invalid_models.fielderrors: "filefield": FileFields require an "upload_to" attribute. diff --git a/tests/modeltests/lookup/models.py b/tests/modeltests/lookup/models.py index 63e45cfb4c..aa90d1e5ec 100644 --- a/tests/modeltests/lookup/models.py +++ b/tests/modeltests/lookup/models.py @@ -8,7 +8,7 @@ from django.db import models from django.conf import settings class Article(models.Model): - headline = models.CharField(maxlength=100) + headline = models.CharField(max_length=100) pub_date = models.DateTimeField() class Meta: ordering = ('-pub_date', 'headline') diff --git a/tests/modeltests/m2m_and_m2o/models.py b/tests/modeltests/m2m_and_m2o/models.py index b5adc63b9d..0ab7a72d57 100644 --- a/tests/modeltests/m2m_and_m2o/models.py +++ b/tests/modeltests/m2m_and_m2o/models.py @@ -7,7 +7,7 @@ Make sure to set ``related_name`` if you use relationships to the same table. from django.db import models class User(models.Model): - username = models.CharField(maxlength=20) + username = models.CharField(max_length=20) class Issue(models.Model): num = models.IntegerField() diff --git a/tests/modeltests/m2m_intermediary/models.py b/tests/modeltests/m2m_intermediary/models.py index 5e56f44872..0f93d5a154 100644 --- a/tests/modeltests/m2m_intermediary/models.py +++ b/tests/modeltests/m2m_intermediary/models.py @@ -13,14 +13,14 @@ writer"). from django.db import models class Reporter(models.Model): - first_name = models.CharField(maxlength=30) - last_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) + last_name = models.CharField(max_length=30) def __unicode__(self): return u"%s %s" % (self.first_name, self.last_name) class Article(models.Model): - headline = models.CharField(maxlength=100) + headline = models.CharField(max_length=100) pub_date = models.DateField() def __unicode__(self): @@ -29,7 +29,7 @@ class Article(models.Model): class Writer(models.Model): reporter = models.ForeignKey(Reporter) article = models.ForeignKey(Article) - position = models.CharField(maxlength=100) + position = models.CharField(max_length=100) def __unicode__(self): return u'%s (%s)' % (self.reporter, self.position) diff --git a/tests/modeltests/m2m_multiple/models.py b/tests/modeltests/m2m_multiple/models.py index 78c35aafc2..26a0a2e798 100644 --- a/tests/modeltests/m2m_multiple/models.py +++ b/tests/modeltests/m2m_multiple/models.py @@ -10,7 +10,7 @@ Set ``related_name`` to designate what the reverse relationship is called. from django.db import models class Category(models.Model): - name = models.CharField(maxlength=20) + name = models.CharField(max_length=20) class Meta: ordering = ('name',) @@ -18,7 +18,7 @@ class Category(models.Model): return self.name class Article(models.Model): - headline = models.CharField(maxlength=50) + headline = models.CharField(max_length=50) pub_date = models.DateTimeField() primary_categories = models.ManyToManyField(Category, related_name='primary_article_set') secondary_categories = models.ManyToManyField(Category, related_name='secondary_article_set') diff --git a/tests/modeltests/m2m_recursive/models.py b/tests/modeltests/m2m_recursive/models.py index 28d98f0600..98f5ce526a 100644 --- a/tests/modeltests/m2m_recursive/models.py +++ b/tests/modeltests/m2m_recursive/models.py @@ -15,7 +15,7 @@ there will be a clash, and tests that symmetry is preserved where appropriate. from django.db import models class Person(models.Model): - name = models.CharField(maxlength=20) + name = models.CharField(max_length=20) friends = models.ManyToManyField('self') idols = models.ManyToManyField('self', symmetrical=False, related_name='stalkers') diff --git a/tests/modeltests/m2o_recursive/models.py b/tests/modeltests/m2o_recursive/models.py index 7421061489..c38200a25b 100644 --- a/tests/modeltests/m2o_recursive/models.py +++ b/tests/modeltests/m2o_recursive/models.py @@ -13,7 +13,7 @@ Set ``related_name`` to designate what the reverse relationship is called. from django.db import models class Category(models.Model): - name = models.CharField(maxlength=20) + name = models.CharField(max_length=20) parent = models.ForeignKey('self', null=True, related_name='child_set') def __unicode__(self): diff --git a/tests/modeltests/m2o_recursive2/models.py b/tests/modeltests/m2o_recursive2/models.py index a8460d6149..47af18ba0e 100644 --- a/tests/modeltests/m2o_recursive2/models.py +++ b/tests/modeltests/m2o_recursive2/models.py @@ -10,7 +10,7 @@ Set ``related_name`` to designate what the reverse relationship is called. from django.db import models class Person(models.Model): - full_name = models.CharField(maxlength=20) + full_name = models.CharField(max_length=20) mother = models.ForeignKey('self', null=True, related_name='mothers_child_set') father = models.ForeignKey('self', null=True, related_name='fathers_child_set') diff --git a/tests/modeltests/manipulators/models.py b/tests/modeltests/manipulators/models.py index 46063828b9..2ee81f62b3 100644 --- a/tests/modeltests/manipulators/models.py +++ b/tests/modeltests/manipulators/models.py @@ -7,14 +7,14 @@ Each model gets an AddManipulator and ChangeManipulator by default. from django.db import models class Musician(models.Model): - first_name = models.CharField(maxlength=30) - last_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) + last_name = models.CharField(max_length=30) def __unicode__(self): return u"%s %s" % (self.first_name, self.last_name) class Album(models.Model): - name = models.CharField(maxlength=100) + name = models.CharField(max_length=100) musician = models.ForeignKey(Musician) release_date = models.DateField(blank=True, null=True) diff --git a/tests/modeltests/many_to_many/models.py b/tests/modeltests/many_to_many/models.py index 446a39b472..198c95c4d5 100644 --- a/tests/modeltests/many_to_many/models.py +++ b/tests/modeltests/many_to_many/models.py @@ -10,7 +10,7 @@ and a publication has multiple articles. from django.db import models class Publication(models.Model): - title = models.CharField(maxlength=30) + title = models.CharField(max_length=30) def __unicode__(self): return self.title @@ -19,7 +19,7 @@ class Publication(models.Model): ordering = ('title',) class Article(models.Model): - headline = models.CharField(maxlength=100) + headline = models.CharField(max_length=100) publications = models.ManyToManyField(Publication) def __unicode__(self): diff --git a/tests/modeltests/many_to_one/models.py b/tests/modeltests/many_to_one/models.py index 1356b1924b..d5d07a1e21 100644 --- a/tests/modeltests/many_to_one/models.py +++ b/tests/modeltests/many_to_one/models.py @@ -7,15 +7,15 @@ To define a many-to-one relationship, use ``ForeignKey()`` . from django.db import models class Reporter(models.Model): - first_name = models.CharField(maxlength=30) - last_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) + last_name = models.CharField(max_length=30) email = models.EmailField() def __unicode__(self): return u"%s %s" % (self.first_name, self.last_name) class Article(models.Model): - headline = models.CharField(maxlength=100) + headline = models.CharField(max_length=100) pub_date = models.DateField() reporter = models.ForeignKey(Reporter) diff --git a/tests/modeltests/many_to_one_null/models.py b/tests/modeltests/many_to_one_null/models.py index 1469dbb5ca..60c5888371 100644 --- a/tests/modeltests/many_to_one_null/models.py +++ b/tests/modeltests/many_to_one_null/models.py @@ -8,13 +8,13 @@ To define a many-to-one relationship that can have a null foreign key, use from django.db import models class Reporter(models.Model): - name = models.CharField(maxlength=30) + name = models.CharField(max_length=30) def __unicode__(self): return self.name class Article(models.Model): - headline = models.CharField(maxlength=100) + headline = models.CharField(max_length=100) reporter = models.ForeignKey(Reporter, null=True) class Meta: diff --git a/tests/modeltests/model_forms/models.py b/tests/modeltests/model_forms/models.py index a21bef02ce..d27f0b0e54 100644 --- a/tests/modeltests/model_forms/models.py +++ b/tests/modeltests/model_forms/models.py @@ -31,20 +31,20 @@ ARTICLE_STATUS = ( ) class Category(models.Model): - name = models.CharField(maxlength=20) - url = models.CharField('The URL', maxlength=40) + name = models.CharField(max_length=20) + url = models.CharField('The URL', max_length=40) def __unicode__(self): return self.name class Writer(models.Model): - name = models.CharField(maxlength=50, help_text='Use both first and last names.') + name = models.CharField(max_length=50, help_text='Use both first and last names.') def __unicode__(self): return self.name class Article(models.Model): - headline = models.CharField(maxlength=50) + headline = models.CharField(max_length=50) pub_date = models.DateField() created = models.DateField(editable=False) writer = models.ForeignKey(Writer) @@ -63,7 +63,7 @@ class Article(models.Model): class PhoneNumber(models.Model): phone = models.PhoneNumberField() - description = models.CharField(maxlength=20) + description = models.CharField(max_length=20) def __unicode__(self): return self.phone @@ -332,6 +332,28 @@ Create a new article, with no categories, via the form. >>> new_art.categories.all() [] +Create a new article, with categories, via the form, but use commit=False. +The m2m data won't be saved until save_m2m() is invoked on the form. +>>> ArticleForm = form_for_model(Article) +>>> f = ArticleForm({'headline': u'The walrus was Paul', 'pub_date': u'1967-11-01', +... 'writer': u'1', 'article': u'Test.', 'categories': [u'1', u'2']}) +>>> new_art = f.save(commit=False) + +# Manually save the instance +>>> new_art.save() +>>> new_art.id +4 + +# The instance doesn't have m2m data yet +>>> new_art = Article.objects.get(id=4) +>>> new_art.categories.all() +[] + +# Save the m2m data on the form +>>> f.save_m2m() +>>> new_art.categories.all() +[<Category: Entertainment>, <Category: It's a test>] + Here, we define a custom Form. Because it happens to have the same fields as the Category model, we can use save_instance() to apply its changes to an existing Category instance. diff --git a/tests/modeltests/model_inheritance/models.py b/tests/modeltests/model_inheritance/models.py index 8fbd518928..ca00e96418 100644 --- a/tests/modeltests/model_inheritance/models.py +++ b/tests/modeltests/model_inheritance/models.py @@ -7,8 +7,8 @@ Model inheritance isn't yet supported. from django.db import models class Place(models.Model): - name = models.CharField(maxlength=50) - address = models.CharField(maxlength=80) + name = models.CharField(max_length=50) + address = models.CharField(max_length=80) def __unicode__(self): return u"%s the place" % self.name diff --git a/tests/modeltests/mutually_referential/models.py b/tests/modeltests/mutually_referential/models.py index 5a3897d21a..7cf7bf8bb2 100644 --- a/tests/modeltests/mutually_referential/models.py +++ b/tests/modeltests/mutually_referential/models.py @@ -7,11 +7,11 @@ To define a many-to-one relationship, use ``ForeignKey()`` . from django.db.models import * class Parent(Model): - name = CharField(maxlength=100, core=True) + name = CharField(max_length=100, core=True) bestchild = ForeignKey("Child", null=True, related_name="favoured_by") class Child(Model): - name = CharField(maxlength=100) + name = CharField(max_length=100) parent = ForeignKey(Parent) __test__ = {'API_TESTS':""" diff --git a/tests/modeltests/one_to_one/models.py b/tests/modeltests/one_to_one/models.py index 99228d21a8..2f3f22e628 100644 --- a/tests/modeltests/one_to_one/models.py +++ b/tests/modeltests/one_to_one/models.py @@ -9,8 +9,8 @@ In this example, a ``Place`` optionally can be a ``Restaurant``. from django.db import models class Place(models.Model): - name = models.CharField(maxlength=50) - address = models.CharField(maxlength=80) + name = models.CharField(max_length=50) + address = models.CharField(max_length=80) def __unicode__(self): return u"%s the place" % self.name @@ -25,18 +25,18 @@ class Restaurant(models.Model): class Waiter(models.Model): restaurant = models.ForeignKey(Restaurant) - name = models.CharField(maxlength=50) + name = models.CharField(max_length=50) def __unicode__(self): return u"%s the waiter at %s" % (self.name, self.restaurant) class ManualPrimaryKey(models.Model): - primary_key = models.CharField(maxlength=10, primary_key=True) - name = models.CharField(maxlength = 50) + primary_key = models.CharField(max_length=10, primary_key=True) + name = models.CharField(max_length = 50) class RelatedModel(models.Model): link = models.OneToOneField(ManualPrimaryKey) - name = models.CharField(maxlength = 50) + name = models.CharField(max_length = 50) __test__ = {'API_TESTS':""" # Create a couple of Places. diff --git a/tests/modeltests/or_lookups/models.py b/tests/modeltests/or_lookups/models.py index 142df16081..ee2cfd2b95 100644 --- a/tests/modeltests/or_lookups/models.py +++ b/tests/modeltests/or_lookups/models.py @@ -14,7 +14,7 @@ a get_sql method). from django.db import models class Article(models.Model): - headline = models.CharField(maxlength=50) + headline = models.CharField(max_length=50) pub_date = models.DateTimeField() class Meta: diff --git a/tests/modeltests/ordering/models.py b/tests/modeltests/ordering/models.py index 1c4e08c11c..3e651d4ee7 100644 --- a/tests/modeltests/ordering/models.py +++ b/tests/modeltests/ordering/models.py @@ -16,7 +16,7 @@ undefined -- not random, just undefined. from django.db import models class Article(models.Model): - headline = models.CharField(maxlength=100) + headline = models.CharField(max_length=100) pub_date = models.DateTimeField() class Meta: ordering = ('-pub_date', 'headline') diff --git a/tests/modeltests/pagination/models.py b/tests/modeltests/pagination/models.py index 2834d293e4..a7af2a7089 100644 --- a/tests/modeltests/pagination/models.py +++ b/tests/modeltests/pagination/models.py @@ -9,7 +9,7 @@ objects into easily readable pages. from django.db import models class Article(models.Model): - headline = models.CharField(maxlength=100, default='Default headline') + headline = models.CharField(max_length=100, default='Default headline') pub_date = models.DateTimeField() def __unicode__(self): diff --git a/tests/modeltests/properties/models.py b/tests/modeltests/properties/models.py index 4ba6b1a808..5326e4ec5f 100644 --- a/tests/modeltests/properties/models.py +++ b/tests/modeltests/properties/models.py @@ -7,8 +7,8 @@ Use properties on models just like on any other Python object. from django.db import models class Person(models.Model): - first_name = models.CharField(maxlength=30) - last_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) + last_name = models.CharField(max_length=30) def _get_full_name(self): return "%s %s" % (self.first_name, self.last_name) diff --git a/tests/modeltests/reserved_names/models.py b/tests/modeltests/reserved_names/models.py index acec978d86..a11b8d9f88 100644 --- a/tests/modeltests/reserved_names/models.py +++ b/tests/modeltests/reserved_names/models.py @@ -10,14 +10,14 @@ reserved-name usage. from django.db import models class Thing(models.Model): - when = models.CharField(maxlength=1, primary_key=True) - join = models.CharField(maxlength=1) - like = models.CharField(maxlength=1) - drop = models.CharField(maxlength=1) - alter = models.CharField(maxlength=1) - having = models.CharField(maxlength=1) - where = models.DateField(maxlength=1) - has_hyphen = models.CharField(maxlength=1, db_column='has-hyphen') + when = models.CharField(max_length=1, primary_key=True) + join = models.CharField(max_length=1) + like = models.CharField(max_length=1) + drop = models.CharField(max_length=1) + alter = models.CharField(max_length=1) + having = models.CharField(max_length=1) + where = models.DateField(max_length=1) + has_hyphen = models.CharField(max_length=1, db_column='has-hyphen') class Meta: db_table = 'select' diff --git a/tests/modeltests/reverse_lookup/models.py b/tests/modeltests/reverse_lookup/models.py index 957c1dfb96..80408ad761 100644 --- a/tests/modeltests/reverse_lookup/models.py +++ b/tests/modeltests/reverse_lookup/models.py @@ -7,20 +7,20 @@ This demonstrates the reverse lookup features of the database API. from django.db import models class User(models.Model): - name = models.CharField(maxlength=200) + name = models.CharField(max_length=200) def __unicode__(self): return self.name class Poll(models.Model): - question = models.CharField(maxlength=200) + question = models.CharField(max_length=200) creator = models.ForeignKey(User) def __unicode__(self): return self.question class Choice(models.Model): - name = models.CharField(maxlength=100) + name = models.CharField(max_length=100) poll = models.ForeignKey(Poll, related_name="poll_choice") related_poll = models.ForeignKey(Poll, related_name="related_choice") diff --git a/tests/modeltests/save_delete_hooks/models.py b/tests/modeltests/save_delete_hooks/models.py index 292cfd8e9e..c1b1d8f08b 100644 --- a/tests/modeltests/save_delete_hooks/models.py +++ b/tests/modeltests/save_delete_hooks/models.py @@ -8,8 +8,8 @@ the methods. from django.db import models class Person(models.Model): - first_name = models.CharField(maxlength=20) - last_name = models.CharField(maxlength=20) + first_name = models.CharField(max_length=20) + last_name = models.CharField(max_length=20) def __unicode__(self): return u"%s %s" % (self.first_name, self.last_name) diff --git a/tests/modeltests/select_related/models.py b/tests/modeltests/select_related/models.py index 235712ef27..43efab3a7d 100644 --- a/tests/modeltests/select_related/models.py +++ b/tests/modeltests/select_related/models.py @@ -12,48 +12,48 @@ from django.db import models # Who remembers high school biology? class Domain(models.Model): - name = models.CharField(maxlength=50) + name = models.CharField(max_length=50) def __unicode__(self): return self.name class Kingdom(models.Model): - name = models.CharField(maxlength=50) + name = models.CharField(max_length=50) domain = models.ForeignKey(Domain) def __unicode__(self): return self.name class Phylum(models.Model): - name = models.CharField(maxlength=50) + name = models.CharField(max_length=50) kingdom = models.ForeignKey(Kingdom) def __unicode__(self): return self.name class Klass(models.Model): - name = models.CharField(maxlength=50) + name = models.CharField(max_length=50) phylum = models.ForeignKey(Phylum) def __unicode__(self): return self.name class Order(models.Model): - name = models.CharField(maxlength=50) + name = models.CharField(max_length=50) klass = models.ForeignKey(Klass) def __unicode__(self): return self.name class Family(models.Model): - name = models.CharField(maxlength=50) + name = models.CharField(max_length=50) order = models.ForeignKey(Order) def __unicode__(self): return self.name class Genus(models.Model): - name = models.CharField(maxlength=50) + name = models.CharField(max_length=50) family = models.ForeignKey(Family) def __unicode__(self): return self.name class Species(models.Model): - name = models.CharField(maxlength=50) + name = models.CharField(max_length=50) genus = models.ForeignKey(Genus) def __unicode__(self): return self.name diff --git a/tests/modeltests/serializers/models.py b/tests/modeltests/serializers/models.py index b7543f9348..2ee6cfce67 100644 --- a/tests/modeltests/serializers/models.py +++ b/tests/modeltests/serializers/models.py @@ -8,7 +8,7 @@ to and from "flat" data (i.e. strings). from django.db import models class Category(models.Model): - name = models.CharField(maxlength=20) + name = models.CharField(max_length=20) class Meta: ordering = ('name',) @@ -17,7 +17,7 @@ class Category(models.Model): return self.name class Author(models.Model): - name = models.CharField(maxlength=20) + name = models.CharField(max_length=20) class Meta: ordering = ('name',) @@ -27,7 +27,7 @@ class Author(models.Model): class Article(models.Model): author = models.ForeignKey(Author) - headline = models.CharField(maxlength=50) + headline = models.CharField(max_length=50) pub_date = models.DateTimeField() categories = models.ManyToManyField(Category) diff --git a/tests/modeltests/str/models.py b/tests/modeltests/str/models.py index 6bd6a7e448..644c6025ab 100644 --- a/tests/modeltests/str/models.py +++ b/tests/modeltests/str/models.py @@ -17,7 +17,7 @@ if you prefer. You must be careful to encode the results correctly, though. from django.db import models class Article(models.Model): - headline = models.CharField(maxlength=100) + headline = models.CharField(max_length=100) pub_date = models.DateTimeField() def __str__(self): @@ -26,7 +26,7 @@ class Article(models.Model): return self.headline class InternationalArticle(models.Model): - headline = models.CharField(maxlength=100) + headline = models.CharField(max_length=100) pub_date = models.DateTimeField() def __unicode__(self): diff --git a/tests/modeltests/transactions/models.py b/tests/modeltests/transactions/models.py index d7eba6e4d3..06d21bbdd4 100644 --- a/tests/modeltests/transactions/models.py +++ b/tests/modeltests/transactions/models.py @@ -10,8 +10,8 @@ manually. from django.db import models class Reporter(models.Model): - first_name = models.CharField(maxlength=30) - last_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) + last_name = models.CharField(max_length=30) email = models.EmailField() def __unicode__(self): diff --git a/tests/modeltests/validation/models.py b/tests/modeltests/validation/models.py index 5be2f867a4..aacd041678 100644 --- a/tests/modeltests/validation/models.py +++ b/tests/modeltests/validation/models.py @@ -12,7 +12,7 @@ from django.db import models class Person(models.Model): is_child = models.BooleanField() - name = models.CharField(maxlength=20) + name = models.CharField(max_length=20) birthdate = models.DateField() favorite_moment = models.DateTimeField() email = models.EmailField() diff --git a/tests/regressiontests/bug639/models.py b/tests/regressiontests/bug639/models.py index 7cfdfc82ef..fc241aba8c 100644 --- a/tests/regressiontests/bug639/models.py +++ b/tests/regressiontests/bug639/models.py @@ -2,7 +2,7 @@ import tempfile from django.db import models class Photo(models.Model): - title = models.CharField(maxlength=30) + title = models.CharField(max_length=30) image = models.FileField(upload_to=tempfile.gettempdir()) # Support code for the tests; this keeps track of how many times save() gets diff --git a/tests/regressiontests/datatypes/models.py b/tests/regressiontests/datatypes/models.py index 8c5c8c285d..ff9666bc0c 100644 --- a/tests/regressiontests/datatypes/models.py +++ b/tests/regressiontests/datatypes/models.py @@ -7,7 +7,7 @@ from django.db import models from django.conf import settings class Donut(models.Model): - name = models.CharField(maxlength=100) + name = models.CharField(max_length=100) is_frosted = models.BooleanField(default=False) has_sprinkles = models.NullBooleanField() baked_date = models.DateField(null=True) diff --git a/tests/regressiontests/fixtures_regress/models.py b/tests/regressiontests/fixtures_regress/models.py index 41ef8c26bf..2c92839f0f 100644 --- a/tests/regressiontests/fixtures_regress/models.py +++ b/tests/regressiontests/fixtures_regress/models.py @@ -2,21 +2,21 @@ from django.db import models from django.contrib.auth.models import User class Animal(models.Model): - name = models.CharField(maxlength=150) - latin_name = models.CharField(maxlength=150) + name = models.CharField(max_length=150) + latin_name = models.CharField(max_length=150) def __unicode__(self): return self.common_name class Plant(models.Model): - name = models.CharField(maxlength=150) + name = models.CharField(max_length=150) class Meta: # For testing when upper case letter in app name; regression for #4057 db_table = "Fixtures_regress_plant" class Stuff(models.Model): - name = models.CharField(maxlength=20, null=True) + name = models.CharField(max_length=20, null=True) owner = models.ForeignKey(User, null=True) def __unicode__(self): diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py index 52cc9ccfa5..2386a7f8b1 100644 --- a/tests/regressiontests/forms/tests.py +++ b/tests/regressiontests/forms/tests.py @@ -173,27 +173,29 @@ u'<input type="hidden" class="special" value="foo@example.com" name="email" />' # FileInput Widget ############################################################ +FileInput widgets don't ever show the value, because the old value is of no use +if you are updating the form or if the provided file generated an error. >>> w = FileInput() >>> w.render('email', '') u'<input type="file" name="email" />' >>> w.render('email', None) u'<input type="file" name="email" />' >>> w.render('email', 'test@example.com') -u'<input type="file" name="email" value="test@example.com" />' +u'<input type="file" name="email" />' >>> w.render('email', 'some "quoted" & ampersanded value') -u'<input type="file" name="email" value="some "quoted" & ampersanded value" />' +u'<input type="file" name="email" />' >>> w.render('email', 'test@example.com', attrs={'class': 'fun'}) -u'<input type="file" name="email" value="test@example.com" class="fun" />' +u'<input type="file" name="email" class="fun" />' You can also pass 'attrs' to the constructor: >>> w = FileInput(attrs={'class': 'fun'}) >>> w.render('email', '') u'<input type="file" class="fun" name="email" />' >>> w.render('email', 'foo@example.com') -u'<input type="file" class="fun" value="foo@example.com" name="email" />' +u'<input type="file" class="fun" name="email" />' >>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'}) -u'<input type="file" class="fun" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" name="email" />' +u'<input type="file" class="fun" name="email" />' # Textarea Widget ############################################################# @@ -1532,6 +1534,42 @@ Traceback (most recent call last): ... ValidationError: [u'Ensure this value has at most 15 characters (it has 20).'] +# FileField ################################################################## + +>>> f = FileField() +>>> f.clean('') +Traceback (most recent call last): +... +ValidationError: [u'This field is required.'] + +>>> f.clean(None) +Traceback (most recent call last): +... +ValidationError: [u'This field is required.'] + +>>> f.clean({}) +Traceback (most recent call last): +... +ValidationError: [u'No file was submitted.'] + +>>> f.clean('some content that is not a file') +Traceback (most recent call last): +... +ValidationError: [u'No file was submitted. Check the encoding type on the form.'] + +>>> f.clean({'filename': 'name', 'content':None}) +Traceback (most recent call last): +... +ValidationError: [u'The submitted file is empty.'] + +>>> f.clean({'filename': 'name', 'content':''}) +Traceback (most recent call last): +... +ValidationError: [u'The submitted file is empty.'] + +>>> type(f.clean({'filename': 'name', 'content':'Some File Content'})) +<class 'django.newforms.fields.UploadedFile'> + # URLField ################################################################## >>> f = URLField() @@ -2573,7 +2611,7 @@ Instances of a dynamic Form do not persist fields from one Form instance to the next. >>> class MyForm(Form): ... def __init__(self, data=None, auto_id=False, field_list=[]): -... Form.__init__(self, data, auto_id) +... Form.__init__(self, data, auto_id=auto_id) ... for field in field_list: ... self.fields[field[0]] = field[1] >>> field_list = [('field1', CharField()), ('field2', CharField())] @@ -2591,7 +2629,7 @@ the next. ... default_field_1 = CharField() ... default_field_2 = CharField() ... def __init__(self, data=None, auto_id=False, field_list=[]): -... Form.__init__(self, data, auto_id) +... Form.__init__(self, data, auto_id=auto_id) ... for field in field_list: ... self.fields[field[0]] = field[1] >>> field_list = [('field1', CharField()), ('field2', CharField())] @@ -3246,6 +3284,35 @@ is different than its data. This is handled transparently, though. <option value="3" selected="selected">No</option> </select> +# Forms with FileFields ################################################ + +FileFields are a special case because they take their data from the request.FILES, +not request.POST. + +>>> class FileForm(Form): +... file1 = FileField() +>>> f = FileForm(auto_id=False) +>>> print f +<tr><th>File1:</th><td><input type="file" name="file1" /></td></tr> + +>>> f = FileForm(data={}, files={}, auto_id=False) +>>> print f +<tr><th>File1:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="file" name="file1" /></td></tr> + +>>> f = FileForm(data={}, files={'file1': {'filename': 'name', 'content':''}}, auto_id=False) +>>> print f +<tr><th>File1:</th><td><ul class="errorlist"><li>The submitted file is empty.</li></ul><input type="file" name="file1" /></td></tr> + +>>> f = FileForm(data={}, files={'file1': 'something that is not a file'}, auto_id=False) +>>> print f +<tr><th>File1:</th><td><ul class="errorlist"><li>No file was submitted. Check the encoding type on the form.</li></ul><input type="file" name="file1" /></td></tr> + +>>> f = FileForm(data={}, files={'file1': {'filename': 'name', 'content':'some content'}}, auto_id=False) +>>> print f +<tr><th>File1:</th><td><input type="file" name="file1" /></td></tr> +>>> f.is_valid() +True + # Basic form processing in a view ############################################# >>> from django.template import Template, Context diff --git a/tests/regressiontests/initial_sql_regress/models.py b/tests/regressiontests/initial_sql_regress/models.py index dedbba8e5c..7cf725991a 100644 --- a/tests/regressiontests/initial_sql_regress/models.py +++ b/tests/regressiontests/initial_sql_regress/models.py @@ -5,7 +5,7 @@ Regression tests for initial SQL insertion. from django.db import models class Simple(models.Model): - name = models.CharField(maxlength = 50) + name = models.CharField(max_length = 50) __test__ = {'API_TESTS':""} diff --git a/tests/regressiontests/invalid_admin_options/models.py b/tests/regressiontests/invalid_admin_options/models.py index 43bcc533ba..14db463735 100644 --- a/tests/regressiontests/invalid_admin_options/models.py +++ b/tests/regressiontests/invalid_admin_options/models.py @@ -12,7 +12,7 @@ model_errors = "" ##This should fail gracefully but is causing a metaclass error #class BadAdminOption(models.Model): # "Test nonexistent admin option" -# name = models.CharField(maxlength=30) +# name = models.CharField(max_length=30) # # class Admin: # nonexistent = 'option' @@ -22,7 +22,7 @@ model_errors = "" class ListDisplayBadOne(models.Model): "Test list_display, list_display must be a list or tuple" - first_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) class Admin: list_display = 'first_name' @@ -32,7 +32,7 @@ model_errors += """invalid_admin_options.listdisplaybadone: "admin.list_display" class ListDisplayBadTwo(models.Model): "Test list_display, list_display items must be attributes, methods or properties." - first_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) class Admin: list_display = ['first_name','nonexistent'] @@ -41,7 +41,7 @@ model_errors += """invalid_admin_options.listdisplaybadtwo: "admin.list_display" """ class ListDisplayBadThree(models.Model): "Test list_display, list_display items can not be a ManyToManyField." - first_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) nick_names = models.ManyToManyField('ListDisplayGood') class Admin: @@ -52,7 +52,7 @@ model_errors += """invalid_admin_options.listdisplaybadthree: "admin.list_displa class ListDisplayGood(models.Model): "Test list_display, Admin list_display can be a attribute, method or property." - first_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) def _last_name(self): return self.first_name @@ -66,8 +66,8 @@ class ListDisplayGood(models.Model): class ListDisplayLinksBadOne(models.Model): "Test list_display_links, item must be included in list_display." - first_name = models.CharField(maxlength=30) - last_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) + last_name = models.CharField(max_length=30) class Admin: list_display = ['last_name'] @@ -78,8 +78,8 @@ model_errors += """invalid_admin_options.listdisplaylinksbadone: "admin.list_dis class ListDisplayLinksBadTwo(models.Model): "Test list_display_links, must be a list or tuple." - first_name = models.CharField(maxlength=30) - last_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) + last_name = models.CharField(max_length=30) class Admin: list_display = ['first_name','last_name'] @@ -92,8 +92,8 @@ model_errors += """invalid_admin_options.listdisplaylinksbadtwo: "admin.list_dis ## This is failing but the validation which should fail is not. #class ListDisplayLinksBadThree(models.Model): # "Test list_display_links, must define list_display to use list_display_links." -# first_name = models.CharField(maxlength=30) -# last_name = models.CharField(maxlength=30) +# first_name = models.CharField(max_length=30) +# last_name = models.CharField(max_length=30) # # class Admin: # list_display_links = ('first_name',) @@ -103,7 +103,7 @@ model_errors += """invalid_admin_options.listdisplaylinksbadtwo: "admin.list_dis class ListDisplayLinksGood(models.Model): "Test list_display_links, Admin list_display_list can be a attribute, method or property." - first_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) def _last_name(self): return self.first_name @@ -118,7 +118,7 @@ class ListDisplayLinksGood(models.Model): class ListFilterBadOne(models.Model): "Test list_filter, must be a list or tuple." - first_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) class Admin: list_filter = 'first_name' @@ -128,7 +128,7 @@ model_errors += """invalid_admin_options.listfilterbadone: "admin.list_filter", class ListFilterBadTwo(models.Model): "Test list_filter, must be a field not a property or method." - first_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) def _last_name(self): return self.first_name @@ -146,7 +146,7 @@ invalid_admin_options.listfilterbadtwo: "admin.list_filter" refers to 'full_name class DateHierarchyBadOne(models.Model): "Test date_hierarchy, must be a date or datetime field." - first_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) birth_day = models.DateField() class Admin: @@ -158,7 +158,7 @@ class DateHierarchyBadOne(models.Model): class DateHierarchyBadTwo(models.Model): "Test date_hieracrhy, must be a field." - first_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) birth_day = models.DateField() class Admin: @@ -169,7 +169,7 @@ model_errors += """invalid_admin_options.datehierarchybadtwo: "admin.date_hierar class DateHierarchyGood(models.Model): "Test date_hieracrhy, must be a field." - first_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) birth_day = models.DateField() class Admin: @@ -177,7 +177,7 @@ class DateHierarchyGood(models.Model): class SearchFieldsBadOne(models.Model): "Test search_fields, must be a list or tuple." - first_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) class Admin: search_fields = ('nonexistent') @@ -188,7 +188,7 @@ class SearchFieldsBadOne(models.Model): class SearchFieldsBadTwo(models.Model): "Test search_fields, must be a field." - first_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) def _last_name(self): return self.first_name @@ -203,8 +203,8 @@ class SearchFieldsBadTwo(models.Model): class SearchFieldsGood(models.Model): "Test search_fields, must be a list or tuple." - first_name = models.CharField(maxlength=30) - last_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) + last_name = models.CharField(max_length=30) class Admin: search_fields = ['first_name','last_name'] @@ -212,7 +212,7 @@ class SearchFieldsGood(models.Model): class JsBadOne(models.Model): "Test js, must be a list or tuple" - name = models.CharField(maxlength=30) + name = models.CharField(max_length=30) class Admin: js = 'test.js' @@ -223,7 +223,7 @@ class JsBadOne(models.Model): class SaveAsBad(models.Model): "Test save_as, should be True or False" - name = models.CharField(maxlength=30) + name = models.CharField(max_length=30) class Admin: save_as = 'not True or False' @@ -234,7 +234,7 @@ class SaveAsBad(models.Model): class SaveOnTopBad(models.Model): "Test save_on_top, should be True or False" - name = models.CharField(maxlength=30) + name = models.CharField(max_length=30) class Admin: save_on_top = 'not True or False' @@ -245,7 +245,7 @@ class SaveOnTopBad(models.Model): class ListSelectRelatedBad(models.Model): "Test list_select_related, should be True or False" - name = models.CharField(maxlength=30) + name = models.CharField(max_length=30) class Admin: list_select_related = 'not True or False' @@ -256,7 +256,7 @@ class ListSelectRelatedBad(models.Model): class ListPerPageBad(models.Model): "Test list_per_page, should be a positive integer value." - name = models.CharField(maxlength=30) + name = models.CharField(max_length=30) class Admin: list_per_page = 89.3 @@ -267,8 +267,8 @@ class ListPerPageBad(models.Model): class FieldsBadOne(models.Model): "Test fields, should be a tuple" - first_name = models.CharField(maxlength=30) - last_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) + last_name = models.CharField(max_length=30) class Admin: fields = 'not a tuple' @@ -279,8 +279,8 @@ class FieldsBadOne(models.Model): class FieldsBadTwo(models.Model): """Test fields, 'fields' dict option is required.""" - first_name = models.CharField(maxlength=30) - last_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) + last_name = models.CharField(max_length=30) class Admin: fields = ('Name', {'description': 'this fieldset needs fields'}) @@ -291,8 +291,8 @@ class FieldsBadTwo(models.Model): class FieldsBadThree(models.Model): """Test fields, 'classes' and 'description' are the only allowable extra dict options.""" - first_name = models.CharField(maxlength=30) - last_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) + last_name = models.CharField(max_length=30) class Admin: fields = ('Name', {'fields': ('first_name','last_name'),'badoption': 'verybadoption'}) @@ -303,8 +303,8 @@ class FieldsBadThree(models.Model): class FieldsGood(models.Model): "Test fields, working example" - first_name = models.CharField(maxlength=30) - last_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) + last_name = models.CharField(max_length=30) birth_day = models.DateField() class Admin: @@ -315,8 +315,8 @@ class FieldsGood(models.Model): class OrderingBad(models.Model): "Test ordering, must be a field." - first_name = models.CharField(maxlength=30) - last_name = models.CharField(maxlength=30) + first_name = models.CharField(max_length=30) + last_name = models.CharField(max_length=30) class Admin: ordering = 'nonexistent' @@ -328,7 +328,7 @@ class OrderingBad(models.Model): ## TODO: Add a manager validator, this should fail gracefully. #class ManagerBad(models.Model): # "Test manager, must be a manager object." -# first_name = models.CharField(maxlength=30) +# first_name = models.CharField(max_length=30) # # class Admin: # manager = 'nonexistent' diff --git a/tests/regressiontests/many_to_one_regress/models.py b/tests/regressiontests/many_to_one_regress/models.py index 8ddec98da4..57bbcd8489 100644 --- a/tests/regressiontests/many_to_one_regress/models.py +++ b/tests/regressiontests/many_to_one_regress/models.py @@ -12,15 +12,15 @@ class Second(models.Model): # Protect against repetition of #1839, #2415 and #2536. class Third(models.Model): - name = models.CharField(maxlength=20) + name = models.CharField(max_length=20) third = models.ForeignKey('self', null=True, related_name='child_set') class Parent(models.Model): - name = models.CharField(maxlength=20) + name = models.CharField(max_length=20) bestchild = models.ForeignKey('Child', null=True, related_name='favored_by') class Child(models.Model): - name = models.CharField(maxlength=20) + name = models.CharField(max_length=20) parent = models.ForeignKey(Parent) diff --git a/tests/regressiontests/maxlength/__init__.py b/tests/regressiontests/maxlength/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/maxlength/__init__.py diff --git a/tests/regressiontests/maxlength/models.py b/tests/regressiontests/maxlength/models.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/regressiontests/maxlength/models.py diff --git a/tests/regressiontests/maxlength/tests.py b/tests/regressiontests/maxlength/tests.py new file mode 100644 index 0000000000..8a5f874c78 --- /dev/null +++ b/tests/regressiontests/maxlength/tests.py @@ -0,0 +1,160 @@ +# Test access to max_length while still providing full backwards compatibility +# with legacy maxlength attribute. +""" + +Don't print out the deprecation warnings during testing. +>>> from warnings import filterwarnings +>>> filterwarnings("ignore") + +# legacy_maxlength function + +>>> from django.utils.maxlength import legacy_maxlength + +>>> legacy_maxlength(None, None) + + +>>> legacy_maxlength(10, None) +10 + +>>> legacy_maxlength(None, 10) +10 + +>>> legacy_maxlength(10, 12) +Traceback (most recent call last): +... +TypeError: field can not take both the max_length argument and the legacy maxlength argument. + +>>> legacy_maxlength(0, 10) +Traceback (most recent call last): +... +TypeError: field can not take both the max_length argument and the legacy maxlength argument. + +>>> legacy_maxlength(0, None) +0 + +>>> legacy_maxlength(None, 0) +0 + +#=============================================================================== +# Fields +#=============================================================================== + +# Set up fields +>>> from django.db.models import fields +>>> new = fields.Field(max_length=15) +>>> old = fields.Field(maxlength=10) + +# Ensure both max_length and legacy maxlength are not able to both be specified +>>> fields.Field(maxlength=10, max_length=15) +Traceback (most recent call last): + ... +TypeError: field can not take both the max_length argument and the legacy maxlength argument. + +# Test max_length +>>> new.max_length +15 +>>> old.max_length +10 + +# Test accessing maxlength +>>> new.maxlength +15 +>>> old.maxlength +10 + +# Test setting maxlength +>>> new.maxlength += 1 +>>> old.maxlength += 1 +>>> new.max_length +16 +>>> old.max_length +11 + +# SlugField __init__ passes through max_length so test that too +>>> fields.SlugField('new', max_length=15).max_length +15 +>>> fields.SlugField('empty').max_length +50 +>>> fields.SlugField('old', maxlength=10).max_length +10 + +#=============================================================================== +# (old)forms +#=============================================================================== + +>>> from django import oldforms + +# Test max_length attribute + +>>> oldforms.TextField('new', max_length=15).render('') +u'<input type="text" id="id_new" class="vTextField" name="new" size="30" value="" maxlength="15" />' + +>>> oldforms.IntegerField('new', max_length=15).render('') +u'<input type="text" id="id_new" class="vIntegerField" name="new" size="10" value="" maxlength="15" />' + +>>> oldforms.SmallIntegerField('new', max_length=15).render('') +u'<input type="text" id="id_new" class="vSmallIntegerField" name="new" size="5" value="" maxlength="15" />' + +>>> oldforms.PositiveIntegerField('new', max_length=15).render('') +u'<input type="text" id="id_new" class="vPositiveIntegerField" name="new" size="10" value="" maxlength="15" />' + +>>> oldforms.PositiveSmallIntegerField('new', max_length=15).render('') +u'<input type="text" id="id_new" class="vPositiveSmallIntegerField" name="new" size="5" value="" maxlength="15" />' + +>>> oldforms.DatetimeField('new', max_length=15).render('') +u'<input type="text" id="id_new" class="vDatetimeField" name="new" size="30" value="" maxlength="15" />' + +>>> oldforms.EmailField('new', max_length=15).render('') +u'<input type="text" id="id_new" class="vEmailField" name="new" size="50" value="" maxlength="15" />' +>>> oldforms.EmailField('new').render('') +u'<input type="text" id="id_new" class="vEmailField" name="new" size="50" value="" maxlength="75" />' + +>>> oldforms.URLField('new', max_length=15).render('') +u'<input type="text" id="id_new" class="vURLField" name="new" size="50" value="" maxlength="15" />' +>>> oldforms.URLField('new').render('') +u'<input type="text" id="id_new" class="vURLField" name="new" size="50" value="" maxlength="200" />' + +>>> oldforms.IPAddressField('new', max_length=15).render('') +u'<input type="text" id="id_new" class="vIPAddressField" name="new" size="15" value="" maxlength="15" />' +>>> oldforms.IPAddressField('new').render('') +u'<input type="text" id="id_new" class="vIPAddressField" name="new" size="15" value="" maxlength="15" />' + +>>> oldforms.CommaSeparatedIntegerField('new', max_length=15).render('') +u'<input type="text" id="id_new" class="vCommaSeparatedIntegerField" name="new" size="20" value="" maxlength="15" />' + + +# Test legacy maxlength attribute + +>>> oldforms.TextField('old', maxlength=10).render('') +u'<input type="text" id="id_old" class="vTextField" name="old" size="30" value="" maxlength="10" />' + +>>> oldforms.IntegerField('old', maxlength=10).render('') +u'<input type="text" id="id_old" class="vIntegerField" name="old" size="10" value="" maxlength="10" />' + +>>> oldforms.SmallIntegerField('old', maxlength=10).render('') +u'<input type="text" id="id_old" class="vSmallIntegerField" name="old" size="5" value="" maxlength="10" />' + +>>> oldforms.PositiveIntegerField('old', maxlength=10).render('') +u'<input type="text" id="id_old" class="vPositiveIntegerField" name="old" size="10" value="" maxlength="10" />' + +>>> oldforms.PositiveSmallIntegerField('old', maxlength=10).render('') +u'<input type="text" id="id_old" class="vPositiveSmallIntegerField" name="old" size="5" value="" maxlength="10" />' + +>>> oldforms.DatetimeField('old', maxlength=10).render('') +u'<input type="text" id="id_old" class="vDatetimeField" name="old" size="30" value="" maxlength="10" />' + +>>> oldforms.EmailField('old', maxlength=10).render('') +u'<input type="text" id="id_old" class="vEmailField" name="old" size="50" value="" maxlength="10" />' + +>>> oldforms.URLField('old', maxlength=10).render('') +u'<input type="text" id="id_old" class="vURLField" name="old" size="50" value="" maxlength="10" />' + +>>> oldforms.IPAddressField('old', maxlength=10).render('') +u'<input type="text" id="id_old" class="vIPAddressField" name="old" size="15" value="" maxlength="10" />' + +>>> oldforms.CommaSeparatedIntegerField('old', maxlength=10).render('') +u'<input type="text" id="id_old" class="vCommaSeparatedIntegerField" name="old" size="20" value="" maxlength="10" />' +""" +if __name__ == "__main__": + import doctest + doctest.testmod() diff --git a/tests/regressiontests/model_regress/models.py b/tests/regressiontests/model_regress/models.py index b4d432d8fa..0fee831212 100644 --- a/tests/regressiontests/model_regress/models.py +++ b/tests/regressiontests/model_regress/models.py @@ -7,7 +7,7 @@ CHOICES = ( ) class Article(models.Model): - headline = models.CharField(maxlength=100, default='Default headline') + headline = models.CharField(max_length=100, default='Default headline') pub_date = models.DateTimeField() status = models.IntegerField(blank=True, null=True, choices=CHOICES) diff --git a/tests/regressiontests/null_queries/models.py b/tests/regressiontests/null_queries/models.py index 2e903876bf..2aa36b2c1a 100644 --- a/tests/regressiontests/null_queries/models.py +++ b/tests/regressiontests/null_queries/models.py @@ -1,14 +1,14 @@ from django.db import models class Poll(models.Model): - question = models.CharField(maxlength=200) + question = models.CharField(max_length=200) def __unicode__(self): return u"Q: %s " % self.question class Choice(models.Model): poll = models.ForeignKey(Poll) - choice = models.CharField(maxlength=200) + choice = models.CharField(max_length=200) def __unicode__(self): return u"Choice: %s in poll %s" % (self.choice, self.poll) diff --git a/tests/regressiontests/one_to_one_regress/models.py b/tests/regressiontests/one_to_one_regress/models.py index be48c842ed..c5ffd3fb3c 100644 --- a/tests/regressiontests/one_to_one_regress/models.py +++ b/tests/regressiontests/one_to_one_regress/models.py @@ -1,8 +1,8 @@ from django.db import models class Place(models.Model): - name = models.CharField(maxlength=50) - address = models.CharField(maxlength=80) + name = models.CharField(max_length=50) + address = models.CharField(max_length=80) def __unicode__(self): return u"%s the place" % self.name @@ -16,7 +16,7 @@ class Restaurant(models.Model): return u"%s the restaurant" % self.place.name class Favorites(models.Model): - name = models.CharField(maxlength = 50) + name = models.CharField(max_length = 50) restaurants = models.ManyToManyField(Restaurant) def __unicode__(self): diff --git a/tests/regressiontests/serializers_regress/models.py b/tests/regressiontests/serializers_regress/models.py index f9af1d26ca..e9df508822 100644 --- a/tests/regressiontests/serializers_regress/models.py +++ b/tests/regressiontests/serializers_regress/models.py @@ -16,7 +16,7 @@ class BooleanData(models.Model): data = models.BooleanField(null=True) class CharData(models.Model): - data = models.CharField(maxlength=30, null=True) + data = models.CharField(max_length=30, null=True) class DateData(models.Model): data = models.DateField(null=True) @@ -90,7 +90,7 @@ class Tag(models.Model): ordering = ["data"] class GenericData(models.Model): - data = models.CharField(maxlength=30) + data = models.CharField(max_length=30) tags = generic.GenericRelation(Tag) @@ -102,13 +102,13 @@ class Anchor(models.Model): """This is a model that can be used as something for other models to point at""" - data = models.CharField(maxlength=30) + data = models.CharField(max_length=30) class UniqueAnchor(models.Model): """This is a model that can be used as something for other models to point at""" - data = models.CharField(unique=True, maxlength=30) + data = models.CharField(unique=True, max_length=30) class FKData(models.Model): data = models.ForeignKey(Anchor, null=True) @@ -144,7 +144,7 @@ class BooleanPKData(models.Model): data = models.BooleanField(primary_key=True) class CharPKData(models.Model): - data = models.CharField(maxlength=30, primary_key=True) + data = models.CharField(max_length=30, primary_key=True) # class DatePKData(models.Model): # data = models.DateField(primary_key=True) @@ -208,9 +208,9 @@ class USStatePKData(models.Model): # data = models.XMLField(primary_key=True) class ComplexModel(models.Model): - field1 = models.CharField(maxlength=10) - field2 = models.CharField(maxlength=10) - field3 = models.CharField(maxlength=10) + field1 = models.CharField(max_length=10) + field2 = models.CharField(max_length=10) + field3 = models.CharField(max_length=10) # Tests for handling fields with pre_save functions, or # models with save functions that modify data diff --git a/tests/regressiontests/string_lookup/models.py b/tests/regressiontests/string_lookup/models.py index 66651ce680..6a341070a4 100644 --- a/tests/regressiontests/string_lookup/models.py +++ b/tests/regressiontests/string_lookup/models.py @@ -2,14 +2,14 @@ from django.db import models class Foo(models.Model): - name = models.CharField(maxlength=50) - friend = models.CharField(maxlength=50, blank=True) + name = models.CharField(max_length=50) + friend = models.CharField(max_length=50, blank=True) def __unicode__(self): return "Foo %s" % self.name class Bar(models.Model): - name = models.CharField(maxlength=50) + name = models.CharField(max_length=50) normal = models.ForeignKey(Foo, related_name='normal_foo') fwd = models.ForeignKey("Whiz") back = models.ForeignKey("Foo") @@ -18,20 +18,20 @@ class Bar(models.Model): return "Bar %s" % self.place.name class Whiz(models.Model): - name = models.CharField(maxlength = 50) + name = models.CharField(max_length = 50) def __unicode__(self): return "Whiz %s" % self.name class Child(models.Model): parent = models.OneToOneField('Base') - name = models.CharField(maxlength = 50) + name = models.CharField(max_length = 50) def __unicode__(self): return "Child %s" % self.name class Base(models.Model): - name = models.CharField(maxlength = 50) + name = models.CharField(max_length = 50) def __unicode__(self): return "Base %s" % self.name |