如何优雅地在Django项目里生成不重复的ID?
前言
本来标题是想叫“生成不重复的四位数”的,不过单纯数字有点局限,推广一下变成不重复 ID 吧~
这个功能是在做下面图片里这个小项目时遇到的,有点像微信的面对面建群,生成一个随机且不重复的密码,其他人输入这个密码就能加入教室。

实现这个功能有不少方法,本文简单记录一下。
不依赖第三方库
首先单纯基于 Django ORM 来实现这个功能
先定义一个模型
from django.db import models
class MyModel(models.Model):
unique_code = models.CharField(max_length=4, unique=True)
单任务
最简单粗暴的方法,写一个死循环
import random
def generate_unique_code():
while True:
code = str(random.randint(1000, 9999))
if not MyModel.objects.filter(unique_code=code).exists():
return code
这个实现在单线程测试环境下肯定是没问题的,不过这个操作并不是原子化的,并发环境下可能会生成重复的数字。
考虑并发
高并发情况下,可以使用数据库事务或乐观锁。
from django.db import transaction, IntegrityError
def create_instance():
# 尝试次数
retry = 10
for _ in range(retry):
code = generate_unique_code()
try:
with transaction.atomic():
instance = MyModel(unique_code=code)
instance.save()
return instance
except IntegrityError:
# 如果出现唯一性冲突,重新尝试
continue
raise Exception("无法生成唯一的四位数")
预先生成
前面两种方法都要频繁读取数据库,性能比较差。
还可以用空间换时间的方式,因为只是四位数,0000-9999 这个范围的数字也不多,预先把这一万行存入数据库,加个 available 字段
当需要生成唯一 ID 的时候,就先筛选 available == True 的数据,然后随机抽取一个;并且把这个字段设置为 False
大概思路就是这样
使用第三方库
在这个项目里,我搭配使用了这三个库(这也是我写这篇文章的主要目的,记录一下这几个库)
- shortuuid
- hashids
- django-autoslug
shortuuid
shortuuid 是一个轻量级的库,可以生成比较短的 UUID
使用这个库来实现这个功能的话很简单
import shortuuid
shortuuid.ShortUUID(alphabet="0123456789").random(length=4)
不过这个项目中,我并没有使用这个库来做这个
事实上,这个库顾名思义有个 uuid,自然是用来做与 python 内置 UUID 有关工作
我用这个库把 Client 模型的 ID 简化到 7 位
class Client(ModelExt):
client_id = models.UUIDField(default=uuid.uuid4, editable=False)
client_key = models.CharField(max_length=100, default=uuid.uuid4)
user = models.OneToOneField(
User, on_delete=models.SET_NULL, db_constraint=False, null=True, blank=True, unique=True,
)
consumer_name = models.CharField(max_length=100, null=True, blank=True)
is_online = models.BooleanField(default=False)
def short_client_id(self):
short = shortuuid.encode(self.client_id)
return short[:7]
使用 shortuuid.encode 方法可以把 32 位的 UUID 变成 22 位,并且还能使用 decode 方法复原
hashids
这个是将数字转为短字符串的库
虽然名字里带个 hash ,但这个库的编码是可逆的
import hashids
h = hashids.Hashids()
h.encode(123, 456)
# Out[15]: 'X68fkp'
h.decode('X68fkp')
# Out[16]: (123, 456)
我用来根据时间戳生成教室名称
def get_timestamp_hashid():
hashids = Hashids(salt='hahaha salt lala')
t = timezone.now().timestamp()
result = tuple(map(int, str(t).split('.')))
return hashids.encode(*result)
因为 encode 方法接收的是数字(也可以是包含数字的 tuple),所以这里把时间戳的整数部分和小数部分转换为 tuple 然后传入 hashids
django-autoslug
这个库用于生成基于字段的唯一 slug,同时可以自定义生成逻辑。
我就是用这个库来实现生成唯一的教室密码功能(但并不是很推荐这种方式)
from autoslug import AutoSlugField
def populate_classroom_number(instance):
return str(random.randint(1000, 9999))
class ClassroomIdiom(ModelExt):
name = models.CharField(max_length=100)
number = AutoSlugField(populate_from=populate_classroom_number, unique=True)
这个库的原理很简单,根据用户定义的规则生成 slug,然后检查数据库是否重复,遇到重复的话就在后面追加数字,这样有可能导致生成出来的数字超过 4 位数
最好的还是我前面说的 不依赖第三方库 的第三种方式。
这里使用 django-autoslug 单纯是为了偷懒,把复杂的判断逻辑交给第三方库,毕竟这只是个玩具项目。
小结
在生成唯一 ID 这件事上,Django 和其他后端框架没啥不同的,思路都是类似的,只不过可以借助 Python 生态偷懒一下…
如何优雅地在Django项目里生成不重复的ID?的更多相关文章
- Django 在Django项目里单独运行某个py文件
Python文件开头写以下代码: import os import django # 在environ字典里设置默认Django环境,'xxxx.settings'指Django项目的配置文件 os. ...
- PHP下生成非重复的id
PHP在多进程运行的情况下,如果不采用内存锁或者文件锁,基本没办法能解决生成唯一Id的问题.试过了静态变量.单例模式等等.查询到php里的uniqid()函数,最后还是找到了一个折中方式,虽然还是有可 ...
- PHP uniqid 高并发生成不重复唯一ID
http://www.51-n.com/t-4264-1-1.html PHP uniqid()函数可用于生成不重复的唯一标识符,该函数基于微秒级当前时间戳.在高并发或者间隔时长极短(如循环代码)的情 ...
- php自动生成不重复的id
PHP uniqid()函数可用于生成不重复的唯一标识符,该函数基于微秒级当前时间戳.在高并发或者间隔时长极短(如循环代码)的情况下,会出现大量重复数据.即使使用了第二个参数,也会重复,最好的方案是结 ...
- jQuery里面click、this事件遇到(Django模型里for)相同的id名和class名想获取值
遇到的原型是这样的!下面我把它简化一下; click事件: 在浏览器里面只能获取横线上面的值,和下面的第一个值!! 这是因为id等级比class高,而且js要求id不能重复! 当 转载于:https: ...
- C# 通过GUID生成不重复的ID
/// <summary> /// 获得32位字符长度的ID /// </summary> /// <param name="information" ...
- 解决在ubuntu上启动的django项目在windows进行访问无法访问的问题
windows想要访问VMware中Ubuntu Server中Debug模式下的django服务,需要设置django允许非本机ip访问. 设置方法:1.查看虚拟机ip(建议VMware中设置Ubu ...
- Django项目:CRM(客户关系管理系统)--67--57PerfectCRM实现admin批量生成上课记录
#admin.py # ————————01PerfectCRM基本配置ADMIN———————— from django.contrib import admin # Register your m ...
- django项目 在进行数据生成迁移文件makemigrations时报Please select a fix:...
问题:django项目 在进行生成迁移文件:python .\manage.py makemigrations时,报错,如图 原因:在之前项目新建模型的时候,缺少一个字段进行迁移了然后数据表中又产生了 ...
- python 全栈开发,Day94(Promise,箭头函数,Django REST framework,生成json数据三种方式,serializers,Postman使用,外部python脚本调用django)
昨日内容回顾 1. 内容回顾 1. VueX VueX分三部分 1. state 2. mutations 3. actions 存放数据 修改数据的唯一方式 异步操作 修改state中数据的步骤: ...
随机推荐
- 【学习笔记】状压DP
状态压缩DP 对于一个集合,他一有\(2^n\)个子集,而状态压缩就是枚举这些子集,每一个状态就是一个由\(01\)构成的集合,如果为\(0\)就表示不选当前的元素,否则就表示选.因为状态压缩将每一个 ...
- 一个 tomcat 下如何部署多个项目?附详细步骤
一个tomcat下如何部署多个项目?Linux跟windows系统下的步骤都差不多,以下linux系统下部署为例.windows系统下部署同理. 一.不修改端口,部署多个项目 清楚tomcat目录结构 ...
- [namespace hdk] string
#include<bits/stdc++.h> using namespace std; namespace hdk{ const int siz=100001; class string ...
- 【赵渝强老师】使用Docker Compose进行服务编排
一.什么是Docker Compose? Docker Compose是一个用来定义和运行复杂应用的Docker工具.一个使用Docker容器的应用,通常由多个容器组成.使用Docker Compos ...
- Nuxt.js 应用中的 kit:compatibility 事件钩子详解
title: Nuxt.js 应用中的 kit:compatibility 事件钩子详解 date: 2024/10/11 updated: 2024/10/11 author: cmdragon e ...
- 014 Python 的数据类型(数字、字符串、列表、字典)
#!/usr/bin/env python # -*- coding:utf-8 -*- # Datatime:2022/7/24 20:31 # Filename:014 Python 的数据类型( ...
- OpenAI官方开源多智能体框架「Swarm」,并不是我想要的多智能体框架
今天早上,OpenAI实施团队的 @shyamal在Github上开源了Swarm这个OpenAI官方的多智能体框架.不得不说,OpenAI官方下场,获得的社区影响就是不一样,在微信群.朋友圈里已经出 ...
- js实现控制音乐播放
js实现控制音乐播放 用js实现控制音乐播放其实很简单,但是第一次去做可能会遇到一点点小问题. 比如说我自己,第一次想实现一个播放器效果,然后在网上搜寻半天照着自己的理解写下如下代码: <!D ...
- Linux查看显卡 GPU信息
1.Linux查看显卡信息: 1.1查询显卡信息 lspci | grep -i vga 前边的序号 "04:00.0″是显卡的代号 ASPEED Technology, Inc. ASPE ...
- Kubernetes 边缘节点抓不到监控指标?试试这个方法!
KubeSphere v3.1.0 通过集成 KubeEdge,将节点和资源的管理延伸到了边缘,也是 KubeSphere 正式支持边缘计算的第一个版本. 笔者也第一时间搭建和试用了边缘节点相关的功能 ...