[英]How to make a Django model fields calculated at runtime?
I have a model: 我有一个模特:
class Person (models.Model):
name = models.CharField ()
birthday = models.DateField ()
age = models.IntegerField ()
I want to make age
field to behave like a property: 我想让
age
字段表现得像一个属性:
def get_age (self):
return (datetime.datetime.now() - self.birthday).days // 365
age = property (get_age)
but at the same time I need age
to be a true field, so I can find it in Person._meta.fields
, and assign attributes to it: age.help_text = "Age of the person"
, etc. 但同时我需要
age
才能成为真正的领域,所以我可以在Person._meta.fields
找到它,并为其指定属性: age.help_text = "Age of the person"
等。
Obviously I cannot just override Person.save()
method to calculate and store age
in the database, because it inevitably will become wrong later (in fact, it shouldn't be stored in the database at all). 显然我不能只重写
Person.save()
方法来计算和存储数据库中的age
,因为它以后不可避免地会出错(事实上,它根本不应该存储在数据库中)。
Actually, I don't need to have setters now, but a nice solution must have setting feature. 实际上,我现在不需要设置setter,但是一个好的解决方案必须具有设置功能。
Is it possible in Django, or probably there is a more pythonic and djangoic approach to my problem? 是否有可能在Django,或者可能有更多的pythonic和djangoic方法来解决我的问题?
you're going about it in a strange way. 你是以一种奇怪的方式去做的。 you only need to store the birthday (which you're already doing).
你只需要存储生日(你已经在做)。
if you need to do queries based on age, take in the age, and then search on the birthdays that fit the requirements. 如果您需要根据年龄进行查询,请考虑年龄,然后搜索符合要求的生日。
from datetime import datetime
# get people over 50
age = 50 # in years
age_ago = datetime.now() - age # use timedelta i don't know the syntax off the top of my head
Person.objects.filter(birthday__lte=age_ago) # people whose birthday is before fifty years ago
you said it yourself "[age] shouldn't be stored in the database at all" 你自己说过“[年龄]根本不应该存储在数据库中”
you're right. 你是对的。 there is no reason to have the age field... just the property will be fine.
没有理由拥有年龄领域...只是财产将没事。
Another way to go about it which might be simpler, is to use custom form in the admin model. 另一种可能更简单的方法是在管理模型中使用自定义表单。 Something like this:
像这样的东西:
class Person (models.Model):
birthday = models.DateField()
class PersonForm(forms.ModelForm):
age = forms.IntegerField() # This will not be in the database
class Meta:
model = Person
def __init__(self, *args, **kwargs):
# verify instance was passed
instance = kwargs.get('instance')
if instance:
self.base_fields['age'].initial = (datetime.datetime.now() - self.birthday).days
super(PersonForm, self).__init__(*args, **kwargs)
class FooAdmin(admin.ModelAdmin):
form = PersonForm
# Save the age in the birthday field
def save_model(self, request, obj, form, change):
obj.birthday = datetime.datetime.now() + form.cleaned_data['age']
obj.save()
I think the solution is to create a custom widget for the birthday field. 我认为解决方案是为生日字段创建自定义窗口小部件。 All you want is to change how the birthday is displayed and how it is edited.
您只想更改生日的显示方式和编辑方式。 that is exactly the widget purpose.
这正是小部件的目的。
Sorry I don't have the code for that, but here is a good place to start: 对不起,我没有相应的代码,但这是一个很好的起点:
https://docs.djangoproject.com/en/dev/ref/forms/widgets/ https://docs.djangoproject.com/en/dev/ref/forms/widgets/
You can achieve this by using django-computed-property . 您可以使用django-computed-property实现此目的。
You first have to pip install django-computed-property with the following command: 首先必须使用以下命令pip install django-computed-property :
pip install django-computed-property
You then add computed_property
to your list of INSTALLED_APPS
in settings.py : 然后,添加
computed_property
到你的列表INSTALLED_APPS
在settings.py:
INSTALLED_APPS = [
...
'computed_property'
]
Now you can import and use the included field classes in your models like so: 现在,您可以在模型中导入和使用包含的字段类,如下所示:
from django.db import models
from computed_property import ComputedTextField
import random
class Person(models.Model):
age = ComputedTextField(compute_from='calculation')
@property
def calculation(self):
return str(random.randint(1,101))
The age field on the Person model returns a random number each time it is called to demonstrate that it is calculated at runtime. Person模型上的age字段每次调用时都会返回一个随机数,以证明它是在运行时计算的。
You can read values from the age field as usual, but you may not set the field's value.
您可以照常读取年龄字段中的值,但不能设置字段的值。 When the field is accessed and when a model instance is saved, it will compute the field's value using the provided callable (function/lambda), property
age
, or attributeage
访问该字段并保存模型实例时,它将使用提供的可调用(函数/ lambda),属性
age
或属性age
来计算字段的值
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.