【问题标题】:Django - ModelForm Dynamic field updateDjango - ModelForm 动态字段更新
【发布时间】:2012-04-19 07:59:16
【问题描述】:

我正在尝试更新 ModelForm 的某些字段,这些字段不固定。 (我只有 tutor 由视图自动填充)

型号:

class Session(models.Model):
  tutor = models.ForeignKey(User)
  start_time = models.DateTimeField()
  end_time = models.DateTimeField()
  status = models.CharField(max_length=1)

表格:

class SessionForm(forms.ModelForm):
  class Meta:
    model = Session
    exclude = ['tutor']

对于给定的会话,有时我只需要更新end_time,有时只需要更新start_timeend_time

如何在视图中做到这一点?


编辑

我已经给出了示例但不限于这些示例,我需要更新的字段不是预定义的,我需要能够更新任何字段

【问题讨论】:

  • 当你说“更新”时,你是什么意思?您是渲染所有表单字段还是仅渲染那些要更新的字段?
  • 我只渲染那些更新的。 (更新我的意思是改变值)
  • 你能举个例子吗,比如使用场景?仍然不太确定你的目的。

标签: python django django-forms


【解决方案1】:

我以前也做过类似的事情,虽然不是很漂亮,但很有效。它涉及在运行时动态创建一个类型,并使用该类型。部分文档可以看DynamicModels for django.

我们开始……您的要求。

  • 您希望能够使用表单更新模型
  • 您希望有选择地指定要在运行时更新哪些字段

所以,一些代码:

def create_form(model, field_names):
    # the inner class is the only useful bit of your ModelForm
    class Meta:
        pass
    setattr(Meta, 'model', model)
    setattr(Meta, 'include', field_names)
    attrs = {'Meta': Meta}

    name = 'DynamicForm'
    baseclasses = (forms.ModelForm,)
    form = type('DynamicForm', baseclasses, attrs)
    return form

def my_awesome_view(request):
    fields = ['start_time', 'end_time']
    form = create_form(Session, fields)
    # work with your form!

【讨论】:

  • 我喜欢这个。什么不漂亮?
  • 我应该说,它不直观。在考虑我的动态表实现时,我写了“不漂亮”的评论。这实际上看起来相当优雅。
  • 为什么不直接生成并返回表单呢?由type() 构造对于在attrs 中具有动态字段的动态模型很有用,在您的代码attrs 中只有Meta 类。无论如何。
  • @okm,我故意使示例比演示答案的不同部分所需的更长。不过,我仍然会使用函数来创建动态类,因为在视图中声明 Meta 类型看起来很可疑。
  • 如果我必须覆盖字段的某些属性,我会在 __init__ 方法中进行。这里我们如何动态编写__init__方法?
【解决方案2】:

将您的表单字段设置为可为空,并使用“干净”方法向字段添加逻辑,例如:

class SessionForm(forms.ModelForm):
    def clean_end_date(self):
        cd = self.cleaned_data
        if (cd["start_date"] and cd["end_date"]) and cd["end_date"] < cd["start_date"]:
            raise forms.ValidationError("WTF?!")
        if not (cd["start_date"] or cd["end_date"]):
            raise forms.ValidationError("need one date")
        return cd['end_date']

如果要更改值,请在 return 语句中使用不同的值。

这是您可能需要进行验证的内容。

如果需要,您可以在视图中复制 GET 字典并在实例化表单之前更新值

def my_view(request):
    r_data = request.GET.copy()
    r_data.merge(request.POST)

    data = dict([(key, my_function(key, value)) for key, value in r_data.iteritems() if key in MyForm.fields])
    form = MyForm(data=data)
    [...]

希望有帮助。

【讨论】:

  • 不完全回答我的问题,但你的验证规则很有趣,我会使用它们:)
【解决方案3】:

你可以像这样调用表单的构造函数:

class SessionForm(forms.ModelForm):
    class Meta:
        model = Session
        exclude = ['tutor', 'start_time']

    def __init__(self, your_extra_args, *args, **kwargs):
        super(SessionForm, self).__init__(*args, **kwargs)
        if need_end_time_start_time(your_extra_args):
            self.fields['start_time'] = forms.DateTimeField()     

要使用此类,您必须将参数“your_extra_args”传递给您的表单:

session_form = SessionForm('foo')

【讨论】:

  • 如果我有一个包含 10 个字段的模型并且每个字段都可以独立更新,那么您的意思是我必须为每个字段都这样做?
  • 在这种情况下,您应该知道必须更新哪个规则吧?为您的 10 个字段的名称指定一个约定,如 field_1、field_2、...,然后您应该使用循环一步完成。
  • 或使用 kwargs,您将能够使用 setattr 轻松转换值。但我认为,复制您的 post/get 查询字典并在视图中修改它可能对您来说是一个好方法,您将能够在字段上进行迭代并计算您想要的内容,然后通过表单验证您的修改。
  • @christophe31,我不这么认为,使用构造函数将使您免于冗余字段,并使您的 html 更小,验证速度更快......这是保持逻辑流畅且易于操作的好方法了解。
【解决方案4】:

您的问题表明您有一个使用相同模型但不同字段隐藏在 ModelForm 中的需求,具体取决于您的需要。

如果我理解您的问题,那么您需要创建两个不同的基于 ModelForm 的类,这两个类在 Meta 类中具有相同的模型值。排除和包括您需要的字段。所以现在你有了不同的 ModelForm 类,你可以在你的视图逻辑中调用它们。

这样,您将拥有两种不同的表单,它们依赖于相同的模型,具有不同的默认字段。

通过巧妙的 url 和视图设计,您将能够使用上述想法为同一模型的多个表单提供服务。

【讨论】:

    猜你喜欢
    • 2012-04-29
    • 2017-10-22
    • 2011-01-15
    • 2018-11-08
    • 2011-08-26
    • 2023-03-09
    • 2012-01-03
    • 2018-05-11
    • 2016-07-09
    相关资源
    最近更新 更多