Djang中跨数据库的“匹配”/关系数据

2024-05-23 20:10:09 发布

您现在位置:Python中文网/ 问答频道 /正文

在开发一个索引系统文档的网站时,我遇到了一个棘手的难题,那就是在Django中跨数据库的数据“匹配”/关系。在

本地数据库的简化模型:

from django.db import models

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

详细信息存储在一个远程数据库中。在

^{pr2}$

我的想法是,当在我的网站上创建一个新的文档条目时,相关系统的ID将存储在本地数据库中。当显示数据时,我必须使用存储的ID从远程数据库中检索系统名称和其他详细信息。在

我已经研究过foreign keys across databases,但这似乎非常广泛,我不确定是否需要关系。相反,我将文档模型/类中的一个函数可视化,该函数能够检索匹配的数据,例如通过导入自定义路由器/函数。在

我该怎么解决这个问题呢?在


请注意,我无法更改远程数据库上的任何内容,而且它是只读的。不确定是否也应该为系统创建一个模型。这两个数据库都使用PostgreSQL,但是我的印象是,它与使用哪个数据库的场景没有实际的关系。在


Tags: 数据django函数文档模型id数据库远程
3条回答

您是正确的,跨数据库的外键在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

用法示例:

^{pr2}$

更进一步,您可以编写一个自定义的db路由器:
https://docs.djangoproject.com/en/dev/topics/db/multi-db/#using-routers

这将允许您通过将System模型的所有读取路由到适当的数据库来消除代码中的using('system_db_name')调用。在

我会使用get_system()方法。所以:

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

这是最简单的解决办法。一个可能的解决方案是使用PostgreSQL的外部数据包装特性。通过使用FDW,您可以从django抽象出multidb处理,并在数据库中执行它—现在您可以使用需要使用document->;system关系的查询。在

最后,如果您的用例允许的话,只需定期将系统数据复制到本地数据库就可以了。在

在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'.

当然,您可以用您想要的任何东西替换.all()。在

^{pr2}$

相关问题 更多 >