Ticket #126 (closed defect: fixed)

Opened 5 years ago

Last modified 4 years ago

unique_together not working with 3 constraints.

Reported by: ashc@… Owned by: andrew
Priority: major Milestone: 0.5
Component: migrations Version: 0.6-pre
Keywords: Cc:


from django.db import models

class Foo(models.Model):

desc = models.CharField?(max_length=20)

class Bar(models.Model):

name = models.CharField?(max_length=20)

class SouthStuff?(models.Model):

foo = models.ForeignKey?(Foo)
bar = models.ForeignKey?(Bar)
name = models.CharField?(max_length=20, blank=True)
other = models.IntegerField?()

class Meta:

unique_together = (

('foo', 'bar', 'name',)


10:48 ashc@dev-django:[trunk/gapadventures]> python migrate southtest zero
Running migrations for southtest:

  • Migrating backwards to just after zero. < southtest: 0001_initial

Traceback (most recent call last):

File "/home/ashc/sandbox/project_gotham/trunk/gapadventures/./third_party/south/", line 246, in run_migrations


File "/home/ashc/sandbox/project_gotham/trunk/gapadventures/southtest/migrations/", line 52, in backwards

db.delete_unique('southtest_southstuff', ['foo_id', 'bar_id', 'name'])

File "/home/ashc/sandbox/project_gotham/trunk/gapadventures/./third_party/south/db/", line 328, in delete_unique

raise ValueError?("Cannot find a UNIQUE constraint on table %s, columns %r" % (table_name, columns))

ValueError?: Cannot find a UNIQUE constraint on table southtest_southstuff, columns ['foo_id', 'bar_id', 'name']

! Error found during dry run of migration! Aborting.

I have narrowed it down to _constraints_affecting_columns generator always being empty - though I am not familiar enough with generators.

Also noticed that the SQL in the _constraints_affecting_columns method fails. If you remove the kc.table_schema = 'public' part, the constraints are returned, however that isnt enough to fix the problem.


Change History

comment:1 Changed 5 years ago by ashc@…

Also should add that I am using MySQL. Modified the migrate script and replaced:

db.delete_unique('southtest_southstuff', ['foo_id', 'bar_id', 'name'])



# Deleting unique_together for [foo, bar, name] on SouthStuff?.
db.delete_unique('southtest_southstuff', ['foo_id', 'bar_id', 'name'])

except ValueError?:

# do manually.
qn = connection.ops.quote_name
constraints = ['foo_id', 'bar_id', 'name']
table_name = 'southtest_southstuff'
for constraint in constraints:

statement = "ALTER TABLE %s DROP CONSTRAINT %s" %(qn(table_name), qn(constraint))

print "------------------------"
print statement
print "------------------------"

and noticed that the alter statement isnt even valid for mysql.

mysql> ALTER TABLE southtest_southstuff DROP CONSTRAINT foo_id

-> ;

ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CONSTRAINT foo_id' at line 1

comment:2 Changed 5 years ago by andrew

  • Status changed from new to assigned
  • Version set to subversion
  • Milestone changed from The Future to 0.5

comment:3 Changed 5 years ago by andrew

Right, two comments:

  • Firstly, the MySQL library uses DROP INDEX not DROP CONSTRAINT, so the SQL is fine when run via South
  • I can't replicate this. I've changed the unique test to include a foreignkey and three columns, and it still works fine.

How did you make the unique constraint in the first place? Was it via django's syncdb (and you later did a migrate --fake)?

It might be helpful if you could attach a schema dump of the database, so I can see what constraints you have.

comment:4 Changed 5 years ago by ashc@…

I have s typescript and sample django app but I can't attach it to this ticket. Is there an I can send it to?

comment:5 Changed 5 years ago by ashc@…

I will also create a typescript of what happens in the app I am currently working on later today.

comment:6 Changed 5 years ago by andrew

You can send the stuff to andrew at if you want.

comment:7 Changed 5 years ago by andrew

  • Status changed from assigned to closed
  • Resolution set to fixed

Finally! This one is because MySQL migrations use dry runs to check things parse, and delete_unique wasn't dry-run safe. Fixed in [229], with a test that catches the bug.

comment:8 Changed 4 years ago by WexWEannakzer


Add a comment

Modify Ticket

as closed

E-mail address and user name can be saved in the Preferences.

Note: See TracTickets for help on using tickets.