Django如何使用snowflake自定义生成主键而不是自动生成主键?

2024-04-16 09:38

本文主要是介绍Django如何使用snowflake自定义生成主键而不是自动生成主键?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

之前ID都是用自增实现的,那现在想用Snowflake算法生成主键,要做什么改动呢?

目录

    • 背景介绍
    • 实现方案
        • 方案1 - 手动添加主键
        • 方案2 - 重写save()方法
        • 方案3 - 使用 Django Signals 中的pre_save()
        • 方案4 - 仿照models.UUIDField,写一个models.SnowflakeIDField
    • 总结

背景介绍

目前工程框架如下

  • Django
  • django.db.backends.postgresql_psycopg2

目前models声明和save()方法如下

# models.py
# 使用的是默认主键
class User(models.Model):name = models.CharField(max_length=100, verbose_name="名字")
# user的新增操作,默认主键
user = User()
user.name = "123"
user.save()

user.save()时执行的SQL语句是

INSERT INTO "polls_user" ("name") VALUES ('xiaoming') RETURNING "polls_user"."id"; args=('xiaoming',)

很明显,并未在语句中设置ID主键

查看表结构,发现id自动是使用序列自增来实现的

CREATE TABLE "public"."polls_user" ("id" int4 NOT NULL DEFAULT nextval('polls_user_id_seq'::regclass),"name" varchar(100) COLLATE "pg_catalog"."default" NOT NULL,CONSTRAINT "polls_user_pkey" PRIMARY KEY ("id")
)

那么基于目前的情况,如何改写使用snowflake算法生成ID,而不是自动生成主键呢?

实现方案

方案1 - 手动添加主键

实现方式如下

  • (1)首先需要声明id,声明为非AutoField类型

    如果不声明,在使用postgresql的情况下,会默认为主键设置为serial类型,使用序列生成主键

# models.pyclass User(models.Model):id = models.BigIntegerField(primary_key=True)name = models.CharField(max_length=100, verbose_name="名字")
  • (2)其次是save( )的时候,需要手动设置主键
# user的新增操作user = User()
user.id = snowflake.next_id()
user.name = "123"
# 可以不指定force_insert=True,如果不指定,默认会先update看是否有记录,如果没有,再执行insert
user.save(force_insert=True)

改动:(1)所有model增加id设置

(2)所有save()之前设置id=snowflake.next_id()

方案2 - 重写save()方法

实现方式如下

  • 单独改写某一个model的save( )方法
# models.pyclass User(models.Model):id = models.BigIntegerField(primary_key=True)name = models.CharField(max_length=100, verbose_name="名字")def save(self, *args, **kwargs):if not self.id:self.id = snowflake.next_id()super(User, self).save(*args, **kwargs)return self.id
  • 调用的地方不用修改,不需要设置 user.id = snowflake.next_id()

按照上面的方法的话,每个新的model都是需要重写save( )方法的,显然工作量仍然比较多。

改动:(1)所有model增加id设置

(2)所有model重写save()方法

方案3 - 使用 Django Signals 中的pre_save()

官方文档地址:https://docs.djangoproject.com/en/3.0/topics/signals/

实现方式如下

  • 修改models.py文件

使用pre_save( )方法,在调用models.save( )之后立即执行

注意

(1)如auth_开头的表的save()以及 其他django_开头的表都会走此逻辑,需要排除这些model的save

(2)save() 包括update和insert,过滤执行update的model

from django.db.models.signals import pre_save
from django.dispatch import receiver
import logging@receiver(pre_save)
def pre_save_set_snowflake_id(sender, instance, *args, **kwargs):"""Django Signals, pre_save适用所有的modelIf we dont include the sender argument in the decorator,like @receiver(pre_save, sender=MyModel), the callback will be called for all models."""# print(__name__)  # = polls.models# print(type(instance)) # = <class 'polls.models.Question'>if __name__ in str(type(instance)) and not instance.id:# 满足条件(1)在本models.py中声明的model (2)id不为空的model 才会使用snowflake生成id# 原因是如果不加条件(1)会有如auth_开头的表以及django_开头的表也会用snowflake生成的id,但是其id长度不够instance.id = snowflake.next_id()class User(models.Model):id = models.BigIntegerField(primary_key=True)name = models.CharField(max_length=100, verbose_name="名字")

如上,修改好models.py之后,就可以安心使用save()了,原先的业务逻辑也不用有其他修改

改动(1)所有model增加id设置,统一设置 id = models.BigIntegerField(primary_key=True)

(2)增加pre_save( ) 方法,统一设置 id = snowflake.next_id()

方案4 - 仿照models.UUIDField,写一个models.SnowflakeIDField

尝试中,但是还没有写出来。

思路就是新写一个field,比如类似models.UUIDField,能否写一个models.SnowflakeIDField

如下是UUIDField写法

# models.py
import uuidclass TestUUID(models.Model):# 一定要设置default=uuid.uuid4id = models.UUIDField(primary_key=True, default=uuid.uuid4)name = models.CharField(max_length=100, verbose_name="名字")
# 新增操作test_uuid = TestUUID()
test_uuid.name = '123123'
test_uuid.save()
-- 执行SQL
(0.005) INSERT INTO "polls_testuuid" ("id", "name") VALUES ('74f8e76c-b80a-4197-a469-81992c46e3c4'::uuid, '123123'); args=(UUID('74f8e76c-b80a-4197-a469-81992c46e3c4'), '123123')

TODO… 那么,SnowflakeIDField如何实现呢?

最终了解下来,发现完全没有必要自己写models.SnowflakeIDField

如下,即可完成…

# models.py
# 添加 default=snowflake_util.next_id 即可
id = models.BigIntegerField(primary_key=True, default=snowflake_util.next_id)

总结

  • 选择上面的方案3,使用 Django Signals 中的pre_save(),可以增加对于参数的校验,不过本次不需要
  • 选择上面的方案4,最简单

这篇关于Django如何使用snowflake自定义生成主键而不是自动生成主键?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/908438

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

如何用Docker运行Django项目

本章教程,介绍如何用Docker创建一个Django,并运行能够访问。 一、拉取镜像 这里我们使用python3.11版本的docker镜像 docker pull python:3.11 二、运行容器 这里我们将容器内部的8080端口,映射到宿主机的80端口上。 docker run -itd --name python311 -p

AI一键生成 PPT

AI一键生成 PPT 操作步骤 作为一名打工人,是不是经常需要制作各种PPT来分享我的生活和想法。但是,你们知道,有时候灵感来了,时间却不够用了!😩直到我发现了Kimi AI——一个能够自动生成PPT的神奇助手!🌟 什么是Kimi? 一款月之暗面科技有限公司开发的AI办公工具,帮助用户快速生成高质量的演示文稿。 无论你是职场人士、学生还是教师,Kimi都能够为你的办公文

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

pdfmake生成pdf的使用

实际项目中有时会有根据填写的表单数据或者其他格式的数据,将数据自动填充到pdf文件中根据固定模板生成pdf文件的需求 文章目录 利用pdfmake生成pdf文件1.下载安装pdfmake第三方包2.封装生成pdf文件的共用配置3.生成pdf文件的文件模板内容4.调用方法生成pdf 利用pdfmake生成pdf文件 1.下载安装pdfmake第三方包 npm i pdfma

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]