首页
学习
活动
专区
工具
TVP
发布

Django基础:数据库的设计之自定义表名,建立索引和使用多数据库主从配置

在我们前篇教程

Django基础(12): QuerySet特性及高级使用技巧

里我们已经介绍了如何减少数据库的访问,节省内存从而提升网站性能。今天小编我将更近一步,分享下Django中如何设计和优化数据库, 从而实现你想要的功能或提升网站的性能。

通过db_table和db_column自定义数据表名和字段名

假如你的数据库里已经有了一张数据表,且该表包含多个字段,你希望通过Django直接访问该数据表的各个字段而不是重新建立新表,你这时可以通过db_table指定数据表名,还可以通过db_column指定希望访问的字段名。

在我们创建一个模型时,Django的ORM会根据应用名(app name), 模型名(model name)和字段名(field name)自动在数据库中创建数据表。比如我们有一个Blog的应用,里面有Article模型, 其中Article模型有title这个字段,那么Django默认会创建一个名为blog_article的数据表,其中有title这个字段。假如我们希望把表名改为article,标题改为article_title,以便与已经存在的数据表或字段建立映射关系,我们可以按如下代码操作。

classArticle(models.Model):

"""文章模型"""

# 通过db_column自定义数据表中字段名

title = models.CharField('标题',max_length=200,db_column='article_title')

slug = models.SlugField('slug',max_length=60,blank=True)

def__str__(self):

returnself.title

classMeta:

db_table ='article'# 通过db_table自定义数据表名

通过db_index和Meta index选项给数据表字段建立索引

使用索引可快速访问数据库表中的特定信息。数据库索引好比是一本书前面的目录,没有索引目录的话,你访问书中某个页面需要从第1页遍历到最后一页,如果有目录,你可以快速地根据目录查找到所需要的页面。Django项目中如果你需要频繁地对数据表中的某些字段(如title)使用filter(), exclude()和order_by()方法进行查询,我们强烈建议你对这些字段建议索引(index), 提升查询效率。

要对模型中的某个字段建立数据库索引,你可以使用db_index选项,也可以使用Meta选项建立索引。使用Meta选项的好处是你可以一次性对多个字段建立索引,还可以对多个字段建立组合索引。

方法一: 使用db_index选项

classArticle(models.Model):

"""文章模型"""

#使用db_index=True对title建立索引

title = models.CharField('标题',max_length=200,db_index=True)

方法二: 使用Meta选项

classArticle(models.Model):

"""文章模型"""

title = models.CharField('标题',max_length=200,)

classMeta:

indexes = [

models.Index(fields=['title']),

]

Django主从数据库配置

当你刚刚开始建立一个网站时,可能每天只有数十到上百人访问。这时你只有一个数据库,所有APP的数据表也都放一起的,一台普通的服务器能够应付, 也便于维护。但是当访问量上来后,你会发现一台服务器和一个数据库会根本应付不了这个压力。这时你可能希望实现数据库的主从配置,读写分离,把各个数据库放在不同的服务器上,有的专门负责写入,有的专门负责读取,这时你就要学会使用Django同时连接多个数据库,并自定义读写操作。

第一步 修改项目的 settings 配置

在中配置需要连接的多个数据库名称和登录信息。在下例中我们自定义了3个数据库,1个主数据库(primary), 2个从数据库(replica)。

#project/settings.py

DATABASES = {

'default': {},

'primary': {

'NAME':'primary',

'ENGINE':'django.db.backends.mysql',

'HOST':'xxxx',

'PORT':'xxxx',

'USER':'mysql_user',

'PASSWORD':'spam',

},

'replica1': {

'NAME':'replica1',

'ENGINE':'django.db.backends.mysql',

'HOST':'xxxx',

'PORT':'xxxx',

'USER':'mysql_user',

'PASSWORD':'eggs',

},

'replica2': {

'NAME':'replica2',

'ENGINE':'django.db.backends.mysql',

'HOST':'xxxx',

'PORT':'xxxx',

'USER':'mysql_user',

'PASSWORD':'bacon',

},

}

我们还需要在添加我们手动编写的数据库路由Router。路由的作用是为数据库的读写制定规则。

DATABASE_ROUTERS = ['Project.database_router.PrimaryReplicaRouter']

注意: 主从数据库的同步是通过MySQL配置实现的,而不是Django实现的。Django只负责多个数据库的访问,不负责各个数据库的同步工作。如果你定义了多个路由,请一定注意路由的执行顺序。

第二步 自定义数据库路由Router

在Django项目的根目录下创建文件, 添加如下代码,自定义数据库路由。该路由规定了读取数据时将随机从replica1和replica2数据库中读取,而写入数据总是写入主数据库primary。该路由还允许三个数据库中的字段建立联系。

classPrimaryReplicaRouter(object):

defdb_for_read(self,model,**hints):

"""

Reads go to a randomly-chosen replica.

"""

returnrandom.choice(['replica1','replica2'])

defdb_for_write(self,model,**hints):

"""

Writes always go to primary.

"""

return'primary'

defallow_relation(self,obj1,obj2,**hints):

"""

Relations between objects are allowed if both objects are

in the primary/replica pool.

"""

db_list = ('primary','replica1','replica2')

ifobj1._state.dbindb_listandobj2._state.dbindb_list:

return True

return None

defallow_migrate(self,db,app_label,model_name=None,**hints):

"""

All models end up in this pool.

"""

return True

一个数据库路由是一个类,这个类最多有四个方法:

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_migrate(db, app_label, model_name)

决定 model 是否可以和 db 为别名的数据库同步。如果可以返回True , 如果不可以返回 False ,或者没有意见时返回 None 。

Django项目按APP分库

在大型web项目中,我们常常会创建多个app来处理不同的业务,如果希望实现app之间的数据库分离,比如app01走数据库db1,app02走数据库db2,而不是实现读写分离。我们可以定义如下所示的数据库路由, 然后将其加入。

classAppDBRouter:

defdb_for_read(self,model,**hints):

ifmodel._meta.app_label =='app01':

return'db1'

ifmodel._meta.app_label =='app02':

return'db2'

defdb_for_write(self,model,**hints):

ifmodel._meta.app_label =='app01':

return'db1'

ifmodel._meta.app_label =='app02':

return'db2'

由于manage.py一次只能创建一个数据库,我们可以使用--database选项来依次创建我们需要的数据库。例如:

将app01下models中的表创建到db01的数据库”db1”中

python manage.py migrate --database=db1

将app02下models中的表创建到db02的数据库”db2”中

python manage.py migrate --database=db2

在使用多数据库时,我们可以使用using方法来手动选择需要读写的数据库,如下所示:

Django中使用多数据库注意事项:

django 目前不为跨多个数据库的外键关系(ForeinKey)或多对多关系提供任何支持。模型定义的任何外键和多对多关系字段都必须存在一个数据库内。

小结

本文总结了在Django项目中如何通过优化数据库的设计来提升网站性能, 包括建立数据库索引和使用多数据库,希望对你有所帮助哦。下面起我们将开始介绍Django的权限控制,欢迎关注。

大江狗

2018.11.19

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181119G0JMZC00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券