一、点击排行展示

  • 在请求根路由时去数据库查询按点击量排行的10条新闻

新闻new模型设计

class News(BaseModel, db.Model):
    """新闻"""
    __tablename__ = "info_news"

    id = db.Column(db.Integer, primary_key=True)  # 新闻编号
    title = db.Column(db.String(256), nullable=False)  # 新闻标题
    source = db.Column(db.String(64), nullable=False)  # 新闻来源
    digest = db.Column(db.String(512), nullable=False)  # 新闻摘要
    content = db.Column(db.Text, nullable=False)  # 新闻内容
    clicks = db.Column(db.Integer, default=0)  # 浏览量
    index_image_url = db.Column(db.String(256))  # 新闻列表图片路径
    category_id = db.Column(db.Integer, db.ForeignKey("info_category.id"))
    user_id = db.Column(db.Integer, db.ForeignKey("info_user.id"))  # 当前新闻的作者id
    status = db.Column(db.Integer, default=0)  # 当前新闻状态 如果为0代表审核通过,1代表审核中,-1代表审核不通过
    reason = db.Column(db.String(256))  # 未通过原因,status = -1 的时候使用
    # 当前新闻的所有评论
    comments = db.relationship("Comment", lazy="dynamic")

    def to_review_dict(self):
        resp_dict = {
            "id": self.id,
            "title": self.title,
            "create_time": self.create_time.strftime("%Y-%m-%d %H:%M:%S"),
            "status": self.status,
            "reason": self.reason if self.reason else ""
        }
        return resp_dict

    def to_basic_dict(self):
        resp_dict = {
            "id": self.id,
            "title": self.title,
            "source": self.source,
            "digest": self.digest,
            "create_time": self.create_time.strftime("%Y-%m-%d %H:%M:%S"),
            "index_image_url": self.index_image_url,
            "clicks": self.clicks,
        }
        return resp_dict

    def to_dict(self):
        resp_dict = {
            "id": self.id,
            "title": self.title,
            "source": self.source,
            "digest": self.digest,
            "create_time": self.create_time.strftime("%Y-%m-%d %H:%M:%S"),
            "content": self.content,
            "comments_count": self.comments.count(),
            "clicks": self.clicks,
            "category": self.category.to_dict(),
            "index_image_url": self.index_image_url,
            "author": self.user.to_dict() if self.user else None
        }
        return resp_dict 

 

后端首页index视图代码

@index_blu.route('/')
def index():
    ...
    # 获取点击排行数据
    news_list = None
    try:
        news_list = News.query.order_by(News.clicks.desc()).limit(constants.CLICK_RANK_MAX_NEWS)
    except Exception as e:
        current_app.logger.error(e)

    click_news_list = []
    for news in news_list if news_list else []:
        click_news_list.append(news.to_basic_dict())

    data = {
        "user_info": user.to_dict() if user else None,
        "click_news_list": click_news_list,
    }

    return render_template('news/index.html', data=data)

  

创建排行榜前三自定义过滤器

def do_class_index(index):

    if index == 0:
        return "first"
    elif index == 1:
        return "second"
    elif index == 2:
        return "third"
    else:
        return ""

 

  • 在 app 创建的函数里面注册过滤器
from info.utils.common import do_index_class
# 添加自定义过滤器
app.add_template_filter(do_index_class, "index_class")

  

 前端index.html进行模板渲染,及通过对span标签使用自定义过滤器对排行前三特别显示

<div class="rank_con fr">
            <div class="rank_title">
                <h3>点击排行</h3>
            </div>
            <ul class="rank_list">
                {% for news in data.click_news_list %}
                    <li><span class="{{ loop.index0 | indexClass }}">{{ loop.index }}</span><a href="#">{{ news.title }}</a></li>
                {% endfor %}
            </ul>
        </div>

  

 

 

 应用效果:

 

 

二、新闻分类展示

  • 在请求根路由的时候去查询新闻分类,并默认设置第1个分类选中
@index_blue.route("/")
def index():
    user_id =  session.get('user_id')
    user = None
    # 判断用户是否已经登陆,user_id 是否有值
    if user_id:
       # 根据用户的id查询用户
       user = User.query.get(user_id)

    # 查询首页右边的热门排行新闻数据
    news = News.query.order_by(News.clicks.desc()).limit(constants.CLICK_RANK_MAX_NEWS)

    news_list = []

    for new_model in news:
        news_list.append(new_model.to_dict())


    # 上面的分类数据
    categorys =  Category.query.all()

    category_list = []

    for category in categorys:
        category_list.append(category.to_dict())

    data = {
        # "click_news_list":news_list
        "user_info": user.to_dict() if user else None,
        "click_news_list": news_list,
        "categories":category_list
    }

    return render_template('news/index.html',data= data )

  

前端模板渲染

<ul class="menu fl">
    {% for category in data.categories %}
        <li class="{% if loop.index0 == 0 %}active{% endif %}" data-cid="{{ category.id }}"><a href="javascript:;">{{ category.name }}</a></li>
    {% endfor %}
</ul>

 效果如下:

 

 

三、新闻列表数据-分页展示

  • 新闻列表数据只是当前页面的一部分
  • 点击分类时需要去获取当前分类下的新闻数据
  • 并在展示的时候需要更新新闻列表界面,不需要整体页面刷新
  • 所以新闻数据也使用 ajax 的方式去请求后台接口进行获取

接口设计

  • URL:/news_list
  • 请求方式:GET
  • 传入参数:JSON格式
  • 参数
参数名类型是否必须参数说明
cid string 分类id
page int 页数,不传即获取第1页
per_page int 每页多少条数据,如果不传,默认10条

 

  • 返回类型:JSON
参数名类型是否必须参数说明
errno int 错误码
errmsg string 错误信息
cid string 当前新闻数据的分类id
total_page int 总页数
current_page int 当前页数
news_dict_list list 新闻列表数据
newsList.title string 新闻标题
newsList.source string 新闻来源
newsList.digest string 新闻摘要
newsList.create_time string 新闻时间
newsList.index_image_url string 新闻索引图

返回示例

{
    "cid":1,
    "current_page":2,
    "errmsg":"OK",
    "errno":"0",
    "news_dict_list":[
        {
            "clicks":65,
            "create_time":"2018-01-17 21:55:55",
            "digest":"1月17日比特币延续了前几日的跌势,并且数字货币血流成河的状况也在持续,跌幅基本保持着两位数。近期全球市场对比特币的监管力度都有所加大。",
            "id":21,
            "index_image_url":"https://wpimg.wallstcn.com/d1643b79-7e69-47c2-91b9-9d3c7a51e0c7.png",
            "source":"WEEX",
            "title":"数字货币继续“血流成河”:比特币遭遇各国监管“围剿”"
        },
        {
            "clicks":8,
            "create_time":"2018-01-17 19:32:04",
            "digest":"今天的话题还包括:1、微信的黄金时代;2、区块链交易暗河:关联利益的庄家,被收割的韭菜;3、霍金的轮椅有多少黑科技。看完想坐...",
            "id":28,
            "index_image_url":"https://wpimg.wallstcn.com/949eab04-2ddf-4601-b9a9-34e6de11b70b.gif",
            "source":"潘凌飞",
            "title":"七点档 | 起底不为人知的网络暴力产业链"
        }
    ],
    "total_page":578
}

  

后端接口实现

@index_blue.route("/news_list", methods=['GET'])
def get_news_list():
    cid = request.args.get("cid", "1")
    page = request.args.get("page", "1")
    per_page = request.args.get("per_page", "10")

    try:
        cid = int(cid)
        page = int(page)
        per_page = int(per_page)
    except Exception as e:
        cid = 1
        page = 1
        per_page = 10

    # 根据创建时间查询最新的新闻,及分页
    try:
        paginate = News.query.order_by(News.create_time.desc()).paginate(page, per_page, False)
        # 查询出来的数据
        items = paginate.items
        # 获取到总的页数
        toal_page = paginate.pages
        # 获取到当前页
        current_page = paginate.page
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="数据查询失败")

    items_list = []
    for item in items:
        items_list.append(item.to_dict())

    data = {
        "current_page": current_page,
        "total_page": toal_page,
        "news_dict_li": items_list
    }

    return jsonify(errno=RET.OK, errmsg="ok", data=data)

  

 前端js

var currentCid = 1; // 当前分类 id
var cur_page = 1; // 当前页
var total_page = 1;  // 总页数
var data_querying = true;   // 是否正在向后台获取数据


$(function () {
    // 界面加载完成之后去加载新闻数据
    updateNewsData()

    // 首页分类切换
    $('.menu li').click(function () {
        // 取到指定分类的cid
        var clickCid = $(this).attr('data-cid')
        // 遍历所有的 li 移除身上的选中效果
        $('.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) {
            // 判断页数,去更新新闻数据

            if (!data_querying) {
                data_querying = true

                // 如果当前页数据如果小于总页数,那么才去加载数据
                if (cur_page < total_page) {
                    cur_page += 1
                    // 去加载数据
                    updateNewsData()
                }

            }
        }
    })
})

function updateNewsData() {
    // 更新新闻数据
    var params = {
        "cid": currentCid,
        "page": cur_page,
        "per_page": 10
    }
    $.get("/news_list", params, function (resp) {
        // 数据加载完毕,设置【正在加载数据】的变量为 false 代表当前没有在加载数据
        data_querying = false

        // 给总页数据赋值
        total_page = resp.data.total_page
        // 代表请求成功
        // 清除已有数据
        if (cur_page == 1) {
            $(".list_con").html("")
        }

        // 添加请求成功之后返回的数据

        // 显示数据
        for (var i = 0; i < resp.data.news_dict_li.length; i++) {
            var news = resp.data.news_dict_li[i]
            var content = '<li>'
            content += '<a href="/news/' + news.id + '" class="news_pic fl"><img src="' + news.index_image_url + '?imageView2/1/w/170/h/170"></a>'
            content += '<a href="/news/' + news.id + '" class="news_title fl">' + news.title + '</a>'
            content += '<a href="/news/' + 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)
        }

    })
}

  

 

 

 

 

 

总结:

  1、自定义模板过滤器,通过app.add_template_filter(函数名, '过滤器名称')进行注册,  过滤器名称为html使用的名称一致,例如上述例子

      app.add_template_filter(do_index_class, "index_class") 与前端<li><span class="{{ loop.index0 | indexClass }}">{{ loop.index }}</span><a href="#">{{ news.title }}</a></li>

    过滤器名称一致;

    2、flask中用paginate可实现数据分页效果,paginate用法及属性如下

 

paginate的用法
paginate(page, per_page, error_out=True)
>>>page 当前页数
>>>per_page 每页显示的条数
>>>error_out 是否打印错误信息

2.paginate的属性
a)paginate.page 当前页数
b)paginate.pages 总页数
c)paginate.total 数据总条数
d)paginate.has_prev 是否存在上一页
返回布尔值

e)paginate.has_next 是否存在下一页
返回布尔值

f)paginate.iter_pages() 所有页码
返回列表 如[1, 2, 3, 4]

g)paginate(page, per_page,error_out).items
返回当前页的所有数据

  

 

posted on 2024-03-24 21:05  RZHL  阅读(68)  评论(0)    收藏  举报