【问题标题】:Django - short non-linear non-predictable ID in the URLDjango - URL中的短非线性不可预测ID
【发布时间】:2017-09-01 09:22:58
【问题描述】:

我知道有类似的问题(如 thisthisthisthis),但我有特定的要求并正在寻找一种更便宜的方法来执行以下操作(在 Django 1.10.2 ):

希望在 URL 中具有连续/可猜测的整数 ID,并且理想情况下满足以下要求:

  • 避免使用 UUID,因为这会使 URL 非常长。
  • 避免使用自定义主键。如果模型有 ManyToManyFields,它似乎不能很好地工作。在尝试时受到至少三个错误的影响(#25012#24030#22997),包括弄乱迁移并不得不删除整个数据库并重新创建迁移(嗯,还有很多很好的学习)
  • 尽可能避免检查冲突(因此避免对每个插入进行数据库查找)
  • 不要只通过 slug 进行查找,因为它的性能不如仅查找整数 id。
  • 不要太在意加密 id - 只是不希望它加密 是一个可见的连续整数。

注意:从长远来看,该应用可能有 500 万条左右的记录。

【问题讨论】:

    标签: python django django-models django-views


    【解决方案1】:

    在研究了很多关于 SO、博客等的选项后,我最终做了以下事情:

    • 为 URL 将 id 编码为 base32 并在 urls.py 中将其解码(使用 Django 的 util functions 的编辑版本编码为 base 36,因为我需要大写字母而不是小写字母)。
    • 不在任何地方存储编码的ID。每次即时进行编码和解码。
    • 保持默认 ID 不变并将其用作主键。

    (好的hintsposts 尤其是this 评论帮助很大)

    此解决方案有助于实现的目标:

    1. 绝对不修改模型或 post_save 信号。
    2. 不需要碰撞检查。避免向数据库发出一个额外请求。
    3. 仍然会在默认 ID 上进行查找,这很快。此外,每个插入的模型都没有双重保存()请求。
    4. 短而甜的编码ID(字符数随着记录数的增加而增加,但仍然不是很长)

    它无助于实现什么/任何缺点:

    1. 加密 - ID 已编码但未加密,因此用户可以 仍然能够找出获取 id 的模式(但我不知道 非常关心它,如上所述)。
    2. 每个 URL 构造/请求的编码和解码开销很小,但这可能比碰撞检查和/或对模型对象多次调用 save() 以进行插入要好。

    作为参考,看起来有多种方法可以生成我在此过程中发现的随机 ID(如 Django 的 get_random_string、Python 的随机、Django 的 UUIDField 等)以及许多编码当前 ID 的方法(基数 36 ,base 62,XORing,等等)。 编码后的 ID 也可以存储为另一个(索引)字段并每次查找(如 here),但取决于 Web 应用程序的性能参数(因为查找 varchar id 的性能不如查找整数 id )。此标识符字段可以从覆盖模型的 save() 函数中保存,也可以使用 post_save() 信号(请参阅here)(虽然这两种方法都需要为每次插入调用两次 save() 函数)。

    全心全意对上述方法进行优化。我爱 SO 和社区。每次在这里都可以学到很多东西。

    更新: 写完这篇文章一年多后,我发现了这个名为 hashids 的很棒的库,它几乎完成了同样的事情!它支持多种语言,包括Python

    【讨论】:

      猜你喜欢
      • 2012-07-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-02
      相关资源
      最近更新 更多