我的模型看起来像:
class MySchedule(models.Model):
start_datetime=models.DateTimeField()
name=models.CharField('Name',max_length=75)
随之而来的是它的ModelForm:
class MyScheduleForm(forms.ModelForm):
startdate=forms.DateField()
starthour=forms.ChoiceField(choices=((6,"6am"),(7,"7am"),(8,"8am"),(9,"9am"),(10,"10am"),(11,"11am"),
(12,"noon"),(13,"1pm"),(14,"2pm"),(15,"3pm"),(16,"4pm"),(17,"5pm"),
(18,"6pm"
startminute=forms.ChoiceField(choices=((0,":00"),(15,":15"),(30,":30"),(45,":45")))),(19,"7pm"),(20,"8pm"),(21,"9pm"),(22,"10pm"),(23,"11pm")))
class Meta:
model=MySchedule
def clean(self):
starttime=time(int(self.cleaned_data.get('starthour')),int(self.cleaned_data.get('startminute')))
return self.cleaned_data
try:
self.instance.start_datetime=datetime.combine(self.cleaned_data.get("startdate"),starttime)
except TypeError:
raise forms.ValidationError("There's a problem with your start or end date")
基本上,我试图将模型中的DateTime字段分成3个更容易使用的表单字段 - 日期选择器,小时下拉列表和分钟下拉列表。然后,一旦我获得了三个输入,我将它们重新组合成DateTime并将其保存到模型中。
几个问题:
1)这完全是错误的做法吗?我不想在模型中创建小时,分钟等字段,因为这基本上只是中间数据,所以我想要一种方法将DateTime字段分解为子字段。
2)我遇到的困难是当startdate字段为空时 - 似乎永远不会检查非空白,并且当程序需要一个日期并获得时,它最终会抛出一个TypeError没有。 Django在哪里检查空白输入,并提出最终返回到表单的错误?这是我的责任吗?如果是这样,我该怎么做,因为它不评估clean_startdate(),因为startdate不在模型中。
3)有没有更好的方法来继承?也许在BetterScheduleForm中继承MyScheduleForm并在那里添加字段?我该怎么做? (我一直在玩它超过一个小时,似乎无法得到它)
谢谢!
[编辑:]关闭返回self.cleaned_data - 原来在复制/粘贴中丢失了
答案 0 :(得分:1)
如果我是你,我会使用customised Django-admin date/time widget(s)输入日期/时间条目。
关于表单验证,请确保传递与其请求关联的表单以显示基于表单的错误。 (以下示例代码)
至于使用继承,对于这个用例来说这将是一种过度杀伤,因为它不会用于任何目的,并且最好保持简单。
示例代码:
if request.POST:
form = MyScheduleForm(request.POST)
if form.is_valid():
# Specific stuff with the variables here
pass
else:
form = MyScheduleForm()
答案 1 :(得分:1)
好的,我想我明白了:
从Django 1.2开始,运行is_valid()会触发ModelForms上的MODEL验证。我曾假设在访问模型clean()函数之前将检查字段是否为空值,因此我的clean函数不会检查空值或None类型。基本上,我的模型中的clean()看起来像:
def clean(self):
if self.start_datetime > datetime.now():
raise ValidationError('Start date can\'t be in the future')
所以我想这主要是回答我的问题。但是,我还剩1个问题:
最好检查模型clean()中的空白值,还是有更好的方法来执行此操作?似乎很难检查模型中的空白而不是ModelForm中的空白 - 表单字段上的验证是否应该标记必填字段上缺少的输入?
感谢大家的帮助。
答案 2 :(得分:0)
1:我认为这不对,因为你有一些非常具体的东西:
2:更新:以下评论表示默认情况下您的字段应为required=True
。这是真的,如果字段留空,您应该在表单中获得ValidationError
。
你能发布你所说的TypeError
吗?它发生在clean()
区块之外吗?因为如果你没有像你的例子那样从你的清理函数中返回cleaned_data
,你的表单将没有任何数据可用,即使它最初通过不提出任何ValidationErrors
来检出。
无论如何,您可以探索每个字段验证的clean_
方法。
def clean_startdate(self):
if not self.cleaned_data['startdate']:
raise forms.ValidationError("Must enter a start date")
http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#overriding-the-clean-method
3:你能在这里澄清一下你要继承什么吗?您的字段定义看起来非常特定于此表单,因此它属于MyScheduleForm
。继承是重用代码:)
如果您希望将其重用于多个DateTimeField
,是的,您可以使用表单继承。您可以像现在一样定义ModelForm
,将其子类化,并覆盖父文件Meta
,如文档中所示,以便在多个模型上使用它:
http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#form-inheritance
我还会看看django如何处理它的SplitDateTimeWidget(检查源代码): http://docs.djangoproject.com/en/dev/ref/forms/widgets/#django.forms.SplitDateTimeWidget
还有一些其他'第三方'分割日期时间小部件也值得一看在互联网上!
答案 3 :(得分:0)
对于可能包含空值的表单字段,您必须按如下方式声明该字段:
start_datetime=models.DateTimeField(blank=True, null=True)
这告诉表单它可以是blank
,数据库字段可以是null
。这可能会解决这个问题。
如果您尝试包含不属于模型的字段,为什么要使用ModelForm? ModelForms旨在快速创建直接绑定到模型的表单。当然,他们有各种自定义,但改变实际字段在我看来是常规表单的用途。
否则,如果您只想拆分formm的VIEW而不是表单本身,请创建一个自定义窗口小部件以显示DateTime字段,例如SplitDateTimeWidget。对其进行子类化,并为下拉列表的值提供选择。