Ticket #302 (closed defect: invalid)
ValueError: You cannot add a null=False column without a default value.
| Reported by: | Tom <toabctl@…> | Owned by: | andrew |
|---|---|---|---|
| Priority: | major | Milestone: | 0.6.3 |
| Component: | databaseapi | Version: | 0.6.1 |
| Keywords: | Cc: |
Description
i have a model looks like this:
#vim poject/models.py
class Project(models.Model):
"""
A Model which describe a Project
"""
auth_group = models.ForeignKey('auth.Group')
name = models.CharField(max_length=200)
timezone = models.CharField(max_length=200, choices = TIMEZONES, blank=True, null=True)
longitude = models.FloatField(help_text=_('Longitude in ° East'), blank=True, null=True)
latitude = models.FloatField(help_text=_('Latitude in ° North'), blank=True, null=True)
altitude = models.FloatField(help_text=_('Altitude in m'), blank=True, null=True)
comment = models.TextField(blank=True, null=True)
class Meta:
ordering = ['name']
def __unicode__(self):
return self.name
the initial migration looks like this:
# vim project/migrations/0001_initial.py
from south.db import db
from django.db import models
from ammonitor.project.models import *
class Migration:
def forwards(self, orm):
# Adding model 'Project'
db.create_table('project_project', (
('id', orm['project.Project:id']),
('auth_group', orm['project.Project:auth_group']),
('name', orm['project.Project:name']),
('timezone', orm['project.Project:timezone']),
('longitude', orm['project.Project:longitude']),
('latitude', orm['project.Project:latitude']),
('altitude', orm['project.Project:altitude']),
('comment', orm['project.Project:comment']),
))
db.send_create_signal('project', ['Project'])
def backwards(self, orm):
# Deleting model 'Project'
db.delete_table('project_project')
models = {
'auth.group': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
},
'auth.permission': {
'Meta': {'unique_together': "(('content_type', 'codename'),)"},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'contenttypes.contenttype': {
'Meta': {'unique_together': "(('app_label', 'model'),)", 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'project.project': {
'altitude': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
'auth_group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.Group']"}),
'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'latitude': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
'longitude': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
'timezone': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
}
}
complete_apps = ['project']
now, i add a field to the models.py:
# vim project/models.py ... name2 = models.CharField(max_length=200) ...
and now i create a migration with:
./manage.py startmigration project wonderful_migration --auto --settings=develsettings
the new migration looks like:
# vim project/migrations/0002_wonderful_migration.py
from south.db import db
from django.db import models
from ammonitor.project.models import *
class Migration:
def forwards(self, orm):
# Adding field 'Project.name2'
db.add_column('project_project', 'name2', orm['project.project:name2'])
def backwards(self, orm):
# Deleting field 'Project.name2'
db.delete_column('project_project', 'name2')
models = {
'auth.group': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
},
'auth.permission': {
'Meta': {'unique_together': "(('content_type', 'codename'),)"},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'contenttypes.contenttype': {
'Meta': {'unique_together': "(('app_label', 'model'),)", 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'project.project': {
'altitude': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
'auth_group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.Group']"}),
'comment': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'latitude': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
'longitude': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
'name2': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
'timezone': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
}
}
complete_apps = ['project']
when i want to apply the migration, i got the following error:
./manage.py migrate --settings=develsettings
/usr/lib/pymodules/python2.6/registration/models.py:4: DeprecationWarning: the sha module is deprecated; use the hashlib module instead
import sha
Running migrations for project:
- Migrating forwards to 0002_wonderful_migration.
> project: 0002_wonderful_migration
Traceback (most recent call last):
File "./manage.py", line 15, in <module>
execute_manager(ammonitorsettings)
File "/usr/lib/pymodules/python2.6/django/core/management/__init__.py", line 362, in execute_manager
utility.execute()
File "/usr/lib/pymodules/python2.6/django/core/management/__init__.py", line 303, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/lib/pymodules/python2.6/django/core/management/base.py", line 195, in run_from_argv
self.execute(*args, **options.__dict__)
File "/usr/lib/pymodules/python2.6/django/core/management/base.py", line 222, in execute
output = self.handle(*args, **options)
File "/usr/lib/pymodules/python2.6/south/management/commands/migrate.py", line 91, in handle
skip = skip,
File "/usr/lib/pymodules/python2.6/south/migration.py", line 578, in migrate_app
result = run_forwards(mapp, [mname], fake=fake, db_dry_run=db_dry_run, verbosity=verbosity)
File "/usr/lib/pymodules/python2.6/south/migration.py", line 385, in run_forwards
verbosity = verbosity,
File "/usr/lib/pymodules/python2.6/south/migration.py", line 326, in run_migrations
runfunc(orm)
File "/home/tom/devel/ammonitor/django-ammonitor/src/ammonitor/../ammonitor/project/migrations/0002_wonderful_migration.py", line 11, in forwards
db.add_column('project_project', 'name2', orm['project.project:name2'])
File "/usr/lib/pymodules/python2.6/south/db/sqlite3.py", line 20, in add_column
raise ValueError("You cannot add a null=False column without a default value.")
ValueError: You cannot add a null=False column without a default value.
i don't understand why i got this error because i have the same field (called 'name') in the database and this field makes no problems.
Attachments
Change History
comment:1 Changed 4 years ago by andrew
- Status changed from new to closed
- Resolution set to invalid
- Milestone set to 0.6.3
comment:2 Changed 3 years ago by wes@…
Hello,
I don't think this should be the expected behaviour. If you don't supply a DEFAULT clause for a NOT NULL constraint then this is perfectly valid for a column, it just means that INSERTs and UPDATEs will fail if no value is provided, this is perfectly valid in pretty much every SQL based DB under the sun, and it is the default behaviour for a Django model field without any params, e.g.:
my_field = models.IntegerField()
Would be:
`my_field` INTEGER NOT NULL;
This current incorrect behaviour is currently causing any migration under a django-cms install to fail, as it involves various IntegerField? and DecimalField? ALTERs.
comment:3 follow-up: ↓ 4 Changed 3 years ago by andrew
Yes, that's fine, but the issue here is because you're adding a column *to an existing table, with existing data*.
There are already rows in that table, and they need a value in the new column, and it can't be NULL.
See the dev docs here: http://south.aeracode.org/docs/tutorial/part2.html#defaults
comment:4 in reply to: ↑ 3 Changed 3 years ago by anonymous
Replying to andrew:
Yes, that's fine, but the issue here is because you're adding a column *to an existing table, with existing data*.
There are already rows in that table, and they need a value in the new column, and it can't be NULL.
See the dev docs here: http://south.aeracode.org/docs/tutorial/part2.html#defaults
Cheers.
The actual issue on my side was a case of PEBKAC on my part causing me to think this was the same issue. ;-)
comment:5 Changed 5 months ago by Chris Wilson <chris+south@…>
I just ran into this issue again. South allowed me to create a migration that can't be applied because it creates a database error. Shouldn't South detect this before creating the migration?
comment:6 Changed 5 months ago by andrew
South detects this particular error - adding a not-null column without a default - but we can't detect all errors (like conflicting constraints, bad data, etc), as there's no way to do this without looking at the live database, at which point you may as well try the change and if it fails roll back - what South does.

Well, you certainly do need a default value, since the database needs something to put in your new column (since you've said the field is NOT NULL, so the database can't just put nothing in there).
I'm not sure how you've managed to add the column in the database so far, but it's probably nullable, not NOT NULL. Future south versions will raise this error even earlier (at startmigration time), but with a helpful message and a prompt asking what to set the default to.
Closing as invalid, since this is an intentional error.