For work recently I've been doing some
Django-related tasks that involve talking to an external API with
POSTed forms. Django forms objects are declared by creating a class that
inherits from django.forms.Form
, with the fields of the
form declared by declaring attributes of that class. Which works well
and is clean and easy to remember—unless the API you're working
with requires a field with the same name as a Python keyword, such as
return
. You can't declare a field like this as an
attribute; it will trigger a syntax error.
I spent some time scratching my head over this, and came up with this as
a workaround after source-diving to find out how Form
objects actually work:
from django import forms
class ExampleForm(forms.Form):
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
initial=None, errorclass=ErrorList, label_suffix=':', empty_permitted=False, return_url=None):
forms.Form.__init__(self, data, files, auto_id, prefix, initial,
errorclass, label_suffix, empty_permitted)
if return_url is not None:
self.fields['return'] = forms.CharField(widget=forms.HiddenInput, initial=return_url)
It turns out that the attribute declaration is just syntactic sugar for
creating a dictionary of key/value pairs, which is then stored in the
fields
attribute. So we can monkeypatch in extra values after
the translation. Which is somewhat more awkward and ugly, but works in a pinch.
Note that I haven't extensively tested what interactions this may cause with other forms code, so use with some caution.
A somewhat nicer way to would be to use the 'type' constructor:
That way, it's guaranteed to hit the same codepaths as if you wrote the form out "longhand".