1

異なるデータベースに外部キーフィールドを持つモデルを作成することは可能ですか?例:

class MultiBDModel(models.Model):
    db1_user = models.ForeignKey(User) # here suppose to be foreign key on `db1`
    db2_user = models.ForeignKey(User) # and here on `db2`

多分何とかユーザーをコピーします。カスタムマネージャーに申し込む。using='db1'で設定されたクエリを返します

settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'db1',                      # Or path to database file if using sqlite3.
        'USER': '',                      # Not used with sqlite3.
        'PASSWORD': '',                  # Not used with sqlite3.
        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    },

    'website': {
        'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'db2',                      # Or path to database file if using sqlite3.
        'USER': '',                      # Not used with sqlite3.
        'PASSWORD': '',                  # Not used with sqlite3.
        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.              # Set to empty string for default. Not used with sqlite3.
    }
}
4

2 に答える 2

2

いいえ。@ignacio-vazquez-abramsによって記述されているように、1つのモデルに同じデータベース内のすべてのフィールドが含まれている必要があります。


しかし

別の方法として、プロキシモデルを使用して、2つの異なるデータベースのモデル間をリンクすることもできます。

標的

1つのモデルは、db1とdb2のフィールドを同時に提供する必要があります

一般的なトリック

  • ContactMessagedb1のモデルがあり、これに名前を付けlegacy_dbます。このモデルは別のプロジェクトからのものであるため、触れたくないと思います。
  • プロキシモデル を作成します。ProxyContactMessageこれは、と同じ属性を持っていますContactMessage
  • データベースルーターを使用してlegacy_db、オブジェクトを探す場所をDjangoに指示しProxyContactMessageます。
  • ExtendedContactMessage追加するフィールドを含む新しいモデルを追加します。で宣言OneToOneFieldProxyContactMessageます。このデータはdb2に保存されますdjango_db
  • プロキシモデルは抽象的であるため、新しいフィールドを保持できませんが、関連するExtendedContactMessageオブジェクト(存在する場合)を要求するメソッドを持つことができます。必要な呼び出し可能オブジェクトを追加します。

では、legacy_app/models.pydb1のモデルlegacy_dbは次のとおりです。

class ContactMessage(models.Model):
    subject = models.CharField(max_length=255)
    message = models.TextField()
    created_at = models.DateTimeField()
    created_by = models.CharField(max_length=255)

    class Meta:
        managed = False
        db_table = 'contact_message'

    def __unicode__(self):
        return self.subject

したがって、で作成しますmyapp/models.py

class ProxyContactMessage(ContactMessage):
    class Meta:
        proxy = True
        verbose_name = 'Contact message'
        verbose_name_plural = 'Contact messages'

    def add_extension(self):
        e = ExtendedContactMessage(contact_message=self)
        e.save()
        return e

    def mark_as_processed(self):
        try:
            e = self.extendedcontactmessage
        except ExtendedContactMessage.DoesNotExist:
            e = self.add_extension()
        e.mark_as_processed()

    def processed(self):
        return self.extendedcontactmessage.processed

    def processed_at(self):
        return self.extendedcontactmessage.processed_at

class ExtendedContactMessage(models.Model):
    contact_message = models.OneToOneField(ProxyContactMessage)
    processed = models.BooleanField(default=False, editable=False)
    processed_at = models.DateTimeField(null=True, default=None, editable=False)

    def mark_as_processed(self):
        self.processed = True
        self.processed_at = timezone.now()
        self.save()

は抽象であるため、非抽象モデルのみExtendedContactMessageがdb2に保存されることに注意してくださいProxyContactMessage

settings.py、クラスを使用してDATABASE_ROUTERSを設定します

class LegacyRouter(object):
    """
    A router to control all database operations on models in the
    legacy database.
    """
    def db_for_read(self, model, **hints):
        if model.__name__ == 'ProxyContactMessage':
            return 'legacy_db'
        return None
    def db_for_write(self, model, **hints):
        """
        Attempts to write in legacy DB for ContactMessage.
        """
        if model.__name__ == 'ProxyContactMessage':
            return 'legacy_db'
        return None

デフォルトルーターはすべてをdb2に送信します。

最後に、次のような管理クラスがあります。

def mark_as_processed(modeladmin, request, queryset):
    for obj in queryset:
        obj.mark_as_processed()
mark_as_processed.short_description = "Mark as processed"

class ProxyContactMessageAdmin(admin.ModelAdmin):
    list_display = (
        'subject',
        'message',
        'created_at',
        'created_by',
        'processed',
        'processed_at',
    )
    actions = (mark_as_processed,)
admin.site.register(ProxyContactMessage, ProxyContactMessageAdmin)

関連している:

プロキシクラスにルーターを使用する

Metaでapp_nameを「ハック」します

クエリセットをキャッチ

于 2017-06-20T16:02:06.883 に答える
1

いいえ。ORMはデータベースエンジンが実行できないことは何もできません。

于 2012-05-22T20:51:31.167 に答える