用Todo来demo, 比如我们创建Todo表,首先有个topic,每个topic下面再挂着多个子item。
效果:
model.py:
class Topic(models.Model):
title = models.CharField(max_length=255)
created_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.title
class Item(models.Model):
topic=models.ForeignKey(Topic, on_delete=models.CASCADE)
title = models.CharField(max_length=255)
content = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.title
url.py:
path('todo/create/', views.createTodo, name='todo_create'),
path('todo//update/', views.updateTodo, name='todo_update'),
form.py中:
class TopicModelForm(forms.ModelForm):
class Meta:
model = Topic
fields = ('title',
)
class ItemDeleteBaseInlineFormSet(BaseInlineFormSet):
"""
Makes the delete field a hidden input rather than the default checkbox
inlineformset_factory(Book, Page, formset=HiddenDeleteBaseInlineFormSet, can_delete=True)
"""
def add_fields(self, form, index):
super(ItemDeleteBaseInlineFormSet, self).add_fields(form, index)
if self.can_delete:
form.fields[DELETION_FIELD_NAME] = forms.BooleanField(
label=('Delete'),
required=False,
widget=forms.CheckboxInput(attrs={"class": "btn_delete"})
)
ItemModelFormSet = forms.inlineformset_factory(Topic,
Item,
fields=('title',
'content',
),
extra=1,
formset=ItemDeleteBaseInlineFormSet,
)
ItemDeleteBaseInlineFormSet是为了给渲染出来的删除按钮加上class,前端能够根据这个css去隐藏:
$('.btn_delete').parent().hide();
view.py:
def createTodo(request):
template_name = 'todo/create.html'
if request.method == 'GET':
t_form = TopicModelForm(request.GET or None)
i_formset = ItemModelFormSet(queryset=Topic.objects.none())
elif request.method == 'POST':
t_form = TopicModelForm(request.POST)
if t_form.is_valid():
t = t_form.save(commit=False)
t.save()
i_formset = ItemModelFormSet(request.POST, instance=t)
if i_formset.is_valid():
i_formset.save()
return redirect('todo_update',pk=t.pk)
return render(request, template_name, {
't_form': t_form,
'i_formset': i_formset,
})
def updateTodo(request, pk):
template_name = 'todo/create.html'
t = get_object_or_404(Topic, pk=pk)
i = Item.objects.filter(topic=t)
if request.method == 'GET':
t_form = TopicModelForm(instance=t)
i_formset = ItemModelFormSet(instance=t)
i_formset.extra = 1 if i_formset.queryset.count() < 1 else 0
elif request.method == 'POST':
t_form = TopicModelForm(request.POST, instance=t)
if t_form.is_valid():
t_form.save()
i_formset = ItemModelFormSet(request.POST, instance=t)
if i_formset.is_valid():
i_formset.save()
return redirect('todo_update', pk=t.pk)
return render(request, template_name, {
't_form': t_form,
'i_formset': i_formset,
'i': i,
't': t,
})
前端,html中,template渲染:
js中主要功能:
1. 当点击添加按钮后,动态增加form-row的总数:
4" id="id_item_set-TOTAL_FORMS">
复制第一个form-row的html,但是需要把index改成最新的。
,
2. 删除按钮后,也要做相应的改变,但是如果是更新页面的话,点击删除,只需要把hidden的删除按钮,状态改成checked就行。
代码: