Django'da yalnızca bir tablo “django_migrations” ile birden çok veritabanı kullanın


11

Django'daki bir proje için iki veritabanı kullanmam gerekiyor: varsayılan ve uzak . Ben yarattım routers.pyve her şey iyi çalışıyor.

Uzak veritabanında tablo oluşturma gereksinimi vardı ve taşıma oluşturdum, çalıştırdım ve tablo django_migrationsoluşturuldum. django_migrationsVarsayılan veritabanında yalnızca bir tablo olmasını istiyorum .

İlgili kısmı routers.pyburada:

class MyRouter(object):
     # ...
     def allow_migrate(self, db, app_label, model_name=None, **hints):
         if app_label == 'my_app':
             return db == 'remote'
         return None

Göçü şu şekilde çalıştırıyorum:

python manage.py migrate my_app --database=remote

Şimdi ne zaman:

python manage.py runserver

Aşağıdaki uyarıyı alıyorum:

Uygulanmamış 1 taşıma işleminiz var. Uygulama (lar) için taşıma işlemleri uygulanana kadar projeniz düzgün çalışmayabilir: my_app.
Bunları uygulamak için 'python manage.py migrate' komutunu çalıştırın.

İçin masalar my_appoluşturulan remoteveritabanında, ve django_migrationsiçeride remoteuygulanan veritabanı göçler işaretlenmiştir.

EDIT:
Django sadece bir tablo kullanmaya zorlamak django_migrations, ancak yine de taşıma farklı veritabanlarına uygulamak için?

Hiçbir veritabanında uyarı yapılmaması için taşıma işlemleri farklı veritabanlarında nasıl uygulanır?


1
'my_app' olmayan diğer uygulamalar için allow_migrate, None döndürür. Belki orada başka bir kontrol yapmak istersin? Yönlendiricinizden anladığım kadarıyla, 'my_app' 'uzak' veritabanını kullanır ve diğer tüm uygulamalar 'varsayılan' veritabanını kullanır mı?
Martin Taleski

@cezar Neredeyse imkansız olanı istiyorsun. Paylaşılan sahip olmak için django_migrationstabloyu onun için taşıma işlemlerine satırları arasında ayrım yapmak gerekecektir defaultve remotedb. Bu django içlerinde oldukça derin. Göç kodunun büyük bir şekilde yeniden yazılmasını gerektirdiğini bile söyleyebilirim.
Kamil Niski

@KamilNiski düşüncelerinizi paylaştığınız için teşekkür ederiz. Soruyu yeniden yazacağım.
cezar

Yanıtlar:


2

Sorum üzerine yaptığım yorumlar sayesinde biraz araştırma yaptım ve aşağıdaki bulguları buldum.

Birden çok veritabanının django_migrationskullanılması, taşıma işlemleri kullanıldığında tablo oluşturulmasına neden olur. Kamil Niski'nin açıkladığı django_migrationsgibi, taşıma işlemlerini yalnızca bir tabloya kaydetme seçeneği yoktur . Bu, dosyayı okuduktan sonra açıktır .django/db/migrations/recorder.py

Bir proje foove proje bariçindeki bir uygulama ile bir örnek göstereceğim . Uygulamanın barsadece bir modeli vardır Baz.

Projeyi yaratıyoruz:

django-admin startproject foo

Şimdi bu içerikler ana proje dizininde:

- foo
- manage.py

Proje dizinindeki tüm uygulamaları gruplandırma alışkanlığım var:

mkdir foo/bar
python manage.py bar foo/bar

Dosyada foo/settings.py, ayarları iki farklı veritabanı kullanacak şekilde ayarlıyoruz, bu örneğin amaçları için kullanıyoruz sqlite3:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db1.sqlite3'),
    },
    'remote': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db2.sqlite3'),
    }
}

Şimdi taşıma işlemini gerçekleştiriyoruz:

python manage.py migrate --database=default

Bu, tüm geçişleri çalıştırır, bölüm --database=defaultisteğe bağlıdır, çünkü belirtilmezse Django varsayılan veritabanını kullanır.

Gerçekleştirilecek işlemler: 
  Tüm taşıma işlemlerini uygulama: yönetici, kimlik doğrulama, içerik türleri, oturumlar
 Taşıma taşıma işlemleri:
  İçerik türleri uygulanıyor.0001_initial ... Tamam
  Auth.0001_initial uygulanıyor ... Tamam
  Admin.0001_initial uygulanıyor ... TAMAM
  Admin.0002_logentry_remove_auto_add uygulanıyor ... TAMAM
  Admin.0003_logentry_add_action_flag_choices uygulanıyor ... TAMAM
  İçerik türleri uygulanıyor.0002_remove_content_type_name ... Tamam
  Auth.0002_alter_permission_name_max_length uygulanıyor ... TAMAM
  Auth.0003_alter_user_email_max_length uygulanıyor ... TAMAM
  Auth.0004_alter_user_username_opts uygulanıyor ... TAMAM
  Auth.0005_alter_user_last_login_null uygulanıyor ... Tamam
  Auth.0006_require_contenttypes_0002 uygulanıyor ... Tamam
  Auth.0007_alter_validators_add_error_messages uygulanıyor ... Tamam
  Auth.0008_alter_user_username_max_length uygulanıyor ... TAMAM
  Auth.0009_alter_user_last_name_max_length uygulanıyor ... TAMAM
  Auth.0010_alter_group_name_max_length uygulanıyor ... TAMAM
  Auth.0011_update_proxy_permissions uygulanıyor ... Tamam
  Oturumlar uygulanıyor.0001_initial ... Tamam

Django tüm geçişleri varsayılan veritabanına uyguladı:

1 içerik türü 0001_initial 2019-11-13 16: 51: 04.767382
2 kimlik doğrulaması 0001_initial 2019-11-13 16: 51: 04.792245
3 admin 0001_initial 2019-11-13 16: 51: 04.827454
4 admin 0002_logentr 2019-11-13 16: 51: 04.846627
5 admin 0003_logentr 2019-11-13 16: 51: 04.864458
6 içerik türü 0002_remove_ 2019-11-13 16: 51: 04.892220
7 kimlik doğrulaması 0002_alter_p 2019-11-13 16: 51: 04.906449
8 kimlik doğrulaması 0003_alter_u 2019-11-13 16: 51: 04.923902
9 auth 0004_alter_u 2019-11-13 16: 51: 04.941707
10 auth 0005_alter_u 2019-11-13 16: 51: 04.958371
11 auth 0006_require 2019-11-13 16: 51: 04.965527
12 auth 0007_alter_v 2019-11-13 16: 51: 04.981532
13 auth 0008_alter_u 2019-11-13 16: 51: 05.004149
14 auth 0009_alter_u 2019-11-13 16: 51: 05.019705
15 auth 0010_alter_g 2019-11-13 16: 51: 05.037023
16 kimlik doğrulaması 0011_update_ 2019-11-13 16: 51: 05.054449
17 oturum 0001_başlangıç ​​2019-11-13 16: 51: 05.063868

Şimdi modeli oluşturuyoruz Baz:

models.py:

from django.db import models

class Baz(models.Model):
    name = models.CharField(max_length=255, unique=True)

Uygulamayı ( ) bariçine kaydedin ve temalar oluşturun:INSTALLED_APPSfoo/settings.py

python manage.py makemigrations bar

Uygulamanın routers.pyiçinde oluşturduğumuz taşıma işlemlerini çalıştırmadan önce bar:

sınıf BarRouter (nesne):
    def db_for_read (benlik, model, ** ipuçları):
        model._meta.app_label == 'bar' ise:
            'uzaktan' döndür
        dönüş Yok

    def db_for_write (benlik, model, ** ipuçları):
        model._meta.app_label == 'bar' ise:
            'uzaktan' döndür
        dönüş Yok

    def allow_relation (self, obj1, obj2, ** ipuçları):
        dönüş Yok

    def allow_migrate (self, db, app_label, model_name = None, ** ipuçları):
        app_label == 'bar' ise:
            return db == 'uzak'
        db == 'uzak' ise:
            Yanlış döndür
        dönüş Yok

ve kaydedin foo/settings.py:

DATABASE_ROUTERS = ['foo.bar.routers.BarRouter']

Şimdi saf yaklaşım bar, remoteveritabanına geçişleri çalıştırmak olacaktır :

python manage.py migrate bar --database=remote
Gerçekleştirilecek işlemler: 
  Tüm taşıma işlemlerini uygula: bar
 Çalışan taşıma işlemlerini gerçekleştirme:
  Bar.0001_initial uygulanıyor ... Tamam

Taşımalar remoteveritabanına uygulandı :

1 çubuk 0001_initial 2019-11-13 17: 32: 39.701784

Koştuğumuzda:

python manage.py runserver

aşağıdaki uyarı verilecektir:

Uygulanmamış 1 taşıma işleminiz var. Uygulama (lar): çubuğu taşımalarını uygulayana kadar projeniz düzgün çalışmayabilir.
Bunları uygulamak için 'python manage.py migrate' komutunu çalıştırın.

Her şey olsa iyi çalışıyor gibi görünüyor. Ancak bu uyarıyı almak tatmin edici değil.

Doğru yanıt , bu yanıtta önerildiği gibi her veritabanı için tüm geçişleri çalıştırmak olacaktır .

Şöyle görünecektir:

python manage.py migrate --database=default
python manage.py migrate --database=remote

ve aşağıdakiler için taşıma işlemleri oluşturduktan sonra bar:

python manage.py migrate bar --database=default
python manage.py migrate bar --database=remote

Yönlendirici, tablonun bar_bazyalnızca remoteveritabanında oluşturulmasına özen gösterir , ancak Django taşıma işlemlerini her iki veritabanında da uygulanmış olarak işaretler. İçin de masalar auth, admin, sessionsvb sadece oluşturulacak defaultbelirtildiği gibi, veritabanı routers.py. Tablo django_migrationsiçinde remoteveritabanı bunları da göçler için kayıtları olacaktır.

Uzun bir okuma, ama umarım bence, resmi belgelerde tam olarak açıklanmayan bir konuya ışık tutuyor .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.