【问题标题】:How to improve approach on save form [closed]如何改进保存表单的方法[关闭]
【发布时间】:2020-11-06 01:50:56
【问题描述】:

我想保存一个表单,它会在保存之前获取一些最初设置/编辑的数据:

class ProductCreateView( CreateView):
    model = Product
    form_class = ProductForm
    template_name = "store/create.html"

    def get_initial(self):
        return {"remark": "testnote"}

    def get_success_url(self):
        return reverse_lazy("index")

    def form_valid(self, form):
        self.object = form.save(commit=False)
        Product.objects.create(name = self.object.name, 
                               price = 99,
                               remark = "NOTE",)
        return HttpResponseRedirect(self.get_success_url())

这很好用,不过我有两个问题:

  1. 我想我可以简单地用get_initial 添加数据,但这是Noneform_valid 中打印self.object.remark 时。
  2. 这通常是一种聪明的方法吗?我需要一个新的pk,这样我想我可以避免猜到一个(nogo ...)。我无法填充 forms.py 中的字段。

【问题讨论】:

  • 我会说,这不是 smart 方法。我没有看到在这里覆盖form_valid(...) 方法的任何优势。我错过了什么吗?

标签: django django-views django-forms


【解决方案1】:

首先,关于你对get_initial的覆盖:你需要用super()调用父方法,你需要返回你从那个调用中得到的对象:

def get_initial(self):
    initial = super().get_initial()

    initial['remark'] = testnote

    return initial

您也可能误解了初始字典的用途:它通常用于用数据预先填充表单。键需要与表单中的字段相对应,您分配给它们的值将在用户看到表单时出现在表单中(预填充)。然后他们可以使用该值,或输入一个新值。

其次,您覆盖 form_valid 的方法在我看来是错误的,除非我误解了您的目的。调用 self.object = form.save() 创建的对象与调用 .create() 创建的对象不同。然后,您将第一个对象的“名称”赋予第二个对象。但这应该都是创造的一个步骤,而不是两个几乎不相关的步骤,这就是你现在正在做的事情。换句话说,对 create() 的调用是多余的,因为 form.save() 的全部意义在于创建一个对象。我可以看到这就是您使用 commit=False 的原因,因此数据库仅在调用 create() 时更新。但是您可以避免这种冗余,并且仍然可以实现您想要做的事情。一种方法是调用 save() 两次:

self.object = form.save(commit=False)   # create python object but do not update the database yet
self.object.some_field = some_value     # modify the new object
self.object.save()       # save the object, updating the database

由于您提到无法访问表单字段,因此您实际上可能打算这样做:

def form_valid(self, form):
    
    form.instance.name = some_name_string
    form.instance.price = 99
    
    return super().form_valid(form) #call to super() saves the form

正如您在上面看到的,您可以使用 .instance.field-name 访问表单的字段。这通常用于为表单中遗漏的字段分配值——您不希望用户为其提供输入的内容。当然,您需要在提交表单之前执行此操作:您基本上是手动更新将要创建的模型中的值,然后通过调用 super() 在返回中保存它陈述。如果您需要更多地控制此方法中发生的事情,您可以像在原始代码中一样使用 self.object = form.save() ,放在上面的“实例”用法之后,然后以重定向结束对 super() 的调用:

def form_valid(self, form):
    
    form.instance.name = some_name_string
    form.instance.price = 99

    self.object = form.save()

    # perform other tasks as needed here, and with access to self.object, the
    # newly created object resulting from saving the form above.
    
    return redirect(self.get_success_url())  # import the redirect shortcut, it's cleaner

如您所见,有很多方法可以覆盖通用编辑视图的 form_valid 方法。采用的方法通常取决于三个主要任务之间所需的事件顺序:提交/保存表单(以及它的对象,这要归功于 ModelForm)、根据需要执行“额外”工作以及重定向。当然,重定向总是最后一个,但您可以根据需要在前两个周围移动,您已经在这样做了。

【讨论】:

  • 我不确定你在问什么,抱歉。 “将这些值保存在隐藏值中”是什么意思?请记住,初始字典中的键直接对应于表单/模型中的字段。如果您在 get_initial 中为它们分配值,这仅意味着这些值将在显示给用户(预填充)时出现在表单中,但它们是否在模型上实际使用/更新取决于用户是否更改它们或遵循- 通过提交表单。
  • 现在完美运行。谢谢!
猜你喜欢
  • 1970-01-01
  • 2014-04-02
  • 1970-01-01
  • 1970-01-01
  • 2013-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多