繁体   English   中英

将字段添加到不在模型中的Django ModelForm

[英]Add fields to Django ModelForm that aren't in the model

我的模型看起来像:

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字段为空时 - 似乎永远不会检查非空白,并且当程序期望日期并且获得None时,最终会抛出TypeError。 Django在哪里检查空白输入,并提出最终返回到表单的错误? 这是我的责任吗? 如果是这样,我该怎么做,因为它不评估clean_startdate()因为startdate不在模型中。

3)有没有更好的方法来继承? 也许在BetterScheduleForm中继承MyScheduleForm并在那里添加字段? 我该怎么做? (我一直在玩它超过一个小时,似乎无法得到它)

谢谢!

[编辑:]关闭返回self.cleaned_data - 最初在复制/粘贴中丢失

  1. 如果我是你,我会使用自定义的Django-admin日期/时间小部件来输入日期/时间条目。

  2. 关于表单验证,请确保传递与请求相关联的表单以显示基于表单的错误。 (以下示例代码)

  3. 至于使用继承,对于这个用例来说这将是一种过度杀伤,因为它不会用于任何目的,并且最好保持简单。

示例代码:

if request.POST:
    form = MyScheduleForm(request.POST)
    if form.is_valid():
        # Specific stuff with the variables here
        pass
else:
    form = MyScheduleForm()

好的,我想我弄清楚了:

从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()中检查空白值,还是有更好的方法来做到这一点? 似乎hackish检查模型中的空白而不是ModelForm中的空白 - 表单字段上的验证是否应标记所需字段上缺少的输入?

谢谢大家的帮助。

1:我认为这不对,因为你有一些非常具体的东西:

  • 具体时间条目(中午,下午5点结束..)
  • startminutes增加15分钟

2:更新:下面的评论说明你的字段应该是required=True默认required=True 确实,如果该字段留空,您应该使用表单获取ValidationError

你可以发布你正在谈论的TypeError吗? 它发生在clean()块之外吗? 因为如果你没有像你的示例中那样从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 /#形式继承

我还要看看django如何处理它的SplitDateTimeWidget(检查源代码): http ://docs.djangoproject.com/en/dev/ref/forms/widgets/#django.forms.SplitDateTimeWidget

还有一些其他的“第三方”分割日期时间小部件也值得一看在互联网上!

对于可能包含空值的表单字段,您必须按如下方式声明该字段:

start_datetime=models.DateTimeField(blank=True, null=True)

这告诉表单它可以是blank ,并且数据库字段可以为null 这可能解决了这个问题。

如果您尝试包含不属于模型的字段,为什么要使用ModelForm? ModelForms旨在快速创建直接绑定到模型的表单。 当然,他们有各种自定义,但改变实际字段在我看来是常规表单的用途。

否则,如果您只想拆分formm的VIEW而不是表单本身,则创建一个自定义小部件以显示DateTime字段,例如SplitDateTimeWidget。 对其进行子类化,并为下拉列表的值提供您的选择。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM