从函数和前缀字符串在 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)
我需要做的是 运行 一个函数,并在该函数返回的结果的开头附加一个前缀。每次为我的模型创建新实例时都需要这样做。
我试过的....
以下将不起作用,因为您不能将字符串添加到函数并将 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)