前言

本来标题是想叫“生成不重复的四位数”的,不过单纯数字有点局限,推广一下变成不重复 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. 前置机器学习(二):30分钟掌握常用Jupyter Notebook用法

    相较于Pycharm执行py文件来说,Jupyter Notebook可保存执行过程,添加图表.注释等富文本说明的功能,使其对机器学习的开发者格外友好. 本文包含机器学习环境安装,Jupyter No ...

  2. 月薪20k以上的软件测试工程师的必备知识点?全部拿走吧!

    我们都知道作为一个软件测试工程师,入门相对比较简单,但是要达到技术精通,甚至薪资能达到20k以上的话,那绝对需要对测试开发有一个系统的了解,以及对这些系统的知识能够熟练掌握. 今天的话是我从阿里以为做 ...

  3. linux安装SVN并设置SVN钩子

    linux安装SVN并设置SVN钩子 检查已安装版本 #检查是否安装了低版本的SVN rpm -qa subversion #卸载旧版本SVN yum rovesubversion 一.安装SVN y ...

  4. cf2009 Codeforces Round 971 (Div. 4)

    A. Minimize! 签到题.计算\((c-a)+(b-c)\)的最小值,其实值固定的,等于\(b-a\). int a, b; void solve() { cin >> a > ...

  5. 墨天轮专访星环科技刘熙:“向量热”背后的冷思考,Hippo如何打造“先发”优势?

    导读: 深耕技术研发数十载,坚持自主可控发展路.星环科技一路砥砺前行.坚持创新为先,建设了全面的产品矩阵,并于2022年作为首个独立基础软件产品公司成功上市.星环科技在今年的向星力•未来技术大会上发布 ...

  6. C# 的布尔类型和字符串类型(模板字符串)

    // 布尔类型 boll bool b = false; b = 1 == 1; // true bool b1 = 1 > 23; // false // 值类型 : 在代码中初始化类型的时候 ...

  7. DataDream:调一调更好,基于LoRA微调SD的训练集合成新方案 | ECCV'24

    尽管文本到图像的扩散模型已被证明在图像合成方面达到了最先进的结果,但它们尚未证明在下游应用中的有效性.先前的研究提出了在有限的真实数据访问下为图像分类器训练生成数据的方法.然而,这些方法在生成内部分布 ...

  8. python机器学习(第一章 Python机器学习基础)

    第一章 Python机器学习基础 基础: Python官网:https://www.python.org/doc/: 历史版本下载与维护信息:https://www.python.org/downlo ...

  9. OpenFeign简单使用

    OpenFeign入门 什么是 OpenFeign? OpenFeign是一个远程访问的组件,用于两个微服务之间互相访问的中间件 OpenFeign使用步骤 1.添加OpenFeign的依赖 < ...

  10. duxapp放弃了redux,在duxapp中局部、全局状态的实现方案

    全局状态 全局状态是一个很实用的功能,例如管理用户信息,组件间状态共享等功能都需要用到全局状态,react有很多成熟的全局状态管理工具,但是很多写起来太过麻烦,duxapp提供了几种应对不同场景的全局 ...