2015-03-05 16 views
12

Jeśli mam pole modelu non-zerowalne, należy go usunąć i utworzyć migrację, że migracja staje się nieodwracalne:Przywróć Django 1.7 RemoveField migracja

Rozważmy następujący model:

class Foo(models.Model): 
    bar = models.TextField() 
    test = models.TextField() # This field is to go away, bye-bye! 

I Migracja:

# app/migrations/003_remove_foo_test.py 

class Migration(migrations.Migration): 

    dependencies = [ 
     ('app', '0002_foo_test'), 
    ] 

    operations = [ 
     migrations.RemoveField(
      model_name='foo', 
      name='test', 
     ), 
    ] 

Unapplying tego przechodzenia wyjątek to

$ src/manage.py migrate app 0002 
Operations to perform: 
    Target specific migration: 0002_foo_test, from app 
Running migrations: 
    Unapplying app.0003_remove_foo_test...Traceback (most recent call last): 
... 
django.db.utils.IntegrityError: column "test" contains null values 

Oczywiście, jest to oczekiwane zachowanie, to clearly documented i nie pytam, dlaczego tak się dzieje:

pamiętać, że po odwróceniu jest to faktycznie dodanie pola do modelu; jeśli pole nie jest zerowane, może to spowodować nieodwracalną operację (z wyjątkiem utraty danych, która oczywiście jest nieodwracalna).

Jednak wszyscy popełniają błędy, a czasami po prostu trzebado jakoś odwrócić usunięcie terenie, nawet jeśli oznacza to ręcznie zapewniając wartość skrótową ad hoc na wszystkich polach odwróconych non-null. Na przykład migracje na południu opcjonalnie umożliwiają odwrócenie takich operacji (poprzez zapytanie dewelopera o ustawienie domyślne dla przywróconych pól lub uniemożliwienie migracji zwrotnej), co nie wydaje się mieć miejsca w przypadku wszystkich nowych wymyślnych migracji Django 1.7 .

Pytanie: jaki jest najłatwiejszy/najszybszy sposób na cofnięcie usunięcia pola przy użyciu migracji Django 1.7+ (zakładając, że już się stało)? To niekoniecznie musi być w pełni skryptowane w Pythonie, zrobi to zestaw instrukcji manualnych.

Odpowiedz

11

można ręcznie ed to twoja migracja i dodaj AlterField z domyślną wartością pola tuż przed RemoveField. Powinien być bezpieczny nawet po zastosowaniu migracji.To sprawi, że RemoveField stanie się po odwróceniu.

Przykład. Mając na pole w modelu summary nazwie profit który został zdefiniowany przed usunięciem tak:

profit = models.PositiveIntegerField(verbose_name='profits') 

należy dodać przed RemoveField nim AlterField tak:

migrations.AlterField(
    model_name='summary', 
    name='profit', 
    field=models.PositiveIntegerField(verbose_name='profits', default=0), 
    preserve_default=False, 
    ), 
+0

'AlterField' nie akceptuje argumentu' preserve_default' (ale nie wydaje się być w tym przypadku potrzebny, ponieważ 'default' i tak nie przechodzi do schematu bazy danych). Poza tym wydaje się to być właściwym i optymalnym rozwiązaniem. Dzięki! –

+0

Zgodnie z [dokumentacją] (https://docs.djangoproject.com/en/1.7/ref/migration-operations/#django.db.migrations.operations.AlterField), tak, ale zostało dodane w 1.7. 1. W takim przypadku preserve_default nie powinno mieć znaczenia. Dostaje się do bazy danych, ale tylko na krótką chwilę. – GwynBleidD

+0

To nie działa w Django 1.8 – jess

3

Jeśli próbujesz uczynić przyszłe migracje odwracalnymi, możesz spróbować usunąć pole jako trzy migracje.

  1. Dodać pole pustych
  2. migracji danych. Naprzód, nie rób nic. Do tyłu, konwertuj wartości null do wartości stub.
  3. Usuń polu

Każdy z tych trzech etapów powinny być odwracalne.

Jeśli już uruchomić migrację i trzeba go odwrócić, można

  1. ręcznie dodać pole, umożliwiając null
  2. konwertować wartości null na wartość skrótowej
  3. ręcznie dodać NOT NULL ograniczenia
  4. Migrate z --fake do poprzedniej migracji
+0

Nie jestem całkiem pewna „ręcznie dodać pole "w kroku 1. Z pewnością chciałbym uniknąć ręcznego uruchamiania ALTER TABLE. DODAĆ KOLUMNĘ, to jest to, co warstwa ORM zawsze robi i zawsze powinno robić. Programista nie musi powtarzać wszystkich małych sztuczek, które robi ORM (nazywanie pól, zarządzanie indeksami itp.). –

+0

Ręczne uruchamianie SQL nie jest idealne, ale czasami nie masz żadnych innych opcji. Ktoś inny może mieć lepszą sugestię. Możesz być w stanie skłonić Django do wygenerowania kodu SQL za pomocą './manage.py sqlmigrate --backwards'. – Alasdair

+0

Mogę potwierdzić, że './manage.py sqlmigrate --backwards' podaje poprawny kod SQL, aby przeprowadzić tę migrację, i że nie jest to bolesne, jeśli używasz IDE, takiego jak PyCharm; podejście do edycji migracji nie działało dla mnie z powodu migracji wstecznej. – Symmetric