29π
I had a little fun looking into how forms works and came up with multiple solutions, just for the heck of it.
Since you are disabling the widget and not the field, as far as the form is concerned itβs always receiving nothing for fieldA and that will always fail validation.
Trying something in the clean() method wonβt help for invalid forms because clean()
data is for processing.
It looks like the way forms pull data for HTML display is field.data
, which is a call to field.widget.value_from_datadict(POST, FILES, field_name)
so it will always be looking at your POST data.
So I think you have a few options. Hack request.POST
, hack the internal form POST data, or hack value_from_datadict
.
Hacking request.POST
: straight forward, makes sense.
myModelobject = get_object_or_404(MyModel.objects, pk=mymodel_id)
if request.method == 'POST':
POST = request.POST.copy()
POST['fieldA'] = myModelobject.fieldA
model_form = MyModelUpdateForm(POST, instance=myModelobject )
if model_form .is_valid():
# ...
Hacking internal dictionary:
def __init__(self, *args, **kwargs):
super(MyModelUpdateForm, self).__init__(*args, **kwargs)
self.data.update({ 'fieldA': self.instance.fieldA })
Hacking value_from_datadict
: kinda ridiculous, but illustrates what you can learn from digging into the source
def __init__(self, *args, **kwargs):
super(MyModelUpdateForm, self).__init__(*args, **kwargs)
self.fields['fieldA'].widget.value_from_datadict = lambda *args: self.instance.first_name
Learned some cool things here : ) Hope it helps.
16π
I used jQuery to solve the problem by removing disabled from all inputs before submitting.
$('#my_form').submit(function(){
$("#my_form :disabled").removeAttr('disabled');
});
- [Django]-Filtering using viewsets in django rest framework
- [Django]-Django admin default filter
- [Django]-Django.db.utils.ProgrammingError: relation "bot_trade" does not exist
2π
You can put it in the form class like this:
class MyForm(forms.Form):
MY_VALUE = 'SOMETHING'
myfield = forms.CharField(
initial=MY_VALUE,
widget=forms.TextInput(attrs={'disabled': 'disabled'})
def __init__(self, *args, **kwargs):
# If the form has been submitted, populate the disabled field
if 'data' in kwargs:
data = kwargs['data'].copy()
self.prefix = kwargs.get('prefix')
data[self.add_prefix('myfield')] = MY_VALUE
kwargs['data'] = data
super(MyForm, self).__init__(*args, **kwargs)
The way it works, is it tests to see if any data has been passed in to the form constructor. If it has, it copies it (the uncopied data is immutable) and then puts the initial value in before continuing to instantiate the form.
- [Django]-Cannot access django app through ip address while accessing it through localhost
- [Django]-Django Multiple Authentication Backend for one project
- [Django]-Getting Values of QuerySet in Django
1π
I solved such problem without touching the backend part, all you need is to add specific class to your fieldA in the forms.py with βvisibility:hiddenβ property.
self.fields['fieldA'].widget.attrs['class'] = 'visibility_hidden_class'
then, in the template your form.fieldA will be hidden but not lost in post request
{{ form.fieldA.label_tag }}
{{ form.fieldA }}
<input type="text" value="{{ form.fieldA.value }}" disabled />
so you will still have your form.fieldA in request form data. And visually your field will be always populated with the form.fieldA.value.
- [Django]-Python 3 list(dictionary.keys()) raises error. What am I doing wrong?
- [Django]-How to format time in django-rest-framework's serializer?
- [Django]-Django error: got multiple values for keyword argument
0π
I faced with similar problem and this is how I solved it.
I set field as hidden:
self.fields['fieldA'].widget.attrs['style'] = 'display:none;'
In template I show field value separately:
{{ form.fieldA.label_tag }}
{{ form.fieldA }}
{{ form.fieldA.value }}
{{ form.fieldA.errors }}
In case of fieldA is a select menu:
{{ form.fieldA.label_tag }}
{{ form.fieldA }}
{% for value, title in form.fields.fieldA.choices %}
{% if value == form.fieldA.value %}
{{ title }}
{% endif %}
{% endfor %}
{{ form.fieldA.errors }}
- [Django]-Filtering dropdown values in django admin
- [Django]-PHP Frameworks (CodeIgniter, Yii, CakePHP) vs. Django
- [Django]-Passing STATIC_URL to file javascript with django
0π
I had to solve a similar issue. I was using like dynamic formset to generate new rows, so once you select the product it was shown as disabled, but I needed to get the value on the form in the view. Jquery and JavaScript were easier for me, so I generate a pre β send event removing the disabled on the selector that I use in my formsets. I was using the widget select2 for this setup, so it does work with select2 too.
Of course, the send button id = "postForm" and the id of the form id = "contractForm".
$('#postForm').click(function(e) {
e.preventDefault();
$('select[id^="id_p_v"][id$="product"]').each(function(){
// getIdNumber returns the digit value from id_field-n- in formset value
// p_v was the prefix of formset
var id = getIdNumber($(this).attr('id'));
// I have an empty form for new forms so skip that one actually on send doesn't matter really. (form POST) but anyway skip
if(id != null){
$(this).prop("disabled", false);
}
});
$('#contractForm').submit();
});
- [Django]-POST jQuery array to Django
- [Django]-UUID as default value in Django model
- [Django]-Django 1.7 β App 'your_app_name' does not have migrations
0π
I know this is an old question, but I recently encountered this problem myself. I think the simplest solution is to use βinitialβ in the init definition:
def __init__(self, *args, **kwargs):
super(MyModelUpdateForm, self).__init__(*args, **kwargs)
self.fields['fieldA'].disabled = True
self.fields['fieldA'].initial = self.instance.fieldA
This assumes the instance already exists, of course. You may want to add an βifβ clause if necessary.
- [Django]-Annotate a queryset with the average date difference? (django)
- [Django]-How to format time in django-rest-framework's serializer?
- [Django]-Create a field whose value is a calculation of other fields' values
0π
When you use disabled attribute the data does not go on POST, you can use readonly that hinder the user from changing the field but sends the value on POST.
- [Django]-How do I install psycopg2 for Python 3.x?
- [Django]-Django Footer and header on each page with {% extends }
- [Django]-Http POST drops port in URL
-1π
In models.py add blank=True
.
Example:
class myModel(models.Model):
myField = models.CharField(max_length=30, blank=True)
- [Django]-Django error: got multiple values for keyword argument
- [Django]-Getting Values of QuerySet in Django
- [Django]-Django composite unique on multiple model fields