如何在使用 Material Design Layout() 功能的 Django CreateView 上放置验证码

How to place captcha on Django CreateView that uses Material Design Layout() feature

我在使用 Django Material 的现有代码库中工作。有一个 CreateView 用 Django Material 布局定义:

class OurModelCreateView(LayoutMixin, CreateView): 
    model = OurModel

    layout = Layout(
        Row('field1', 'field2', 'field3'),
        Row(...)
    )

此视图收到大量垃圾邮件注册,因此需要验证码。我使用 Django Recaptcha,并且我过去设置了一些验证码。但是,我从来没有在不使用 ModelForm 的情况下进行设置。如果我创建一个 Django 模型表单并像往常一样在表单中定义验证码字段:

from captcha.fields import ReCaptchaField
from captcha.widgets import ReCaptchaV3

class OurModelForm(ModelForm):
    
captcha = ReCaptchaField(widget=ReCaptchaV3)

    class Meta:
        model = OurModel
        exclude = ()

然后在 CreateView 上指定 form_class = OurModelFormModelFormMixin.get_form_class() 引发以下错误:“不允许同时指定 'fields' 和 'form_class' ”。出现此错误是因为,虽然我没有明确指定 fields,但 Django Material 的 LayoutMixin 定义了 fields: https://github.com/viewflow/django-material/blob/294129f7b01a99832a91c48f129cefd02f2fe35f/material/base.py(页面底部)

我可以从 CreateView 中删除 Material Layout(),但这意味着必须创建一个 html 表单来呈现 Django/Django Material 表单 - 不太理想,因为实际上有几个 CreateViews 需要应用验证码。

所以我认为完成我所追求的唯一方法是以某种方式将 captcha 字段动态插入到表单中。

我过去通过将字段定义放在 Django 表单定义的 __init__() 中动态地将字段插入到 Django 表单中,但我不知道在 [=14] 中覆盖什么=](或包含 CreateView 的各种 mixin)或 Django Material 的 LayoutMixin,以便动态地将 captcha 字段插入表单。以下几次尝试覆盖 get_formfields 以动态插入 captcha 字段不起作用:

   On the CreateView:
       def get_form(self, form_class=None):
           form = super(OurModelCreate, self).get_form(form_class)
           form.fields['captcha'] = ReCaptchaField(widget=ReCaptchaV3)
           return form

       def fields(self):
           fields = super().fields(*args, **kwargs)
           fields['captcha'] = ReCaptchaField(widget=ReCaptchaV3)
           return [field.field_name for field in fields

       # fields is actually a list, so trying the following too, but it doesn't include the ReCaptchaField(widget=ReCaptchaV3) anywhere at this point
       def fields(self):
           fields = super().fields(*args, **kwargs)
           fields.append('captcha')
           return fields

如有任何帮助,我们将不胜感激。

根据上面@Alasdair 的评论指出我的答案,我通过从 CreateView 中删除 Django Material 的 LayoutMixin 解决了这个问题,创建了一个 Django定义了验证码字段的表单,然后将 CreateView 添加到 Django 表单的 form_class。另请参阅我上面的最后一条评论。这对我来说是违反直觉的,直到我在@Alasdair 的第二条评论后再次查看代码:CreateView 上的 layout = Layout(...) 不需要在 CreateView 上使用 LayoutMixin ] 上班。