Django - URL中的非短线非可预测ID

时间:2017-04-06 11:16:50

标签: python django django-models django-views

我知道有类似的问题(例如thisthisthisthis)但我有特定的要求,并寻找更便宜的方法以下(关于Django 1.10.2):

希望在网址中包含顺序/可猜测的整数ID,并且理想情况下符合以下要求:

  • 避免UUID,因为这会使URL真的很长。
  • 避免使用自定义主键。如果模型具有ManyToManyFields,它似乎不能很好地工作。在尝试(#25012#24030#22997时受到至少三个错误的影响,包括搞乱迁移并且必须删除整个数据库并重新创建迁移(好吧,很多)也很好的学习)
  • 尽可能避免检查冲突(因此避免对每个插入进行数据库查找)
  • 不要仅仅想要查看slug,因为它不仅仅是查找整数id。
  • 不要太在意加密id - 只是不想要它 是一个明显的顺序整数。

注意:从长远来看,该应用程序可能会有500万条记录。

1 个答案:

答案 0 :(得分:4)

在SO,博客等方面研究了很多选项后,我最终做了以下事情:

  • 将ID编码为base32 仅用于以获取URL并在urls.py中将其解码回来(使用已编辑的Django util functions版本编码到base 36,因为我需要使用大写字母代替小写的。)
  • 不将编码的id 存储在任何地方。只需动态编码和解码即可。
  • 保持默认ID不变并将其用作主键。

(好hintsposts,特别是this评论有很多帮助)

此解决方案有助于实现:

  1. 绝对不会对模型或post_save信号进行编辑。
  2. 无需进行碰撞检查。避免向db发送一个额外请求。
  3. 查找仍然发生在快速的默认ID上。此外,对于每个插入,模型上没有double save()请求。
  4. 短而甜的编码ID(字符数随着记录数量的增加而增加但仍不会很长)
  5. 它没有帮助实现/任何缺点:

    1. 加密 - ID已编码但未加密,因此用户可以 仍然能够找出模式来获取id(但我不 如上所述,关心它很多。
    2. 对每个URL构造/请求进行编码和解码的微小开销,但可能比模型对象上的冲突检查和/或多次save()调用更适合插入。
    3. 作为参考,看起来有很多方法可以生成我在路上发现的随机ID(比如Django的get_random_string,Python的随机,Django的UUIDField等)以及编码当前的许多方法ID(基数36,基数62,异或,什么不是)。 编码的ID也可以存储为另一个(索引的)字段,并且每次都会查找(例如here)但是取决于Web应用程序的性能参数(因为查找varchar id不太容易查找整数id)。这个标识符字段既可以从覆盖模型的save()函数中保存,也可以使用post_save()信号保存(参见here)(两种方法都需要为每个插入调用save()函数两次)。

      所有人都倾向于对上述方法进行优化。我喜欢SO和社区。每次在这里学到很多东西。

      更新:在这篇文章发表一年多之后,我发现了这个名为hashids的优秀图书馆,它做得非常相似!它有多种语言版本,包括Python