【问题标题】:Validate Django forms for user specified dynamically generated fields验证用户指定的动态生成字段的 Django 表单
【发布时间】:2014-05-07 16:10:57
【问题描述】:

如何对用户指定的未知数量的字段执行 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 数据)

让我感到困惑的部分原因是,我自定义了表单模板,根据用户输入添加了一个带有 name="track" 的数字输入字段(例如:创建一个包含 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 数据自定义验证。我解决这个问题的第一种方法是生成带有 name="track_1"、name="track_2" 等的递增输入。然后尝试基于此进行验证。但是,在这种情况下,我将无法使用request.POST.getlist('track')。

【问题讨论】:

    标签: python django validation django-forms


    【解决方案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 即可获取表单集中的每个表单:

    for form in track_formset.ordered_forms:
        data = form.cleaned_data
        # Do what you want with the data
    

    如果你使用model formsets,这会更强大,因为你可以在track model中设置一个指向专辑模型的外键,Django可以自动为你保存它们。

    【讨论】:

    • 完全成功,谢谢!我尝试搜索有关表单的所有信息,但都没有让我找到表单集。我现在唯一遇到的问题是将新的 formset 对象从我的 GET 视图传递到我的 POST 视图......我相信我可以弄清楚。
    猜你喜欢
    • 1970-01-01
    • 2020-11-27
    • 2021-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多