kbytesys/django-recaptcha2

Unable to render captcha for multiple forms on a single page

Closed this issue · 3 comments

I have multiple user registration forms on a single page. The captcha is getting rendered for only first form on the page and not for others. Even though I have set explicit=True in forms.py and have also included
{% recaptcha_explicit_support %} and {% recaptcha_explicit_init %} in the template.

@kbytesys I have created a simpler template to show the issue.

{% load recaptcha2 %}
<!DOCTYPE html>
<html lang="en">
<head>
{% recaptcha_explicit_support %}
<title>Workshop</title>
</head>
<body>
{% for workshop in workshops %}
{{workshop.name}}
{{workshop.description|safe}}
{{form.as_p}}
<input type="submit">
<br>
{% endfor %}
{% recaptcha_explicit_init %}
</body>
</html>

forms.py --

    class WorkshopRegistrationForm(ModelForm):
        captcha = ReCaptchaField(widget=ReCaptchaWidget(explicit=True))

issue

So the captcha never gets generated for other forms.

The problem is that it takes container id as the name of the field.

class ReCaptchaWidget(Widget):
    def __init__(self, explicit=False, theme=None, type=None, size=None, tabindex=None, callback=None,
                 expired_callback=None, attrs={}, *args, **kwargs):
        super(ReCaptchaWidget, self).__init__(*args, **kwargs)
        self.explicit = explicit
        self.theme = theme
        self.type = type
        self.size = size
        self.tabindex = tabindex
        self.callback = callback
        self.expired_callback = expired_callback
        self.attrs = attrs

    def render(self, name, value, attrs=None):
        template = 'snowpenguin/recaptcha/'
        template += 'recaptcha_explicit.html' if self.explicit else 'recaptcha_automatic.html'

        return mark_safe(
            render_to_string(template, {
                'container_id': 'id_%s' % name,
                'public_key': settings.RECAPTCHA_PUBLIC_KEY,
                'theme': self.theme,
                'type': self.type,
                'size': self.size,
                'tabindex': self.tabindex,
                'callback': self.callback,
                'expired_callback': self.expired_callback
            })
        )

    def value_from_datadict(self, data, files, name):
        return [data.get('g-recaptcha-response', None)]

What if a page contains multiple forms with same field names.? The captcha will always be rendered for the first field because we are setting container id as the name of field. So if we want to render the captcha for all the fields we need to have unique ids for them. So the solution is when explicit is set true supply a unique id with the field.

So the solution is when explicit is set true supply a unique id with the field.

This could be a solution, when I will return from my holiday I will try to fix this issue.