Django обмен данными - PullRequest
       2

Django обмен данными

5 голосов
/ 19 декабря 2010

Я успешно запустил свое приложение на нескольких базах данных, используя схему маршрутизации, основанную на моделях.Т.е. модель A живет в БД A, а модель B - в БД B. Теперь мне нужно защитить свои данные.Я смотрю на документы и не могу понять, как это сделать, поскольку одна и та же модель должна существовать на нескольких серверах баз данных.Я хочу иметь флаг, чтобы сказать, что DB для НОВЫХ участников теперь является базой данных X, и что члены XY живут в базе данных N и т. Д.

Как мне это сделать?Использует ли он ** подсказки, мне кажется, это недостаточно документировано.

Ответы [ 2 ]

6 голосов
/ 02 августа 2012

Параметр hints разработан, чтобы помочь вашему маршрутизатору базы данных решить, куда он должен читать или записывать свои данные. Он может развиваться с будущими версиями python, но на данный момент есть только один вид подсказки, который может дать инфраструктура Django, и это instance, над которой он работает.

Я написал этот очень простой маршрутизатор базы данных, чтобы увидеть, что делает Django:

# routers.py
import logging
logger = logging.getLogger("my_project")

class DebugRouter(object):
    """A debugging router"""

    def db_for_read(self, model, **hints):
        logger.debug("db_for_read %s" % repr((model, hints)))
        return None

    def db_for_write(self, model, **hints):
        logger.debug("db_for_write %s" % repr((model, hints)))
        return None

    def allow_relation(self, obj1, obj2, **hints):
        logger.debug("allow_relation %s" % repr((obj1, obj2, hints)))
        return None

    def allow_syncdb(self, db, model):
        logger.debug("allow_syncdb %s" % repr((db, model)))
        return None

Вы заявляете это в settings.py:

DATABASE_ROUTERS = ["my_project.routers.DebugRouter"]

Убедитесь, что протоколирование правильно сконфигурировано для вывода отладочной информации (например, в stderr):

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        [...some other handlers...] 
        'stderr': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler'
        }
    },
    'loggers': {
        [...some other loggers...]
        'my_project': {
            'handlers': ['stderr'],
            'level': 'DEBUG',
            'propagate': True,
        },
    }
}

Затем вы можете открыть оболочку Django и протестировать несколько запросов, чтобы увидеть, какие данные получает ваш маршрутизатор:

$ ./manage.py shell
[...]
>>> from my_project.my_app.models import User
>>> User.objects.get(pk = 1234)
db_for_read (<class 'my_project.my_app.models.User'>, {})
<User: User object>
>>> user = User.objects.create(name = "Arthur", title = "King")
db_for_write (<class 'my_project.my_app.models.User'>, {})
>>> user.name = "Kong"
>>> user.save()
db_for_write (<class 'my_project.my_app.models.User'>, {'instance':
              <User: User object>})
>>>

Как видите, hints всегда пуст, когда еще нет экземпляра (в памяти). Таким образом, вы не можете использовать маршрутизаторы, если вам нужны параметры запроса (например, идентификатор объекта), чтобы определить, какую базу данных запрашивать. Это может произойти в будущем, если Django предоставит объекты запроса или набора запросов в hints dict.

Итак, чтобы ответить на ваш вопрос, я бы сказал, что сейчас вы должны создать собственного менеджера, как это предложил Аарон Мерриам. Но переопределения только метода create недостаточно, поскольку вам также необходимо иметь возможность извлекать объект в соответствующей базе данных. Примерно так может работать (пока не тестировалось):

class CustomManager(models.Manager)
    def self.find_database_alias(self, pk):
        return #... implement the logic to determine the shard from the pk

    def self.new_object_database_alias(self):
        return #... database alias for a new object

    def get(self, *args, **kargs):
        pk = kargs.get("pk")
        if pk is None:
            raise Exception("Sharded table: you must provide the primary key")
        db_alias = self.find_database_alias(pk)
        qs = self.get_query_set().using(db_alias)
        return qs.get(*args, **kargs)

    def create(self, *args, **kwargs):
        db_alias = self.new_object_database_alias()
        qs = super(CustomManager, self).using(db_alias)
        return qs.create(*args, **kwargs)

class ModelA(models.Model):
    objects = CustomManager()

Приветствия

2 голосов
/ 19 мая 2011

с использованием позволит вам указать, какую базу данных вы хотите использовать.

создание подкласса метода create может выполнить то, что вы хотите.

class CustomManager(models.Manager)
    def get_query_set(self):
        return super(CustomManager, self).get_query_set()

    def create(self, *args, **kwargs):
        return super(CustomManager, self).using('OTHER_DB').create(*args, **kwargs)

class ModelA(models.Model):
    objects = CustomManager()

Я не проверял это, поэтому я не знаю, можете ли вы прикрепить 'create' к концу 'using'

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...