django inlineformset_factory 内联model前端动态增删操作

用Todo来demo, 比如我们创建Todo表,首先有个topic,每个topic下面再挂着多个子item。

效果:

django inlineformset_factory 内联model前端动态增删操作_第1张图片

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渲染:

{% csrf_token %}

Topic

{{ t_form.as_p }}

Item

{{ i_formset.management_form }} {% for form in i_formset %}
{{ form.as_p }}
{% endfor %}

js中主要功能:

1. 当点击添加按钮后,动态增加form-row的总数:

4" id="id_item_set-TOTAL_FORMS">

复制第一个form-row的html,但是需要把index改成最新的。

2. 删除按钮后,也要做相应的改变,但是如果是更新页面的话,点击删除,只需要把hidden的删除按钮,状态改成checked就行。

代码:

 

 

你可能感兴趣的:(django,前端)