35👍
This is a pretty horrible abuse of the API, but there is a form method called add_prefix
that is called to determine what the HTML name of each field should be, taking into account the form’s prefix if any. You could override that so that it looks up the field name in a dictionary somewhere and returns the name you want – not forgetting to preserve the existing prefix behaviour:
FIELD_NAME_MAPPING = {
'field1': 'html_field1',
'field2': 'html_field2'
}
class MyForm(forms.ModelForm):
def add_prefix(self, field_name):
# look up field name; return original if not found
field_name = FIELD_NAME_MAPPING.get(field_name, field_name)
return super(MyForm, self).add_prefix(field_name)
6👍
I’ve implemented a simple function which overwrites the widget render
method and assigns a custom name:
def namedWidget(input_name, widget=forms.CharField):
if isinstance(widget, type):
widget = widget()
render = widget.render
widget.render = lambda name, value, attrs=None: \
render(input_name, value, attrs)
return widget
The usage is simple:
class AliasCreationForm(forms.Form):
merchant_id = forms.CharField(
max_length=30,
widget=namedWidget('PSPID', forms.HiddenInput),
)
- [Django]-Django: using objects.values() and get ForeignKey data in template
- [Django]-Uncaught TypeError: Cannot read property 'ownerDocument' of undefined
- [Django]-This QueryDict instance is immutable
3👍
the name attr is coupled to the name of the property used for the field.
From your description (“If that other form changes the names of any of its fields, I need to change the names of the fields in my form and then change those names everywhere else in my application – since “, “If the remote form uses silly names then my form object must also have properties with silly names which pollutes my application’s code.”) you recognize this as a fragile design decision.
You should consider that your view function totally solves this problem in a trivial way.
Rather than align names between the remote application and your application, use your view functions to map from your nice names to their horrible names.
This is what view functions are for.
To take it a step further, your view function does three things.
- Validate inputs. Perhaps persist them in some local database.
- Map data from your form to their request structure.
- Make the remote request (via
httplib
orurllib2
or whatever).
Items 1 and 3 don’t change much.
Item 2 is a field-by-field mapping from the request.POST to a dictionary which you then url lib.urlencode to create the POST request. (Or whatever the protocol is.)
So break out item 2 into a flexible thing that you specify in your settings.
settings
MY_MAPPING_FUNCTION = module.function
In your views.py
def submit( request ):
if request.method == POST:
form = SomeForm( request.POST )
if is_valid(form):
form.save()
to_be_submitted = settings.MY_MAPPING_FUNCTION( form )
remote_post( to_be_submitted ) # or whatever your protocol is
Add the mapping module to your application
module.py
def version_1_2( form ):
return {
'silly_name_1': form.cleaned_data['your_nice_name'],
'from': form.cleaned_data['another_nice_name'],
}
def version_2_1( form ):
return {
'much_worse_name': form.cleaned_data['your_nice_name'],
'from': form.cleaned_data['another_nice_name'],
}
- [Django]-How to deal with "SubfieldBase has been deprecated. Use Field.from_db_value instead."
- [Django]-Django Broken pipe in Debug mode
- [Django]-Django REST Framework: Setting up prefetching for nested serializers
1👍
I realize this question is old, but here’s another (possibly cleaner) way to do it. Most of the answers here involve monkey patching or overriding a superclass method. This does as well, but I think it’s a clean way to do it.
Create a new Widget that extends the widget you need, such as TextInput:
class TextInputSansName(forms.TextInput):
def build_attrs(self, extra_attrs=None, **kwargs):
if extra_attrs:
extra_attrs.pop('name', None)
kwargs.pop('name', None)
return super().build_attrs(extra_attrs, **kwargs)
Django calls build_attrs on a widget during the render() operation. In the method, I’m removing ‘name’ if it is in either of the dictionaries. This effectively removes the name just before it renders.
This answer overrides as little as possible of the Django API.
In one of my sites, the payment processor needs inputs to be without names. Here’s the control declaration in the form class:
card_number = forms.IntegerField(
label='Card Number',
widget=TextInputSansName(attrs={ 'data-stripe': 'number' })
)
Cheers.
- [Django]-AttributeError: 'Settings' object has no attribute 'ROOT_URLCONF'
- [Django]-'function' object has no attribute 'as_view'
- [Django]-Get Authenticated user from token in Django Rest Framework
-1👍
It’s simple. Just use the attribute ‘labels’ of the class Meta:
class AuthorForm(ModelForm):
class Meta:
model = Author
fields = ('name', 'title', 'birth_date')
labels = {
'name': 'new_name',
}
where ‘new name’ will be the name displayed in the html.
- [Django]-How to lock a critical section in Django?
- [Django]-Choose test database?
- [Django]-How to stream an HttpResponse with Django