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

时间:2022-06-01 11:47:38

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:

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

    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.

但同时我需要年龄才能成为一个真正的领域,所以我可以在Person._meta.fields中找到它,并为其指定属性:age.help_text =“人的年龄”等。

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()方法来计算和存储数据库中的年龄,因为它以后不可避免地会出错(事实上,它根本不应该存储在数据库中)。

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方法来解决我的问题?

3 个解决方案

#1


3  

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.

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

#2


1  

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

#3


0  

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/

#1


3  

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.

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

#2


1  

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

#3


0  

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/