简体   繁体   English

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

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

I have a model that looks like: 我的模型看起来像:

class MySchedule(models.Model):
  start_datetime=models.DateTimeField()
  name=models.CharField('Name',max_length=75)

With it comes its ModelForm: 随之而来的是它的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")

Basically, I'm trying to break the DateTime field in the model into 3 more easily usable form fields -- a date picker, an hour dropdown, and a minute dropdown. 基本上,我试图将模型中的DateTime字段分成3个更容易使用的表单字段 - 日期选择器,小时下拉列表和分钟下拉列表。 Then, once I've gotten the three inputs, I reassemble them into a DateTime and save it to the model. 然后,一旦我获得了三个输入,我将它们重新组装成DateTime并将其保存到模型中。

A few questions: 几个问题:

1) Is this totally the wrong way to go about doing it? 1)这完全是错误的做法吗? I don't want to create fields in the model for hours, minutes, etc, since that's all basically just intermediary data, so I'd like a way to break the DateTime field into sub-fields. 我不想在模型中创建小时,分钟等字段,因为这基本上只是中间数据,所以我想要一种方法将DateTime字段分解为子字段。

2) The difficulty I'm running into is when the startdate field is blank -- it seems like it never gets checked for non-blankness, and just ends up throwing up a TypeError later when the program expects a date and gets None. 2)我遇到的困难是当startdate字段为空时 - 似乎永远不会检查非空白,并且当程序期望日期并且获得None时,最终会抛出TypeError。 Where does Django check for blank inputs, and raise the error that eventually goes back to the form? Django在哪里检查空白输入,并提出最终返回到表单的错误? Is this my responsibility? 这是我的责任吗? If so, how do I do it, since it doesn't evaluate clean_startdate() since startdate isn't in the model. 如果是这样,我该怎么做,因为它不评估clean_startdate()因为startdate不在模型中。

3) Is there some better way to do this with inheritance? 3)有没有更好的方法来继承? Perhaps inherit the MyScheduleForm in BetterScheduleForm and add the fields there? 也许在BetterScheduleForm中继承MyScheduleForm并在那里添加字段? How would I do this? 我该怎么做? (I've been playing around with it for over an hours and can't seem to get it) (我一直在玩它超过一个小时,似乎无法得到它)

Thanks! 谢谢!

[Edit:] Left off the return self.cleaned_data -- lost it in the copy/paste originally [编辑:]关闭返回self.cleaned_data - 最初在复制/粘贴中丢失

  1. If I were you, I would have used the customised Django-admin date/time widget(s) for entering date/time entries. 如果我是你,我会使用自定义的Django-admin日期/时间小部件来输入日期/时间条目。

  2. Regarding form validation, make sure you pass the form associated with the request for it to show up form-based errors. 关于表单验证,请确保传递与请求相关联的表单以显示基于表单的错误。 (Sample code below) (以下示例代码)

  3. As for using inheritance, it would be a overkill for this use-case as it will not serve any purpose and it would be better to keep things simple. 至于使用继承,对于这个用例来说这将是一种过度杀伤,因为它不会用于任何目的,并且最好保持简单。

Sample code: 示例代码:

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

Ok, I think I figured it out: 好的,我想我弄清楚了:

As of Django 1.2, running is_valid() triggers MODEL validation on ModelForms. 从Django 1.2开始,运行is_valid()会触发ModelForms上的MODEL验证。 I had assumed that fields would be checked for blank values BEFORE hitting the model clean() function, so my clean function doesn't check for blank values or None types. 我曾假设在访问模型clean()函数之前将检查字段是否为空值,因此我的clean函数不会检查空值或None类型。 Basically, my clean() in my model looks something like: 基本上,我的模型中的clean()看起来像:

def clean(self):
  if self.start_datetime >  datetime.now():
        raise ValidationError('Start date can\'t be in the future')

So I suppose that mostly answer my question. 所以我想这主要是回答我的问题。 However, I have 1 remaining question: 但是,我还剩1个问题:

Is it best to check for blank values in the model clean(), or is there a better way to do this? 最好在模型clean()中检查空白值,还是有更好的方法来做到这一点? Seems hackish to check for blanks in the model instead of in the ModelForm -- is the validation on the form field supposed to flag missing inputs on required fields? 似乎hackish检查模型中的空白而不是ModelForm中的空白 - 表单字段上的验证是否应标记所需字段上缺少的输入?

Thanks for everyone's help. 谢谢大家的帮助。

1: I don't think it's wrong, because you have some very specific stuff going on there: 1:我认为这不对,因为你有一些非常具体的东西:

  • Specific time entries (noon, ending at 5PM..) 具体时间条目(中午,下午5点结束..)
  • 15 minute increments for startminutes startminutes增加15分钟

2: Update: comment below says your field should be required=True by default. 2:更新:下面的评论说明你的字段应该是required=True默认required=True It's true, you should be getting a ValidationError with your form if the field is left blank. 确实,如果该字段留空,您应该使用表单获取ValidationError

Can you post the TypeError you're speaking about? 你可以发布你正在谈论的TypeError吗? Is it happening outside the clean() block? 它发生在clean()块之外吗? Because if you don't return cleaned_data from your clean function like in your example, your form won't have any data to work with even if it initially checks out by not raising any ValidationErrors . 因为如果你没有像你的示例中那样从clean函数返回cleaned_data ,那么即使最初通过不引发任何ValidationErrors进行检出,你的表单也不会有任何数据可以使用。

Anyways, you can explore the clean_ methods for per field validation. 无论如何,您可以探索每个字段验证的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 http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#overriding-the-clean-method

3: Can you clarify here what you're trying to do with inheritance? 3:你能在这里澄清一下你要继承什么吗? It looks like your field definitions are very specific to this form, so it belongs right here in the MyScheduleForm . 看起来您的字段定义非常特定于此表单,因此它就属于MyScheduleForm Inheritance is for re-using code : ) 继承是重用代码:)

If you are looking to reuse this for multiple DateTimeField s, yes you can use form inheritance. 如果您希望将其重用于多个DateTimeField ,是的,您可以使用表单继承。 You could define a ModelForm like you have now, subclass it, and override the parent's Meta as shown here in the docs to use it on multiple models: http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#form-inheritance 你可以定义ModelForm像你现在,它的子类,并重写父的Meta如下所示在文档中使用它的多个模型: http://docs.djangoproject.com/en/dev/topics/forms/modelforms /#形式继承

I'd also check out how the django does its SplitDateTimeWidget (check the source): http://docs.djangoproject.com/en/dev/ref/forms/widgets/#django.forms.SplitDateTimeWidget 我还要看看django如何处理它的SplitDateTimeWidget(检查源代码): http ://docs.djangoproject.com/en/dev/ref/forms/widgets/#django.forms.SplitDateTimeWidget

There are some other '3rd party' split date time widgets worth taking a look at on the interwebs too! 还有一些其他的“第三方”分割日期时间小部件也值得一看在互联网上!

For form fields that may contain blank values, you must declare the field as follows: 对于可能包含空值的表单字段,您必须按如下方式声明该字段:

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

This tells the form that it can be blank , and that the database field can be null . 这告诉表单它可以是blank ,并且数据库字段可以为null That may fix that problem. 这可能解决了这个问题。

Why are you using a ModelForm if you're trying to include fields that are not a part of the Model? 如果您尝试包含不属于模型的字段,为什么要使用ModelForm? ModelForms are designed to quickly create forms that bind directly to your model. ModelForms旨在快速创建直接绑定到模型的表单。 Of course they have various customizations, but changing the actual fields seems to me something that a regular Form is for. 当然,他们有各种自定义,但改变实际字段在我看来是常规表单的用途。

Otherwise, if you just want to split the VIEW of the formm, not the form itself, create a custom widget to display the DateTime field, such as the SplitDateTimeWidget. 否则,如果您只想拆分formm的VIEW而不是表单本身,则创建一个自定义小部件以显示DateTime字段,例如SplitDateTimeWidget。 Subclass it, and provide your CHOICES for the values of the drop down. 对其进行子类化,并为下拉列表的值提供您的选择。

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

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