Django中 页面与模态框数据传输

模态框经常在一些网站的填写数据,或者登陆框中出现。当我们点击模态框的按钮时我们到底该怎么将数据传输到弹出来的框中呢?通常如果模态框中只需要简单的填一些数据,那么安分的通过标签获取数据,再填充数据就可以,但如果弹出的模态框中存在一对多,多对多关系的字段时,就比较难处理。因为你保存到数据库时是要保存对象,而不仅仅是用户输入的字符串。

最开始我看到的是bootstrap中的data属性,但经我尝试,这个data只获取到了当前按键中传输的数据,而如果我对过parent()方法转到父级标签就不生效了,前端这块确实比较弱。如果这个思路能实现真的是很省事。下面简单说一下获取data数据:

<button type="button" class="btn btn-primary btn-md" data-toggle="modal" data-target="#myModal" data-book_id="{{ book.id }}">
    编辑
</button>

然后js中获取数据的方法

$('#myModal').on('show.bs.modal', function (event) {
        var button = $(event.relatedTarget); // 触发模态框的按钮,这里是编辑
        var book_id = button.data('book_id'); // 编辑按钮有个data-book_id属性,获取时只需要book_id

        var modal = $(this); //获取弹出来的模态框对象
        modal.find('.book_id').text(book_id)  //在弹出的模态框中找到book_id的类标签,将book_id值填充
    })

我尝试将获取button的父级标签,但再对其使用data方法时则只能获取到 undefined. 所以改变了思路。

思路一:模态框也是网页,那如果我将模态框的内容事先渲染好,再填充到模态框的这个 <div class='modal-body'></div>内。也就是把中间这部分内容写成独立的html组件,渲染成HttpResponse对象,再通过ajax的返回值填充到modal-body中。

这种方法有一个好处,它可以直接渲染出一对多,多对多的多选,单选关系来,非常方便。但也有它的问题,因为点击的过程中实际上已经发生了一次网络请求,可能会比较慢,导致模态框弹出来没有内容,而如果要渲染的内容较多就更慢了。

    var edit = $(".edit");
        edit.click(function () {
            book_id = $(this).val();
            $.ajax(
                {
                    url: '/edit_book/' + book_id + '/',
                    method: 'GET',
                    success: function (response) {
                        $(".modal-body").html(response);
                    }
                }
            )
        });

注意,通过id获取到对象后要将对象渲染到前端,返回HttpResponse对象,这样才能渲染到html(HttpResponse,或者render都可以)

另一种思路就是,老老实实获取当前点击的一栏数据,一个个获取到值再传到弹出的模态框中,填充。

我们通过当前按钮获取到当前栏的tr对象,再获取到所有的td,按列表的方式取它里面的值(因为authors是多对多字段,有多个值,这里用replace去掉了空格),获取这到些值再到模态框中找到对应的标签,将这些值填充进去。待修改后,点击保存时,触发提交事件,将数据发送到后台。后台保存后填充到前端的表格中。

<script>
    $('#myModal').on('show.bs.modal', function (event) {
        var button = $(event.relatedTarget); // Button that triggered the modal
        var book_id = button.data('book_id'); // Extract info from data-* attributes

        var tds = button.parent().parent().children();
        var name = tds.eq(1).text();
        var authors = tds.eq(2).text().replace(/\ +/g,"");
        var price = tds.eq(3).text();
        var publish = tds.eq(4).text();

        var modal = $(this);
        modal.find('#name').val(name);
        modal.find('#authors').val(authors);
        modal.find('#price').val(price);
        modal.find('#publish').val(publish);

        var save_btn = $(".modal-footer .btn-primary");
        var csrf_token = $("[name='csrfmiddlewaretoken']").val();


        save_btn.click(function () {
            var form = new FormData();
            name = $("#name").val();
            authors = $("#authors").val();
            price = $("#price").val();
            publish = $("#publish").val();

            $.ajax({
                url: '/edit/' + book_id + '/',
                method: 'POST',
                data: {
                    'name': name,
                    'authors': authors,
                    'price': price,
                    'publish': publish,
                    'csrfmiddlewaretoken': csrf_token,
                },
                success: function (response) {
                    tds.eq(1).text(response.name);
                    tds.eq(2).text(response.authors);
                    tds.eq(3).text(response.price);
                    tds.eq(4).text(response.publish);
                    $("#myModal").modal('hide');
                }
            })

        })
    })

</script>

这种方式有很多不好的地方,一是多对多,一对多关系,在后台处理麻烦,另外客户不能乱填信息,如果填了一个不存在的用户,则无法保存成功,当有多个作者时,需要有一种约定来出来比如作者名间用逗号隔开。总的来说增加了后端写代码的难度。

def edit(request, id):
    book = Book.objects.filter(id=id).first()
    if request.is_ajax():
        data = request.POST
        book.name = data['name']
        book.price = data['price']

        publish_obj = Publish.objects.filter(name=data['publish']).first()
        book.publish = publish_obj
        book.author.clear()  # 添加新的关系前解除之前的关系
        if ',' in data['authors']:
            author_list = data['authors'].split(',')
            author_objs = [Author.objects.filter(name=author_name).first() for author_name in author_list]
            book.author.add(*author_objs)
        else:
            author_objs = Author.objects.filter(name=data['authors']).first()
            book.author.add(author_objs)
        book.save()
        return JsonResponse(data)

可以看到,这里处理作者信息比较麻烦,而这样仍不能保证填写成功,比如逗号分中英文。当填写的作者信息不存在时也是处理不了的。而第一种方法我们可以通过把所有可选的作者全部渲染到前端的多选框,并将原来数据设置成选中状态,这种体验肯定是不同的。

暂时没找到更好的方法处理这种情况的方法,先记录,如果后面有更好的办法,再更新。

上一篇:Ajax发送多选框的值的bug

下一篇:Django modelformset_factory使用