如何从出生日期算起年龄作为DateField?

时间:2019-12-01 08:09:25

标签: django attributes derived

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

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

可能我还将基于相同的原理实现属性adult。 显然,从age导出adult/age是完全可以的。

如何在Django中实现?我应该在哪里编写使数学推导age的代码?是在models.py,forms.py,views.py内部还是在模板内部?

P.S。我知道看到PositiveInteger属性被声明为DurationField看起来很奇怪,但是正如我所说的,我正在尝试尝试不同的属性字段。如果我的问题的答案要求将其更改为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) ,则我不介意更改它。

我的models.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',

        ]

我的forms.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)

这是我的观点。py

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

非常感谢您提前提供帮助

编辑

我可以按照建议在views.py中编写减法,并运行所有迁移,但是当我尝试在localhost上创建新人员时,出现以下错误:

if (Person.date_today - Person.date_of_birth) >= 18:

这似乎是由这行代码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) 引起的。 我还尝试了this解决方案,该解决方案涉及models.py而不是views.py,但是出现了同样的错误。我也正在尝试在Django文档中找到某些内容,但是我不得不说它并不是“初学者友好的”。

也许我应该提一下,我只具备基本的Python知识,而且我可能将事情推得太远了。

我忘记上传我编写的代码:

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)

这就是我在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)

    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

编辑2

我现在正在尝试python文档中的this解决方案(在“方法”部分中,重新排列婴儿潮一代的状态),但是,该解决方案在models.py而不是views.py中进行计算(如该问题的评论)。

所以我尝试过类似的事情:

import Combine
import SwiftUI

class ImageLoader: ObservableObject {
    let id: String = UUID().uuidString

    // !!! no need in didChange, @Published is already Publisher
    // see below .onReceive for usage example
    @Published var isPresented = false
    @Published var image: UIImage?

    func load(url: URL) {
        URLSession.shared.dataTask(with: url) { data, _, error in
            DispatchQueue.main.async {
                if error != nil {
                    self.isPresented = true
                    return
                }
                self.image = UIImage(data: data!)
            }
        }.resume()
    }
}

class MySettings: ObservableObject { // << reconstructed for testing
    @Published var name = "My Name"
    @Published var isPresented = false
}

enum ImageURLError: Error {
    case dataIsNotAnImage
}

struct URLImage: View {
    @EnvironmentObject var settings: MySettings
    @ObservedObject var imageLoader: ImageLoader
    var placeholder: Image

    init() {
        self.placeholder = Image(systemName: "photo")
        self.imageLoader = ImageLoader()
    }

    var body: some View {
        VStack {
            imageLoader.image == nil ?
                placeholder : Image(uiImage: imageLoader.image!)
            Button(action: {
                self.settings.name = "Happy Thanks Giving"
                self.settings.isPresented = true
            }, label: {
                Text("Touch Me")
            })
        }
        .onReceive(imageLoader.$isPresented) { self.settings.isPresented = $0 }
    }
}

struct ContentView: View {
    @EnvironmentObject var settings: MySettings
    @State private var url: String = "https://garbage.com"  // << this url is valid
    @State private var image: URLImage = URLImage()
    @State private var angelFish: Image = Image("QueenAngelfish")

    var body: some View {
        ZStack {
            Color.green
            NavigationView {
                VStack {
                    Button(action: {
                        self.url = "garbage.com" // << this url is not valid [to test alert]
                        self.image.imageLoader.load(url: URL(string: self.url)!)
                    }) {
                        Text("Get An Image")
                    }

                    angelFish
                        .resizable()
                        .frame(width: 300, height: 200, alignment: .center)
                        .padding()
                    image
                        .alert(isPresented: $settings.isPresented) {
                            Alert(title: Text(verbatim: "Unable to Acquire Image."))
                        }
                }.navigationBarTitle(Text(settings.name))
            }
        }
    }
}

struct TestDelayedAlert_Previews: PreviewProvider {
    static var previews: some View {
        ContentView().environmentObject(MySettings())
    }
}

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

2 个答案:

答案 0 :(得分:1)

我的想法是将这样的计算结果放入您的views.py中,用户在其中将其date_of_birth输入到表单中。在他提交表单后,它将计算用户是>还是<18/21,并相应地为adult返回true / false。然后将其推送到您的模型。
或者,您可以实现一种逻辑,当用户输入adult时,该逻辑会自动在视图的表单内显示no adultdate_of_birth。确实取决于您想要的解决方案。用户应该在输入后立即看到成人没有成人字段,还是应该进行一些后端处理?

答案 1 :(得分:0)

要回答修改后的问题,成年人保留为假的原因是因为您没有在方法结束时保存更新的模型对象实例。您可能想要做的是在保存时更新Adult字段,或使用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)