Django的formset用于编辑部分预定义的数据

时间:2015-01-28 03:20:55

标签: django django-forms

这是我的域名模式:

class Seat(models.Model):
    name = models.CharField(max_length=8)

class Event(models.Model):
    ...

class Occupation(models.Model):
    event = models.ForeignKey(Event, related_name='occupations')
    seat = models.ForeignKey(Seat)
    number = models.CharField(max_length=20)

Seat是一个小表,就像5-10条记录一样。)

我们对事件编辑页面的UI要求如下所示:

[1-01] [enter number]
[1-02] [enter number]
[1-03] [enter number]
[2-01] [enter number]
[2-02] [enter number]
[2-03] [enter number]

用户导航到活动的职业页面,他们会在系统中看到所有席位的列表,并提示您填写数字外部资源进入系统。

由于席位表非常小,并且为了防止选择相同的座位两次的错误,我们需要显示预填充到表单中的所有席位并锁定,因此用户无法更改座位选项,仅限于输入相应的数字

此外,席位可以添加或删除,因此我们无法制作"静态"表格有6个预定义的行。

我认为它应该是一个Django的内联模型formset,其形式类似于

class OccupationForm(forms.ModelForm):
    class Meta:
        model = Occupation
        fields = ('seat', 'number')

    ...

但我不确定如何显示预填充表单,阻止用户更改席位(而不仅仅是通过disabled或javascript进行客户端锁定)

1 个答案:

答案 0 :(得分:1)

首先将seat小部件设置为HiddenInput,然后将seat_name属性添加到表单中。稍后将在HTML模板中使用此属性:

class OccupationForm(forms.ModelForm):

    class Meta:
        model = Occupation
        fields = ('seat', 'number')
        widgets = {'seat': forms.HiddenInput}

    def __init__(self, *args, **kwargs):
        super(OccupationForm, self).__init__(*args, **kwargs)
        self.fields['number'].required = False
        self.seat_name = self.initial['seat'].name

然后使用该事件的席位和数字填充initial数据。将此initial传递给formset。像往常一样验证并保存formset:

from django.forms.formsets import formset_factory

def update_seats(request, event_id):

    event = Event.objects.get(pk=event_id)
    numbers = dict((o.seat, o.number) for o in event.occupations.all())
    initial = [{'seat': seat, 'number': numbers.get(seat, '')}
                                            for seat in Seat.objects.all()]

    OccupationFormSet = formset_factory(OccupationForm,
                                     min_num=len(initial), validate_min=True,
                                     max_num=len(initial), validate_max=True,
                                     extra=0)

    if request.method == 'POST':
        formset = OccupationFormSet(request.POST, initial=initial)
        if formset.is_valid():
            for form in formset:
                seat = form.initial['seat']
                number = form.cleaned_data.get('number', '').strip()
                if number:
                    Occupation.objects.update_or_create(
                                                 event=event, seat=seat,
                                                 defaults={'number': number})
                else:
                    Occupation.objects.filter(event=event, seat=seat).delete()
            return redirect('.')
    else:
        formset = OccupationFormSet(initial=initial)

    return render(request, 'update_seats.html', {'formset': formset})

update_seats.html模板,其中我们将座位名称显示为{{ form.seat_name }}

<form action="" method="post">

    {% csrf_token %}

    <table>
        {{ formset.management_form }}

        <tr>
            <th>Seat</th>
            <th>Number</th>
        </tr>

        {% for form in formset %}
        <tr>
            <td>[{{ form.seat_name }}]{{ form.seat }}</td>
            <td>{{ form.number }}</td>
        </tr>
        {% endfor %}

    </table>

    <button>Update</button>

</form>