ManyToManyField и Южная миграция - PullRequest
9 голосов
/ 23 мая 2011

У меня есть модель профиля пользователя с полем M2M

class Account(models.Model):
    ...
    friends = models.ManyToManyField('self', symmetrical=True, blank=True)
    ...

Теперь мне нужно знать, КАК и КОГДА добавить друг друга как ДРУГА И я создал модель для этого

class Account(models.Model):
    ...
    friends = models.ManyToManyField('self', symmetrical=False, blank=True, through="Relationship")
    ...


class Relationship(models.Model):    
    """ Friends """        
    from_account = models.ForeignKey(Account, related_name="relationship_set_from_account")            
    to_account = models.ForeignKey(Account, related_name="relationship_set_to_account")
    # ... some special fields for friends relationship

    class Meta:                    
        db_table = "accounts_account_friends"            
        unique_together = ('from_account','to_account')

Должен ли я создать какую-либо миграцию для этих изменений или нет? Если у вас есть предложения, вы можете написать их здесь.

Спасибо

PS: accounts_account таблица уже содержит записи

Ответы [ 2 ]

8 голосов
/ 23 июня 2011

Во-первых, я бы не стал использовать псевдоним db_table, если вы можете.Это усложняет понимание структуры таблицы, поскольку она больше не синхронизируется с моделями.

Во-вторых, южный API предлагает функции, подобные db.rename_table(), которые можно использовать путем ручного редактирования файла миграции.Вы можете переименовать таблицу accounts_account_friends в accounts_relation (как Django назвал бы ее по умолчанию) и добавить дополнительные столбцы.

Это объединение дает вам следующую миграцию:

def forwards(self, orm):
    # the Account.friends field is a many-to-many field which got a through= option now.
    # Instead of dropping+creating the table (or aliasing in Django),
    # rename it, and add the required columns.

    # Rename table
    db.delete_unique('accounts_account_friends', ['from_account', 'to_account'])
    db.rename_table('accounts_account_friends', 'accounts_relationship')

    # Add extra fields
    db.add_column('accounts_relationship', 'some_field',  ...)

    # Restore unique constraint
    db.create_unique('accounts_relationship', ['from_account', 'to_account'])


def backwards(self, orm):

    # Delete columns
    db.delete_column('accounts_relationship', 'some_field')
    db.delete_unique('accounts_relationship', ['from_account', 'to_account'])

    # Rename table
    db.rename_table('accounts_relationship', 'accounts_account_friends')
    db.create_unique('accounts_account_friends', ['from_account', 'to_account'])


models = {
    # Copy this from the final-migration.py file, see below
}

Уникальное отношение удаляется и воссоздается, поэтому ограничение имеет правильное имя.

Операторы добавления столбцов легко генерируются с помощью следующего трюка:

  • Добавление модели Relationshipв models.py только с полями внешнего ключа и без изменений в поле M2M.
  • Перенос на него
  • Добавление полей в модель Relationship.
  • Сделайте ./manage.py schemamigration app --auto --stdout | tee final-migration.py | grep column
  • Отменить первую миграцию.

Тогда у вас есть все необходимое для создания файла миграции.

1 голос
/ 23 мая 2011

Как у вас там написано, вы вручную определяете модель, которая выполняет ту же работу, что и таблица соединения m2m, которую Django автоматически создаст для вас.Дело в том, что автоматически созданная таблица будет называться accounts_relationship_friend.

Итак, то, что вы делаете там, создаст модель, которая пытается дублировать то, что ORM сделал под поверхностью, но она указывает нанеправильная таблица.

Если вам не нужна явная модель объединения, я бы оставил удалить ее из вашей кодовой базы, а не создавать миграцию для ее добавления, а вместо этого использовать M2M для поиска отношений между друзьями.(Я не думаю об этом слишком глубоко, но это должно работать).

Если, однако, вы хотите сделать что-то особенное с вашей моделью отношений (например, хранить атрибуты о типе отношений и т. Д.)), Я бы объявил модель отношений как сквозную модель, которую вы используете в своем определении m2m для Friend.friends. Смотри документы здесь.

...