我的 Django 项目有问题。我有一个模型“Fattura”和一个表单“EntrataForm”,这是模型的代码:
class Fattura(models.Model):
TIPO_CHOICES = [
('T', 'Tasse'),
('B', 'Burocrazia'),
('C', 'Clienti'),
('S', 'Spese'),
]
numero = models.CharField(max_length=20)
data = models.DateField(default=django.utils.timezone.now)
tipo = models.CharField(max_length=1, choices=TIPO_CHOICES)
importo = models.DecimalField(max_digits=10, decimal_places=2)
cliente = models.ForeignKey(Cliente, on_delete=models.CASCADE, null=True, blank=True)
viaggi = models.ManyToManyField(Viaggio)
def clean(self):
if self.importo is None:
raise ValidationError('L\'importo non può essere None.')
def __str__(self):
return f"{self.numero} - {self.data} - {self.importo} - {self.tipo}"
和形式:
class EntrataForm(forms.ModelForm):
class Meta:
model = Fattura
fields = ['numero', 'data', 'cliente','viaggi','importo','tipo']
def __init__(self, *args, **kwargs):
id = kwargs.pop('id',None)
super(EntrataForm, self).__init__(*args, **kwargs)
importo_finale = 0
viaggi = Viaggio.objects.filter(cliente_id=id)
for viaggio in viaggi:
importo_finale += viaggio.prezzo_viaggio
print(id)
self.fields['tipo'].widget.attrs['readonly'] = True
self.fields['tipo'].required = False
self.fields['tipo'].widget = forms.HiddenInput()
self.fields['tipo'].initial = 'C'
self.fields['viaggi'].widget.attrs['readonly'] = True
self.fields['viaggi'].required = False
self.fields['viaggi'].widget = forms.HiddenInput()
self.fields['viaggi'].initial = viaggi
self.fields['cliente'].widget.attrs['readonly'] = True
self.fields['cliente'].required = False
self.fields['cliente'].widget = forms.HiddenInput()
self.fields['cliente'].initial = Cliente.objects.get(id=id)
self.fields['importo'].widget.attrs['readonly'] = True
self.fields['importo'].required = False
self.fields['importo'].widget = forms.HiddenInput()
self.fields['importo'].initial = importo_finale
print(self.fields['importo'].initial)
如您所见,我对 4 个字段使用了“.initial”属性,但只有“importo”未正确初始化。在 init 中,最终值是正确的,最后一行打印我想要的内容,但是当它返回到视图并执行 form.is_valid() 行时,它会引发 ValidationError,因为“importo”是 None 。其他字段没有这个错误,但是程序是一样的,我不明白值“importo”在哪里变成了None。
查看代码如下:
def entrata(request, id):
viaggi = Viaggio.objects.filter(cliente_id=id)
cliente = Cliente.objects.get(id=id)
if request.method == 'POST':
form = EntrataForm(request.POST, id=id)
if form.is_valid():
nuova_fattura = form.save()
return redirect('fatture')
else:
# Se il form non è valido, potresti restituire un template renderizzato
print(form.errors)
return redirect('fatture')
else:
form = EntrataForm(id=id)
return render(request, 'fatture/crea/cliente/entrata.html', {'form': form, 'cliente': cliente, 'viaggi':viaggi})
这是模板:
{% extends 'fatture/index.html' %}
{% block corpo %}
<body>
<button onclick="location.href = '{% url 'fatture' %}'" id="indietro">Indietro</button>
<section>
<h2>Viaggi per {{ cliente }}</h2>
<h3>Seleziona i viaggi che vuoi inserire nella fattura</h3>
<div id="banner">
<form id="fattura-form" method="post" action="{% url 'entrata' cliente.id%}">
{% csrf_token %}
<label for="{{ form.numero.id_for_label }}">Numero:</label>
{{ form.numero }}
<br>
<label for="{{ form.data.id_for_label }}">Data:</label>
{{ form.data }}
<br>
<button type="submit">Inserisci</button>
</form>
<table id="tabella-fatture" style="margin-top: 30px;">
<thead>
<tr>
<th>Data</th>
<th>Distanza</th>
<th>Prezzo Viaggio</th>
</tr>
</thead>
<tbody>
{% for viaggio in viaggi %}
<tr>
<td>{{ viaggio.data_viaggio }}</td>
<td>{{ viaggio.distanza_km }}</td>
<td>{{ viaggio.prezzo_viaggio }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</section>
</body>
{% endblock %}
更新
我更改了模板,我用 {{form.as_p}} 而不是两个表单值,现在问题也出在其他字段上。现在的form.error是:
<ul class="errorlist"><li>viaggi<ul class="errorlist"><li>"" non � un valore valido.</li></ul></li><li>importo<ul class="errorlist"><li>Questo campo � obbligatorio.</li></ul></li><li>tipo<ul class="errorlist"><li>Questo campo � obbligatorio.</li></ul></li><li>__all__<ul class="errorlist nonfield"><li>L'importo non pu� essere None.</li></ul></li></ul>
您没有在模板中呈现该字段,因此在发布表单时不包含该字段及其初始值。视图中请求的 POST 数据不包含
importo
字段,并且表单是使用该不完整的数据实例化的。并且您在 init 方法中设置的初始值无法替代数据中缺少的值:
使用initial在运行时声明表单字段的初始值。 ...这些值仅针对未绑定的表单显示,如果未提供特定值,它们不会用作后备值。
https://docs.djangoproject.com/en/4.2/ref/forms/api/#initial-form-values
由于模型需要
importo
(null!=True
) 的值,因此表单验证“通常”会在此处失败,并显示需要 importo
的消息。但是您在表单 init 方法中将 importo
设置为不需要,这意味着表单验证至少首先通过。然后,模型上的自定义 clean 方法会触发验证错误,因为从未设置 importo
的值,即它仍然是 None
。