How do I make form fields in a model formset disabled when the forms already exist and just need a couple columns updated, but make those same fields editable when a new form is added to the formset by the user?
models.py:
from django.db import models
from django.utils import timezone
class MyModel(models.Model):
idno = models.CharField(max_length=20)
date = models.DateTimeField(default=timezone.now)
entity = models.CharField(max_length=50)
logic = models.CharField(max_length=100)
choices = (
('1', 'Choice1'),
('2', 'Choice2'),
('3','Choice3'),
)
choices = models.CharField(
max_length=20,
choices=choices,
null=True,
)
comment = models.CharField(max_length=500, null=True)
def __str__(self):
return self.idno
forms.py:
from .models import MyModel
from django.forms import modelformset_factory, ModelForm
class MyForm(ModelForm):
class Meta:
model = MyModel
fields = '__all__'
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
self.fields['idno'].disabled = True
self.fields['date'].disabled = True
self.fields['entity'].disabled = True
self.fields['logic'].disabled = True
MyFormSet = modelformset_factory(MyModel, extra=1, exclude=(), form=MyForm)
views.py:
from django.shortcuts import render
from django.http import HttpResponseRedirect
from .models import Alert
from .forms import AlertFormSet
from django.contrib import messages
def index(request):
newAlerts = MyModel.objects.filter(choices__isnull=True)
modelformset = MyFormSet(request.POST or None, queryset=newAlerts)
context = {'modelformset':modelformset}
if request.method == 'POST':
for form in modelformset:
if form.is_valid():
if form.has_changed():
form.save()
idno = form.cleaned_data['idno']
entity = form.cleaned_data['entity']
messages.success(request, 'idno %s for %s was saved' % (idno, entity))
return HttpResponseRedirect('/')
return render(request, 'selfserve/index.html', context)
index.html:
<form method="post" action="">
{% csrf_token %}
{{ modelformset.management_form }}
<div id="form_set">
{% for form in modelformset %}
<table class='no_error'>
{{ form.as_table }}
</table>
{% endfor %}
</div>
<input type="button" value="Add More" id="add_more">
<input type="submit" value="Submit">
<div id="empty_form" style="display:none">
<table class='no_error'>
{{ modelformset.empty_form.as_table }}
</table>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
$('#add_more').click(function() {
var form_idx = $('#id_form-TOTAL_FORMS').val();
$('#form_set').append($('#empty_form').html().replace(/__prefix__/g, form_idx));
$('#id_form-TOTAL_FORMS').val(parseInt(form_idx) + 1);
});
</script>
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
</form>
Right now, the fields I want disabled for existing forms are also disabled when the user adds a new form with the "Add More" button. I've seen this question:In a Django form, how do I make a field readonly (or disabled) so that it cannot be edited?. However, I don't understand how to combine both elements of the solution: fields.disabled = True in django > 1.9, and an if statement to delineate between existing and new forms in the formset. I've also heard of the _construct_form method as a potential option, but I think an if statement in the Model Form creation would be cleaner and easier to understand.
Thank you for any and all insight you might have!
It seems to me that you can use the technique in the question you link to:
class MyForm(ModelForm):
class Meta:
model = MyModel
fields = '__all__'
def __init__(self, *args, **kwargs):
super(MyForm, self).__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
if instance and instance.pk:
self.fields['idno'].disabled = True
self.fields['date'].disabled = True
self.fields['entity'].disabled = True
self.fields['logic'].disabled = True
Note that you can only do this by checking the instance exists because all fields are required. If some of them weren't you would need to check whether each of them had a value.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With