如何对用户指定的未知数量的字段执行Django表单验证?在我的例子中,表单允许用户创建具有任意数量轨道的音乐专辑并将其与艺术家相关联。视图询问有多少曲目,然后生成一个包含许多输入字段的表单。
形式:
class NumberOfTracks(forms.Form):
track_no = forms.IntegerField()
class CustomAlbumAdmin(forms.Form):
artist = forms.CharField(max_length=150)
album = forms.CharField(max_length=150)
track_no = forms.IntegerField()
track = forms.CharField(max_length=150)
查看:
def album_admin(request):
if request.GET.get('track_no'):
number_of_tracks = request.GET.get('track_no')
artists = Artist.objects.all()
return render(request, 'customadmin/album_admin1.html', {
'number_of_tracks': number_of_tracks,
'tracks': range(1, int(number_of_tracks) + 1),
'artists': artists,
})
elif request.method == 'POST':
form = CustomAlbumAdmin(request.POST)
print form
artist = request.POST['artist']
album = request.POST['album']
all_tracks = request.POST.getlist('track')
create_album = CreateAlbum(artist=artist, album=album, tracks=all_tracks)
create_album.save_album()
create_album.save_tracks()
form = NumberOfTracks()
return render(request, 'customadmin/no_tracks1.html', {
'form': form,
})
else:
form = NumberOfTracks()
return render(request, 'customadmin/no_tracks1.html', {
'form': form,
})
(就这么明白,我使用了if form.is_valid()
和form.cleaned_data
但是为了让这个工作到目前为止,我不得不绕过它,转而采用原始版本POST数据)
让我感到困惑的一部分原因是我已经自定义了我的表单模板,以添加一个数字输入字段,其名称为" track"取决于用户输入(EX:创建包含13首曲目的专辑)。当我进入print form = CustomAlbumAdmin(request.POST)
的视图时,它根据我的表单提供了一个非常简单的表:一个艺术家,一个专辑,一个曲目和一个track_no如此验证,当然会返回False
,除非我有一个只有一个曲目的专辑。
这是模板:
{% extends 'base.html' %}
{% block content %}
<form action="/customadmin/album1/" method="POST">{% csrf_token %}
<select name="artist">
{% for entry in artists %}
<option value="{{ entry.name }}">{{ entry.name }}</option>
{% endfor %}
</select>
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.album.errors }}
<label for="id_album">Album:</label>
<input id="id_album" maxlength="150" name="album" type="text" />
</div>
<div class="fieldWrapper">
{{ form.track.errors }}
<input type="hidden" name="number_of_tracks" value="{{ number_of_tracks }}">
{% for e in tracks %}
<label for="id_track">Track No. {{ forloop.counter }}</label>
<input id="id_track_{{ forloop.counter }}" maxlength="150" name="track" type="text" /></br>
{% endfor %}
</div>
<p><input type="submit" value="Save album" /></p>
</form>
{% endblock %}
我想要接近这个的一种方法是创建一个自定义的clean_track方法,该方法获取我在视图中使用all_tracks = request.POST.getlist('track')
完成输入的所有曲目的列表,但不知道如何做这一点。
我遇到的一个相关问题是,我是否可以根据POST数据自定义验证。我接近这个的第一种方法是生成增量输入,名称=&#34; track_1&#34;,name =&#34; track_2&#34;等等。然后尝试基于此验证。但是,在这种情况下,我无法使用request.POST.getlist('track')
。
答案 0 :(得分:1)
使用formsets可能是更好的方法。
class AlbumForm(forms.Form):
artist = forms.CharField(max_length=150)
name = forms.CharField(max_length=150)
class TrackForm(forms.Form):
track_no = forms.IntegerField()
name = forms.CharField(max_length=150)
# In view
from django.forms.formsets import formset_factory
TrackFormSet = formset_factory(TrackForm)
if request.method == 'POST':
track_formset = TrackFormSet(request.POST)
album_form = AlbumForm(request.POST)
if track_formset.is_valid() and album_form.is_valid():
save_album(album_form, track_formset)
else:
track_formset = TrackFormSet()
album_form = AlbumForm()
在save_album
中,您可以遍历track_formset.ordered_forms
以获取formset中的每个表单:
for form in track_formset.ordered_forms:
data = form.cleaned_data
# Do what you want with the data
如果您使用model formsets,这可能会更强大,因为您可以在轨道模型中设置指向相册模型的外键,Django可以自动为您保存它们。