动态添加属性到 Django 模型
Dynamically add properties to Django model
目前我有以下Django模型
class TestUser(models.Model):
name = models.CharField(max_length=250)
email = models.CharField(max_length=250)
...
class Meta:
db_table = 'temp_user'
我有以下方法。
def print_name(self):
return self.name
我想将此方法作为 属性 添加到 TempUser
模型。我知道这可以通过将方法放在 TempUser
class 和用户 @property
中来完成。但是我想动态地做。
我从 python shell.
试过这个
In [10]: TempUser.print_name = property(print_name)
In [11]: TempUser.print_name
Out[11]: <property at 0x7efc374e7c58>
In [12]: user = TempUser.objects.get(pk=1)
In [13]: user.print_name
Out[13]: u'Test User'
但是一旦我退出 shell,我就会松开 属性。有什么方法可以永久添加属性。
But once I exit the shell, I loose the property. Is there any way to add the property permanently.
不,不是通过您在 运行 时设置的属性。与 Django 模型实例关联的数据通过数据库持久化。 持久化 数据的唯一选择是在数据库中创建一个用于存储信息的字段。如果您想保留 class 上可用的方法,请编辑源代码。
您也表示希望在 运行 时动态执行此操作。但是,这样做的好处充其量是可疑的,并且可能对您的代码库有害。很难想象一个可证明的用例,它可以解决一个没有更好解决方案的实际问题。几乎可以肯定有更好的方法来实现您的目标。如果您的目标是保持代码干爽,请考虑其他模式,例如从抽象模型继承。
您可以在您的模型 class 上实现常规属性(使用 @property
方法装饰器),这些属性可以获取现有字段并查看相关模型字段以即时组合信息,但是它仍然没有保存在数据库中...
例如,如果您的模型具有 start_time
和 end_time
,您可以添加 total_time
属性 而不必为其创建字段.
class MyModel(models.Model):
start_time = models.DateTimeField()
end_time = models.DateTimeField()
@property
def total_time(self):
return self.end_time - self.start_time
但是,这样做将不允许您对此进行查询 属性。例如 MyModel.objects.filter(total_time__lt=delta)
单独使用 属性 是不可能的。
您拥有的其他一些选项包括 annotation and aggregation,它可以在 运行 时动态完成,并使您能够查询数据库。
使用与上面相同的示例,而不是使用 @property
可以以类似的方式注释查询集,这也允许您在此 'virtual field' 上查询数据库,甚至传递带注释的查询集大约。您甚至可以进行算术和聚合,例如总和、平均值等...
from django.db.models import F, ExpressionWrapper, fields
duration = ExpressionWrapper(F('end_time') - F('start_time'), output_field=fields.DurationField())
qs = MyModel.objects.annotate(duration=duration)
# query for objects with a delta of more than five minutes
results = qs.filter(duration__gt=five_minutes)
简而言之:不,如果可以的话,这几乎肯定是个坏主意。坚持既定的做事方法。 Django 是一个非常自以为是的框架,它是专门为你做事的'the django way'。违背规律只会伤害自己。
目前我有以下Django模型
class TestUser(models.Model):
name = models.CharField(max_length=250)
email = models.CharField(max_length=250)
...
class Meta:
db_table = 'temp_user'
我有以下方法。
def print_name(self):
return self.name
我想将此方法作为 属性 添加到 TempUser
模型。我知道这可以通过将方法放在 TempUser
class 和用户 @property
中来完成。但是我想动态地做。
我从 python shell.
试过这个In [10]: TempUser.print_name = property(print_name)
In [11]: TempUser.print_name
Out[11]: <property at 0x7efc374e7c58>
In [12]: user = TempUser.objects.get(pk=1)
In [13]: user.print_name
Out[13]: u'Test User'
但是一旦我退出 shell,我就会松开 属性。有什么方法可以永久添加属性。
But once I exit the shell, I loose the property. Is there any way to add the property permanently.
不,不是通过您在 运行 时设置的属性。与 Django 模型实例关联的数据通过数据库持久化。 持久化 数据的唯一选择是在数据库中创建一个用于存储信息的字段。如果您想保留 class 上可用的方法,请编辑源代码。
您也表示希望在 运行 时动态执行此操作。但是,这样做的好处充其量是可疑的,并且可能对您的代码库有害。很难想象一个可证明的用例,它可以解决一个没有更好解决方案的实际问题。几乎可以肯定有更好的方法来实现您的目标。如果您的目标是保持代码干爽,请考虑其他模式,例如从抽象模型继承。
您可以在您的模型 class 上实现常规属性(使用 @property
方法装饰器),这些属性可以获取现有字段并查看相关模型字段以即时组合信息,但是它仍然没有保存在数据库中...
例如,如果您的模型具有 start_time
和 end_time
,您可以添加 total_time
属性 而不必为其创建字段.
class MyModel(models.Model):
start_time = models.DateTimeField()
end_time = models.DateTimeField()
@property
def total_time(self):
return self.end_time - self.start_time
但是,这样做将不允许您对此进行查询 属性。例如 MyModel.objects.filter(total_time__lt=delta)
单独使用 属性 是不可能的。
您拥有的其他一些选项包括 annotation and aggregation,它可以在 运行 时动态完成,并使您能够查询数据库。
使用与上面相同的示例,而不是使用 @property
可以以类似的方式注释查询集,这也允许您在此 'virtual field' 上查询数据库,甚至传递带注释的查询集大约。您甚至可以进行算术和聚合,例如总和、平均值等...
from django.db.models import F, ExpressionWrapper, fields
duration = ExpressionWrapper(F('end_time') - F('start_time'), output_field=fields.DurationField())
qs = MyModel.objects.annotate(duration=duration)
# query for objects with a delta of more than five minutes
results = qs.filter(duration__gt=five_minutes)
简而言之:不,如果可以的话,这几乎肯定是个坏主意。坚持既定的做事方法。 Django 是一个非常自以为是的框架,它是专门为你做事的'the django way'。违背规律只会伤害自己。