web-dev-qa-db-de.com

Der einfachste Weg, ein Model mit Django / South umzubenennen?

Ich habe auf der Website von South, Google und SO nach einer Antwort darauf gesucht, aber keinen einfachen Weg gefunden, dies zu tun.

Ich möchte ein Django -Modell mit South umbenennen. Angenommen, Sie haben Folgendes:

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

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

und Sie möchten Foo in Bar konvertieren, und zwar

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

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

Um es einfach zu halten, ich versuche nur, den Namen von Foo in Bar zu ändern, aber ignoriere das foo -Element in FooTwo fürs Erste.

Wie geht das am einfachsten mit South?

  1. Ich könnte wahrscheinlich eine Datenmigration durchführen, aber das scheint ziemlich kompliziert zu sein.
  2. Schreiben Sie eine benutzerdefinierte Migration, z. db.rename_table('city_citystate', 'geo_citystate'), aber ich bin nicht sicher, wie ich den Fremdschlüssel in diesem Fall reparieren soll.
  3. Ein einfacher Weg, den Sie kennen?
141
vaughnkoch

Um Ihre erste Frage zu beantworten, ist die einfache Umbenennung von Modell/Tabelle ziemlich einfach. Führen Sie den Befehl aus:

./manage.py schemamigration yourapp rename_foo_to_bar --empty

(Update 2: versuchen Sie --auto Anstatt von --empty, um die folgende Warnung zu vermeiden. Danke an @KFB für den Tipp.)

Wenn Sie eine ältere Version von south verwenden, benötigen Sie startmigration anstelle von schemamigration.

Bearbeiten Sie dann die Migrationsdatei manuell so, dass sie folgendermaßen aussieht:

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')   

Sie können dies einfacher mit dem db_table Meta-Option in Ihrer Modellklasse. Aber jedes Mal, wenn Sie dies tun, erhöhen Sie das Legacy-Gewicht Ihrer Codebasis. Wenn Klassennamen von Tabellennamen abweichen, ist Ihr Code schwieriger zu verstehen und zu pflegen. Der Klarheit halber unterstütze ich solche einfachen Refactorings voll und ganz.

(Update) Ich habe dies gerade in der Produktion versucht und eine seltsame Warnung erhalten, als ich die Migration anwenden wollte. Es sagte:

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'.

Ich antwortete "nein" und alles schien in Ordnung zu sein.

130
Leopd

Nehmen Sie die Änderungen in models.py Vor und führen Sie dann aus

./manage.py schemamigration --auto myapp

Wenn Sie die Migrationsdatei überprüfen, werden Sie feststellen, dass sie eine Tabelle löscht und eine neue erstellt

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):
        ...

Das ist nicht ganz das, was du willst. Bearbeiten Sie die Migration stattdessen so, dass sie wie folgt aussieht:

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')

Wenn die Anweisung update nicht vorhanden ist, erstellt der Aufruf db.send_create_signal Eine neue ContentType mit dem neuen Modellnamen. Es ist jedoch besser, nur update das ContentType zu verwenden, das Sie bereits haben, falls Datenbankobjekte darauf verweisen (z. B. über ein GenericForeignKey).

Wenn Sie einige Spalten, die Fremdschlüssel des umbenannten Modells sind, umbenannt haben, vergessen Sie Folgendes nicht

db.rename_column(myapp_model, foo_id, bar_id)
66
Jian

South kann es nicht selbst tun - woher weiß es, dass Bar das darstellt, was Foo früher war? Dies ist die Art von Dingen, für die ich eine benutzerdefinierte Migration schreiben würde. Sie können Ihren ForeignKey -In-Code wie oben beschrieben ändern. Anschließend müssen Sie nur noch die entsprechenden Felder und Tabellen umbenennen.

Müssen Sie das wirklich tun? Ich muss noch Modelle umbenennen - Modellnamen sind nur ein Implementierungsdetail - insbesondere angesichts der Verfügbarkeit der verbose_name Meta-Option.

5
Dominic Rodger