手动选择数据库

Django 也提供一个可以让你通过代码完全控制数据库使用的 API 。手动定义数据库分配 优先于路由。



为一个 查询集 手动选择一个数据库

你可以在 查询集 “链”中的任何点为 查询集 选择数据库。我们通过在 查询集 上调用 using() 来得到使用指定数据库的另一个 查询集 。

using() 使用一个参数:你想要运行查询的数据库的别名。例如:



>>> # 这会运行在“缺省”数据库上。 >>> Author.objects.all() >>> # 这同样会运行在“缺省”数据库上。
>>> Author.objects.using('default').all() >>> # 这会运行在“ other ”数据库上。 >>> Author.objects.using('other').all()



为 save() 选择一个数据库

在使用 Model.save() 时加上 using 关键字可以指定保存到哪个数据库。

例如,要把一个对象保存到 legacy_users 数据库应该这样做:



>>> my_object.save(using='legacy_users')



如果你不定义 using ,那么 save() 方法会根据路由分配把数据保存到缺省 数据库中。



把一个对象从一个数据库移动到另一个数据库

当你已经在一个数据库中保存了一个对象后,你可能会使用 save(using=...) 把这个 对象移动到另一个数据库中。但是,如果你没有使用恰当的方法,那么可能会出现意想不 到的后果。

假设有如下的例子:



>>> p = Person(name='Fred') >>> p.save(using='first') # (第一句) >>> p.save(using='second') # (第二名)



在第一名中,一个新的 Person 对象被保存到 first 数据库中。这时, p 还没有一个主键,因此 Django 执行了一个INSERT SQL 语句。这样就会创建一个 主键,并将这个主键分配给 p 。

在第二句中,因为 p 已经有了一个主键,所以 Django 在保存对象时会尝试在新的 数据库中使用这个主键。如果 second数据库中没有使用这个主键,那就不会有问题, 该对象会复制到新数据库。

然而,如果 p 的主键在 second 数据库中已经使用过了,那么 second 使用 这个主键的已存在的对象将会被 p 覆盖。

有两种方法可以避免上述情况的发生。第一,你可以清除实例的主键。如果一个对象没有 主主键,那么 Django 会把它看作一个新对象,在保存到 second 数据库中时就不会 带来数据的损失:



>>> p = Person(name='Fred') >>> p.save(using='first') >>> p.pk = None # 清除主键。 >>> p.save(using='second') # 写入一个全新的对象。


第二种方法是在 save() 方法中使用 force_insert 选项来保证 Django 执行 一个 INSERT SQL:



>>> p = Person(name='Fred') >>> p.save(using='first') >>> p.save(using='second', force_insert=True)



这样可以保证名为 Fred 的人员在两个数据库中使用相同的主键。如果在保存到 second 数据库时主键已被占用,会抛出一个错误。



选择一个要删除数据的数据库

缺省情况下,一个现存对象从哪个数据库得到,删除这个对象也会在这个数据库中进行:


>>> u = User.objects.using('legacy_users').get(username='fred') >>> u.delete() # 会从 `legacy_users` 数据库中删除


通过向 Model.delete() 方法传递 using 关键字参数可以定义在哪个数据库中删除 数据。 using 的用法与 save() 方法中使用这个参数类似。

例如,假设我们要把一个用户从 legacy_users 数据库移动到 new_users 数据库 可以使用如下命令:



>>> user_obj.save(using='new_users') >>> user_obj.delete(using='legacy_users')



多数据库情况下使用管理器

在管理器上使用 db_manager() ,可以让管理器访问一个非缺省数据库。

例如,假设你有一个操作数据库的自定义管理器 User.objects.create_user() 。 因为 create_user() 是一个管理器方法,不是一个 查询集 ,所以你不能用 User.objects.using('new_users').create_user() 。( create_user() 方法 只能用于 User.objects 管理器,而不能用于,管理器衍生出的 查询集 。) 解决方法是使用 db_manager() ,就象下面这样:



User.objects.db_manager('new_users').create_user(...)


db_manager() 返回的是绑定到你指定的数据库的管理器的一个副本。



多数据库情况下使用 get_query_set()

如果你在管理器中重载了 get_query_set() ,请确保在其父类中也调用了相同的方法 (使用 super() )或者正确处理管理器中的 _db 属性(一个包含要使用的数据库 名称的字符串)。

例如,如果你要从 get_query_set 方法返回一个自定义 查询集 类,那么你可以 这样做:



class MyManager(models.Manager): def get_query_set(self): qs = CustomQuerySet(self.model) if self._db is not None: qs = qs.using(self._db) return qs