Django表单-根据另一个字段的答案限制字段的选项



我有一个Django表单,它接收来自用户的带有外科手术信息的条目。每个程序只有一种(外科)技术和一种诊断。每种技术可能与有限数量的诊断相关,每种诊断可能用于不同的技术。我想根据用户先前在表单上选择的技术来限制表单中出现的诊断。

我尝试使用smart_select chainedmanymany字段相对成功,但它使多个诊断被选择,我只想有一个。

我还使用DAL自动完成技术(超过1,6k选项)作为用户类型。

我的模型:

# The "Technique" model
class Sigtap(models.Model):
codigo = models.CharField(max_length=10)
descricao = models.CharField(max_length=175, default='')

# The "Diagnosis" model
class Cid10(models.Model):
codigo = models.CharField(max_length=4)
descricao = models.CharField(max_length=270, default='')
sigtap_compativel = models.ManyToManyField(Sigtap, blank=True)

# The "Surgical Procedure" model
class Cirurgia(models.Model):
paciente = models.PositiveIntegerField(verbose_name='Número do prontuário')
data = models.DateField(verbose_name='Data de realização')
procedimento = models.ForeignKey(Sigtap, on_delete=models.CASCADE,
verbose_name='Código do procedimento (SIGTAP)')
cid = ChainedManyToManyField(
Cid10, horizontal=True, chained_field='procedimento', chained_model_field='sigtap_compativel', auto_choose=True, verbose_name='CID-10')

我的形式:

class CirurgiaModelForm(forms.ModelForm):
class Meta:
model = Cirurgia
fields = ['paciente', 'data', 'procedimento', 'cid']
widgets = {
'procedimento': autocomplete.ModelSelect2(url='sigtap-autocomplete'),
}

如何使表单字段只显示与所选技术相关的诊断,并且只允许一个选项?

你命名字段和类的方式让我很困惑,因为类的名字并不能代表它们的本质……还有这个:

procedimento = models.ForeignKey(Sigtap, on_delete=models.CASCADE,
verbose_name='Código do procedimento (SIGTAP)')

你改变名字的地方,我不知道是什么原因,如果你要用像cidsigtap这样的代码,就坚持下去。这是一个非常糟糕的做法。

无论如何,您需要的是使用AJAX向视图发送请求,在该视图中您根据给定的id过滤Model,然后在模板中使用该数据。由于关系的性质(需要深入研究),我无法将此解决方案适合ModelForm,因此我在HTML表单内使用了<select>标签:

forms.py:

class CirurgiaModelForm(forms.ModelForm):
procedimento = forms.ModelChoiceField(queryset=Sigtap.objects.all(), widget=forms.Select({'onchange' : "myFunction(this.value);"}))
class Meta:
model = Cirurgia
fields = ['paciente', 'data', 'procedimento']
widgets = {
'data': forms.DateInput(attrs={'type': 'date'}),
}

views.py

import json
from django.http import JsonResponse
def surgery(request):
if request.method == 'POST':
form = CirurgiaModelForm(request.POST)
if form.is_valid():
try:
cid = Cid10.objects.get(id=request.POST.get('cid'))
cirurgia = Cirurgia.objects.create(**form.cleaned_data)
cirurgia.cid.add(cid)
except ObjectDoesNotExist:
pass
return redirect('/surgery/')
else:
form = CirurgiaModelForm()

return render(request, 'surgery.html', {'form': form})
def filter_diagnosis_ajax(request):
data = json.loads(request.body)
procedimento = Sigtap.objects.get(id=data['technique_id'])
cid_list = list(Cid10.objects.filter(sigtap_compativel=procedimento).values())
return JsonResponse({'diagnoses': cid_list})

function function

function function function function
{% block content %}
<form action="surgery/" method="post">
{% csrf_token %}
{{form.as_p}}
<label>diagnosis: </label><select name="cid" id="id_cid"></select>
<br>
<br>
<button type="submit" >Create Procedure</button>
</form>
<script>
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
function removeOptions(selectElement) {
var i, L = selectElement.options.length - 1;
for(i = L; i >= 0; i--) {
selectElement.remove(i);
}
}
function myFunction(value) {
url = '/filter/technique/'
const csrftoken = getCookie('csrftoken');
fetch(url, {
method: 'POST',
headers: {
'X-CSRFToken': csrftoken,
'Content-Type': 'application/json'
},
mode: 'same-origin',
body: JSON.stringify({'technique_id': value}),
})
.then((response) => response.json())
.then((data) => {
var diagnosis_select = document.getElementById("id_cid");
removeOptions(diagnosis_select);
for (var i = 0; i<=data.diagnoses.length-1; i++){
var opt = document.createElement('option');
opt.value = data.diagnoses[i]['id'];
opt.innerHTML = data.diagnoses[i]['descricao'];
diagnosis_select.appendChild(opt);
}

})
.catch((error) => {
console.error('Error:', error);
});
}
</script>
{% endblock %} 

由于我已经在使用Django - Autocomplete - Light,所以我设法在Django Autocomplete Light文档中做了一些修改

最新更新