首页 > 解决方案 > 如何从出生日期计算年龄作为 DateField?

问题描述

这是我正在试验 Django 文档的第一个项目:一个Person模型。和两个特色视图(一个用于创建人员,另一个用于查看创建的人员列表)。到目前为止,一个人只有两个CharFieldsfirst_namelast_name

我现在想做的是实现 a BooleanField adultTrue如果今天的日期和出生日期之间的差异大于或等于 18 (或 16,没关系),则返回。

可能我还会age根据相同的原则实现一个属性。显然,adultage.

这如何在 Django 中实现?我应该在哪里编写使数学推导的代码adult/age?在models.py、forms.py、views.py 或者模板里面?

PS 我知道看到属性被声明为 DurationField 看起来很奇怪age,但正如我所说的,我正在尝试使用不同的属性字段。如果我的问题的答案需要将其更改为,例如PositiveInteger,我不介意更改它。

我的 models.py 看起来像这样

from django.db import models


# Create your models here.
class Person(models.Model):
    first_name = models.CharField(max_length=20)
    last_name = models.CharField(max_length=30)
    adult = models.BooleanField(default=False)
    date_of_birth = models.DateField(default=None)
    created_on = models.DateTimeField(auto_now_add=True, auto_now=False)
    updated_on = models.DateTimeField(auto_now_add=False, auto_now=True)
    age = models.DurationField(default=None)

我的 forms.py 如下

from django import forms
from .models import Person


class CreatePersonForm(forms.ModelForm):
    class Meta:
        model = Person
        fields = [
            'first_name',
            'last_name',
            'adult',
            'date_of_birth',
            'age',

        ]

这是我的views.py

from django.shortcuts import render
from .models import Person
from .forms import CreatePersonForm


# Create your views here.
def home_view(request):
    return render(request, 'home.html')


def persons_list_view(request):
    persons = Person.objects.all()
    context = {
        'persons': persons
    }
    return render(request, 'persons_list.html', context)


def create_person_view(request):
    if request.method == 'POST':
        form = CreatePersonForm(request.POST)
        persons = Person.objects.all()
        context = {
            'persons': persons
        }
        if form.is_valid():
            instance = form.save(commit=False)
            instance.save()
            return render(request, 'persons_list.html', context)
    else:
        form = CreatePersonForm()
    context = {'form': form}
    return render(request, 'create_person.html', context)

感谢您提前提供任何帮助

编辑

我尝试在 views.py 中编写减法(如建议的那样),并运行了所有迁移,但是当我尝试在 localhost 上创建一个新人时,我收到以下错误:

Exception Type: TypeError
Exception Value:    
unsupported operand type(s) for -: 'DeferredAttribute' and 'DeferredAttribute'

这似乎是由这行代码引起的if (Person.date_today - Person.date_of_birth) >= 18:。我也尝试过 这个解决方案,它涉及models.py而不是views.py,但我得到了同样的错误。我也在尝试在 Django 文档上找到一些东西,但我不得不说这并不是真正的“初学者友好”。

可能我应该提一下,我只有基本的 Python 知识,而且我可能把事情推得太远了。

我忘了上传我写的代码:

def create_person_view(request):
    if (Person.date_today - Person.date_of_birth) >= 18:
        Person.adult=True
    if request.method == 'POST':
        form = CreatePersonForm(request.POST)
        persons = Person.objects.all()
        context = {
            'persons': persons
        }
        if form.is_valid():
            instance = form.save(commit=False)
            instance.save()
            return render(request, 'persons_list.html', context)
    else:
        form = CreatePersonForm()
    context = {'form': form}
    return render(request, 'create_person.html', context)

这就是我在 models.py 中评估的

class Person(models.Model):
    first_name = models.CharField(max_length=20)
    last_name = models.CharField(max_length=30)
    adult = models.BooleanField(default=False)
    date_of_birth = models.DateField(default=None)
    date_today = models.DateField(auto_now=True)

编辑 2

我现在正在从 python 文档中尝试这个解决方案(在方法部分,重新​​排列婴儿潮一代的状态),但是,它在 models.py 而不是 views.py 中进行计算(如对这个问题的评论中所建议的那样)。

所以我尝试了类似的方法:

class Person(models.Model):
    first_name = models.CharField(max_length=20)
    last_name = models.CharField(max_length=30)
    adult = models.BooleanField(default=False)
    date_of_birth = models.DateField(default=None)

    def __str__(self):
        return '%s %s' % (self.first_name, self.last_name)

    def is_adult(self):
        import datetime
        if (datetime.date.today() - self.date_of_birth) > datetime.timedelta(days=18*365):
            self.adult = True

这次我没有收到任何错误,但是当我尝试使用管理员创建一个出生于 1985 年 4 月 28 日的人并保存它时,成人仍然是错误的。有谁知道如何实际实现这一点?

标签: djangoattributesderived

解决方案


要回答您修改后的问题,成人保持错误的原因是因为您没有在方法结束时保存更新的模型对象实例。您可能想要做的是在保存时更新成人字段,或使用 post_save 信号。

假设您的 is_adult() 方法中的年龄计算逻辑是正确的,您所要做的就是覆盖模型上的 save 方法,如下所示:

class Person(models.Model):
    first_name = models.CharField(max_length=20)
    last_name = models.CharField(max_length=30)
    adult = models.BooleanField(default=False)
    date_of_birth = models.DateField(default=None)

    def __str__(self):
        return '%s %s' % (self.first_name, self.last_name)

    def is_adult(self):
        import datetime
        if (datetime.date.today() - self.date_of_birth) > datetime.timedelta(days=18*365):
            self.adult = True

    def save(self, *args, **kwargs):
        self.is_adult()
        super(MyModel, self).save(*args, **kwargs)

推荐阅读