Search code examples
djangoformsdjango-allauthdjango-crispy-forms

Django Reoder norecaptcha field on allauth signup using crispy forms


I was able to get the noRecaptcha form on my Django-allauth signup form, with the template using crispy forms. Using this answer

The question is really about forcing a field order on the crispy form layout, when the form is contained in django-allauth and does not specify a layout (per the author). So when overriding the signup form with a custom form of my own, I've tried to specify a layout, but am not sure I'm getting it recognized.
Combining other posts' answers:

from django import forms
from neatf.users.models import User

from nocaptcha_recaptcha.fields import NoReCaptchaField


class AllauthSignupForm(forms.Form):
    captcha = NoReCaptchaField()

    class Meta:
        model = User
        fields = ['username', 'email', 'password1', 'password2', 'captcha']
        field_order = ['username', 'email', 'password1', 'password2', 
                        'captcha']

    def signup(self, request, user):
        """ Required, or else it throws deprecation warnings """
        pass

I'm sure I have the wrong model referenced or it's simply ignored. The noRecaptcha field just sits happily at the top of the form, instead of at the bottom where I'd like it.

I've also tried using FormHelper - but must clearly be doing it wrong.

helper = FormHelper()
helper.form_class = '.form-inline'
helper.field_template = 'bootstrap4/layout/inline_field.html'
helper.layout = Layout(
    Fieldset('Contact data', 'username', 'email',),
    Fieldset('Password', 'password1', 'password2', 'captcha'))

I'd rather not rewrite the template, and hope there is a way to override the layout.


Solution

  • I found the answer to this in a reported issue on django-crispy in github. An "undocumented" feature (at that time) that I finally found in the docs on tags reference (not mentioned in layout sections).

    Very simple and done on the template, requiring zero alterations of the forms.py:

    signup.html

    <form class="signup" id="signup_form" method="post" action="{% url 'account_signup' %}">
        {% csrf_token %}
    
        {{ form.username|as_crispy_field }}
        {{ form.email|as_crispy_field }}
        {{ form.password1|as_crispy_field }}
        {{ form.password2|as_crispy_field }}
        {{ form.captcha|as_crispy_field }}
    
        {% if redirect_field_value %}
            <input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}"/>
        {% endif %}
    
        <script src='https://www.google.com/recaptcha/api.js'></script>
        <button class="btn btn-primary" type="submit">{% trans "Sign Up" %} &raquo;</button>
    </form>
    

    forms.py

    from django import forms
    
    from nocaptcha_recaptcha.fields import NoReCaptchaField
    
    
    class AllauthSignupForm(forms.Form):
        captcha = NoReCaptchaField()
    
        def signup(self, request, user):
            """ Required, or else it throws deprecation warnings """
            pass
    

    Hopefully this helps others.