前言

本来标题是想叫“生成不重复的四位数”的,不过单纯数字有点局限,推广一下变成不重复 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?的更多相关文章

  1. Django 在Django项目里单独运行某个py文件

    Python文件开头写以下代码: import os import django # 在environ字典里设置默认Django环境,'xxxx.settings'指Django项目的配置文件 os. ...

  2. PHP下生成非重复的id

    PHP在多进程运行的情况下,如果不采用内存锁或者文件锁,基本没办法能解决生成唯一Id的问题.试过了静态变量.单例模式等等.查询到php里的uniqid()函数,最后还是找到了一个折中方式,虽然还是有可 ...

  3. PHP uniqid 高并发生成不重复唯一ID

    http://www.51-n.com/t-4264-1-1.html PHP uniqid()函数可用于生成不重复的唯一标识符,该函数基于微秒级当前时间戳.在高并发或者间隔时长极短(如循环代码)的情 ...

  4. php自动生成不重复的id

    PHP uniqid()函数可用于生成不重复的唯一标识符,该函数基于微秒级当前时间戳.在高并发或者间隔时长极短(如循环代码)的情况下,会出现大量重复数据.即使使用了第二个参数,也会重复,最好的方案是结 ...

  5. jQuery里面click、this事件遇到(Django模型里for)相同的id名和class名想获取值

    遇到的原型是这样的!下面我把它简化一下; click事件: 在浏览器里面只能获取横线上面的值,和下面的第一个值!! 这是因为id等级比class高,而且js要求id不能重复! 当 转载于:https: ...

  6. C# 通过GUID生成不重复的ID

    /// <summary> /// 获得32位字符长度的ID /// </summary> /// <param name="information" ...

  7. 解决在ubuntu上启动的django项目在windows进行访问无法访问的问题

    windows想要访问VMware中Ubuntu Server中Debug模式下的django服务,需要设置django允许非本机ip访问. 设置方法:1.查看虚拟机ip(建议VMware中设置Ubu ...

  8. Django项目:CRM(客户关系管理系统)--67--57PerfectCRM实现admin批量生成上课记录

    #admin.py # ————————01PerfectCRM基本配置ADMIN———————— from django.contrib import admin # Register your m ...

  9. django项目 在进行数据生成迁移文件makemigrations时报Please select a fix:...

    问题:django项目 在进行生成迁移文件:python .\manage.py makemigrations时,报错,如图 原因:在之前项目新建模型的时候,缺少一个字段进行迁移了然后数据表中又产生了 ...

  10. python 全栈开发,Day94(Promise,箭头函数,Django REST framework,生成json数据三种方式,serializers,Postman使用,外部python脚本调用django)

    昨日内容回顾 1. 内容回顾 1. VueX VueX分三部分 1. state 2. mutations 3. actions 存放数据 修改数据的唯一方式 异步操作 修改state中数据的步骤: ...

随机推荐

  1. Angular 18+ 高级教程 – Component 组件 の Dependency Injection & NodeInjector

    前言 在 Dependency Injection 依赖注入 文章中,我们学习了 50% 的 Angular DI 知识,由于当时还不具备组件知识,所以我们无法完成另外 50% 的学习. 经过了几篇组 ...

  2. [33](CSP 集训)CSP-S 模拟 4

    A 商品 对于任意一组相邻的数 \((l,r)\ (l\le r)\),可以发现,不管怎么压缩,都会有 \(l\le r\),也就是说,相邻两个数的大小关系是不变的 那么我们就可以把 \(\sum(| ...

  3. 手搓大模型Task03:手搓一个最小的 Agent 系统

    前言   训练一个大模型是一件高投入低回报的事情,况且训练的事情是由大的巨头公司来做的事情:通常我们是在已有的大模型基础之上做微调或Agent等:大模型的能力是毋庸置疑的,但大模型在一些实时的问题上, ...

  4. 关于pytorch中@和*的用处

    1.@是用来对tensor进行矩阵相乘的: import torch d = 2 n=50 X = torch.randn(n,d) true_w = torch.tensor([[-1.0],[2. ...

  5. 15 Transformer 框架概述

    博客配套视频链接: https://space.bilibili.com/383551518?spm_id_from=333.1007.0.0 b 站直接看 配套 github 链接:https:// ...

  6. 博客配套视频已上传至 B 站,欢迎关注

    博客配套视频已上传至 B 站,欢迎关注+一键三连 链接: https://space.bilibili.com/383551518?spm_id_from=333.1007.0.0 b 站直接看 链接 ...

  7. WiFi基础(六):天线基础知识

    liwen01 2024.10.01 前言 麦克斯韦预言了电磁波的存在,赫兹通过实验证实了麦克斯韦的预言,马可尼基于无线电磁波的原理发明了无线电报系统,从此人类进入无线通信系统时代. 天线是通信系统中 ...

  8. KubeSphere 社区双周报 | OpenFunction v1.0.0 发布 | 2023.03.03-03.16

    KubeSphere 社区双周报主要整理展示新增的贡献者名单和证书.新增的讲师证书以及两周内提交过 commit 的贡献者,并对近期重要的 PR 进行解析,同时还包含了线上/线下活动和布道推广等一系列 ...

  9. 为 KubeSphere 集群启用免费的泛域名 SSL 证书并实现证书自动更新和分发

    作者:scwang18,主要负责技术架构,在容器云方向颇有研究. 前言 KubeSphere 集群默认安装的证书是自签发证书,浏览器访问访问会发出安全提醒.本文记录了利用 let's encrytp ...

  10. 快速部署mysql并开启binlog

    curl -fsSL https://get.docker.com | bash yum -y install docker-ce sudo systemctl start docker sudo s ...