django全自动分库分表(横向)
生活随笔
收集整理的这篇文章主要介绍了
django全自动分库分表(横向)
小编觉得挺不错的,现在分享给大家,帮大家做个参考.
django全自动分库分表
期待大神指点方法的不足之处或者其他更好的方法
由于当前项目目前只需要实现写,所以这里也没有考虑读写分离。如果要考虑读写分离,则在路由处进行设置即可。
分库原理
django在初始化的时候,从自己的数据库管理服务器获取当前的所有数据库,以及数据库的入库规则,在获取数据的时候,根据数据字段值动态生成Model,并动态保存到指定的数据库中。
动态生成的Model不仅能够实现分库,还能实现动态横向分表,牛逼吧。
一句话:通过动态路由分库,通过动态model分表
1 从数据库管理服务器获取设置
settings.py #尽量放在靠前 GROUP_ID_TO_DATABASE={}#记录对应的动态model需要保存到哪个数据库 # # Application definition def get_db_setting():"""从数据库管理服务器获取数据库设置和数据标对应的数据库db_setting_url:连接数据库管理服务器的地址django_info:当前配置的服务器的信息,必须为一个不重复的固定值:return:"""import requestsdjango_info={'django_device_id':'',#该服务器的设备id,建议从配置文件读取,且各个django服务器之间不要重复}r=requests.post(url=db_setting_url,data=django_info)return r.json()DATABASES,GROUP_ID_TO_DATABASE=get_db_setting()2 创建数据库表
该model在collect这个app里面
#对应model.py里面的model #MyModel是我自定义的一个抽象基类model,你可以直接使用models.Model class BaseGetFaceRecord(MyModel):"""入库记录基础的入库记录,该model为abstract=True的model,在之后会进行继承并创建真正需要的数据库"""collected_face = models.ForeignKey(BaseCollectFace, on_delete=models.CASCADE, verbose_name="对应人脸信息")group_id = models.CharField(max_length=128, verbose_name="人脸库")camera_id = models.CharField(max_length=128, verbose_name="抓拍相机ID")arrived_time = models.DateTimeField(max_length=10, verbose_name="抓拍时间戳")person_id = models.CharField(max_length=128, verbose_name="人脸ID(faceToken)")first_arrive_time = models.DateTimeField(max_length=10, verbose_name="首次到访时间戳")class Meta:abstract = Trueverbose_name = "人脸照片库"verbose_name_plural = verbose_nameclass BaseGetFaceRecord(MyModel):"""入库记录基础的入库记录,该model为abstract=True的model,在之后会进行继承并创建真正需要的数据库"""collected_face = models.ForeignKey(BaseCollectFace, on_delete=models.CASCADE, verbose_name="对应人脸信息")group_id = models.CharField(max_length=128, verbose_name="人脸库")camera_id = models.CharField(max_length=128, verbose_name="抓拍相机ID")arrived_time = models.DateTimeField(max_length=10, verbose_name="抓拍时间戳")person_id = models.CharField(max_length=128, verbose_name="人脸ID(faceToken)")first_arrive_time = models.DateTimeField(max_length=10, verbose_name="首次到访时间戳")class Meta:abstract = Trueverbose_name = "人脸照片库"verbose_name_plural = verbose_nameclass CreateGetFaceRecordModel(object):"""动态创建动态创建人脸库的类主要用来提供静态方法也可以不写成类"""@staticmethoddef __get_GetFaceRecord_model(group_id: str):"""创建FaceRecord模型:param group_id:人脸库名称:return: FaceRecord"""#要连接的数据表,table_name = 'getfacerecord_%s' % str(group_id)#这里会重新设置创建的model的名字,每个model名字都是动态的,不是GetFaceRecordclass Metaclass(models.base.ModelBase):def __new__(cls, name, bases, attrs):name += group_id # 这是Model的name.return models.base.ModelBase.__new__(cls, name, bases, attrs)# 注意继承的顺序class GetFaceRecord(BaseAlgoFace, metaclass=Metaclass):@staticmethoddef is_exists(table_name1):"""判断这个表是否已经在数据库:param table_name1::return:"""table_name1 = 'getfacerecord_' + table_name1return table_name1 in connection.introspection.table_names()class Meta:abstract = Falsedb_table = table_nameapp_label="collect"return GetFaceRecord@staticmethoddef create_GetFaceRecord(group_id: str):"""注册GetFaceRecord模型:param group_id: 人脸库名称:return: GetFaceRecord"""try:# cls = apps.get_model('__main__', 'ExcelData_%s' % project_name)# 获取模型对应的model,如果有的话,第一个参数为collect这个app,第二个参数为model的名字# 这里不用__main__是因为之后会考虑到分库,不同的app会到不同的库里cls = apps.get_model('collect', 'GetFaceRecord_%s' % group_id)except LookupError:cls = CreateGetFaceRecordModel.__get_GetFaceRecord_model(group_id)except Exception as e:raise eif not cls.is_exists(group_id):# 将数据表创建with connection.schema_editor() as schema_editor:# 创建模型,调用的应该是migrate和makemigrations里面的方法schema_editor.create_model(cls)return clselse:return clsdef get_GetFaceRecord(group_id: str):"""获取注册人脸的人脸库对应model,但是请注意,如果没有会创建该表和该模型,如果有,返回该模型:param group_id:人脸库信息:return:"""return CreateGetFaceRecordModel.create_GetFaceRecord(group_id)3 创建数据库路由器
在对应的app里面创建自己的router.py,注意这部分内容也应该从数据库管理服务器获取
""" @version: 1.0 @author: chise @time : 2019/07/24 10:51 """ from MultiAlgorithm.settings import GROUP_ID_TO_DATABASEclass BaseRouter():def db_for_read(self, model, **hints):"""返回对应的数据库名称:param model::param hints::return:"""if model._meta.label == "base.UserGroup" or model._meta.label == "base.FaceAggregation":return 'default'else:model_name = str(model.__class__.__name__)return GROUP_ID_TO_DATABASE[model_name]def db_for_write(self, model, **hints):if model._meta.label == "base.UserGroup" or model._meta.label == "base.FaceAggregation":return 'default'else:model_name = str(model.__class__.__name__)return GROUP_ID_TO_DATABASE[model_name]def allow_relation(self, obj1, obj2, **hints):"""是否允许通过外键访问??如果应该允许obj1和obj2之间的关系,返回True;如果应该阻止这种关系,返回False;如果路由器没有意见,返回None。这纯粹是一个验证操作,由外键和许多对许多操作使用,以确定是否应该允许两个对象之间存在关系。:param obj1::param obj2::param hints::return:"""return Truedef allow_migrate(self, db, app_label, model_name=None, **hints):"""是否允许migrate进行迁移的验证这里不允许通过migrate的方式将数据迁移,数据库表只能在数据库管理器里面进行创建:param db::param app_label::param model_name::param hints::return:"""if app_label == 'base':return db == 'base.UserGroup' or db == 'base.UserGroup'return None至此,就完成了动态的数据库配置
总结
通过这个方法,再结合nginx,就可完成django配置数据库。
注意,这里只是一个demo,还有很多东西没有进行实现,比如数据库DATABASE设置的热更新,如果配置,即可实现动态添加数据库和增加服务器配置。
创建路由的介绍可以看这,挺合适:https://www.jb51.net/article/141182.htm
总结
以上是生活随笔为你收集整理的django全自动分库分表(横向)的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 统一论:3G手机、云计算、SaaS、业务
- 下一篇: 016 Rust死灵书之安全方式内存初始