143 votes

La manière la plus simple de renommer un modèle en utilisant Django / South?

J'ai été à la chasse pour la réponse à cette Sud du site, Google, etc, mais ne pouvait pas trouver un moyen simple de faire cela.

Je veux renommer un Django modèle à l'aide du Sud. Disons que vous avez les éléments suivants:

class Foo(models.Model):
    name = models.CharField()

class FooTwo(models.Model):
    name = models.CharField()
    foo = models.ForeignKey(Foo)

et vous voulez les convertir Foo Bar", à savoir

class Bar(models.Model):
    name = models.CharField()

class FooTwo(models.Model):
    name = models.CharField()
    foo = models.ForeignKey(Bar)

Pour faire simple, je suis juste en train de changer le nom de Foo de Bar, mais ignorer l' foo membre en FooTwo pour l'instant.

Quelle est la meilleure façon de le faire à l'aide du Sud?

  1. Je pourrais probablement faire une migration de données, mais qui semble assez impliqués.
  2. Écrire une migration personnalisée, par exemple, db.rename_table('city_citystate', 'geo_citystate'), mais je ne suis pas sûr de la façon de fixer la clé étrangère dans ce cas.
  3. Un moyen plus facile que vous le savez?

131voto

Leopd Points 12652

Pour répondre à votre première question, le modèle simple/table rename est assez simple. Exécutez la commande:

./manage.py schemamigration yourapp rename_foo_to_bar --empty

(Mise à jour 2: essayez --auto au lieu de --empty pour éviter l'avertissement ci-dessous. Grâce à @KFB pour l'astuce.)

Si vous utilisez une version plus ancienne du sud, vous aurez besoin d' startmigration au lieu de schemamigration.

Puis modifier manuellement le fichier de migration pour ressembler à ceci:

class Migration(SchemaMigration):

    def forwards(self, orm):
        db.rename_table('yourapp_foo', 'yourapp_bar')


    def backwards(self, orm):
        db.rename_table('yourapp_bar','yourapp_foo')   

Vous pouvez accomplir cela plus simplement à l'aide de l' db_table Meta option dans votre classe de modèle. Mais à chaque fois que vous faites cela, vous augmentez l'héritage du poids de votre base de code-avoir de la classe des noms différents à partir de la table des noms rend votre code plus difficile à comprendre et à maintenir. Je soutiens pleinement en faisant de simples refactorings comme ceci par souci de clarté.

(mise à jour) j'ai juste essayé ce dans la production, et a reçu un avertissement étrange quand je suis allé à appliquer la migration. Il a dit:

The following content types are stale and need to be deleted:

    yourapp | foo

Any objects related to these content types by a foreign key will also
be deleted. Are you sure you want to delete these content types?
If you're unsure, answer 'no'.

J'ai répondu "non" et tout semblait bien se passer.

67voto

Jian Points 1323

Les modifications de l' models.py , puis exécutez

./manage.py schemamigration --auto myapp

Lorsque vous examinez le fichier de migration, vous verrez qu'il supprime une table et en crée une nouvelle

class Migration(SchemaMigration):

    def forwards(self, orm):
        # Deleting model 'Foo'                                                                                                                      
        db.delete_table('myapp_foo')

        # Adding model 'Bar'                                                                                                                        
        db.create_table('myapp_bar', (
        ...
        ))
        db.send_create_signal('myapp', ['Bar'])

    def backwards(self, orm):
        ...

Ce n'est pas tout à fait ce que vous voulez. Au lieu de cela, modifier la migration, de sorte qu'il ressemble à:

class Migration(SchemaMigration):

    def forwards(self, orm):
        # Renaming model from 'Foo' to 'Bar'                                                                                                                      
        db.rename_table('myapp_foo', 'myapp_bar')                                                                                                                        
        if not db.dry_run:
            orm['contenttypes.contenttype'].objects.filter(
                app_label='myapp', model='foo').update(model='bar')

    def backwards(self, orm):
        # Renaming model from 'Bar' to 'Foo'                                                                                                                      
        db.rename_table('myapp_bar', 'myapp_foo')                                                                                                                        
        if not db.dry_run:
            orm['contenttypes.contenttype'].objects.filter(app_label='myapp', model='bar').update(model='foo')

En l'absence de l' update - déclaration, l' db.send_create_signal appel de créer un nouveau ContentType avec le nouveau nom du modèle. Mais il est préférable de simplement update le ContentType vous avez déjà dans le cas où il y a des objets de base de données pointant vers celui-ci (par exemple, via un GenericForeignKey).

Aussi, si vous avez renommé certaines colonnes qui sont des clés étrangères pour le nouveau nom de modèle, n'oubliez pas de

db.rename_column(myapp_model, foo_id, bar_id)

5voto

Dominic Rodger Points 44489

Sud-ne peut pas le faire elle - même-comment sait-il qu' Bar représente quel Foo ? C'est le genre de truc que j'aimerais écrire une migration personnalisés pour. Vous pouvez modifier votre ForeignKey dans le code comme vous l'avez fait ci-dessus, et puis c'est juste une affaire de renommer les champs appropriés et des tables, vous pouvez le faire de la manière que vous voulez.

Enfin, avez-vous vraiment besoin de faire cela? Je n'ai pas encore besoin de renommer les modèles - les noms de modèles sont juste un détail d'implémentation - en particulier compte tenu de la disponibilité de l' verbose_name Meta option.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X