最近看到了一篇讲Django性能测试和优化的文章, 文中除了提到了很多有用的优化方法, 演示程序的数据库模型写法我觉得也很值得参考, 在这单独记录下.

原文的演示代码有些问题, 我改进了下, 这里可以查看: https://github.com/wanghaoxi3000/development/tree/master/Python/Django/optimize_django

在实际项目中, 有时需要隐藏数据库中表的主键, 我之前采用的大多是为需要隐藏主键ID的表添加一个字段, 再用散列或者UUID等填充来唯一标识一行数据. 而上面提到的文章中则是使用了一个专门生成ID对应散列值的基类, 需要隐藏散列的表可以通过继承这个类来实现隐藏自己的主键ID.

比较特别的是此文的散列值是通过主键ID和ContentType的ID来一起生成的. ContentType是Django自带的一套的框架, 在新模型安装时会自动创建新的ContentType实例, ContentType 实例具有返回它们表示的模型类的方法, 以及从这些模型查询对象的方法. 从而提供一个高层次的, 通用的接口来与模型进行交互.

ContentType使用说明:

https://docs.djangoproject.com/en/2.0/ref/contrib/contenttypes/

通过这样的机制, 解码一个散列值后就可以直接得到对应的Django ORM模型类和实例. 对于一些需要一个集中的地方对模型进行解码并对不同类的不同模型实例进行处理时会很有用.

Hasher 类代码

from django.contrib.contenttypes.models import ContentType
import basehash class Hasher:
base36 = basehash.base36() @classmethod
def from_model(cls, obj, klass=None):
if obj.pk is None:
return None
return cls.make_hash(obj.pk, klass if klass is not None else obj) @classmethod
def make_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' % {
'contenttype_pk': content_type.pk,
'object_pk': object_pk
}) @classmethod
def parse_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
def to_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
def hash(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

def get_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

参考:

http://blog.csdn.net/dev_csdn/article/details/78782570

Django 用散列隐藏数据库中主键ID的更多相关文章

  1. 关于mybatis插入数据库返回主键id

    关于Sequence主键的数据库来说,如: <insert id="add" parameterType="vo.Category"> <se ...

  2. 关系型数据库中主键(primary key)和外键(foreign key)的概念。

    刚接触关系型数据库的同学,会听过主键和外键的概念.这是关系型数据库的基本概念,需要清楚理解.今天我就以简洁的语言总结一下这个概念. 主键.一句话概括:一张表中,可以用于唯一标识一条记录的字段组(或者说 ...

  3. 【基础知识】C#数据库中主键类型的选择

    主键在数据库中占有很大的地位,对于表的关联性,和数据的唯一识别性有重要的作用: 1,在C#开发中,Int自增字段和Guid(数据库中是uniqueidentifier类型)可设置为主键: 1>G ...

  4. MySQL中主键id不连贯重置处理办法

    MySQL中有时候会出现主键字段不连续,或者顺序乱了,想重置从1开始自增,下面处理方法 先删除原有主键,再新增新主键字段就好了 #删除原有自增主键 ALTER TABLE appraiser_info ...

  5. mysql insert插入时实现如果数据表中主键重复则更新,没有重复则插入的四种方法

    [CSDN下载] Powerdesigner 设计主键code不能重复等问题 [CSDN博客] Oracle中用一个序列给两个表创建主键自增功能的后果 [CSDN博客] MySQL自增主键删除后重复问 ...

  6. Mybatis「MySQL-Oracle」 中主键自动生成 <selectKey> 序列化

    有时候我们不仅仅是通过返回 int 影响行数来确定数据是否插入成功就行了,因为我们总是会用到这个刚刚插入的自增主键,比如主子表入库,子表需要主表的 id,那这个时候我们再去数据库查就显得有点 low ...

  7. 开启事务时mybatis返回主键id

    先说一下没有注解的 先给出实体类: public class City { private int city_id; private String city_name; public int getC ...

  8. MyBatis插入记录时返回主键id的方法

    有时候插入记录之后需要使用到插入记录的主键,通常是再查询一次来获取主键,但是MyBatis插入记录时可以设置成返回主键id,简化操作,方法大致有两种. 对应实体类: public class User ...

  9. Java中实现MongoDB自增主键ID

    1.了解MongoDB的ObjectId        MongoDB的文档固定是使用“_id”作为主键的,它可以是任何类型的,默认是个ObjectId对象(在Java中则表现为字符串),那么为什么M ...

随机推荐

  1. n年前,我没钱但年轻,我怕n年后我老时,还是一无所成——2017我的收获和反思

    记得当年我刚从学校里出来时,应该和现在的95后差不多,当时还是很惶恐的,怕找不到工作,怕无法挣到足够的钱买房子支撑家庭,(当然还有其它的担心点),却唯独没意识到自己拥有着最宝贵的财富:年轻. 年轻意味 ...

  2. SDP(0):Streaming-Data-Processor - Data Processing with Akka-Stream

    再有两天就进入2018了,想想还是要准备一下明年的工作方向.回想当初开始学习函数式编程时的主要目的是想设计一套标准API給那些习惯了OOP方式开发商业应用软件的程序员们,使他们能用一种接近传统数据库软 ...

  3. Android破解学习之路(五)——Android游戏 割绳子:魔法 + 在游戏加入Toast弹窗提示

    前言:这一期的破解教程,有新的知识内容出现啦! 这一期破解的游戏是找不到之前的关键字,怎么破解呢? 破解成功之后,添加一个Toast弹窗提示由XX破解,这操作该如何实现呢?请往下看~ 链接: http ...

  4. [置顶] webapi token、参数签名是如何生成的

    一个问题 在这里我想问大家一句,如果你向一个刚刚接触.net web后端程序开发的同学(别人刚刚也就学了webform的request,response,会提交表单的这种刚接触不久的同学),你怎么去解 ...

  5. Windows as a Service(1)—— Windows 10服务分支

    前言 作为公司的IT管理员,管理全公司Windows 10操作系统的更新一直是工作中的头疼之处.微软提供了很多方法来帮助我们管理公司的Windows 10更新,比如Windows Server Upd ...

  6. Docker安装入门 -- 中间件镜像

    Docker安装入门 -- 中间件镜像 php-fpm 1.docker build -t csphere/php-fpm:5.4 .   //在当前目录下创建镜像 2.docker run -d - ...

  7. MySQL 权限与用户表

    1.授权时创建用户 grant all privileges on *.* to zhengwenqiang@localhost identified by 'zhengwenqiang'; 2.收回 ...

  8. MyBatis中批量插入数据对插入记录数的限制

    <基于Mybatis框架的批量数据插入的性能问题的探讨>(作者:魏静敏 刘欢杰 来源:<计算机光盘软件与应用> 2013 年第 19 期)中提到批量插入的记录数不能超过1000 ...

  9. 队列详解及java实现

    导读 栈和队列是有操作限制的线性表. 目录 1.队列的概念.特点.存储结构. 2.栈队列的java实现. 概念 队列是一种在一端进行插入,而在另一端进行删除的线性表.1.队列的插入端称为队尾:队列的删 ...

  10. jQuery 入门

    不能正常引用jQuery-2.2.4.min.js所以代码没生效 jQuery 是一个 JavaScript 函数库.jQuery 库包含以下特性: HTML 元素选取 HTML 元素操作 CSS 操 ...