Yeni bir tablo ekleyen ve yeni bir taşıma oluşturmadan onu geri döndürüp taşımayı silmek istediğiniz bir geçiş yaptım.
Nasıl yaparım? Son geçişi geri almak için bir komut var mı ve daha sonra geçiş dosyasını silebilir miyim?
Yeni bir tablo ekleyen ve yeni bir taşıma oluşturmadan onu geri döndürüp taşımayı silmek istediğiniz bir geçiş yaptım.
Nasıl yaparım? Son geçişi geri almak için bir komut var mı ve daha sonra geçiş dosyasını silebilir miyim?
Yanıtlar:
Önceki taşıma işlemine geçerek geri dönebilirsiniz.
Örneğin, son iki taşıma işleminiz şuysa:
0010_previous_migration
0011_migration_to_revert
Sonra yapardınız:
./manage.py migrate my_app 0010_previous_migration
Ardından taşımayı silebilirsiniz 0011_migration_to_revert
.
Django 1.8+ kullanıyorsanız, tüm taşıma işlemlerinin adlarını
./manage.py showmigrations my_app
Bir uygulamanın tüm taşıma işlemlerini geri almak için şunları çalıştırabilirsiniz:
./manage.py migrate my_app zero
'0010_previous_migration'
, bu davranışı neden göreceğinizi bilmiyorum.
Alasdair'in cevabı temelleri kapsıyor
./manage.py showmigrations
migrate
uygulama adını ve taşıma adını kullanmaAma hepsi göçler değil işaret edilmelidir olabilir tersine. Bu, Django'nun geri dönüşü yapmak için bir kuralı yoksa olur. Otomatik olarak geçiş yaptığınız çoğu değişiklik ./manage.py makemigrations
için geri dönüş mümkün olacaktır. Ancak, özel komut dosyalarının aşağıdaki örnekte açıklandığı gibi hem ileri hem de geri yazılmış olması gerekir:
https://docs.djangoproject.com/en/1.9/ref/migration-operations/
Bir RunPython
işleminiz varsa, belki de mantıksal olarak titiz bir ters komut dosyası yazmadan taşımayı geri almak isteyebilirsiniz. Dokümanlardaki örnekteki aşağıdaki hızlı saldırı (yukarıdaki bağlantı) buna izin verir ve veritabanını, geçiş yapıldıktan sonra bile geri döndükten sonra olduğu gibi bırakır.
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
def forwards_func(apps, schema_editor):
# We get the model from the versioned app registry;
# if we directly import it, it'll be the wrong version
Country = apps.get_model("myapp", "Country")
db_alias = schema_editor.connection.alias
Country.objects.using(db_alias).bulk_create([
Country(name="USA", code="us"),
Country(name="France", code="fr"),
])
class Migration(migrations.Migration):
dependencies = []
operations = [
migrations.RunPython(forwards_func, lambda apps, schema_editor: None),
]
Bu Django 1.8, 1.9 için çalışır
Güncelleme: Bu yazı daha iyi bir yolu değiştirmek şeklinde olur lambda apps, schema_editor: None
ile migrations.RunPython.noop
yukarıdaki kod parçasında. Bunların ikisi de işlevsel olarak aynı şeydir. (yorumlara kredi)
RunPython.noop
satır içi lambda veya eşdeğeri yerine kullanmalısınız : docs.djangoproject.com/en/1.8/ref/migration-operations/…
migrations.RunPython(forwards_func, migrations.RunPython.noop)
. Bunu işlevsel olarak kontrol etmeniz gerekiyor. Bu bir ara bir cevap ya da düzenleme olarak eklenmelidir.
İşte benim çözümüm, çünkü yukarıdaki çözüm kullandığınızda kullanım kutusunu gerçekten kapsamaz RunPython
.
Tabloya ORM üzerinden
from django.db.migrations.recorder import MigrationRecorder
>>> MigrationRecorder.Migration.objects.all()
>>> MigrationRecorder.Migration.objects.latest('id')
Out[5]: <Migration: Migration 0050_auto_20170603_1814 for model>
>>> MigrationRecorder.Migration.objects.latest('id').delete()
Out[4]: (1, {u'migrations.Migration': 1})
Böylece tabloları sorgulayabilir ve sizin için uygun olan girişleri silebilirsiniz. Bu şekilde ayrıntılı olarak değiştirebilirsiniz. Taşıma işlemlerinde RynPython
, eklenen / değiştirilen / kaldırılan verilerle de ilgilenmeniz gerekir. Yukarıdaki örnek yalnızca, tabloya Djang ORM üzerinden nasıl eriştiğinizi gösterir.
django.db.utils.ProgrammingError: relation "<relation name>" already exists
yaptığım gibi hata mesajı vardı migrate --fake
, bu yüzden geri dönmeye çalıştım, sonra psycopg2.ProgrammingError: relation "<other <relation name>" does not exist
TEŞEKKÜRLER var
Yapabileceğiniz bir diğer şey, manuel olarak oluşturulan tabloyu silmektir.
Bununla birlikte, söz konusu taşıma dosyasını silmeniz gerekir. Ayrıca, django-migrations tablosundaki (muhtemelen sizin durumunuzdaki son giriş) ilgili belirli bir geçişle ilişkili olan bu girişi silmeniz gerekir .
Geçiş dosyasını geri dönüşün sonuna kadar silmeyin. Bu hatayı yaptım ve geçiş dosyası olmadan, veritabanı neyin kaldırılacağını bilmiyordu.
python manage.py showmigrations
python manage.py migrate {app name from show migrations} {00##_migration file.py}
Taşıma dosyasını silin. İstediğiniz taşıma modellerinizde olduğunda ...
python manage.py makemigrations
python manage.py migrate
Bunu 1.9.1'de yaptım (oluşturulan son veya en son geçişi silmek için):
rm <appname>/migrations/<migration #>*
misal: rm myapp/migrations/0011*
veritabanına giriş yaptı ve bu SQL'i çalıştırdı (bu örnekte postgres)
delete from django_migrations where name like '0011%';
Daha sonra, yeni sildiğim taşıma numarasıyla başlayan yeni taşıma işlemleri oluşturabildim (bu durumda, 11).
Alasdair'in en iyi cevabı yardımcı olmazsa bu cevap benzer durumlar içindir . (Örneğin, istenmeyen geçiş her yeni geçişle kısa süre sonra tekrar oluşturulursa veya geri döndürülemeyen daha büyük bir geçişte ise veya tablo manuel olarak kaldırılmışsa.)
... yeni bir taşıma oluşturmadan taşıma silinsin mi?
TL; DR : Geri döndürülen (karışık) birkaç geçişi silebilir ve modelleri düzelttikten sonra yeni bir tane oluşturabilirsiniz . Ayrıca migrate komutuyla tablo oluşturmayacak şekilde yapılandırmak için başka yöntemler de kullanabilirsiniz . Son taşıma, mevcut modellerle eşleşecek şekilde oluşturulmalıdır .
Kılıflar kimse mevcut olması gereken Modeli için bir tablo oluşturmak istemiyorum nedenleri:
A) Böyle bir tablo, hiçbir makinede ve hiçbir koşulda veritabanında bulunmamalıdır.
class Meta: abstract = True
B) Tablo nadiren, başka bir şeyle veya manuel olarak özel bir şekilde oluşturulur.
class Meta: managed = False
C) Masa sadece bazı makinelerde kullanılır (örneğin geliştirme aşamasında).
class Meta: managed = some_switch
.D) Proje,settings.DATABASES
allow_migrate
.Taşıma, Django 1.9+ ile tüm A), B), C), D) durumlarında (ve yalnızca Django 1.8 ile B, C, D durumlarında) oluşturulur, ancak veritabanına yalnızca uygun durumlarda uygulanır veya gerekli. Django 1.8'den bu yana testlerin yürütülmesi için göçler gerekli olmuştur. Yönetilen / yönetilmeyen modeller arasında bir ForeignKey oluşturmak veya modeli daha sonra yönetebilmek için yönetilen = False 1.9 + 'da yönetilen modellerde bile geçerli ilgili durumun tamamı göçlerle kaydedilir. (Bu soru Django 1.8 zamanında yazılmıştır. Buradaki her şey 1.8 ile şu anki 2.2 arasındaki sürümler için geçerli olmalıdır.)
Son taşıma (geri alınamazsa) kolayca geri döndürülemezse (veritabanı yedeklemesinden sonra) sahte bir geri alma işlemi yapmak dikkatlice yapılabilir ./manage.py migrate --fake my_app 0010_previous_migration
, tabloyu manuel olarak silin.
Gerekirse, sabit modelden sabit bir taşıma oluşturun ve veritabanı yapısını değiştirmeden uygulayın ./manage.py migrate --fake my_app 0011_fixed_migration
.
Taşımayı geri alırken sorun yaşıyorsanız ve bir şekilde onu karıştırdıysanız, fake
taşıma işlemi gerçekleştirebilirsiniz .
./manage.py migrate <name> --ignore-ghost-migrations --merge --fake
İçin Django sürümü <1.7 bunda bir giriş oluşturulur south_migrationhistory
masaya, o girdiyi silmek için gerek yoktur.
Artık taşımayı kolayca geri alabileceksiniz.
PS: Çok zaman takılıp takıldım ve sahte göç yaptım ve sonra geri dönmek bana yardımcı oldu.