Работа со сторонней базой данных в django

Возникла потребность получать информацию из соседнего проекта. В частности авторизовывать пользователей не по собственной базе, а по чужой. Писать отдельный API для этого не хотелось, базы находятся рядом и доступны одному пользователю. Поэтому решено было настроить модели Django поверх уже существующих таблиц. Что нам для этого потребовалось ? А потребовался отдельный роутер для базы данных. Его задача определять на какую базу отправлять запросы для каждого из приложений.

Файл роутера положил в корень проекта и назвал скромно: project_db_router.py

class ProjectDbRouter(object):
    """A router to control all database operations on models in the myapp application"""

    def db_for_read(self, model, **hints):
        """Suggest the database that should be used for read operations for objects of type model."""
        if model._meta.app_label == "specialapp":
            return "second"
        return None

    def db_for_write(self, model, **hints):
        """Suggest the database that should be used for writes of objects of type Model."""
        if model._meta.app_label == "specialapp":
            return "second"
        return None

    def allow_relation(self, obj1, obj2, **hints):
        """Deny any relation if a model in specialapp is involved"""
        if obj1._meta.app_label == "specialapp" or \
                obj2._meta.app_label == "specialapp":
            return False
        return None

    def allow_syncdb(self, db, model):
        """Deny sync db for the specialapp models"""
        if model._meta.app_label == "specialapp":
            return False
        if db == "second":
            return False
        return None

В коде

specialapp - наше специальное приложение, работающее со второй (second) базой.

Для того, чтоб Django воспринял новый роутер в настройках надо прописать:

DATABASE_ROUTERS = ["project_db_router.ProjectDbRouter"]

Далее осталось только определить модели и можно работать с ними как с любыми другими.

from django.db import models

class Owner(models.Model):
    STATUSES = (("Y", "Active"), ("N", "Blocked"), ("DEL", "Deleted"))

    user_id = models.IntegerField(primary_key=True)
    login = models.CharField(max_length=100, unique=True)
    password = models.CharField(max_length=32, db_column="pass")
    status = models.CharField(max_length=3, choices=STATUSES, default="Y")

    class Meta:
        db_table = "users"
        managed = False

Тут главное не забыть указать название таблицы и флаг

managed = False, дабы django не пытался создать эту таблицу при syncdb.

Возможные проблемы:

  • Для таблиц без первичного ключа (primary key) или с ключом на нескольких полях модели не будут работать. Можно в таком случае или создавать ключ, или использовать прямые запросы к базе данных.
  • При использовании второй базы данных могут сыпаться тесты. Даже если они эту базу не используют. Можно обойти добавив в настройки подключения к этой базе опцию “TEST_MIRROR”: “default”. Тем самым указав, что эта база является зеркалом основной и создавать ее каждый раз не надо. Но это только в случае, если она не используется в тестах.
 
comments powered by Disqus