I have a few models, two of which are as follows:
class Receivables(models.Model):
patient=models.ForeignKey(Patient, on_delete=CASCADE)
pattern = RegexValidator(r'(RT|rt|rT|Rt)\/[0-9]{4}\/[0-9]{2}\/[0-9]{4}', 'Enter RT Number properly!')
rt_number=models.CharField(max_length=15, validators=[pattern])
discount=models.DecimalField(max_digits=9, decimal_places=2, default=0)
approved_package=models.DecimalField(max_digits=10, decimal_places=2, default=0)
approval_date=models.DateField(default=None)
proposed_fractions=models.IntegerField()
done_fractions=models.IntegerField()
base_value=models.DecimalField(max_digits=10, decimal_places=2, blank=True)
expected_value=models.DecimalField(max_digits=10, decimal_places=2, blank=True)
class Discharge(models.Model):
patient=models.ForeignKey(Patient, on_delete=CASCADE)
date_of_discharge=models.DateField(default=None)
mould_charges=models.DecimalField(max_digits=7, decimal_places=2, default=0, blank=True)
ct_charges=models.DecimalField(max_digits=7, decimal_places=2, default=0, blank=True)
discharge_updated=models.BooleanField(default=False)
The views to save the new instance and update the existing one respectively, are:
1.
def discharge_view(request):
if request.method=='POST':
fm_discharge=DischargeForm(request.POST, request=request)
if fm_discharge.is_valid():
discharge=fm_discharge.save()
ipd=IpdReport.objects.create(patient=discharge.patient, package=Package.objects.filter(patient=discharge.patient).order_by('-id').first(), receivables=Receivables.objects.filter(patient=discharge.patient).order_by('-id').first(), discharge=discharge)
if discharge is not None:
OngoingReport.objects.filter(ipdreport__patient=discharge.patient).delete()
package=Package.objects.filter(patient=discharge.patient).order_by('-id').first().patient_type.patient_type
if discharge.discharge_updated==False and package!='CASH':
UnclaimedPendingCases.objects.create(ipdreport=ipd)
elif discharge.discharge_updated==True and package!='CASH':
ClaimedPendingCases.objects.create(ipdreport=ipd)
fm_discharge=DischargeForm(request=request)
return render(request, 'account/discharge.html', {'form':fm_discharge})
else:
fm_discharge=DischargeForm(request=request)
return render(request, 'account/discharge.html', {'form':fm_discharge})
def update_discharge_view(request, id):
di1=Discharge.objects.get(pk=id)
fm1=di1.discharge_updated
if request.method=='POST':
print(request.POST)
di=Discharge.objects.get(pk=id)
form=DischargeForm(request.POST, instance=di, request=request)
if form.is_valid():
discharge=form.save()
else:
di=Discharge.objects.get(pk=id)
form=DischargeForm(instance=di, request=request)
return render(request, 'account/update_discharge.html', {'form':form})
The ModelForm looks as below:
class DischargeForm(ModelForm):
class Meta:
model=Discharge
fields='__all__'
widgets={
'date_of_discharge': DateInput(attrs={'type': 'date'}),
}
def __init__(self, *args, **kwargs):
self.request=kwargs.pop('request')
self.instance=kwargs.pop('instance')
super(DischargeForm, self).__init__(*args, **kwargs)
def clean(self):
super().clean()
pt=self.request.POST.get('patient')
if not self.instance:
rec=Receivables.objects.filter(patient__pk=pt).order_by('-id').first()
if Discharge.objects.filter(patient__pk=pt, date_of_discharge__gt=rec.approval_date).exists():
raise ValidationError('The patient has already been discharged!')
I want the discharge to be saved only once, for each time the patient gets treatment. Though it can be updated. Earlier I had written it like:
class DischargeForm(ModelForm):
class Meta:
model=Discharge
fields='__all__'
widgets={
'date_of_discharge': DateInput(attrs={'type': 'date'}),
}
def clean(self):
super().clean()
pt=self.cleaned_data['patient']
rec=Receivables.objects.filter(patient__pk=pt).order_by('-id').first()
if Discharge.objects.filter(patient__pk=pt, date_of_discharge__gt=rec.approval_date).exists():
raise ValidationError('The patient has already been discharged!')
without passing the request kwargs to fm_discharge=DischargeForm()
in views.py
and it worked fine for the new instances being created. But it threw the same ValidationError
for the instance coming in for the update, because, obviously the discharge
instance already exists in the database for the same patient. Then, when I added the init method and accessed request and instance to resolve this, two problems showed up:
- It created a new instance of the data which was supposed to be just updated.
- As the new entry does not have an instance already, the init threw a KeyError for instance.
What can I do here? How to handle different scenarios such as this in the ModelForm?
CodePudding user response:
To fix this, don't pop instance
in __init__
, as doing so will cause the super()
call to tell the ModelForm
that it will be working on creating a new object. Essentially it would be like the instance wasn't passed to the form at all.
For the clean
call, just add a flag that the validation should only run when creating an instance (and not when updating) using self.instance.pk
, so:
def clean(self):
super().clean()
if not self.instance.pk:
pt=self.cleaned_data['patient']
rec=Receivables.objects.filter(patient__pk=pt).order_by('-id').first()
if Discharge.objects.filter(patient__pk=pt, date_of_discharge__gt=rec.approval_date).exists():
raise ValidationError('The patient has already been discharged!')