如何在运行时计算Django模型字段?

时间:2010-04-02 13:17:27

标签: python django django-models field

我有一个模特:

class Person (models.Model):
    name     = models.CharField ()
    birthday = models.DateField ()
    age      = models.IntegerField ()

我想让age字段表现得像一个属性:

    def get_age (self):
        return (datetime.datetime.now() - self.birthday).days // 365

    age = property (get_age)

但与此同时我需要age成为真正的字段,因此我可以在Person._meta.fields中找到它,并为其指定属性:age.help_text = "Age of the person"等。

显然我不能只重写Person.save()方法来计算和存储age数据库,因为以后它不可避免地会出错(事实上,它根本不应该存储在数据库中)

实际上,我现在不需要设置setter,但一个不错的解决方案必须具有设置功能。<​​/ p>

是否有可能在Django,或者可能有更多的pythonic和djangoic方法解决我的问题?

4 个答案:

答案 0 :(得分:3)

你会以一种奇怪的方式谈论它。你只需要存储生日(你已经在做)。

如果您需要根据年龄进行查询,请考虑年龄,然后搜索符合要求的生日。

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

你自己说过“[年龄]根本不应该存储在数据库中”

你是对的。没有理由拥有年龄领域...只是财产会没事。

答案 1 :(得分:1)

另一种可能更简单的方法是在管理模型中使用自定义表单。 像这样:

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()

答案 2 :(得分:0)

我认为解决方案是为生日字段创建自定义窗口小部件。 您只想更改生日的显示方式和编辑方式。 这正是小部件的目的。

抱歉,我没有相应的代码,但这是一个很好的起点:

https://docs.djangoproject.com/en/dev/ref/forms/widgets/

答案 3 :(得分:0)

您可以使用django-computed-property来实现。

您首先必须使用以下命令来安装 django-computing-property

pip install django-computed-property

然后,您在 settings.py 中将computed_property添加到INSTALLED_APPS的列表中:

INSTALLED_APPS = [
    ...
    'computed_property'
]

现在,您可以像这样导入和使用模型中包含的字段类:

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))

Person模型上的age字段在每次调用时都会返回一个随机数,以证明它是在运行时计算得出的。

  

您可以照常从“年龄”字段中读取值,但可能没有设置   字段的值。何时访问字段以及何时建立模型   实例已保存,它将使用来计算该字段的值   提供的可调用(函数/ lambda),属性age或属性age

相关问题