【问题标题】:Generate a random alphanumeric string as a primary key for a model生成随机字母数字字符串作为模型的主键
【发布时间】:2013-12-21 22:49:03
【问题描述】:

我希望模型在创建新实例时自动生成随机字母数字字符串作为其主键。

示例:

from django.db import models

class MyTemporaryObject(models.Model):
    id = AutoGenStringField(lenght=16, primary_key=True)
    some_filed = ...
    some_other_field = ...

在我看来,密钥应该类似于“Ay3kJaBdGfcadZdao03293”。这是非常临时的使用。万一发生冲突,我希望 Django 尝试一个新密钥。

我想知道那里是否已经有一些东西,或者我没有看到一个非常简单的解决方案(我对 python 和 Django 还很陌生)。否则我会考虑做我自己的models.AutoField 版本,那会是正确的方法吗?

我已经找到了如何生成密钥here,所以不是关于字符串生成的。我只想让它与一个简单的 Django 服务无缝协作,而不会给代码增加太多复杂性。

编辑: 可能的解决方案?你怎么看?

id = models.CharField(unique=True, primary_key=True, default=StringKeyGenerator(), editable=False)

class StringKeyGenerator(object):
    def __init__(self, len=16):
        self.lenght = len
    def __call__(self):
        return ''.join(random.choice(string.letters + string.digits) for x in range(self.lenght))

我是在再看一遍 Django 文档后想到的。

【问题讨论】:

  • 这个的用例是什么?很多 Django 特性都假设一个整数主键,最值得注意的是外键字段。我不会说这绝不是一个好主意,但我认为您可能会发现将自动生成的字符串用作另一个字段并设置 unique=True 会更简单。
  • 这是一个临时令牌,用于访问更“隐藏”的数据。访问窗口很短,因此我对避免碰撞的需求大大减少了。
  • (题外话)具有单个__call__ 方法的类称为函数,可以更简洁地编写:def generate_string(length): ''.join(...)
  • 你试过使用default=StringKeyGenerator,不带括号吗?这样,you pass a callable as the attribute,就像 Django 文档中的 UUIDField 示例代码一样。

标签: python django postgresql


【解决方案1】:

在 python 中生成唯一字符串的最简单方法之一是使用uuid 模块。如果你想得到字母数字输出,你也可以简单地使用 base64 编码:

import uuid
import base64
uuid = base64.b64encode(uuid.uuid4().bytes).replace('=', '')
# sample value: 1Ctu77qhTaSSh5soJBJifg

然后您可以将此代码放入模型的 save 方法中,或使用它定义自定义模型字段。

【讨论】:

  • 我不想使用 uuid。抱歉应该早点提到。
  • uuid4 只是一个更聪明的随机字节生成版本,它总是会返回唯一的结果(''.join(...) 这样的简单解决方案并非如此)。
  • +1 很棒的技巧。但是@PeterDeGlopper 回答了我所有的问题,感谢您的帮助。
  • 这不是字母数字:R0oX1ebxQpepGQ/JQsGpNwuCRmokb7QFC+zQCs1hBqNA
【解决方案2】:

在不将该字段设为主键的情况下,我会这样做:

from django.db import IntegrityError

class MyTemporaryObject(models.Model):
    auto_pseudoid = models.CharField(max_length=16, blank=True, editable=False, unique=True)
    # add index=True if you plan to look objects up by it
    # blank=True is so you can validate objects before saving - the save method will ensure that it gets a value

    # other fields as desired

    def save(self, *args, **kwargs):
        if not self.auto_pseudoid:
            self.auto_pseudoid = generate_random_alphanumeric(16)
            # using your function as above or anything else
        success = False
        failures = 0
        while not success:
            try:
                super(MyTemporaryObject, self).save(*args, **kwargs)
            except IntegrityError:
                 failures += 1
                 if failures > 5: # or some other arbitrary cutoff point at which things are clearly wrong
                     raise
                 else:
                     # looks like a collision, try another random value
                     self.auto_pseudoid = generate_random_alphanumeric(16)
            else:
                 success = True

与使用字段作为主键相比,这避免了两个问题:

1) Django 的内置关系字段需要整数键

2) Django 使用数据库中存在的主键作为save 应该更新现有记录而不是插入新记录的标志。这意味着,如果您的主键字段确实发生冲突,它将默默地覆盖该行中曾经存在的任何其他内容。

【讨论】:

  • 那我是不是应该保留原来的整数主键,用伪键搜索呢?这不会减慢请求速度吗?
  • 如果你索引它就不会。至少,不会比使用文本代替整数 PK 更重要。写入会慢一些,因为有两个元素要索引而不是一个。但是如果没有这种方法,我看不到任何方法可以使随机生成的 PK 可靠地检测碰撞。
  • 太好了,我可以忍受慢写。
【解决方案3】:

试试这个:

下面的 if 语句是为了确保模型可以更新。

如果没有 if 语句,您每次重新保存模型时都会更新 id 字段,因此每次都会创建一个新模型

from uuid import uuid4
from django.db import IntegrityError

class Book(models.Model):
    id = models.CharField(primary_key=True, max_length=32)

    def save(self, *args, **kwargs):
        if self.id:
            super(Book, self).save(*args, **kwargs)
            return

        unique = False
        while not unique:
            try:
                self.id = uuid4().hex
                super(Book, self).save(*args, **kwargs)
            except IntegrityError:
                self.id = uuid4().hex
            else:
                unique = True

【讨论】:

    猜你喜欢
    • 2010-09-08
    • 1970-01-01
    • 2021-04-05
    • 2011-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多