I'm working in an existing codebase that uses Django Material. There is a CreateView
defined with a Django Material Layout:
class OurModelCreateView(LayoutMixin, CreateView):
model = OurModel
layout = Layout(
Row('field1', 'field2', 'field3'),
Row(...)
)
This view is getting lots of spam signups and so needs to have a captcha. I use Django Recaptcha, and I've set up a number of captchas in the past. However, I've never set one up without using a ModelForm
. If I create a Django model form and define the captcha field in the form as I've always done:
from captcha.fields import ReCaptchaField
from captcha.widgets import ReCaptchaV3
class OurModelForm(ModelForm):
captcha = ReCaptchaField(widget=ReCaptchaV3)
class Meta:
model = OurModel
exclude = ()
and then specify form_class = OurModelForm
on the CreateView
, the following error is raised by ModelFormMixin.get_form_class()
: "Specifying both 'fields' and 'form_class' is not permitted". This error is being raised because, though I've not explicitly specified fields
, Django Material's LayoutMixin
defines fields
: https://github.com/viewflow/django-material/blob/294129f7b01a99832a91c48f129cefd02f2fe35f/material/base.py (bottom of the page)
I COULD drop the Material Layout()
from the CreateView
, but then that would mean having to create an html form to render the Django/Django Material form - less than desirable as there are actually several of these CreateViews
that need to have a captcha applied.
So I think that the only way to accomplish what I'm after is to somehow dynamically insert the captcha
field into the form.
I've dynamicaly inserted fields into Django forms in the past by placing the field definition in the __init__()
of the Django form definition, but I can't figure out what to override in either CreateView
(or the various mixins that comprise CreateView
) or Django Material's LayoutMixin
in order to dynamically insert the captcha
field into the form. The following several attempts to override get_form
and fields
in order to dynamically insert the captcha
field do not work:
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
Any help would be greatly appreciated.
Following up on the comment from @Alasdair above which pointed me to the answer, I solved this problem by removing Django Material's LayoutMixin
from CreateView
, creating a Django form with the captcha field defined, and then adding to CreateView
the form_class
for the Django form. Also see my last comment above. It was counterintuitive to me until I looked again at the code after @Alasdair's second comment: the use of LayoutMixin
on the CreateView
isn't necessary for the layout = Layout(...)
on the CreateView
to work.