这是我的域名模式:
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进行客户端锁定)
答案 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>