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、业务
- 下一篇: Android 11.0 修改添加的默认