zoukankan      html  css  js  c++  java
  • DAY18-Django之分页和中间件

    分页

    Django的分页器(paginator)

    view

    from django.shortcuts import render,HttpResponse
    
    # Create your views here.
    from app01.models import *
    from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
    
    def index(request):
    
        '''
        批量导入数据:
    
        Booklist=[]
        for i in range(100):
            Booklist.append(Book(title="book"+str(i),price=30+i*i))
        Book.objects.bulk_create(Booklist)
        '''
    
        '''
    分页器的使用:
    
        book_list=Book.objects.all()
    
        paginator = Paginator(book_list, 10)    #把所有数据按10条一页分
    
        print("count:",paginator.count)           #数据总数
        print("num_pages",paginator.num_pages)    #总页数
        print("page_range",paginator.page_range)  #页码的列表range(1,8)
    
    
    
        page1=paginator.page(1) #第1页的page对象
        for i in page1:         #遍历第1页的所有数据对象
            print(i)
    
        print(page1.object_list) #第1页的所有数据
    
    
        page2=paginator.page(2)
    
        print(page2.has_next())            #是否有下一页
        print(page2.next_page_number())    #下一页的页码
        print(page2.has_previous())        #是否有上一页
        print(page2.previous_page_number()) #上一页的页码
    
    
    
        # 抛错
        #page=paginator.page(12)   # error:EmptyPage
    
        #page=paginator.page("z")   # error:PageNotAnInteger
    
        '''
    
    
        book_list=Book.objects.all()
    
        paginator = Paginator(book_list, 10)
        page = request.GET.get('page',1)     #如果get请求的page为空,则使用默认值1
        currentPage=int(page)
    
    
        try:
            print(page)
            book_list = paginator.page(page)
        except PageNotAnInteger:
            book_list = paginator.page(1)
        except EmptyPage:
            book_list = paginator.page(paginator.num_pages)
    
    
        return render(request,"index.html",{"book_list":book_list,"paginator":paginator,"currentPage":currentPage})

    index.html:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" 
        integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    </head>
    <body>
    
    <div class="container">
    
        <h4>分页器</h4>
        <ul>
    
            {% for book in book_list %}
                 <li>{{ book.title }} -----{{ book.price }}</li>
            {% endfor %}
    
         </ul>
    
    
        <ul class="pagination" id="pager">
    
                     {% if book_list.has_previous %}
                        <li class="previous"><a href="/index/?page={{ book_list.previous_page_number }}">上一页</a></li>
                     {% else %}
                        <li class="previous disabled"><a href="#">上一页</a></li>
                     {% endif %}
    
    
                     {% for num in paginator.page_range %}
    
                         {% if num == currentPage %}
                           <li class="item active"><a href="/index/?page={{ num }}">{{ num }}</a></li>
                         {% else %}
                           <li class="item"><a href="/index/?page={{ num }}">{{ num }}</a></li>
    
                         {% endif %}
                     {% endfor %}
    
    
    
                     {% if book_list.has_next %}
                        <li class="next"><a href="/index/?page={{ book_list.next_page_number }}">下一页</a></li>
                     {% else %}
                        <li class="next disabled"><a href="#">下一页</a></li>
                     {% endif %}
    
                </ul>
    </div>
    
    
    
    </body>
    </html>

    扩展

    def index(request):
    
    
        book_list=Book.objects.all()
    
        paginator = Paginator(book_list, 15)
        page = request.GET.get('page',1)
        currentPage=int(page)
    
        #  如果页数十分多时,换另外一种显示方式
        if paginator.num_pages>30:
    
            if currentPage-5<1:
                pageRange=range(1,11)
            elif currentPage+5>paginator.num_pages:
                pageRange=range(currentPage-5,paginator.num_pages+1)
    
            else:
                pageRange=range(currentPage-5,currentPage+5)
    
        else:
            pageRange=paginator.page_range
    
    
        try:
            print(page)
            book_list = paginator.page(page)
        except PageNotAnInteger:
            book_list = paginator.page(1)
        except EmptyPage:
            book_list = paginator.page(paginator.num_pages)
    
    
        return render(request,"index.html",locals())

     自己写的low版:

    from django.shortcuts import render,HttpResponse,redirect
    from app01.models import Book
    from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
    # Create your views here.
    
    def index(request):
        #插入数据
        # obj_list=[]
        # for i in range(1,101):
        #     obj=Book(title='book%s'%i,price=i*i)
        #     obj_list.append(obj)
        # Book.objects.bulk_create(obj_list)
        # return HttpResponse("ok")
    
        book_list=Book.objects.all()
        paginator=Paginator(book_list,5)
    
        currentPage=request.GET.get("page",1)
        if not currentPage.isdigit() or currentPage=="0":
            currentPage=1
        currentPage=int(currentPage)
        if currentPage > paginator.num_pages:
            currentPage=paginator.num_pages
    
        book_list=paginator.page(currentPage)
    
        start=currentPage-3
        if start<2:
            start=2
        end=start+7
        if end>paginator.num_pages:
            end=paginator.num_pages
        if end-7>2:
            start=end-7
        page_range=range(start,end)
    
        return render(request,"index.html",locals())
    views.py
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
        <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
              integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    </head>
    <body>
    <div>
        {% for book in book_list %}
            <div>{{ book.title }}----->{{ book.price }}</div>
        {% endfor %}
    
    
        <nav aria-label="Page navigation">
            <ul class="pagination">
                {% if currentPage == 1 %}
                    <li class="disabled">
                        {% else %}
                    <li>
                {% endif %}
    
                <a href="?page={{ currentPage|add:-1 }}" aria-label="Previous">
                    <span aria-hidden="true">&laquo;</span>
                </a>
                </li>
                {% if currentPage == 1 %}
                    <li class="active">
                        {% else %}
                    <li>
                {% endif %}
    
                <a href="?page=1">1</a></li>
                {% if start == 2 %}
                    <li><span class="hidden">...</span></li>
                {% else %}
                    <li><span>...</span></li>
                {% endif %}
    
                {% for num in page_range %}
                    {% if num == currentPage %}
                        <li class="active">
                            {% else %}
                        <li>
                    {% endif %}
                <a href="?page={{ num }}">{{ num }}</a></li>
                {% endfor %}
                {% if end == paginator.num_pages %}
                    <li><span class="hidden">...</span></li>
                {% else %}
                    <li><span>...</span></li>
                {% endif %}
                {% if currentPage == paginator.num_pages %}
                    <li class="active">
                        {% else %}
                    <li>
                {% endif %}
    
                <a href="?page={{ paginator.num_pages }}">{{ paginator.num_pages }}</a></li>
                {% if currentPage == paginator.num_pages %}
                    <li class="disabled">
                        {% else %}
                    <li>
                {% endif %}
                <a href="?page={{ currentPage|add:1 }}" aria-label="Next">
                    <span aria-hidden="true">&raquo;</span>
                </a>
                </li>
            </ul>
        </nav>
    
    </div>
    </body>
    </html>
    index.html

    自定义分页器

    """
    分页组件使用示例:
    
        obj = Pagination(request.GET.get('page',1),len(USER_LIST),request.path_info)
        page_user_list = USER_LIST[obj.start:obj.end]
        page_html = obj.page_html()
    
        return render(request,'index.html',{'users':page_user_list,'page_html':page_html})
    
    
    """
    
    
    class Pagination(object):
    
        def __init__(self,current_page,all_count,base_url,per_page_num=2,pager_count=11):
            """
            封装分页相关数据
            :param current_page: 当前页
            :param all_count:    数据库中的数据总条数
            :param per_page_num: 每页显示的数据条数
            :param base_url: 分页中显示的URL前缀
            :param pager_count:  最多显示的页码个数
            """
    
            try:
                current_page = int(current_page)
            except Exception as e:
                current_page = 1
    
            if current_page <1:
                current_page = 1
    
            self.current_page = current_page
    
            self.all_count = all_count
            self.per_page_num = per_page_num
    
            self.base_url = base_url
    
            # 总页码
            all_pager, tmp = divmod(all_count, per_page_num)
            if tmp:
                all_pager += 1
            self.all_pager = all_pager
    
    
            self.pager_count = pager_count
            self.pager_count_half = int((pager_count - 1) / 2)
    
        @property
        def start(self):
            return (self.current_page - 1) * self.per_page_num
    
        @property
        def end(self):
            return self.current_page * self.per_page_num
    
        def page_html(self):
            # 如果总页码 < 11个:
            if self.all_pager <= self.pager_count:
                pager_start = 1
                pager_end = self.all_pager + 1
            # 总页码  > 11
            else:
                # 当前页如果<=页面上最多显示11/2个页码
                if self.current_page <= self.pager_count_half:
                    pager_start = 1
                    pager_end = self.pager_count + 1
    
                # 当前页大于5
                else:
                    # 页码翻到最后
                    if (self.current_page + self.pager_count_half) > self.all_pager:
                        pager_end = self.all_pager + 1
                        pager_start = self.all_pager - self.pager_count + 1
                    else:
                        pager_start = self.current_page - self.pager_count_half
                        pager_end = self.current_page + self.pager_count_half + 1
    
            page_html_list = []
    
            first_page = '<li><a href="%s?page=%s">首页</a></li>' % (self.base_url,1,)
            page_html_list.append(first_page)
    
            if self.current_page <= 1:
                prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
            else:
                prev_page = '<li><a href="%s?page=%s">上一页</a></li>' % (self.base_url,self.current_page - 1,)
    
            page_html_list.append(prev_page)
    
            for i in range(pager_start, pager_end):
                if i == self.current_page:
                    temp = '<li class="active"><a href="%s?page=%s">%s</a></li>' % (self.base_url,i, i,)
                else:
                    temp = '<li><a href="%s?page=%s">%s</a></li>' % (self.base_url,i, i,)
                page_html_list.append(temp)
    
            if self.current_page >= self.all_pager:
                next_page = '<li class="disabled"><a href="#">下一页</a></li>'
            else:
                next_page = '<li><a href="%s?page=%s">下一页</a></li>' % (self.base_url,self.current_page + 1,)
            page_html_list.append(next_page)
    
            last_page = '<li><a href="%s?page=%s">尾页</a></li>' % (self.base_url,self.all_pager,)
            page_html_list.append(last_page)
    
            return ''.join(page_html_list)

    自定义分页(葫芦版)

    data = []
    
    for i in range(1, 302):
        tmp = {"id": i, "name": "alex-{}".format(i)}
        data.append(tmp)
    
    print(data)
    
    
    def user_list(request):
    
        # user_list = data[0:10]
        # user_list = data[10:20]
        try:
            current_page = int(request.GET.get("page"))
        except Exception as e:
            current_page = 1
    
        per_page = 10
    
        # 数据总条数
        total_count = len(data)
        # 总页码
        total_page, more = divmod(total_count, per_page)
        if more:
            total_page += 1
    
        # 页面最多显示多少个页码
        max_show = 11
        half_show = int((max_show-1)/2)
    
        if current_page <= half_show:
            show_start = 1
            show_end = max_show
        else:
            if current_page + half_show >= total_page:
                show_start = total_page - max_show
                show_end = total_page
            else:
                show_start = current_page - half_show
                show_end = current_page + half_show
    
        # 数据库中获取数据
        data_start = (current_page - 1) * per_page
        data_end = current_page * per_page
    
        user_list = data[data_start:data_end]
    
        # 生成页面上显示的页码
        page_html_list = []
        # 加首页
        first_li = '<li><a href="/user_list/?page=1">首页</a></li>'
        page_html_list.append(first_li)
        # 加上一页
        if current_page == 1:
            prev_li = '<li><a href="#">上一页</a></li>'
        else:
            prev_li = '<li><a href="/user_list/?page={}">上一页</a></li>'.format(current_page - 1)
        page_html_list.append(prev_li)
        for i in range(show_start, show_end+1):
            if i == current_page:
                li_tag = '<li class="active"><a href="/user_list/?page={0}">{0}</a></li>'.format(i)
            else:
                li_tag = '<li><a href="/user_list/?page={0}">{0}</a></li>'.format(i)
            page_html_list.append(li_tag)
    
        # 加下一页
        if current_page == total_page:
            next_li = '<li><a href="#">下一页</a></li>'
        else:
            next_li = '<li><a href="/user_list/?page={}">下一页</a></li>'.format(current_page+1)
        page_html_list.append(next_li)
    
        # 加尾页
        page_end_li = '<li><a href="/user_list/?page={}">尾页</a></li>'.format(total_page)
        page_html_list.append(page_end_li)
    
        page_html = "".join(page_html_list)
    
        return render(request, "user_list.html", {"user_list": user_list, "page_html": page_html})
    稳扎稳打版
    class Pagination(object):
        def __init__(self, current_page, total_count, base_url, per_page=10, max_show=11):
            """
            :param current_page: 当前页
            :param total_count: 数据库中数据总数
            :param per_page: 每页显示多少条数据
            :param max_show: 最多显示多少页
            """
            try:
                current_page = int(current_page)
            except Exception as e:
                current_page = 1
    
            self.current_page = current_page
            self.total_count = total_count
            self.base_url = base_url
            self.per_page = per_page
            self.max_show = max_show
    
            # 总页码
            total_page, more = divmod(total_count, per_page)
            if more:
                total_page += 1
            
            half_show = int((max_show - 1) / 2)
            self.half_show = half_show
            self.total_page = total_page
    
        @property
        def start(self):
            return (self.current_page - 1) * self.per_page
    
        @property
        def end(self):
            return self.current_page * self.per_page
    
        def page_html(self):
    
            if self.current_page <= self.half_show:
                show_start = 1
                show_end = self.max_show
            else:
                if self.current_page + self.half_show >= self.total_page:
                    show_start = self.total_page - self.max_show
                    show_end = self.total_page
                else:
                    show_start = self.current_page - self.half_show
                    show_end = self.current_page + self.half_show
    
                    # 生成页面上显示的页码
            page_html_list = []
            # 加首页
            first_li = '<li><a href="{}?page=1">首页</a></li>'.format(self.base_url)
            page_html_list.append(first_li)
            # 加上一页
            if self.current_page == 1:
                prev_li = '<li><a href="#">上一页</a></li>'
            else:
                prev_li = '<li><a href="{0}?page={1}">上一页</a></li>'.format(self.base_url, self.current_page - 1)
            page_html_list.append(prev_li)
            for i in range(show_start, show_end + 1):
                if i == self.current_page:
                    li_tag = '<li class="active"><a href="{0}?page={1}">{1}</a></li>'.format(self.base_url, i)
                else:
                    li_tag = '<li><a href="{0}?page={1}">{1}</a></li>'.format(self.base_url, i)
                page_html_list.append(li_tag)
    
            # 加下一页
            if self.current_page == self.total_page:
                next_li = '<li><a href="#">下一页</a></li>'
            else:
                next_li = '<li><a href="{0}?page={1}">下一页</a></li>'.format(self.base_url, self.current_page + 1)
            page_html_list.append(next_li)
    
            # 加尾页
            page_end_li = '<li><a href="{0}?page={1}">尾页</a></li>'.format(self.base_url, self.total_page)
            page_html_list.append(page_end_li)
    
            return "".join(page_html_list)
    封装保存版
    def user_list(request):
        pager = Pagination(request.GET.get("page"), len(data), request.path_info)
        user_list = data[pager.start:pager.end]
        page_html = pager.page_html()
        return render(request, "user_list.html", {"user_list": user_list, "page_html": page_html})

    Django内置分页

    from django.shortcuts import render
    from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
    
    L = []
    for i in range(999):
        L.append(i)
    
    def index(request):
        current_page = request.GET.get('p')
    
        paginator = Paginator(L, 10)
        # per_page: 每页显示条目数量
        # count:    数据总个数
        # num_pages:总页数
        # page_range:总页数的索引范围,如: (1,10),(1,200)
        # page:     page对象
        try:
            posts = paginator.page(current_page)
            # has_next              是否有下一页
            # next_page_number      下一页页码
            # has_previous          是否有上一页
            # previous_page_number  上一页页码
            # object_list           分页之后的数据列表
            # number                当前页
            # paginator             paginator对象
        except PageNotAnInteger:
            posts = paginator.page(1)
        except EmptyPage:
            posts = paginator.page(paginator.num_pages)
        return render(request, 'index.html', {'posts': posts})
    内置分页view部分
    <!DOCTYPE html>
    <html>
    <head lang="en">
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
    <ul>
        {% for item in posts %}
            <li>{{ item }}</li>
        {% endfor %}
    </ul>
    
    <div class="pagination">
          <span class="step-links">
            {% if posts.has_previous %}
                <a href="?p={{ posts.previous_page_number }}">Previous</a>
            {% endif %}
              <span class="current">
                Page {{ posts.number }} of {{ posts.paginator.num_pages }}.
              </span>
              {% if posts.has_next %}
                  <a href="?p={{ posts.next_page_number }}">Next</a>
              {% endif %}
          </span>
    
    </div>
    </body>
    </html>
    内置分页HTML部分

    中间件

    中间件的概念

    中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能。

    Django的中间件的定义:

    #Middleware is a framework of hooks into Django’s request/response processing. <br>It’s a light, low-level “plugin” system for globally altering Django’s input or output.

    如果你想修改请求,例如被传送到view中的HttpRequest对象。 或者你想修改view返回的HttpResponse对象,这些都可以通过中间件来实现。

    可能你还想在view执行之前做一些操作,这种情况就可以用 middleware来实现。

    大家可能频繁在view使用request.user吧。 Django想在每个view执行之前把user设置为request的属性,于是就用了一个中间件来实现这个目标。所以Django提供了可以修改request 对象的中间件 AuthenticationMiddleware

    Django默认的Middleware

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]

    每一个中间件都有具体的功能。

    自定义中间件

    中间件中一共有四个方法:

    process_request
    
    process_view
    
    process_exception
    
    process_response

    process_request,process_response

    当用户发起请求的时候会依次经过所有的的中间件,这个时候的请求时process_request,最后到达views的函数中,views函数处理后,在依次穿过中间件,这个时候是process_response,最后返回给请求者。

    上述截图中的中间件都是django中的,我们也可以自己定义一个中间件,我们可以自己写一个类,但是必须继承MiddlewareMixin

    需要导入

    from django.utils.deprecation import MiddlewareMixin

    注意,自定义的中间件模块名称和存放位置也不用固定,也可以放到具体应用文件夹中.

    in views:

    def index(request):
    
        print("view函数...")
        return HttpResponse("OK")

    in Mymiddlewares.py:

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    
    class Md1(MiddlewareMixin):
    
        def process_request(self,request):
            print("Md1请求")
     
        def process_response(self,request,response):
            print("Md1返回")
            return response
    
    class Md2(MiddlewareMixin):
    
        def process_request(self,request):
            print("Md2请求")
            #return HttpResponse("Md2中断")
        def process_response(self,request,response):
            print("Md2返回")
            return response

    结果:

    Md1请求
    Md2请求
    view函数...
    Md2返回
    Md1返回

    注意:如果当请求到达请求2的时候直接不符合条件返回,即return HttpResponse("Md2中断"),程序将把请求直接发给中间件2返回,然后依次返回到请求者,结果如下:

    返回Md2中断的页面,后台打印如下:

    Md1请求
    Md2请求
    Md2返回
    Md1返回

    流程图如下:

    process_view

    process_view(self, request, callback, callback_args, callback_kwargs)

     Mymiddlewares.py修改如下

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse
    
    class Md1(MiddlewareMixin):
    
        def process_request(self,request):
            print("Md1请求")
            #return HttpResponse("Md1中断")
        def process_response(self,request,response):
            print("Md1返回")
            return response
    
        def process_view(self, request, callback, callback_args, callback_kwargs):
            print("Md1view")
    
    class Md2(MiddlewareMixin):
    
        def process_request(self,request):
            print("Md2请求")
            return HttpResponse("Md2中断")
        def process_response(self,request,response):
            print("Md2返回")
            return response
    
        def process_view(self, request, callback, callback_args, callback_kwargs):
            print("Md2view")

    结果如下:

    Md1请求
    Md2请求
    Md1view
    Md2view
    view函数...
    Md2返回
    Md1返回

    下图进行分析上面的过程:

     

    当最后一个中间的process_request到达路由关系映射之后,返回到中间件1的process_view,然后依次往下,到达views函数,最后通过process_response依次返回到达用户。

    process_view可以用来调用视图函数:

    class Md1(MiddlewareMixin):
    
        def process_request(self,request):
            print("Md1请求")
            #return HttpResponse("Md1中断")
        def process_response(self,request,response):
            print("Md1返回")
            return response
    
        def process_view(self, request, callback, callback_args, callback_kwargs):
    
            # return HttpResponse("hello")
    
            response=callback(request,*callback_args,**callback_kwargs)
            return response

    结果如下:

    Md1请求
    Md2请求
    view函数...
    Md2返回
    Md1返回

    注意:process_view如果有返回值,会越过其他的process_view以及视图函数,但是所有的process_response都还会执行。

    process_exception

    process_exception(self, request, exception)

    示例修改如下:

    class Md1(MiddlewareMixin):
    
        def process_request(self,request):
            print("Md1请求")
            #return HttpResponse("Md1中断")
        def process_response(self,request,response):
            print("Md1返回")
            return response
    
        def process_view(self, request, callback, callback_args, callback_kwargs):
    
            # return HttpResponse("hello")
    
            # response=callback(request,*callback_args,**callback_kwargs)
            # return response
            print("md1 process_view...")
    
        def process_exception(self):
            print("md1 process_exception...")
    
    
    
    class Md2(MiddlewareMixin):
    
        def process_request(self,request):
            print("Md2请求")
            # return HttpResponse("Md2中断")
        def process_response(self,request,response):
            print("Md2返回")
            return response
        def process_view(self, request, callback, callback_args, callback_kwargs):
            print("md2 process_view...")
    
        def process_exception(self):
            print("md1 process_exception...")

    结果如下:

    Md1请求
    Md2请求
    md1 process_view...
    md2 process_view...
    view函数...
    
    Md2返回
    Md1返回

    流程图如下:

    当views出现错误时:

      将md2的process_exception修改如下:

    def process_exception(self,request,exception):
    
            print("md2 process_exception...")
            return HttpResponse("error")

    结果如下:

    Md1请求
    Md2请求
    md1 process_view...
    md2 process_view...
    view函数...
    md2 process_exception...
    Md2返回
    Md1返回
  • 相关阅读:
    jquery 序列化form表单
    nginx for windows 安装
    nodejs idea 创建项目 (一)
    spring 配置 shiro rememberMe
    idea 2018 解决 双击shift 弹出 search everywhere 搜索框的方法
    redis 在windows 集群
    spring IOC控制反转和DI依赖注入
    redis 的安装
    shiro 通过jdbc连接数据库
    handlebars的用法
  • 原文地址:https://www.cnblogs.com/guoyunlong666/p/8996907.html
Copyright © 2011-2022 走看看