django全自动分库分表(横向)
django全自動(dòng)分庫分表
期待大神指點(diǎn)方法的不足之處或者其他更好的方法
由于當(dāng)前項(xiàng)目目前只需要實(shí)現(xiàn)寫,所以這里也沒有考慮讀寫分離。如果要考慮讀寫分離,則在路由處進(jìn)行設(shè)置即可。
分庫原理
django在初始化的時(shí)候,從自己的數(shù)據(jù)庫管理服務(wù)器獲取當(dāng)前的所有數(shù)據(jù)庫,以及數(shù)據(jù)庫的入庫規(guī)則,在獲取數(shù)據(jù)的時(shí)候,根據(jù)數(shù)據(jù)字段值動(dòng)態(tài)生成Model,并動(dòng)態(tài)保存到指定的數(shù)據(jù)庫中。
動(dòng)態(tài)生成的Model不僅能夠?qū)崿F(xiàn)分庫,還能實(shí)現(xiàn)動(dòng)態(tài)橫向分表,牛逼吧。
一句話:通過動(dòng)態(tài)路由分庫,通過動(dòng)態(tài)model分表
1 從數(shù)據(jù)庫管理服務(wù)器獲取設(shè)置
settings.py #盡量放在靠前 GROUP_ID_TO_DATABASE={}#記錄對(duì)應(yīng)的動(dòng)態(tài)model需要保存到哪個(gè)數(shù)據(jù)庫 # # Application definition def get_db_setting():"""從數(shù)據(jù)庫管理服務(wù)器獲取數(shù)據(jù)庫設(shè)置和數(shù)據(jù)標(biāo)對(duì)應(yīng)的數(shù)據(jù)庫db_setting_url:連接數(shù)據(jù)庫管理服務(wù)器的地址django_info:當(dāng)前配置的服務(wù)器的信息,必須為一個(gè)不重復(fù)的固定值:return:"""import requestsdjango_info={'django_device_id':'',#該服務(wù)器的設(shè)備id,建議從配置文件讀取,且各個(gè)django服務(wù)器之間不要重復(fù)}r=requests.post(url=db_setting_url,data=django_info)return r.json()DATABASES,GROUP_ID_TO_DATABASE=get_db_setting()2 創(chuàng)建數(shù)據(jù)庫表
該model在collect這個(gè)app里面
#對(duì)應(yīng)model.py里面的model #MyModel是我自定義的一個(gè)抽象基類model,你可以直接使用models.Model class BaseGetFaceRecord(MyModel):"""入庫記錄基礎(chǔ)的入庫記錄,該model為abstract=True的model,在之后會(huì)進(jìn)行繼承并創(chuàng)建真正需要的數(shù)據(jù)庫"""collected_face = models.ForeignKey(BaseCollectFace, on_delete=models.CASCADE, verbose_name="對(duì)應(yīng)人臉信息")group_id = models.CharField(max_length=128, verbose_name="人臉庫")camera_id = models.CharField(max_length=128, verbose_name="抓拍相機(jī)ID")arrived_time = models.DateTimeField(max_length=10, verbose_name="抓拍時(shí)間戳")person_id = models.CharField(max_length=128, verbose_name="人臉I(yè)D(faceToken)")first_arrive_time = models.DateTimeField(max_length=10, verbose_name="首次到訪時(shí)間戳")class Meta:abstract = Trueverbose_name = "人臉照片庫"verbose_name_plural = verbose_nameclass BaseGetFaceRecord(MyModel):"""入庫記錄基礎(chǔ)的入庫記錄,該model為abstract=True的model,在之后會(huì)進(jìn)行繼承并創(chuàng)建真正需要的數(shù)據(jù)庫"""collected_face = models.ForeignKey(BaseCollectFace, on_delete=models.CASCADE, verbose_name="對(duì)應(yīng)人臉信息")group_id = models.CharField(max_length=128, verbose_name="人臉庫")camera_id = models.CharField(max_length=128, verbose_name="抓拍相機(jī)ID")arrived_time = models.DateTimeField(max_length=10, verbose_name="抓拍時(shí)間戳")person_id = models.CharField(max_length=128, verbose_name="人臉I(yè)D(faceToken)")first_arrive_time = models.DateTimeField(max_length=10, verbose_name="首次到訪時(shí)間戳")class Meta:abstract = Trueverbose_name = "人臉照片庫"verbose_name_plural = verbose_nameclass CreateGetFaceRecordModel(object):"""動(dòng)態(tài)創(chuàng)建動(dòng)態(tài)創(chuàng)建人臉庫的類主要用來提供靜態(tài)方法也可以不寫成類"""@staticmethoddef __get_GetFaceRecord_model(group_id: str):"""創(chuàng)建FaceRecord模型:param group_id:人臉庫名稱:return: FaceRecord"""#要連接的數(shù)據(jù)表,table_name = 'getfacerecord_%s' % str(group_id)#這里會(huì)重新設(shè)置創(chuàng)建的model的名字,每個(gè)model名字都是動(dòng)態(tài)的,不是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):"""判斷這個(gè)表是否已經(jīng)在數(shù)據(jù)庫: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):"""注冊(cè)GetFaceRecord模型:param group_id: 人臉庫名稱:return: GetFaceRecord"""try:# cls = apps.get_model('__main__', 'ExcelData_%s' % project_name)# 獲取模型對(duì)應(yīng)的model,如果有的話,第一個(gè)參數(shù)為collect這個(gè)app,第二個(gè)參數(shù)為model的名字# 這里不用__main__是因?yàn)橹髸?huì)考慮到分庫,不同的app會(huì)到不同的庫里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):# 將數(shù)據(jù)表創(chuàng)建with connection.schema_editor() as schema_editor:# 創(chuàng)建模型,調(diào)用的應(yīng)該是migrate和makemigrations里面的方法schema_editor.create_model(cls)return clselse:return clsdef get_GetFaceRecord(group_id: str):"""獲取注冊(cè)人臉的人臉庫對(duì)應(yīng)model,但是請(qǐng)注意,如果沒有會(huì)創(chuàng)建該表和該模型,如果有,返回該模型:param group_id:人臉庫信息:return:"""return CreateGetFaceRecordModel.create_GetFaceRecord(group_id)3 創(chuàng)建數(shù)據(jù)庫路由器
在對(duì)應(yīng)的app里面創(chuàng)建自己的router.py,注意這部分內(nèi)容也應(yīng)該從數(shù)據(jù)庫管理服務(wù)器獲取
""" @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):"""返回對(duì)應(yīng)的數(shù)據(jù)庫名稱: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):"""是否允許通過外鍵訪問??如果應(yīng)該允許obj1和obj2之間的關(guān)系,返回True;如果應(yīng)該阻止這種關(guān)系,返回False;如果路由器沒有意見,返回None。這純粹是一個(gè)驗(yàn)證操作,由外鍵和許多對(duì)許多操作使用,以確定是否應(yīng)該允許兩個(gè)對(duì)象之間存在關(guān)系。:param obj1::param obj2::param hints::return:"""return Truedef allow_migrate(self, db, app_label, model_name=None, **hints):"""是否允許migrate進(jìn)行遷移的驗(yàn)證這里不允許通過migrate的方式將數(shù)據(jù)遷移,數(shù)據(jù)庫表只能在數(shù)據(jù)庫管理器里面進(jìn)行創(chuàng)建: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至此,就完成了動(dòng)態(tài)的數(shù)據(jù)庫配置
總結(jié)
通過這個(gè)方法,再結(jié)合nginx,就可完成django配置數(shù)據(jù)庫。
注意,這里只是一個(gè)demo,還有很多東西沒有進(jìn)行實(shí)現(xiàn),比如數(shù)據(jù)庫DATABASE設(shè)置的熱更新,如果配置,即可實(shí)現(xiàn)動(dòng)態(tài)添加數(shù)據(jù)庫和增加服務(wù)器配置。
創(chuàng)建路由的介紹可以看這,挺合適:https://www.jb51.net/article/141182.htm
總結(jié)
以上是生活随笔為你收集整理的django全自动分库分表(横向)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 统一论:3G手机、云计算、SaaS、业务
- 下一篇: Android 11.0 修改添加的默认