Search code examples
djangodjango-allauthdjango-crispy-forms

Crispy forms throws VariableDoesNotExist error failed lookup for key [html5_required] on forms


I use allauth to sign in with emails and did a very basic custom login form and a template override for allauth and display the login form. Hitting the URL throws me straight into the exception:

Failed lookup for key [html5_required] in [{'True': True, 'False': False, 'None': None}, {'True': True, 'False': False, 'None': None, 'form': , 'form_show_errors': True, 'form_show_labels': True, 'label_class': '', 'field_class': ''}, {'forloop': {'parentloop': {}, 'counter0': 1, 'counter': 2, 'revcounter': 2, 'revcounter0': 1, 'first': False, 'last': False}, 'field': }, {}]

where I then have to continue the debugger twice to end up on the form.

I tried looking for this specific [html5_required] tag/key but haven't found anybody with the same missing key.

I removed the custom login form in settings.py to see if there is an issue but that didn't help.

I even tested it with a simple ```ModelForm`` just displaying two fields and got the same issue.

I have tried both: class based view (for Login) and a function based view (for Profile) and I am getting the same problem on both.

settings.py:


INSTALLED_APPS = [
   ...
   'crispy_forms',
   'allauth',
   'allauth.account',
   'allauth.socialaccount',
   'allauth.socialaccount.providers.google',
   ...
]

CRISPY_TEMPLATE_PACK = 'bootstrap4'

ACCOUNT_FORMS = {
   "login": "users.forms.CustomLoginForm"
}

forms.py

from django.utils.translation import ugettext as _
from django.urls import reverse_lazy
from allauth.account.forms import LoginForm, SignupForm
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML
from django.forms import ModelForm

class CustomLoginForm(LoginForm):
    def __init__(self, *args, **kwargs):
        super(CustomLoginForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper(self)
        # Add magic stuff to redirect back.
        self.helper.layout.append(
            HTML(
                "{% if redirect_field_value %}"
                "<input type='hidden' name='{{ redirect_field_name }}'"
                " value='{{ redirect_field_value }}' />"
                "{% endif %}"
            )
        )
        # Add password reset link.
        self.helper.layout.append(
            HTML(
                "<p><a class='button secondaryAction' href={url}>{text}</a></p>".format(
                    url=reverse_lazy('account_reset_password'),
                    text=_('Forgot Password?')
                )
            )
        )
        # Add submit button like in original form.
        self.helper.layout.append(
            HTML(
                '<button class="btn btn-primary btn-block" type="submit">'
                '%s</button>' % _('Sign In')
            )
        )

        self.helper.form_class = 'form-horizontal'
        self.helper.label_class = 'col-xs-2 hide'
        self.helper.field_class = 'col-xs-8'

templates/account/login.html

{% extends 'base.html' %}
{% load crispy_forms_tags %}


{% block content %}
  <h2>Login</h2>
  <form method="post">
    {% csrf_token %}
    {{ form|crispy }}
    <button class="btn btn-primary" type="submit">Login</button>
  </form>
{% endblock %}

the following code is the quick function based view for the profile which is using pretty much the same template:

#in urls.py: path('profile/', views.profile_view, name='user_profile')

#forms.py:
class UserProfileForm(ModelForm):

    class Meta:
        model = UserProfile
        fields = ('gender', 'birthdate')

#view.py:
def profile_view(request, *args, **kwargs):
    if request.method == "POST":
        form = UserProfileForm(request.POST)
        if form.is_valid():
            profile = form.save(commit=False)
            profile.user = request.user
            #profile.author = request.user
            #profile.published_date = timezone.now()
            profile.save()
            # TODO: add message or redirect ?!
    else:
        form = UserProfileForm()
    return render(request, 'profile.html', {'form': form})
{% extends 'base.html' %}
{% load crispy_forms_tags %}

{% block content %}

<h2>Profile</h2>
<form method="post">
  {% csrf_token %}
   {{ form|crispy }}
  <button class="btn btn-primary" type="submit">Update</button>
</form>
{% endblock %}

I don't understand why this key is missing, have i forgotten something or missed a configuration part?

the versions I am using:

  • django: 2.2.4
  • allauth: 0.39.1
  • crispy-forms: 1.7.2
  • python: 3.7.4

any guidance is really appreciated.

EDIT: I created a complete new project as a test with just crispy forms, a model with just 2 char fields, the ModelForm and template as mentioned above and receive the same issue.

So either I am doing something wrong/missing something or there is a problem, I also raised on their github issue https://github.com/django-crispy-forms/django-crispy-forms/issues/891


Solution

  • I leave this as an "partial" answer since I do not know why or what the difference (in behavior) is but changing the call to the form in the template from:

    {{ form|crispy }}
    

    to

    {% crispy form %}
    

    got rid of the exception.

    Then, as @skilled-in-blockchain mentions I can add the FormHelper to the form to make additional modifications. Thanks.