Opened 3 years ago
Closed 3 years ago
#33995 closed Bug (fixed)
Rendering empty_form crashes when empty_permitted is passed to form_kwargs
| Reported by: | claypooj21 | Owned by: | Bhuvnesh |
|---|---|---|---|
| Component: | Forms | Version: | 4.1 |
| Severity: | Normal | Keywords: | formset, empty_form, empty_permitted, form |
| Cc: | Triage Stage: | Ready for checkin | |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | yes | UI/UX: | no |
Description
Issue
When explicitly setting form_kwargs = {'empty_permitted':True} or form_kwargs = {'empty_permitted':False} , a KeyError occurs when rendering a template that uses a formset's empty_form.
Expected Behavior
empty_permitted is ignored for formset.empty_form since empty_permitted is irrelevant for empty_form, as empty_form is not meant to be used to pass data and therefore does not need to be validated.
Steps to Reproduce
# views.py from django.shortcuts import render from .models import MyModel def test_view(request): context = {} ff = modelformset_factory(MyModel, fields = ['a_field']) context['formset'] = ff( queryset = MyModel.objects.none(), form_kwargs = {'empty_permitted':True} # or form_kwargs = {'empty_permitted':False} ) return render(request, 'my_app/my_model_formset.html', context) # urls.py from django.urls import path, include from .views import test_view urlpatterns = [ path('test', test_view) ] # my_model_formset.html {% extends "my_app/base.html" %} {% block content %} <form id="my-form" method="post"> {% csrf_token %} {{ formset }} <input type="submit" value="Save"> </form> {{ formset.empty_form }} {% endblock %}
Change History (6)
comment:1 by , 3 years ago
| Easy pickings: | set |
|---|---|
| Summary: | Key Error 'empty_permitted' when rendering 'formset.empty_form' → Rendering empty_form crashes when empty_permitted is passed to form_kwargs |
| Triage Stage: | Unreviewed → Accepted |
comment:2 by , 3 years ago
The KeyError is confusing here. It's raised because we're in the context of rendering the template:
>>> self.form(empty_permitted=True, **self.get_form_kwargs(None))
Traceback (most recent call last):
File "/Users/carlton/Projects/Django/django/django/template/base.py", line 880, in _resolve_lookup
current = current[bit]
File "/Users/carlton/Projects/Django/django/django/forms/formsets.py", line 118, in __getitem__
return self.forms[index]
TypeError: list indices must be integers or slices, not str
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<console>", line 1, in <module>
KeyError: 'empty_permitted'
The real exception is better seen using the formset directly:
>>> from ticket_33995.models import MyModel
>>> from django.forms import modelformset_factory
>>> ff = modelformset_factory(MyModel, fields=['name'])
>>> formset = ff(queryset=MyModel.objects.none(), form_kwargs={'empty_permitted': True})
>>> formset.empty_form
> /Users/carlton/Projects/Django/django/django/forms/formsets.py(262)empty_form()
-> form_kwargs = self.get_form_kwargs(None)
(Pdb) c
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/carlton/Projects/Django/django/django/forms/formsets.py", line 265, in empty_form
form = self.form(
TypeError: django.forms.widgets.MyModelForm() got multiple values for keyword argument 'empty_permitted'
That's expected:
>>> class Example:
... def __init__(self, a_kwarg=None):
... pass
...
>>> Example(a_kwarg=True)
<__main__.Example object at 0x102352950>
>>> Example(a_kwarg=True, a_kwarg=False)
File "<stdin>", line 1
SyntaxError: keyword argument repeated: a_kwarg
>>> {"a":1, **{"a":2}}
{'a': 2}
>>> Example(a_kwarg=True, **{"a_kwarg": False})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __main__.Example() got multiple values for keyword argument 'a_kwarg'
Resolving the kwargs before the constructor call, as per Mariusz' suggestion would resolve.
#21501 was on a similar topic.
comment:3 by , 3 years ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
comment:5 by , 3 years ago
| Patch needs improvement: | unset |
|---|---|
| Triage Stage: | Accepted → Ready for checkin |
Thanks for the report. It should be enough to change
form_kwargsforempty_form, e.g.django/forms/formsets.py
Would you like to prepare a patch? (a regression test is required)