16. 你很勇哦,这么点数据就敢用异步加载?

Posted 梦想橡皮擦

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了16. 你很勇哦,这么点数据就敢用异步加载?相关的知识,希望对你有一定的参考价值。

爬虫训练场项目第16课,异步AJAX加载学校清单。
爬虫训练场,让天下没有失效的爬虫,2023年橡皮擦最新专栏。
项目仓库地址 :https://gitcode.net/hihell/spider_playground
博客清单:https://pachong.vip/blog

文章目录

Bootstrap 实现 ajax 请求

本篇博客的核心是使用 Bootstrap 中的 javascript 插件发送 Ajax 请求,下面先看一个示例,展示如何使用 Bootstrap 中的 $.ajax() 方法发送 AJAX 请求,这里使用的 $.ajax() 由 jQuery 插件实现,所以提前在模板文件中进行一下导入。

https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.6.0.min.js

实现本步骤操作,需要在 app/templates/school 目录中新增 ajax_list.html 文件,然后输入下述代码。

% extends "base.html" %
% block script %
<script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.6.0.min.js"></script>
<script type="text/javascript">

</script>
% endblock script %


% block content %
% endblock %

该文件继承了 base.html 文件,然后在其 script 块中,可以编写JS代码。

使用 jQuery 发送 Ajax 请求的示例代码如下所示,后续将在此基础上实现请求和渲染逻辑。

$.ajax(
  type: "POST",
  url: "/path/to/server",
  data: 
    key1: "value1",
    key2: "value2"
  ,
  success: function(response) 
    console.log("AJAX request succeeded!");
  ,
  error: function(error) 
    console.log("AJAX request failed: " + error);
  
);

接下来将刚刚的文件,绑定到视图函数中,代码编写到 school/index.py 中,如下所示。

@s.route('ajax_list')
def ajax_list():
    page = 1  # 初始化第一页数据

    pagination = pagination_object(page)
    return render_template('school/ajax_list.html', pagination=pagination)

这里将分页对象的创建的函数进行了封装,便于后续重复使用,pagination_object() 函数内容如下所示。

def pagination_object(page=1):
    # schools = School.query.all()

    query = School.query

    total = query.count()  # 获取数据总量
    pagination = Pagination(page, total)  # 获取分页对象详细参数

    if total != 0:
        data_list = query.offset(pagination["offset"]).limit(pagination["page_size"]).all()
    else:
        data_list = []
    pagination["data_list"] = data_list
    return pagination

使用 AJAX 渲染数据重点在 JS 部分,核心操作为分页请求,所以首次进入页面,需要对第一页数据进行渲染,补充 ajax_list.html 首次渲染部分代码。

<div class="container" id="school_list">

    % for school in pagination.data_list %
    <div class="row mt-3">
        <div class="col">
            <div class="d-flex">
                <div class="flex-shrink-0">
                    <a href="#">
                        <img class="rounded-pill img-thumbnail" width="64" height="64" src="school.pic" alt="">
                    </a>
                </div>
                <div class="flex-grow-1 ms-3">
                    <h5 class="float-start pe-3">school.name</h5>
                    <p class="ms-3">
                        % for fea in school.feature.split(',') %
                        <span class="badge rounded-pill bg-primary">fea</span>
                        % endfor %
                    </p>
                    <p><em>所在省市:<span class="text-black-50">school.province -- school.city</span></em></p>
                </div>
            </div>
        </div>
    </div>
    % endfor %

</div>
<div class="container">
    <div class="row">
        <div class="col">
            <span class="text-dark float-end align-middle"
                  style="line-height: 40px;">合计  pagination.total 条数据</span>
            <ul class="pagination float-end">
                <li class="page-item prev" page="pagination.prev_page">
                    <a class="page-link" href="#">上一页</a>
                </li>
                <li class="page-item next" page=" pagination.next_page "><a class="page-link"
                                                                                href="#">下一页</a>
                </li>
            </ul>
        </div>
    </div>
</div>

上述代码进行了两部分修改,第一个是给 .container 类绑定的 DIV 增加了一个 ID 值,第二个修改是给分页 <li> 标签增加了自定义属性 page,并分别绑定上一页和下一页的页码,然后取消原来的超链接跳转。

核心 JS 部分

准备工作已经完成,下面的重点在数据 AJAX 请求部分。该部分逻辑分步骤实现。

第一步,给上一页和下一个按钮绑定事件

    $(function()
        $('.page-item').on('click',function()
            page = $(this).attr('page');
            // 获取数据
            get_data(page);
        )
    )

这部分直接使用 .on() 方法进行绑定即可,注意看上述代码中的 get_data(),该函数用于发起 AJAX 请求,获取响应,并渲染数据,代码如下。

    function get_data(page)
        $.ajax(
            type: "get",
            url: "/ss/api2",
            data: 
                page: page
            ,
            success: function(response) 
                // ajax 请求成功
                render_data(response);
                // 修改分页数据
                $('.prev').attr('page',response["prev_page"]);
                $('.next').attr('page',response["next_page"]) ;
                console.log("AJAX request succeeded!");
            ,
            error: function(error) 
                console.log("AJAX request failed: " + error);
            
         );
    

请求的数据接口地址为 /ss/api2,所以还需要回到 school/index.py 文件中,增加该部分函数。

@s.route('api2')
def ajax_list_school():
    page = int(request.args.get("page", 1))

    pagination = pagination_object(page)

    return jsonify(pagination)

上述代码出现了一个新函数 jsonify(),在 Python Flask 中,可以使用 jsonify() 函数将数据转换为 JSON 并返回给客户端。

简单的案例如下所示。

from flask import Flask, jsonify

app = Flask(__name__)

@app.route('/data')
def get_data():
    data = 'key1': 'value1', 'key2': 'value2'
    return jsonify(data)

if __name__ == '__main__':
    app.run()

在上面的代码中,我们定义了一个视图函数 get_data(),该函数创建了一个字典,并使用 jsonify() 函数将其转换为 JSON 并返回给客户端。

继续回到JS代码部分,在接收到数据请求之后,我们依次编写了如下代码,其分为两部分,第一部分是数据渲染,第二部分是分页组件页码变化。

render_data(response);
// 修改分页数据
$('.prev').attr('page',response["prev_page"]);
$('.next').attr('page',response["next_page"]) ;

这里主要看 render_data() 函数的实现,代码如下所示。

    function render_data(response)
            data_list = response["data_list"];
            if(data_list.length>0)
             // 清空原有数据
                $('#school_list').empty();
                $.each(data_list,function(index,item)
     // 循环渲染数据
                    var row = $('<div>', 
                      'class': 'row mt-3',
                      'data-custom-attribute': 'value'
                    );
                    var col =$('<div>', 
                      'class': 'col'
                    );
                    var d_flex = $('<div>', 
                      'class': 'd-flex'
                    );
                    d_flex.append('<div class="flex-shrink-0"><a href="#"><img class="rounded-pill img-thumbnail" width="64" height="64" src="'+item.pic+'" alt=""></a></div>');
                    // 生成一下标签代码
                    var badge = "";
                    $.each(item.feature.split(','),function(i,f)
                       badge += ' <span class="badge rounded-pill bg-primary">'+f+'</span> ';
                    );

                    d_flex.append('<div class="flex-grow-1 ms-3"><h5 class="float-start pe-3">'+item.name+'</h5><p class="ms-3">'+badge+'</p><p><em>所在省市:<span class="text-black-50">'+item.province+'--'+item.city+'</span></em></p></div>')

                    col.append(d_flex);
                    row.append(col);
                    $('#school_list').append(row);
                )
            
    

JS代码使用了循环渲染,拼接HTML DOM 对象的方式实现,其重点代码就是在循环后台发送过来的学校对象数组,然后追加到 ID = school_list 的 DIV 中。

到此,核心代码已经编写完毕,可以进行运行测试。

但是当点击下一页时,控制台出现了如下错误。

TypeError: Object of type 'School' is not JSON serializable

该原因是由于 School 实体直接返回的是对象,不是可JSON序列化的数据,所以要继续进行修改。

找到 model.py 文件,修改 School 类文件,增加一个 to_dict() 方法。

class School(db.Model, EntityBase):

 # 前面的字典注意不要丢失
    def to_dict(self):
        return 
            'name': self.name,
            'province': self.province,
            'city': self.city,
            'feature': self.feature,
            'hotValue': self.hotValue,
            'pic': self.pic,
            'category': self.category,
            'batchTimes': self.batchTimes
        

然后回到 school/index.py 文件中,在 pagination_object() 函数中增加类型转换代码。

data_list = [row.to_dict() for row in data_list]
pagination["data_list"] = data_list
return pagination

重启项目,再次点击分页,即完成本案例,无刷新 AJAX 请求。

本案例到此结束,已更新到 爬虫训练场 欢迎大家访问学习。
项目同步到代码仓库 https://gitcode.net/hihell/spider_playground

📢📢📢📢📢📢
💗 你正在阅读 【梦想橡皮擦】 的博客
👍 阅读完毕,可以点点小手赞一下
🌻 发现错误,直接评论区中指正吧
📆 橡皮擦的第 813 篇原创博客

从订购之日起,案例 5 年内保证更新

以上是关于16. 你很勇哦,这么点数据就敢用异步加载?的主要内容,如果未能解决你的问题,请参考以下文章

省市县三级异步加载导航

022-异步加载省市区联动

ashx一般处理程序---ajax异步加载---省市级联

程序员半夜12点睡觉,领导怒斥:这么早睡觉,你很会养生啊

程序员半夜12点睡觉,领导怒斥:这么早睡觉,你很会养生啊

2017-6-7AJAX异步刷新 省市区 三级联动