Метод clean() в Django ModelForm для предотвращения дублирования записей создает еще один экземпляр при обновлении данных. И даже не сохраняет новый экземпляр.
У меня есть несколько моделей, две из которых следующие:
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)
Представления для сохранения нового экземпляра и обновления существующего, соответственно, следующие:
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})
Форма модели выглядит следующим образом:
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!')
Я хочу, чтобы выписка сохранялась только один раз, для каждого случая, когда пациент получает лечение. Хотя она может быть обновлена. Ранее я писал это так:
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!')
без передачи kwargs запроса fm_discharge=DischargeForm()
в views.py
и он работал нормально для новых создаваемых экземпляров. Но для экземпляра, поступающего для обновления, он выбрасывал тот же ValidationError
, потому что, очевидно, экземпляр discharge
уже существует в базе данных для того же пациента. Затем, когда я добавил метод init и получил доступ к запросу и экземпляру, чтобы решить эту проблему, возникли две проблемы:
- 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.
Что я могу здесь сделать? Как обрабатывать различные сценарии, подобные этому, в ModelForm?
Чтобы исправить это, не вставляйте instance
в __init__
, так как это приведет к тому, что вызов super()
сообщит ModelForm
, что он будет работать над созданием нового объекта. По сути, это будет выглядеть так, как будто экземпляр вообще не был передан в форму.
Для вызова clean
просто добавьте флаг, что проверка должна выполняться только при создании экземпляра (а не при обновлении) с помощью self.instance.pk
, так:
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!')