Django表单预览 - 如何使用'cleaning_data'

时间:2021-11-04 16:27:22

Thanks to Insin for answering a previous question related to this one.

感谢Insin回答与此相关的上一个问题。

His answer worked and works well, however, I'm perplexed at the provision of 'cleaned_data', or more precisely, how to use it?

他的回答有效并且运作良好,然而,我对'cleaning_data'的提供感到困惑,或者更确切地说,如何使用它?

class RegistrationFormPreview(FormPreview):
    preview_template    = 'workshops/workshop_register_preview.html'
    form_template       = 'workshops/workshop_register_form.html'

    def done(self, request, cleaned_data):
        # Do something with the cleaned_data, then redirect
        # to a "success" page. 

        registration            = Registration(cleaned_data)
        registration.user       = request.user
        registration.save()
        # an attempt to work with cleaned_data throws the error: TypeError 
        # int() argument must be a string or a number, not 'dict'
        # obviously the fk are python objects(?) and not fk_id
        # but how to proceed here in an easy way?



        # the following works fine, however, it seems to be double handling the POST data
        # which had already been processed in the django.formtools.preview.post_post
        # method, and passed through to this 'done' method, which is designed to 
        # be overidden.
        '''
        form                    = self.form(request.POST)   # instansiate the form with POST data
        registration            = form.save(commit=False)   # save before adding the user
        registration.user       = request.user              # add the user
        registration.save()                                 # and save.
        '''

        return HttpResponseRedirect('/register/success')

For quick reference, here's the contents of the post_post method:

为了快速参考,这里是post_post方法的内容:

def post_post(self, request):
    "Validates the POST data. If valid, calls done(). Else, redisplays form."
    f = self.form(request.POST, auto_id=AUTO_ID)
    if f.is_valid():
        if self.security_hash(request, f) != request.POST.get(self.unused_name('hash')):
            return self.failed_hash(request) # Security hash failed.
        return self.done(request, f.cleaned_data)
    else:
        return render_to_response(self.form_template,
            {'form': f, 'stage_field': self.unused_name('stage'), 'state': self.state},
            context_instance=RequestContext(request))

1 个解决方案

#1


I've never tried what you're doing here with a ModelForm before, but you might be able to use the ** operator to expand your cleaned_data dictionary into the keyword arguments expected for your Registration constructor:

我以前从未尝试过使用ModelForm进行的操作,但是您可以使用**运算符将您的cleaning_data字典扩展为您的Registration构造函数所需的关键字参数:

   registration = Registration (**cleaned_data)

The constructor to your model classes take keyword arguments that Django's Model meta class converts to instance-level attributes on the resulting object. The ** operator is a calling convention that tells Python to expand your dictionary into those keyword arguments.

模型类的构造函数采用Django的Model元类转换为结果对象的实例级属性的关键字参数。 **运算符是一种调用约定,它告诉Python将字典扩展为那些关键字参数。

In other words...

换一种说法...

What you're doing currently is tantamount to this:

你目前正在做的是等于这个:

registration = Registration ({'key':'value', ...})

Which is not what you want because the constructor expects keyword arguments as opposed to a dictionary that contains your keyword arguments.

这不是你想要的,因为构造函数需要关键字参数而不是包含关键字参数的字典。

What you want to be doing is this

你想要做的就是这个

registration = Registration (key='value', ...)

Which is analogous to this:

这类似于:

registration = Registration (**{'key':'value', ...})

Again, I've never tried it, but it seems like it would work as long as you aren't doing anything fancy with your form, such as adding new attributes to it that aren't expected by your Registration constructor. In that case you'd likely have to modify the items in the cleaned_data dictionary prior to doing this.

同样,我从来没有尝试过,但只要你没有对你的表单做任何花哨的东西,比如向你的注册构造函数不期望添加新的属性,它似乎会起作用。在这种情况下,您可能必须在执行此操作之前修改cleaning_data字典中的项目。

It does seem like you're losing out on some of the functionality inherent in ModelForms by going through the form preview utility, though. Perhaps you should take your use case to the Django mailing list and see if there's a potential enhancement to this API that could make it work better with ModelForms.

但是,通过浏览表单预览实用程序,您似乎正在失去ModelForms中固有的某些功能。也许你应该将你的用例带到Django邮件列表中,看看是否有一个潜在的增强功能可以使这个API更好地使用ModelForms。

Edit

Short of what I've described above, you can always just extract the fields from your cleaned_data dictionary "by hand" and pass those into your Registration constructor too, but with the caveat that you have to remember to update this code as you add new fields to your model.

除了我上面描述的内容之外,您总是可以“手动”从您的cleaning_data字典中提取字段并将它们传递到您的注册构造函数中,但需要注意的是,您必须记住在添加新代码时更新此代码字段到您的模型。

registration = Registration (
    x=cleaned_data['x'],
    y=cleaned_data['y'],
    z=cleaned_data['z'],
    ...
)

#1


I've never tried what you're doing here with a ModelForm before, but you might be able to use the ** operator to expand your cleaned_data dictionary into the keyword arguments expected for your Registration constructor:

我以前从未尝试过使用ModelForm进行的操作,但是您可以使用**运算符将您的cleaning_data字典扩展为您的Registration构造函数所需的关键字参数:

   registration = Registration (**cleaned_data)

The constructor to your model classes take keyword arguments that Django's Model meta class converts to instance-level attributes on the resulting object. The ** operator is a calling convention that tells Python to expand your dictionary into those keyword arguments.

模型类的构造函数采用Django的Model元类转换为结果对象的实例级属性的关键字参数。 **运算符是一种调用约定,它告诉Python将字典扩展为那些关键字参数。

In other words...

换一种说法...

What you're doing currently is tantamount to this:

你目前正在做的是等于这个:

registration = Registration ({'key':'value', ...})

Which is not what you want because the constructor expects keyword arguments as opposed to a dictionary that contains your keyword arguments.

这不是你想要的,因为构造函数需要关键字参数而不是包含关键字参数的字典。

What you want to be doing is this

你想要做的就是这个

registration = Registration (key='value', ...)

Which is analogous to this:

这类似于:

registration = Registration (**{'key':'value', ...})

Again, I've never tried it, but it seems like it would work as long as you aren't doing anything fancy with your form, such as adding new attributes to it that aren't expected by your Registration constructor. In that case you'd likely have to modify the items in the cleaned_data dictionary prior to doing this.

同样,我从来没有尝试过,但只要你没有对你的表单做任何花哨的东西,比如向你的注册构造函数不期望添加新的属性,它似乎会起作用。在这种情况下,您可能必须在执行此操作之前修改cleaning_data字典中的项目。

It does seem like you're losing out on some of the functionality inherent in ModelForms by going through the form preview utility, though. Perhaps you should take your use case to the Django mailing list and see if there's a potential enhancement to this API that could make it work better with ModelForms.

但是,通过浏览表单预览实用程序,您似乎正在失去ModelForms中固有的某些功能。也许你应该将你的用例带到Django邮件列表中,看看是否有一个潜在的增强功能可以使这个API更好地使用ModelForms。

Edit

Short of what I've described above, you can always just extract the fields from your cleaned_data dictionary "by hand" and pass those into your Registration constructor too, but with the caveat that you have to remember to update this code as you add new fields to your model.

除了我上面描述的内容之外,您总是可以“手动”从您的cleaning_data字典中提取字段并将它们传递到您的注册构造函数中,但需要注意的是,您必须记住在添加新代码时更新此代码字段到您的模型。

registration = Registration (
    x=cleaned_data['x'],
    y=cleaned_data['y'],
    z=cleaned_data['z'],
    ...
)