2014-07-08 100 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()  
    ... 

這個想法是,當我在我的網站上創建一個新的Document條目時,相關係統的ID將被存儲在本地數據庫中。在呈現數據時,我將不得不使用存儲的ID從遠程數據庫中檢索系統名稱和其他詳細信息。

我已看過foreign keys across databases,但這似乎是非常廣泛的,我不確定是否需要關係。相反,我在Document model/class內部可視化一個能夠檢索匹配數據的函數,例如通過導入自定義路由器/函數。

我該如何解決這個問題?


請注意,我將無法更改遠程數據庫上的任何內容,並且它是隻讀的。不知道我是否應該爲系統創建一個模型。這兩個數據庫都使用PostgreSQL,但我的印象是,這與使用哪個數據庫的場景並不相關。

回答

4

在Django文檔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'. 

當然,你可以更換。所有()與任何你想要的。

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,您可以從django中抽象出multidb處理並在數據庫中執行 - 現在您可以使用需要使用文檔 - >系統關係的查詢。最後,如果你的用例允許的話,只要將系統數據定期複製到本地數據庫就可以是一個很好的解決方案。

1

你是正確的,跨數據庫的外鍵是Django ORM中的問題,在某種程度上也是在db級別。

您已經有了基本答案:「我想象的文檔模型內的函數/類,這是能夠檢索匹配的數據」

我會做這樣的:

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類實現Python的描述符的協議,在這裏看到更多的信息:
https://docs.python.org/2/howto/descriptor.html

用法示例:

>>> 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模型到適當的D b。