Как я могу иметь ограничение unique_together, включающее поле ForeignKey в MySQL? - PullRequest
3 голосов
/ 20 августа 2011

MySQL, похоже, не работает в отношении уникальных ограничений для нескольких столбцов с внешними ключами. Вот самый маленький пример, который я могу придумать, чтобы показать это (используя MySQL / InnoDB):

models.py

from django.db import models

class Team(models.Model):
    pass

class Player(models.Model):
    team = models.ForeignKey(Team)
    number = models.PositiveIntegerField()

    class Meta:
        unique_together = ("team", "number")

Запуск schemamigration --initial, юг выплевывает следующую миграцию (только важные биты):

class Migration(SchemaMigration):                                                                                                                                                
    def forwards(self, orm):
        # Adding model 'Team'
        db.create_table('fkuniq_team', (
            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
        ))
        db.send_create_signal('fkuniq', ['Team'])

        # Adding model 'Player'
        db.create_table('fkuniq_player', (
            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
            ('team', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['fkuniq.Team'])),
            ('number', self.gf('django.db.models.fields.PositiveIntegerField')()),
        ))
        db.send_create_signal('fkuniq', ['Player'])

        # Adding unique constraint on 'Player', fields ['team', 'number']
        db.create_unique('fkuniq_player', ['team_id', 'number'])

А в MySQL:

mysql> SHOW COLUMNS FROM fkuniq_player;
+---------+------------------+------+-----+---------+----------------+
| Field   | Type             | Null | Key | Default | Extra          |
+---------+------------------+------+-----+---------+----------------+
| id      | int(11)          | NO   | PRI | NULL    | auto_increment |
| team_id | int(11)          | NO   | MUL | NULL    |                |
| number  | int(10) unsigned | NO   |     | NULL    |                |
+---------+------------------+------+-----+---------+----------------+

Я думаю, что юг молча не смог создать уникальное ограничение, которое я хотел. В столбце Key я вижу индекс первичного ключа на id и индекс внешнего ключа на team_id, но в строке number также должен быть MUL, так как на * должен быть индекс UNIQUE это с team_id. Кроме того, удаление ограничения unique_together из модели приводит к сбою следующей миграции с ошибкой:

Traceback (most recent call last):
  ...
  File "/home/aogier/uniques/../uniques/fkuniq/migrations/0002_auto__del_unique_player_number_team.py", line 12, in forwards
    db.delete_unique('fkuniq_player', ['number', 'team_id'])
  File "/home/aogier/.virtualenvs/uniques/lib/python2.7/site-packages/south/db/generic.py", line 479, 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 fkuniq_player, columns ['number', 'team_id']

Я считаю, что он отсутствует, потому что MySQL не работает хорошо, когда ограничения внешнего ключа и ограничения нескольких столбцов UNIQUE совпадают. Об этом есть комментарий к документации по MySQL для ALTER TABLE: http://dev.mysql.com/doc/refman/5.1/en/alter-table.html (см. Примерно на полпути, комментарий Хади Растгоу).

В любом случае, извините за длинный вопрос: у кого-нибудь есть способ заставить эту работу? Я хотел бы иметь чистый способ сделать это в процессе миграции, даже если мне нужно написать специфичный для MySQL запрос в необработанном SQL. Или, может быть, это просто невозможно сделать в MySQL, что было бы полезно узнать, прежде чем я потрачу на это больше времени.

1 Ответ

2 голосов
/ 20 августа 2011

Аааа, исправил это сам.Это известная ошибка на юге, исправленная в их ветке разработки.http://south.aeracode.org/ticket/747

...