09.新闻项目——新闻前台——首页

关于首页,我们有这样几个地方需要操作一下:

这三部分都需要从后台的数据库中进行获取,我们从简单到难逐级完成。

处理点击排行部分功能

1.点击排行的展示

目前,点击排行都是死代码:

我们要做的就是在News数据库表中查询,根据点击量clicks倒序查询新闻信息。

后端代码

info -> modules -> index -> views.py

    ....

@index_blue.route('/index')
def index():

    ....

    # 2.新闻点击排行展示
    # news_clicks = [News,News,News,News,News,News]
    news_clicks = []
    try:
        news_clicks = News.query.order_by(News.clicks.desc()).limit(6)
    except Exception as e:
        current_app.logger.error(e)

    # 构造渲染模板的上下文数据
    context = {
        'user': user,
        'news_clicks': news_clicks
    }

    # 渲染主页
    return render_template('news/index.html', context=context)

 

前端代码

修改点击排行部分的代码

        <div class="rank_con fr">
            <div class="rank_title">
                <h3>点击排行</h3>
            </div>
            <ul class="rank_list">
                {% for news in context.news_clicks %}
                    <li><span class="first">{{ loop.index }}</span><a href="#">{{ news.title }}</a></li>
                {% endfor %}
{#                <li><span class="first">1</span><a href="#">势如破竹!人民币再度连闯四道关口 在岸、离岸双双升破6.42</a></li>#}
{#                <li><span class="second">2</span><a href="#">凛冬已至,还有多少银行人在假装干银行</a></li>#}
{#                <li><span class="third">3</span><a href="#">人民日报:部分城市楼市放松限制引关注,楼市调控不会“拉抽屉”</a></li>#}
{#                <li><span>4</span><a href="#">势如破竹!人民币再度连闯四道关口 在岸、离岸双双升破6.42</a></li>#}
{#                <li><span>5</span><a href="#">凛冬已至,还有多少银行人在假装干银行</a></li>#}
{#                <li><span>6</span><a href="#">人民日报:部分城市楼市放松限制引关注,楼市调控不会“拉抽屉”</a></li>#}
            </ul>
        </div>

当修改完成之后,我们运行下代码,会看到下面的运行结果:

 新闻排序没啥毛病,就是这个和一开始的样式好像不太一样,一开始的样式中,前三个是有些特别的,而现在都是一个样式了,而这个就是我们接下来要解决的问题。

 

2、自定义过滤器

在前面,我们发现排序的样式有些不同,而通过看前端代码:

 我们可以发现,前三个它们有自己的class类,那相对应的应该有设置样式的css。所以现在要做的就是解决这个class问题。

我们在学Jinja2的时候学过一个东西,叫做过滤器,它能够帮助我们解决这个问题。

在项目中,我们经常会需要写一些工具来完成一些功能,所以这里我们写一个过滤器来帮助给不同排行的消息设置不同的class。

我们之前在项目中创建了一个名为utils的文件夹,它用来专门存放工具,我们在这个文件夹中新建一个文件comment.py,专门存放一些公用的工具文件。

在这个工具类中,放入下面的自定义过滤器:

info -> utils -> comment.py

def do_rank(index):
    """根据index,返回对应的first,second,third"""
    if index == 1:
        return 'first'
    elif index == 2:
        return 'second'
    elif index == 3:
        return 'third'
    else:
        return ''

写好这个过滤器之后,还不行,因为我们还需要将它添加到app的过滤器列表当中

info -> __init__.py

    ....

def create_app(config_name):
    """创建app的工厂方法
    参数:根据参数选择不同的配置类
    """

    ....

    # 将自定义的过滤器函数,添加到app的过滤器列表中
    # rank : 在模板中使用的别名
    app.add_template_filter(do_rank, 'rank')

    ....

接下来,就是在前端模板中使用这个定义好的过滤器:

info -> templates -> news -> index.html

                    <li><span class="{{ loop.index | rank }}">{{ loop.index }}</span><a href="#">{{ news.title }}</a></li>

好了,到这里,点击排行的相关逻辑应该就可以了!

 

新闻列表数据处理

逻辑分析

新闻列表处理是一个比较麻烦的地方,我们需要先来分析一些内容。

新闻中,默认有六个分类,要查询信息,首先我们要搞明白要查询的是哪一类的新闻。所以在请求的时候,这个参数不可或缺。

除了分类信息,还有个东西也需要思考,比如我们有一万个信息,用户去看个首页都发给前端吗?当然不是,我们只给他一部分,所以,这部分需要用到分页的相关操作。也就是说,在请求的时候也要携带一个参数,告诉我们它要看的是第几页的新闻。

而除了告诉服务器要看第几页的,你还得告诉服务器一页要多少,因为不同的场景对新闻数量的需求是不一样的,所以这个我们也需要考虑一下。

参数一开始能分析的就这些,现在还有一个问题,我们要思考一下,用什么请求方式?

没有私密信息,貌似使用get就可以。那么是否要使用ajax呢?

那怎么把这些信息都表现出来呢?

 一行搞定!

 

 接口设计

 

{
    "cid": "0",
    "currentPage": 1,
    "errmsg": "OK",
    "errno": "0",
    "newsList": [
        {
            "clicks": 105,
            "create_time": "2018-01-17 17:00:41",
            "digest": "一周前,新京报获悉,滴滴已在杭州成立代号为“黑马”的事业部,主攻共享电单车和电动汽车,并已经在杭州小范围内测。共享电单车的发布也为滴滴在中短途出行版图中填补了空缺。",
            "id": 1168,
            "index_image_url": "https://wpimg.wallstcn.com/aaabf95b-610d-4548-afbb-7cb13fa2f85a.jpg",
            "source": "张超",
            "status": 0,
            "title": "滴滴被曝电单车起名“街兔” 需缴押金99元"
        },
        {
            "clicks": 40,
            "create_time": "2018-01-17 16:41:46",
            "digest": "绿光资本四季度买进推特、时代华纳、海上钻井平台运营商ESV,其称推特改善了用户体验,2018收入有望再增。绿光资本去年全年投资回报仅有1.6%,远远落后于同期标普21.8%的涨幅。",
            "id": 1165,
            "index_image_url": "https://wpimg.wallstcn.com/d5bd842c-0026-4d69-a620-4ebf6ad7317d.jpg",
            "source": "陶旖洁",
            "status": 0,
            "title": "绿光资本致股东信:今年Twitter会是大赢家"
        }
    ],
    "totalPage": 116
}
返回内容示例

 代码实现

1.新闻列表数据的查询

后端代码

indo -> modules -> index -> views.py

@index_blue.route('/news_list')
def index_news_list():
    """提供主页新闻列表数据
    1.接受参数(分类id,要看第几页,每页几条数据)
    2.校验参数 (判断以上参数是否为数字)
    3.根据参数查询用户想看的新闻列表数据
    4.构造响应的新闻列表数据
    5.响应新闻列表数据
    """
    # 1.接受参数(分类id,要看第几页,每页几条数据)
    cid = request.args.get('cid', '1')
    page = request.args.get('page', '1')
    per_page = request.args.get('per_page', '10')

    # 2.校验参数 (判断以上参数是否为数字)
    try:
        cid = int(cid)
        page = int(page)
        per_page = int(per_page)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=response_code.RET.PARAMERR, errmsg='参数错误')

    # 3.根据参数查询用户想看的新闻列表数据
    if cid == 1:
        # 从所有的新闻中,根据时间倒叙,每页取出10条数据
        # paginate = [News,News,News,News,News,News,News,News,News,News]
        #                      排序     时间倒序排列                分页  第几页页数 每页几个  默认值
        paginate = News.query.order_by(News.create_time.desc()).paginate(page, per_page, False)
    else:
        # 从指定的分类中,查询新闻,根据时间倒叙,每页取出10条数据
        paginate = News.query.filter(News.category_id==cid).order_by(News.create_time.desc()).paginate(page, per_page, False)

    # 4.构造响应的新闻列表数据
    # news_list = [News,News,News,News,News,News,News,News,News,News]
    # 取出当前页的所有的模型对象(paginate只是一个分页对象,并不是查询集)
    news_list = paginate.items
    # 读取分页的总页数,将来在主页新闻列表上拉刷新时使用的
    total_page = paginate.pages
    # 读取当前是第几页,将来在主页新闻列表上拉刷新时使用的
    current_page = paginate.page

    # # 将模型对象列表转成字典列表,让json在序列化时乐意认识
    # news_dict_list = []
    # for news in news_list:
    #     news_dict_list.append(news.to_basic_dict())

    # 构造响应给客户单的数据
    data = {
        'news_dict_list': news_list,
        'total_page': total_page,
        'current_page': current_page
    }

    # 5.响应新闻列表数据
    return jsonify(errno=response_code.RET.OK, errmsg='OK', data=data)

在视图中加入上面代码之后,我们 使用下面连接测试一下

http://127.0.0.1:8080/news_list?cid=2&page=3&per_page=10

会发现报了下面的错误: 

 这是因为: 

News对象在序列化为json的时候序列化失败,因为json序列化的时候不认识模型类对象列表的数据形式。

json在序列化的时候只认识:字典,列表,字典列表

这个很关键,也就是说,我们需要将这种模型类对象列表转换为可以序列化的json数据。

要解决的话,首先修改视图函数中的内容:

 indo -> modules -> index -> views.py

 

 说明:to_basic_dict()是在定义模型类的时候定义的一个函数,用来封装基本的新闻信息。

 修改之后,我们再次访问,就可以看到基本的新闻信息了:

 

将这些数据放到在线的json解析网站,可以看到简单地看到这些数据的构成:

 

其实这就是前后端交互的方式,无论前端是app,小程序,还是网页,基本都是用这种方式完成数据交换的。

 

 2.修改前端逻辑

目前新闻的渲染都是“死代码”,这明项不行,所以将这部分代码统统删掉,我们要用js来实现新闻的动态刷新:

我们进入渲染主页的index.js当中,完成这部分js的代码。

在这个js中,正好有我们要补充的内容:

在这个代码中补充下面内容:

function updateNewsData() {
    // TODO 更新新闻数据
    var params = {
        'cid':currentCid,
        'page':cur_page
        // 每页多少条不用传,默认10条
    };

    $.get('/news_list', params, function (response) {
        if (response.errno == '0') {
            for (var i=0;i<response.data.news_dict_list.length;i++) {
                var news = response.data.news_dict_list[i]
                var content = '<li>'
                content += '<a href="#" class="news_pic fl"><img src="' + news.index_image_url + '?imageView2/1/w/170/h/170"></a>'
                content += '<a href="#" class="news_title fl">' + news.title + '</a>'
                content += '<a href="#" class="news_detail fl">' + news.digest + '</a>'
                content += '<div class="author_info fl">'
                content += '<div class="source fl">来源:' + news.source + '</div>'
                content += '<div class="time fl">' + news.create_time + '</div>'
                content += '</div>'
                content += '</li>'
                $(".list_con").append(content)
            }
        } else {
            alert(response.errmsg);
        }
    });
}

完成了这个函数之后,还需要完成一个内容,就是调用它。还是在这个index.js中,在代码中增加下面的内容:

 

3.上拉刷新新闻

而滚动刷新的相关内容,是在js当中完成的,我们再次打开index.js,查看这部分代码,这些就是更新新闻的js了

 

这些代码的意思是,当滚动条里页面下方还有100像素的时候去更新新闻。

下面是修改后的index.js:

var currentCid = 1; // 当前分类 id
var cur_page = 1; // 当前页
var total_page = 1;  // 总页数
var data_querying = true;   // 是否正在向后台获取数据:如果为ture表示正在加载数据;反之,没有加载数据


$(function () {

    // 当主页加载完成之后,立即刷新主页的分页数据
    // 默认加载第一页
    updateNewsData();

    // 首页分类切换
    $('.menu li').click(function () {
        var clickCid = $(this).attr('data-cid')
        $('.menu li').each(function () {
            $(this).removeClass('active')
        })
        $(this).addClass('active')

        if (clickCid != currentCid) {
            // 记录当前分类id
            currentCid = clickCid;

            // 重置分页参数
            cur_page = 1;
            total_page = 1;
            updateNewsData()
        }
    });

    //页面滚动加载相关
    $(window).scroll(function () {

        // 浏览器窗口高度
        var showHeight = $(window).height();

        // 整个网页的高度
        var pageHeight = $(document).height();

        // 页面可以滚动的距离
        var canScrollHeight = pageHeight - showHeight;

        // 页面滚动了多少,这个是随着页面滚动实时变化的
        var nowScroll = $(document).scrollTop();

        if ((canScrollHeight - nowScroll) < 100) {
            // TODO 判断页数,去更新新闻数据
            if (!data_querying) {
                // 表示正在加载数据
                data_querying = true;

                // 计算当前在第几页
                cur_page += 1;

                if (cur_page < total_page) {
                    // 加载指定页码的新闻数据
                    updateNewsData();
                }
            }
        }
    })
});

function updateNewsData() {
    // TODO 更新新闻数据
    var params = {
        'cid':currentCid,
        'page':cur_page
        // 每页多少条不用传,默认10条
    };

    $.get('/news_list', params, function (response) {
        // 得到响应后,表示一次加载数据结束了
        data_querying = false;

        if (response.errno == '0') {
            // 记录总页数
            total_page = response.data.total_page;

            if (cur_page == 1) {
                $(".list_con").html("");
            }

            for (var i=0;i<response.data.news_dict_list.length;i++) {
                var news = response.data.news_dict_list[i]
                var content = '<li>'
                content += '<a href="/news/detail/'+news.id+'" class="news_pic fl"><img src="' + news.index_image_url + '?imageView2/1/w/170/h/170"></a>'
                content += '<a href="/news/detail/'+news.id+'" class="news_title fl">' + news.title + '</a>'
                content += '<a href="/news/detail/'+news.id+'" class="news_detail fl">' + news.digest + '</a>'
                content += '<div class="author_info fl">'
                content += '<div class="source fl">来源:' + news.source + '</div>'
                content += '<div class="time fl">' + news.create_time + '</div>'
                content += '</div>'
                content += '</li>'
                $(".list_con").append(content);
            }
        } else {
            alert(response.errmsg);
        }
    });
}
View Code

 

毕竟前端代码,能看懂多少看多少。 

 

新闻分类处理

关于新闻分类信息,我们专门存放到了一个表中,所以我们要做的就是遍历这个表,然后获取目前的分类信息。

而这部分的内容与主页渲染有关,所以要修改渲染主页的相关视图函数。

indo -> modules -> index -> views.py

    ....

@index_blue.route('/index')
def index():
    """主页
    处理网页右上角的用户展示数据:当用户已登录展示'用户名 退出';反之,展示'登录 注册'
    """

    ....

    # 3.新闻分类
    # categories = [Category,Category,Category,Category,Category,Category]
    categories = []
    try:
        categories = Category.query.all()
    except Exception as e:
        current_app.logger.error(e)

    # 构造渲染模板的上下文数据
    context = {
        'user':user,
        'news_clicks':news_clicks,
        'categories':categories
    }

    # 渲染主页
    return render_template('news/index.html', context=context)


    ....

接下来,修改前端代码,将写死的内容,替换成下面代码:

                {% for category in context.categories %}
                    {% if loop.index == 1 %}
                        <li class="active" data-cid="{{ category.id }}"><a href="javascript:;">{{ category.name }}</a></li>
                    {% else %}
                        <li data-cid="{{ category.id }}"><a href="javascript:;">{{ category.name }}</a></li>
                    {% endif %}
                {% endfor %}

到这里,如果都ok,主页的内容就可以了。

posted @ 2019-11-20 15:59  苦行僧95  阅读(158)  评论(0编辑  收藏  举报