从函数和前缀字符串在 Django 中创建默认 ID

Creating a default ID in Django from a function and prefix string

我需要做的是 运行 一个函数,并在该函数返回的结果的开头附加一个前缀。每次为我的模型创建新实例时都需要这样做。

我试过的....

以下将不起作用,因为您不能将字符串添加到函数并将 ID 设置为 s_<function name etc> 而不是函数的结果。

APP_PREFIX = "_s"
id = models.CharField(primary_key=True, max_length=50, unique=True,
                      default="{}{}".format(APP_PREFIX, make_id))

也不会将前缀传递给函数,因为 Django 每次以这种方式调用函数时都会生成相同的键,不知道为什么:

id = models.CharField(primary_key=True, max_length=50, unique=True,
                      default=make_id(APP_PREFIX))

这也行不通:

id = models.CharField(primary_key=True, max_length=50, unique=True,
                      default=make_id + APP_PREFIX)

或者这样:

id = models.CharField(primary_key=True, max_length=50, unique=True,
                      default=make_id() + APP_PREFIX)

如何实现?

我可以重写 save() 方法并实现此目的,但必须有一种方法可以使用字段上的默认参数来完成此操作!

您可以为您的模型创建自定义管理器并覆盖 create() 方法。然后,在 create() 方法中,您可以通过显式调用 make_id 函数来生成 ID 字段。唯一的问题是您不应该为 id 字段设置默认值 属性。

所以模型看起来像这样:

class MyModel(models.Model):
  id = models.CharField(primary_key=True, max_length=50, unique=True)
  objects = MyModelManager()

那么,MyModelManager 的实现应该是这样的:

class MyModelManager(models.Manager):
  def create(self, **kwargs):
    kwargs['id'] = make_id()
    return super(MyModelManager, self).create(**kwargs)

当然,您应该将创建模型实例所需的任何其他参数添加到创建方法中。

然后通过以下方式创建 MyModel 的对象实例:

my_model = MyModel.objects.create()

或者,如果您想使用默认值 属性,以下内容应该适合您:

class MyModel(models.Model):
  APP_PREFIX = "_s"
  id = models.CharField(primary_key=True, max_length=50, unique=True,
                        default=lambda: generate_id(MyModel.APP_PREFIX))

def generate_id(prefix):
  return make_id() + prefix

重写save方法应该很容易实现:

from django.db import models

class YourModel(models.Model):
    id = models.CharField(primary_key=True, max_length=50, unique=True)
    # other fields for YourModel

    def make_id():
        return base64.b64encode(uuid.uuid4().bytes).decode("utf-8")

    def save(self, *args, ***kwargs):
        if not self.id:
            self.id = self.make_id()
        super(YourModel, self).save(*args, **kwargs)

最终 make_id 不是 YourModel 的方法,但这只是代码中的一个小改动。在方法 save 中,您可以连接 "s_" 或任何您需要的东西。仅当条目没有任何 ID(意味着它尚不存在)时才会生成 ID。

使用 self.pk 可能是另一种(也许)更好的方法。您可以省略显式创建字段 id.

我找到了一种在我的模型上实现此目的的方法:

PREFIX = settings.PREFIXES['THIS']
def get_id():
  return make_id(PREFIX)

    class MyModel(models.Model):
        id = models.CharField(primary_key=True,unique=True,
                                  default=get_id,)

提示:使用 functools 创建可调用对象。
下面的示例将生成带前缀的散列,例如 tag_HKh7788GjhbJu8K

import random
import string
from functools import partial

class PrefixedHashField(models.CharField):

    @staticmethod
    def gen_value(prefix, hash_length):
        hashtext = ''.join(random.choices(string.ascii_letters + string.digits, k=hash_length))
        return f"{prefix}_{hashtext}"

    def __init__(self, *args, **kwargs):
        prefix = kwargs.pop('prefix')
        hash_length = kwargs.pop("hash_length")
        kwargs['default'] = partial(self.gen_value, prefix, hash_length)
        super(PrefixedHashField, self).__init__(*args, **kwargs)


class Tag(models.Model):
    id = PrefixedHashField(primary_key=True, prefix="tag", hash_length=15, max_length=30)