2014-07-08 3 views
4

При разработке веб-сайта для документирования системной документации я столкнулся с жестким орехом, чтобы взломать «сопоставление» данных и отношения между базами данных в Django.«Соответствие»/отношения данных по базам данных в Django

Упрощенная модель для моей локальной базы данных:

from django.db import models 

class Document(models.Model): 
    name = models.CharField(max_length=200) 
    system_id = models.IntegerField() 
    ... 

Воображаемая модель, детали системы хранятся в удаленной базе данных.

from django.db import models    

class System(models.Model):  
    name = models.CharField(max_length=200)   
    system_id = models.IntegerField()  
    ... 

Идея заключается в том, что при создании новой записи документа на моем сайте идентификатор соответствующей системы будет храниться в локальной базе данных. При представлении данных мне пришлось бы использовать сохраненный идентификатор, чтобы получить имя системы среди других деталей из удаленной базы данных.

Я просмотрел foreign keys across databases, но это кажется очень обширным, и я не уверен, хочу ли я отношений. Скорее я визуализую функцию внутри модели/класса Document, которая способна извлекать соответствующие данные, например, путем импорта настраиваемого маршрутизатора/функции.

Как я могу решить это?


Обратите внимание, что я ничего не могу изменить в удаленной базе данных, и он доступен только для чтения. Не уверен, что я должен создать модель для Системы. Обе базы данных используют PostgreSQL, однако мое впечатление заключается в том, что на самом деле это не имеет отношения к этому сценарию, какая база данных используется.

ответ

4

В Джанго документации multi-db (manually-selecting-a-database)

# This will run on the 'default' database. 
Author.objects.all() 

# So will this. 
Author.objects.using('default').all() 

# This will run on the 'other' database. 
Author.objects.using('other').all() 

The 'default' and 'other' are aliases for you databases. 
In your case it would could be 'default' and 'remote'. 

, конечно, вы могли бы заменить .all() все, что вы хотите.

Example: System.objects.using('remote').get(id=123456) 
1

Я бы выбрал метод get_system(). Таким образом:

class Document: 
    def get_system(self): 
     return System.objects.using('remote').get(system_id=self.system_id) 

Это простейшее решение. Возможным решением также является использование функции PostgreSQL для внешних данных. Используя FDW, вы можете абстрагировать обработку multidb из django и делать это внутри базы данных - теперь вы можете использовать запросы, которые должны использовать системное отношение document ->.

И, наконец, если ваш прецедент позволяет, простое копирование системных данных периодически на локальный db может быть хорошим решением.

1

Вы правы, что внешние ключи в базах данных являются проблемой в Django ORM, а в некоторой степени и на уровне db.

У вас уже есть ответ в основном: «Я представляю себе функции внутри модели Document/класс, который способен получать данные соответствия»

Я бы сделать это так:

class RemoteObject(object): 
    def __init__(self, remote_model, remote_db, field_name): 
     # assumes remote db is defined in Django settings and has an 
     # associated Django model definition: 
     self.remote_model = remote_model 
     self.remote_db = remote_db 
     # name of id field on model (real db field): 
     self.field_name = field_name 
     # we will cache the retrieved remote model on the instance 
     # the same way that Django does with foreign key fields: 
     self.cache_name = '_{}_cache'.format(field_name) 

    def __get__(self, instance, cls): 
     try: 
      rel_obj = getattr(instance, self.cache_name) 
     except AttributeError: 
      system_id = getattr(instance, self.field_name) 
      remote_qs = self.remote_model.objects.using(self.remote_db) 
      try: 
       rel_obj = remote_qs.get(id=system_id) 
      except self.remote_model.DoesNotExist: 
       rel_obj = None 
      setattr(instance, self.cache_name, rel_obj) 
     if rel_obj is None: 
      raise self.related.model.DoesNotExist 
     else: 
      return rel_obj 

    def __set__(self, instance, value): 
     setattr(instance, self.field_name, value.id) 
     setattr(instance, self.cache_name, value) 


class Document(models.Model: 
    name = models.CharField(max_length=200) 
    system_id = models.IntegerField() 
    system = RemoteObject(System, 'system_db_name', 'system_id') 

Вы можете признать, что RemoteObject класс выше реализует протокол дескриптора Питона, смотрите здесь для получения дополнительной информации:
https://docs.python.org/2/howto/descriptor.html

Использование 210

Пример:

>>> doc = Document.objects.get(pk=1) 
>>> print doc.system_id 
3 
>>> print doc.system.id 
3 
>>> print doc.system.name 
'my system' 
>>> other_system = System.objects.using('system_db_name').get(pk=5) 
>>> doc.system = other_system 
>>> print doc.system_id 
5 

Двигаясь дальше вы могли бы написать собственный дб маршрутизатор:
https://docs.djangoproject.com/en/dev/topics/db/multi-db/#using-routers

Это позволит вам устранить using('system_db_name') вызовы в коде маршрутизации все читает для System модели к соответствующему дб.

Смежные вопросы