django查询数据库 如何在django中使用多个数据库
大家好,django查询数据库相信很多的网友都不是很明白,包括如何在django中使用多个数据库也是一样,不过没有关系,接下来就来为大家分享关于django查询数据库和如何在django中使用多个数据库的一些知识点,大家可以关注收藏,免得下次来找不到哦,下面我们开始吧!
如何在django中使用多个数据库
使用多个数据库
New in Django 1.2: Please, see the release notes
大多数其他文档都假设使用单一数据库,本文主要讨论如何在 Django中使用多个数据库。使用多个数据库,要增加一些步骤。
定义你的数据库
使用多数据库的第一步是通过 DATABASES设置要使用的数据库服务。这个设置用于映射数据库别名和特定的联结设置字典,这是 Django定义数据库一贯的手法。字典内部的设置参见 DATABASES文档。
数据库可以使用任何别名,但是 default有特殊意义。当没有选择其他数据库时, Django总是使用别名为 default的数据库。因此,如果你没有定义一个名为 default的数据库时,你应当小心了,在使用数据库前要指定你想用的数据库。
以下是一个定义两个数据库的 settings.py代码片断。定义了一个缺省的 PostgreSQL数据库和一个名为 users的 MySQL数据库:
DATABASES={'default':{'NAME':'app_data','ENGINE':'django.db.backends.postgresql_psycopg2','USER':'postgres_user','PASSWORD':'s3krit'},'users':{'NAME':'user_data','ENGINE':'django.db.backends.mysql','USER':'mysql_user','PASSWORD':'priv4te'}}
如果你尝试访问 DATABASES设置中没有定义的数据库, Django会抛出一个 django.db.utils.ConnectionDoesNotExist异常。
同步你的数据库
syncdb管理命令一次只操作一个数据库。缺省情况下,它操作 default数据库。但是加上--database参数,你可以让 syncdb同步不同的数据库。所以要同步我们例子中的所有数据库的所有模型可以使用如下命令:
$./manage.py syncdb
$./manage.py syncdb--database=users
如果你不是同步所有的程序到同一个数据库中,你可定义一个数据库路由来为指定的模型实施特定的控制策略。
如果你要精细地控制同步,那么还有一种方式是修改 sqlall的输出,手工在数据库中执行命令,命令如下:
$./manage.py sqlall sales|./manage.py dbshell
使用其他管理命令
其他操作数据库的 django-admin.py命令与 syncdb类似,他们一次只操作一个数据库,使用--database来控制使用哪个数据库。
自动数据库路由
使用多数据库最简单的方法是设置一个数据库路由方案。缺省的路由方案确保对象“紧贴”其原本的数据库(例如:一个对象从哪个数据库取得,就保存回哪个数据库)。缺省的路由方案还确保如果一个数据库没有指定,所有的查询都会作用于缺省数据库。
你不必为启动缺省路由方案作任何事,因为它是“开箱即用”的。但是,如果你要执行一些更有趣的数据库分配行为的话,你可以定义并安装你自己的数据库路由。
数据库路由
一个数据库路由是一个类,这个类最多有四个方法:
db_for_read(model,**hints)
建议 model对象写操作时使用的数据库。
如果一个数据库操作可以提供对选择数据库有用的附加信息,那么可以通过 hints字典提供。详见下文。
如果没有建议则返回 None。
db_for_write(model,**hints)
建议 model对象读操作时使用的数据库。
如果一个数据库操作可以提供对选择数据库有用的附加信息,那么可以通过 hints字典提供。详见下文。
如果没有建议则返回 None。
allow_relation(obj1, obj2,**hints)
当 obj1和 obj2之间允许有关系时返回 True,不允许时返回 False,或者没有意见时返回 None。这是一个纯粹的验证操作,用于外键和多对多操作中,两个对象的关系是否被允许。
allow_syncdb(db, model)
决定 model是否可以和 db为别名的数据库同步。如果可以返回 True,如果不可以返回 False,或者没有意见时返回 None。这个方法用于决定一个给定数据库的模型是否可用。
一个路由不必提供所有这些方法,可以省略其中一个或多个。如果其中一个方法被省略了,那么 Django会在执行相关检查时跳过相应路由。
提示参数
数据库路由接收的“提示”参数可用于决定哪个数据库应当接收一个给定的请求。
目前,唯一可以提供的提示参数是实例,即一个与读写操作相关的对象的实例。可以是一个已保存的对象的实例,也可以是一个多对多关系中添加的实例。在某些情况下,也可能没有对象的实例可以提供。路由会检查提示实例是否存在,并相应地决定是否改变路由行为。
使用路由
数据库路由使用 DATABASE_ROUTERS设置来安装。这个设置定义一个类名称列表,每个类定义一个用于主路由(django.db.router)的路由。
主路由用于 Django分配数据库操作。当一个查询想要知道使用哪个数据库时,会提供一个模型和一个提示(如果有的话),并调用主路由。
Django就会按次序尝试每个路由,
直到找到合适的路由建议。如果找不到路由建议就会尝试实例提示的当前的 _state.db。如果没有提供路由提示,或者实例没有当前数据库状态,那么
主路由会分配缺省数据库。
一个例子
仅用于示例目的!
这个例子仅用于展示路由如何改变数据库的使用。本例有意忽略了一些复杂的东西以便于更好的展示路由是如何工作的。
如果任何一个 myapp中的模型包含与另一个数据库中模型的关系时,本例是无效的。参见跨数据库关系一节中介绍的 Django引用完整性问题。
本例的主/从配置也是有缺陷的:它没有处理复制延时(比如因为把写操作传递给从数据库耗费时间而产生的查询不一致),也没有考虑与数据库使用策略的交互作用。
那么,这个例子有什么用呢?本例仅用于演示一个 myapp存在于 other数据库,所有其他模型之间是主/从关系,且存在于 master、 slave1和 slave2数据库。本例使用了两个路由:
class MyAppRouter(object):"""一个控制 myapp应用中模型的所有数据库操作的路由""" def db_for_read(self, model,**hints):"myapp应用中模型的操作指向'other'" if model._meta.app_label=='myapp': return'other' return None def db_for_write(self, model,**hints):"myapp应用中模型的操作指向'other'" if model._meta.app_label=='myapp': return'other' return None def allow_relation(self, obj1, obj2,**hints):"如果包含 myapp应用中的模型则允许所有关系" if obj1._meta.app_label=='myapp' or obj2._meta.app_label=='myapp': return True return None def allow_syncdb(self, db, model):"确保 myapp应用只存在于'other'数据库" if db=='other': return model._meta.app_label=='myapp' elif model._meta.app_label=='myapp': return False return None class MasterSlaveRouter(object):"""一个设置简单主/从定义的路由""" def db_for_read(self, model,**hints):"所有读操作指向一个随机的从数据库" return random.choice(['slave1','slave2']) def db_for_write(self, model,**hints):"所有写操作指向主数据库" return'master' def allow_relation(self, obj1, obj2,**hints):"允许数据库池中的两个对象间的任何关系" db_list=('master','slave1','slave2') if obj1._state.db in db_list and obj2._state.db in db_list: return True return None def allow_syncdb(self, db, model):"显示地放置所有数据库中的模型" return True
然后在你的设置文件增加如下内容(把 path.to.替换为你定义路由的模型的路径):
DATABASE_ROUTERS= ['path.to.MyAppRouter','path.to.MasterSlaveRouter']
这个设置中,路由的顺序是很重要的,因为查询时是按这个设置中的顺序依次查询的。上例中, MyAppRouter先于MasterSlaveRouter,因此, myapp中的模型就优先于其他模型。如果 DATABASE_ROUTERS设置中两个路由的顺序变换了,那么 MasterSlaveRouter.allow_syncdb()会优先执行。因为 MasterSlaveRouter是包罗万象的,这样就会导致所有模型可以使用所有数据库。
设置好之后让我们来运行一些代码:
>>>#从'credentials'数据库获得数据>>> fred= User.objects.get(username='fred')>>> fred.first_name='Frederick'>>>#保存到'credentials'数据库>>> fred.save()>>>#随机从从数据库获得数据>>> dna= Person.objects.get(name='Douglas Adams')>>>#新对象创建时还没有分配数据库>>> mh= Book(title='Mostly Harmless')>>>#这个赋值会向路由发出请求,并把 mh的数据库设置为与 author对象同样的>>>#数据库>>> mh.author= dna>>>#这会强制'mh'实例使用主数据库...>>> mh.save()>>>#...但如果我们重新获取对象,就会从从数据库中获取>>> mh= Book.objects.get(title='Mostly Harmless')
手动选择数据库
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
在 Django管理接口中使用多数据库
Django的管理接口没有明显支持多数据库。如果想要支持的话你必须写自定义 ModelAdmin。
如果要支持多数据库,那么 ModelAdmin对象有五个方法要自定义:
class MultiDBModelAdmin(admin.ModelAdmin):#为方便起见定义一个数据库名称常量。 using='other' def save_model(self, request, obj, form, change):#让 Django保存对象到'other'数据库。 obj.save(using=self.using) def delete_model(self, request, obj):#让 Django从'other'数据库中删除对象。 obj.delete(using=self.using) def queryset(self, request):#让 Django在'other'数据库中搜索对象。 return super(MultiDBModelAdmin, self).queryset(request).using(self.using) def formfield_for_foreignkey(self, db_field, request=None,**kwargs):#让 Django基于'other'数据库生成外键控件。 return super(MultiDBModelAdmin, self).formfield_for_foreignkey(db_field, request=request, using=self.using,**kwargs) def formfield_for_manytomany(self, db_field, request=None,**kwargs):#让 Django基于'other'数据库生成多对多关系控件。 return super(MultiDBModelAdmin, self).formfield_for_manytomany(db_field, request=request, using=self.using,**kwargs)
python + django 多表联合查询方法求教
先让我们回忆一下在第五章里的关于书本(book)的数据模型:1fromdjango.dbimportmodelsclassPublisher(models.Model):name=models.CharField(max_length=30)address=models.CharField(max_length=50)city=models.CharField(max_length=60)state_province=models.CharField(max_length=30)country=models.CharField(max_length=50)website=models.URLField()def__unicode__(self):returnself.nameclassAuthor(models.Model):first_name=models.CharField(max_length=30)last_name=models.CharField(max_length=40)email=models.EmailField()def__unicode__(self):returnu'%s%s'%(self.first_name,self.last_name)classBook(models.Model):title=models.CharField(max_length=100)authors=models.ManyToManyField(Author)publisher=models.ForeignKey(Publisher)publication_date=models.DateField()def__unicode__(self):returnself.title如我们在第5章的讲解,获取数据库对象的特定字段的值只需直接使用属性。例如,要确定ID为50的书本的标题,我们这样做:>>>frommysite.books.modelsimportBook>>>b=Book.objects.get(id=50)>>>b.titleu'TheDjangoBook'但是,在之前有一件我们没提及到的是表现为ForeignKey或ManyToManyField的关联对象字段,它们的作用稍有不同。访问外键(ForeignKey)值当你获取一个ForeignKey字段时,你会得到相关的数据模型对象。例如:>>>b=Book.objects.get(id=50)>>>b.publisher>>>b.publisher.websiteu'http://www.apress.com/'对于用``ForeignKey``来定义的关系来说,在关系的另一端也能反向的追溯回来,只不过由于不对称性的关系而稍有不同。通过一个``publisher``对象,直接获取books,用publisher.book_set.all(),如下:>>>p=Publisher.objects.get(name='ApressPublishing')>>>p.book_set.all()[,,]实际上,book_set只是一个QuerySet(参考第5章的介绍),所以它可以像QuerySet一样,能实现数据过滤和分切,例如:1>>>p=Publisher.objects.get(name='ApressPublishing')>>>p.book_set.filter(name__icontains='django')[,]属性名称book_set是由模型名称的小写(如book)加_set组成的。访问多对多值(Many-to-ManyValues)多对多和外键工作方式相同,只不过我们处理的是QuerySet而不是模型实例。例如,这里是如何查看书籍的作者:>>>b=Book.objects.get(id=50)>>>b.authors.all()[,]>>>b.authors.filter(first_name='Adrian')[]>>>b.authors.filter(first_name='Adam')[]反向查询也可以。要查看一个作者的所有书籍,使用author.book_set,就如这样:>>>a=Author.objects.get(first_name='Adrian',last_name='Holovaty')>>>a.book_set.all()[,]这里,就像使用ForeignKey字段一样,属性名book_set是在数据模型(model)名后追加_set。更改数据库模式(DatabaseSchema)3在我们在第5章介绍syncdb这个命令时,我们注意到syncdb仅仅创建数据库里还没有的表,它并不对你数据模型的修改进行同步,也不处理数据模型的删除。如果你新增或修改数据模型里的字段,或是删除了一个数据模型,你需要手动在数据库里进行相应的修改。这段将解释了具体怎么做:当处理模型修改的时候,将Django的数据库层的工作流程铭记于心是很重要的。如果模型包含一个未曾在数据库里建立的字段,Django会报出错信息。当你第一次用Django的数据库API请求表中不存在的字段时会导致错误(就是说,它会在运行时出错,而不是编译时)。3Django不关心数据库表中是否存在未在模型中定义的列。Django不关心数据库中是否存在未被模型表示的表格。1改变模型的模式架构意味着需要按照顺序更改Python代码和数据库。添加字段1当要向一个产品设置表(或者说是model)添加一个字段的时候,要使用的技巧是利用Django不关心表里是否包含model里所没有的列的特性。策略就是现在数据库里加入字段,然后同步Django的模型以包含新字段。3然而这里有一个鸡生蛋蛋生鸡的问题,由于要想了解新增列的SQL语句,你需要使用Django的manage.pysqlall命令进行查看,而这又需要字段已经在模型里存在了。(注意:你并不是非得使用与Django相同的SQL语句创建新的字段,但是这样做确实是一个好主意,它能让一切都保持同步。)3这个鸡-蛋的问题的解决方法是在开发者环境里而不是发布环境里实现这个变化。(你正使用的是测试/开发环境,对吧?)下面是具体的实施步骤。首先,进入开发环境(也就是说,不是在发布环境里):在你的模型里添加字段。运行manage.pysqlall[yourapp]来测试模型新的CREATETABLE语句。注意为新字段的列定义。开启你的数据库的交互命令界面(比如,psql或mysql,或者可以使用manage.pydbshell)。执行ALTERTABLE语句来添加新列。使用Python的manage.pyshell,通过导入模型和选中表单(例如,MyModel.objects.all()[:5])来验证新的字段是否被正确的添加,如果一切顺利,所有的语句都不会报错。3然后在你的产品服务器上再实施一遍这些步骤。启动数据库的交互界面。5执行在开发环境步骤中,第三步的ALTERTABLE语句。将新的字段加入到模型中。如果你使用了某种版本控制工具,并且在第一步中,已经提交了你在开发环境上的修改,现在,可以在生产环境中更新你的代码了(例如,如果你使用Subversion,执行svnupdate。重新启动Webserver,使修改生效。让我们实践下,比如添加一个num_pages字段到第五章中Book模型。首先,我们会把开发环境中的模型改成如下形式:classBook(models.Model):title=models.CharField(max_length=100)authors=models.ManyToManyField(Author)publisher=models.ForeignKey(Publisher)publication_date=models.DateField()**num_pages=models.IntegerField(blank=True,null=True)**def__unicode__(self):returnself.title
Django里面怎么实现数据库视图啊 就是虚拟表
正经回答:先在数据库中建立好视图,然后django中建立对应的model。表所对应的类下面再建立一个Meta类,大致如下
classViewModel(models.Model):
"""这个model类对应你所建立好的视图"""
classMeta(object):
"""同理,该方法可用于使用mysql中任何已有的表,不仅是视图"""
db_table='your_view'#显式指定表名,也就是你建立的视图的名字
managed=false#默认是ture,设成falsedjango将不会执行建表和删表操作
#建立字段间的映射
#需要注意的是,必须设一个字段为主键
#不然django会自动创建一个id字段为主键,引发错误
百度知道越来越辣鸡了,全是答非所问的。
文章到此结束,如果本次分享的django查询数据库和如何在django中使用多个数据库的问题解决了您的问题,那么我们由衷的感到高兴!