Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django 1.8 app mysteriously fails with initial migration due to errno: 150 "Foreign key constraint is incorrectly formed"

I'm writing an app in django 1.8 with python 3.4 and I'm encountering an issue with using MySQL as the database backend which has got me completely stumped.

When I start off with a new database and call ./manage.py migrate (or syncdb) and it tries to create the initial database, I get the following traceback:

(virtualenv)~/projects/projmoj (master ✘)✹✭ ᐅ ./manage.py migrate
Operations to perform:
  Synchronize unmigrated apps: allauth, rest_framework, registration, rest_auth, projmoj, messages, project, staticfiles
  Apply all migrations: contenttypes, sites, sessions, task, auth, admin, authtoken, static_precompiler, account
Synchronizing apps without migrations:
  Creating tables...
    Creating table project_project
    Creating table project_membership
    Running deferred SQL...
Traceback (most recent call last):
  File "/home/tobbe/projects/projmoj/virtualenv/lib/python3.4/site-packages/django/db/backends/utils.py", line 62, in execute
    return self.cursor.execute(sql)
  File "/home/tobbe/projects/projmoj/virtualenv/lib/python3.4/site-packages/django/db/backends/mysql/base.py", line 124, in execute
    return self.cursor.execute(query, args)
  File "/home/tobbe/projects/projmoj/virtualenv/lib/python3.4/site-packages/MySQLdb/cursors.py", line 220, in execute
    self.errorhandler(self, exc, value)
  File "/home/tobbe/projects/projmoj/virtualenv/lib/python3.4/site-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
    raise errorvalue
  File "/home/tobbe/projects/projmoj/virtualenv/lib/python3.4/site-packages/MySQLdb/cursors.py", line 209, in execute
    r = self._query(query)
  File "/home/tobbe/projects/projmoj/virtualenv/lib/python3.4/site-packages/MySQLdb/cursors.py", line 371, in _query
    rowcount = self._do_query(q)
  File "/home/tobbe/projects/projmoj/virtualenv/lib/python3.4/site-packages/MySQLdb/cursors.py", line 335, in _do_query
    db.query(q)
  File "/home/tobbe/projects/projmoj/virtualenv/lib/python3.4/site-packages/MySQLdb/connections.py", line 280, in query
    _mysql.connection.query(self, query)
_mysql_exceptions.OperationalError: (1005, 'Can\'t create table `tasks`.`#sql-1c32_9` (errno: 150 "Foreign key constraint is incorrectly formed")')

This error happens when I do the same on a web hosting service, it works however using sqlite on both the hosting service and localhost.

I have no migrations, and these are my models:

class Project(models.Model):
  name = models.CharField(max_length = 32) 
  description = models.TextField(null=True, blank=True)
  creation_date = models.DateTimeField(auto_now_add=True)

  def get_owner(self):
    return self.members.filter(status=OWNER).first().user

  def get_membership(self, user):
    return self.members.filter(user=user).first()

  def __str__(self):
    return str(self.name) + " - by " + str(self.get_owner().username)

class Membership(models.Model):
  user = models.ForeignKey(User, related_name='joined_projects')
  project = models.ForeignKey(Project, related_name='members')
  status = models.PositiveSmallIntegerField(choices=MEMBER_STATUS)
  join_date = models.DateTimeField(auto_now_add=True)

  def __str__(self):
    return str(self.user.username)

class Sprint(models.Model):
  name = models.CharField(max_length = 32, null=True, blank=True)
  start_date = models.DateTimeField()
  due_date = models.DateTimeField(null=True, blank=True)
  project = models.ForeignKey(Project, related_name='sprints')
  status = models.PositiveSmallIntegerField(choices=SPRINT_STATUS, default=PLANNING)

  def __str__(self):
    return str(self.name) + " - " + str(self.project)

class Category(models.Model):
  name = models.CharField(max_length = 32) 
  project = models.ForeignKey(Project, related_name='categories')

  def __str__(self):
    return str(self.name) + " - " + str(self.project)

class Goal(models.Model):
  name = models.CharField(max_length = 32) 
  description = models.TextField(null=True, blank=True)
  project = models.ForeignKey(Project, related_name='goals')
  completion = models.PositiveSmallIntegerField(choices=COMPLETION, default=NOT_COMPLETED)

  def __str__(self):
    return str(self.name) + " - " + str(self.project)

class Task(models.Model):
  name = models.CharField(max_length = 64)
  description = models.TextField(null=True, blank=True)
  project = models.ForeignKey(Project, related_name='tasks')
  category = models.ForeignKey(Category, related_name='tasks', null=True, blank=True)
  goal = models.ForeignKey(Goal, related_name='tasks', null=True, blank=True)
  creation_date = models.DateTimeField(auto_now_add=True)
  sprint = models.ForeignKey(Sprint, related_name='tasks', null=True, blank=True)
  status = models.PositiveSmallIntegerField(choices=TASK_STATUS, default=WAITING)
  dedicated_hours = models.DecimalField(max_digits=6, decimal_places=2, null=True, blank=True)
  assigned_worker = models.ForeignKey(User, null=True, blank=True)
  priority = models.PositiveSmallIntegerField(choices=PRIORITY, default=NORMAL)

  def __str__(self):
    return str(self.name) + " - " + str(self.project)

class HourReport(models.Model):
  task = models.ForeignKey(Task, related_name='hour_reports')
  worker = models.ForeignKey(User, related_name='hour_reports')
  hours_spent = models.DecimalField(max_digits=6, decimal_places=2)
  date = models.DateTimeField(auto_now_add=True)

  def __str__(self):
    return str(self.hours_spent) + " on " + str(self.task)

My database settings:

DATABASES = { 
  'default': {
      'ENGINE': 'django.db.backends.mysql',
      'NAME': 'tasks',
      'USER': 'root',
      'PASSWORD': 'mysqlmysql',
      'HOST': 'localhost',
  }
}

Versions etc:

  • Django 1.8
  • Python 3.4
  • Default storage engine: InnoDB
  • Mysqlclient 1.3.6
  • Server: MySQL 5.5.42 on Amazon RDS (at web hosting)
  • Server: 10.0.21-MariaDB-log MariaDB Server (localhost)

When googling it seems like this error is often when people stuff up their manual SQL code, but I am doing it all automatically through django.

Any ideas?

like image 865
Tobias Avatar asked Sep 14 '15 20:09

Tobias


2 Answers

The log is telling you that you have not created migrations for your project app. You should create migrations for the app before running migrate.

./manage.py makemigrations project
./manage.py migrate

Since it's a new database, you'd be better to completely reset it before creating and applying the migrations, otherwise you'll have to manually deal with its current inconsistent state.

like image 69
Alasdair Avatar answered Sep 19 '22 15:09

Alasdair


According to the Django documentation MySQL notes. Storage engine

If you upgrade an existing project to MySQL 5.5.5 and subsequently add some tables, ensure that your tables are using the same storage engine (i.e. MyISAM vs. InnoDB). Specifically, if tables that have a ForeignKey between them use different storage engines, you may see an error like the following when running migrate:

 _mysql_exceptions.OperationalError: (
    1005, "Can't create table '\\db_name\\.#sql-4a8_ab' (errno: 150)"
 )

Stop you backend and do backup. Than change storage engine for tables from MyISAM to InnoDB. It's fix the problem.

Also in the MySQL docs ( B.3 Server Error Codes and Messages chapter) specified about this error:

Error: 1005 SQLSTATE: HY000 (ER_CANT_CREATE_TABLE)

Message: Can't create table '%s' (errno: %d - %s)

InnoDB reports this error when a table cannot be created. If the error message refers to error 150, table creation failed because a foreign key constraint was not correctly formed. If the error message refers to error −1, table creation probably failed because the table includes a column name that matched the name of an internal InnoDB table.

like image 23
M.Void Avatar answered Sep 22 '22 15:09

M.Void