Django 用雜湊隱藏資料庫中主鍵ID

2021-08-14 21:55:41 字數 2997 閱讀 4362

最近看到了一篇講django效能測試和優化的文章, 文中除了提到了很多有用的優化方法, 演示程式的資料庫模型寫法我覺得也很值得參考, 在這單獨記錄下.

原文的演示**有些問題, 我改進了下, 這裡可以檢視:

在實際專案中, 有時需要隱藏資料庫中表的主鍵, 我之前採用的大多是為需要隱藏主鍵id的表新增乙個字段, 再用雜湊或者uuid等填充來唯一標識一行資料. 而上面提到的文章中則是使用了乙個專門生成id對應雜湊值的基類, 需要隱藏雜湊的表可以通過繼承這個類來實現隱藏自己的主鍵id.

比較特別的是此文的雜湊值是通過主鍵id和contenttype的id來一起生成的.contenttype是django自帶的一套的框架, 在新模型安裝時會自動建立新的contenttype例項,contenttype例項具有返回它們表示的模型類的方法, 以及從這些模型查詢物件的方法. 從而提供乙個高層次的, 通用的介面來與模型進行互動.

contenttype使用說明:

通過這樣的機制, 解碼乙個雜湊值後就可以直接得到對應的django orm模型類和例項. 對於一些需要乙個集中的地方對模型進行解碼並對不同類的不同模型例項進行處理時會很有用.

hasher 類**

from django.contrib.contenttypes.models import contenttype

import basehash

class

hasher:

base36 = basehash.base36()

@classmethod

deffrom_model

(cls, obj, klass=none):

if obj.pk is

none:

return

none

return cls.make_hash(obj.pk, klass if klass is

notnone

else obj)

@classmethod

defmake_hash

(cls, object_pk, klass):

# 使用**模型時通過 for_concrete_model=false 獲取**模型的contenttype

content_type = contenttype.objects.get_for_model(klass, for_concrete_model=false)

return cls.base36.hash('%(contenttype_pk)03d%(object_pk)06d' % )

@classmethod

defparse_hash

(cls, obj_hash):

unhashed = '%09d' % cls.base36.unhash(obj_hash)

contenttype_pk = int(unhashed[:-6])

object_pk = int(unhashed[-6:])

return contenttype_pk, object_pk

@classmethod

defto_object_pk

(cls, obj_hash):

return cls.parse_hash(obj_hash)[1]

hasher 類主要用來完成雜湊值的計算和解碼過程, 將contenttype和主鍵組合後進行base36計算, 生成一段12位的**. 主要使用了basehash模組, 通過安裝gmpy2模組可以進一步提公升計算速度.

hashablemodel 基類

from django.db import models

from .utils import hasher

class

hashablemodel

(models.model):

"""提供每個模型提供 hash id 的基類"""

class

meta:

abstract = true

@property

defhash

(self):

return hasher.from_model(self)

hashablemodel通過在meta元選項中設定abstract = true而成為django orm中的乙個基類, 其它模型可以通過繼承這個基類來具備產生對應雜湊的能力.

基本使用

現在, 通過乙個雜湊值便可以編寫很多通用的介面了. 例如有兩張表, 都有乙個path的字段:

class

testmodelone

(hashablemodel):

path = models.charfield(max_length=30)

class

testmodeltwo

(hashablemodel):

path = models.charfield(max_length=30)

通過這樣一段**, 便可以同時用來獲取兩張表的path欄位了:

from django.contrib.contenttypes.models import contenttype

defget_path

(hash_id):

content_id, pk = hasher.parse_hash()

obj = contenttype.objects.get_for_id(content_id).get_object_for_this_type(pk=pk)

return obj.path

參考:

Django中資料庫配置

在settings.py中儲存了資料庫的連線配置資訊,django預設初始配置使用sqlite資料庫。databases 使用mysql資料庫首先需要安裝驅動程式 pip install pymysql 在django的工程同名子目錄的 init py檔案中新增如下語句 from pymysql i...

用 Django 管理現有資料庫

在多數專案中,總有一些幾乎一成不變的 crud 操作,編寫這些 很無聊,但又是整個系統必不可少的功能之一。我們在上乙個專案中也面臨類似的問題,雖然已經實現了乙個功能相對完整的管理後台,也盡量做到了 復用,但隨著專案規模的增長,需要編寫的樣本 也不斷膨脹,占用了大量開發時間。面對這種局面,我自然想到了...

Django中資料庫的配置

最近再用django開發乙個專案,其中肯定少不了資料庫的操作,我自己用的主要還是mysql資料庫,我用的是mysql 5.4.40版本,但是基本上所有的資料庫操作連線都可以用。在這之前首先必須安裝python mysql,記得安裝對應的版本。之前我的做法是在檔案中寫資料庫的連線,沒有在setting...