Flask搭建新闻网站①

news/2024/5/9 18:40:01/文章来源:https://blog.csdn.net/weixin_43746433/article/details/105918685

跟之前flask做的ihome租房网站类似,配置信息几乎完全一样,这里只记录下重点内容

git忽略log日志可在logs文件夹下加 .gitkeep文件

文章目录

  • 项目预览
    • 文章列表页
    • 文章详情页
    • 个人中心
  • Day1
    • 08_表结构分析
    • 数据库迁移
    • 显示网站logo文件
  • Day2
    • 使用请求钩子
    • 自定义过滤器(热门文章排名颜色显示)
    • 获取文章列表
    • 用户登录注册
    • 定义登录装饰器,封装用户的登录数据
    • 使用try except小技巧
    • 热门新闻
  • Day3
    • 发布评论接口
    • 详情页-获取用户对评论的赞
    • 详情页-获取的点赞评论前端渲染
    • 详情页-点赞接口与js
  • Day4
    • 用户中心与资料修改
    • 用户头像-上传七牛
      • 七牛配置
      • 头像上传逻辑
      • 前端提交图片ajax
    • 提交新闻
    • 用户新闻列表
    • 关注与取消关注

项目预览

文章列表页

在这里插入图片描述

文章详情页

在这里插入图片描述

个人中心

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Day1

08_表结构分析

在这里插入图片描述

数据库迁移

在这里插入图片描述

显示网站logo文件

from flask import render_template, current_appfrom . import index_bp
from info import redis_store@index_bp.route('/')
def show_index():# 渲染首页return render_template('news/index.html')# 处理网站logo
@index_bp.route('/favicon.ico')
def get_web_logo():return current_app.send_static_file('news/favicon.ico')

Day2

实现的功能目录
在这里插入图片描述

使用请求钩子

# 使用请求钩子拦截所有请求, 在返回的响应cookie设置csrf_token@app.after_requestdef after_request(resp):# 调用系统方法,获取csrf_tokencsrf_token = generate_csrf()# 将csrf_token 设置到cookie中resp.set_cookie('csrf_token', csrf_token)# 返回响应return resp

前端ajax需要从cookie中获取csrf_token的值

$.ajax({url:'/passport/register',type:'post',data:JSON.stringify(params),contentType:'application/json',headers:{'X-CSRFToken':getCookie('csrf_token')},success: function (resp) {//判断是否注册成功if(resp.errno == '0'){//重新加载当前页面window.location.reload()}else{alert(resp.errmsg);}}})

自定义过滤器(热门文章排名颜色显示)

在这里插入图片描述

# 将函数添加到系统默认的过滤器中from info.utils.commons import hot_news_filter# 参数1:函数的名字 参数2:过滤器的名字app.add_template_filter(hot_news_filter, 'my_filter')
# 自定义过滤器实现热门新闻的颜色过滤
def hot_news_filter(index):if index == 1:return 'first'elif index == 2:return 'second'elif index == 3:return 'third'else:return ""

将函数添加到系统默认的过滤器中
在这里插入图片描述

获取文章列表

# 首页新闻列表
# 请求路径: /newslist
# 请求方式: GET
# 请求参数: cid,page,per_page
# 返回值: data数据
@index_bp.route('/newslist')
def newslist():# 1.获取参数cid = request.args.get('cid', '1')  # 默认为最新分类page = request.args.get('page', '1')  # 默认第一页per_page = request.args.get('per_page', '10')# 2.参数类型转换try:page = int(page)per_page = int(per_page)except Exception as e:page = 1per_page = 10# 3.分页查询try:filters = []if cid != '1':filters.append(News.category_id == cid)paginate = News.query.filter(*filters).order_by(News.create_time.desc()).paginate(page, per_page, False)except Exception as e:current_app.logger.error(e)return jsonify(errno=RET.DBERR, errmsg='获取新闻失败')# 4.获取分页对象中的属性,总页数,当前页,当前页的对象列表totalPage = paginate.pagescurrentPage = paginate.pageitems = paginate.items# 5.将对象列表转换成字典列表news_list = []for news in items:news_list.append(news.to_dict())# 6.携带数据,返回响应return jsonify(errno=RET.OK,errmsg='获取新闻成功',totalPage=totalPage,currentPage=currentPage,newsList=news_list)

用户登录注册

# 登陆用户
# 请求路径: /passport/login
# 请求方式: POST
# 请求参数: mobile,password
# 返回值: errno, errmsg
@passport_bp.route('/login', methods=['POST'])
def login():# 1.获取参数mobile = request.json.get('mobile')password = request.json.get('password')# 2.校验参数, 为空校验if not all([mobile, password]):return jsonify(errno=RET.PARAMERR, errmsg='参数不全')# 3.通过手机号码,到数据库查询用户对象try:user = User.query.filter(User.mobile == mobile).first()except Exception as e:current_app.logger.error(e)return jsonify(errno=RET.DBERR, errmsg='获取用户失败')# 4.判断用户是否存在if not user:return jsonify(errno=RET.NODATA, errmsg='该用户不存在')# 5.校验密码是否正确if not user.check_password(password):return jsonify(errno=RET.DATAERR, errmsg='密码错误')# 6.讲用户的登录信息保存到session中session['user_id'] = user.id# 6.1 记录用户最后一次的登录时间# 记录登录时间,是为了方便后期进行用户的活跃统计user.last_login = datetime.now()try:db.session.add(user)db.session.commit()except Exception as e:current_app.logger.error(e)db.session.rollback()return jsonify(errno=RET.DBERR, errmsg='修改用户登录时间错误')# 7.返回响应return jsonify(errno=RET.OK, errmsg='登录成功')# 注册用户
# 请求路径: /passport/register
# 请求方式: POST
# 请求参数: mobile, sms_code,password
# 返回值: errno, errmsg
@passport_bp.route('/register', methods=['POST'])
def register():# 1.获取参数dict_data = request.jsonmobile = dict_data.get('mobile')sms_code = dict_data.get('sms_code')password = dict_data.get('password')# 2.校验参数if not all([mobile, sms_code, password]):return jsonify(errno=RET.PARAMERR, errmsg='参数不全')# 3.手机号作为key取出redis中的短信验证码try:redis_sms_code = redis_store.get('sms_code:%s'%mobile)except Exception as e:current_app.logger.error(e)return jsonify(errno=RET.DBERR, errmsg='短信验证码取出失败')# 4.判断短信验证码是否过期if not redis_sms_code:return jsonify(errno=RET.NODATA, errmsg='短信验证码已经过期')# 5.判断验证码是否正确if sms_code != redis_sms_code:return jsonify(errno=RET.DATAERR, errmsg='短信验证码填写错误')# 6.删除短信验证码try:redis_store.delete('sms_code:%s'%mobile)except Exception as e:current_app.logger.error(e)return jsonify(errno=RET.DBERR, errmsg='短信验证码删除失败')# 7. 创建用户对象user = User()# 8. 设置用户对象属性user.nick_name = mobileuser.password = passworduser.mobile = mobileuser.signature = '改用户很懒,什么都没写'# 9. 保存用户到数据库try:db.session.add(user)db.session.commit()except Exception as e:current_app.logger.error(e)db.session.rollback()return jsonify(errno=RET.DBERR, errmsg='用户注册失败')# 10. 返回响应return jsonify(errno=RET.OK, errmsg='注册成功')

定义登录装饰器,封装用户的登录数据

# 定义登录装饰器,封装用户的登录数据
def user_login_data(view_func):def wrapper(*args, **kwargs):# 1.通过session获取用户的登录信息user_id = session.get('user_id')# 2.通过user_id取出用户对象user = Noneif user_id:try:user = User.query.get(user_id)except Exception as e:current_app.logger.error(e)else:return redirect(url_for("index.show_index", next=request.url))# 3.将user数据封装到g对象g.user = userreturn view_func(*args, **kwargs)return wrapper

使用try except小技巧

try:except Exception as e:current_app.logger.error(e)return jsonify(errno=RET.DBERR, errmsg='')

在这里插入图片描述

热门新闻

template模板试用过滤器
base.html

 <ul class="rank_list">{# 遍历热门新闻 #}{% for news in data.news_list %}<li><span class="{{ loop.index | my_filter }}">{{ loop.index }}</span><a href="{{ "/news/%s" %(news.id) }}">{{ news.title }}</a></li>{% endfor %}</ul>

Day3

在这里插入图片描述

发布评论接口

# 新闻评论后端
# 请求路径: /news/news_comment
# 请求方式: POST
# 请求参数:news_id,comment,parent_id
# 返回值: errno,errmsg,评论字典
@news_bp.route('/news_comment', methods=['POST'])
@user_login_data
def news_comment():# 1.判断用户是否登录了if not g.user:return jsonify(errno=RET.NODATA, errmsg='用户未登录')# 2.获取参数news_id = request.json.get('news_id')content = request.json.get('comment')parent_id = request.json.get('parent_id')# 3.为空校验if not all([news_id, content]):return jsonify(errno=RET.PARAMERR, errmsg='参数不全')# 4.根据新闻的编号取出新闻对象try:news = News.query.get(news_id)except Exception as e:current_app.logger.error(e)return jsonify(errno=RET.DBERR, errmsg='获取新闻失败')# 5.创建评论对象,设置属性comment = Comment()comment.user_id = g.user.idcomment.news_id = news_idcomment.content = contentif parent_id:comment.parent_id = parent_id# 6.保存评论对象到数据库中try:db.session.add(comment)db.session.commit()except Exception as e:current_app.logger.error(e)db.session.rollback()return jsonify(errno=RET.DBERR, errmsg='评论失败')# 7.返回响应,携带平路数据return jsonify(errno=RET.OK, errmsg='评论成功', data=comment.to_dict())

评论js

在这里插入代码片        // 评论回复if(sHandler.indexOf('reply_sub')>=0){var $this = $(this)var news_id = $this.parent().attr('data-newsid')var parent_id = $this.parent().attr('data-commentid')var comment = $this.prev().val()if (!comment) {alert('请输入评论内容')return}var params = {"news_id": news_id,"comment": comment,"parent_id": parent_id}$.ajax({url: "/news/news_comment",type: "post",contentType: "application/json",headers: {"X-CSRFToken": getCookie("csrf_token")},data: JSON.stringify(params),success: function (resp) {if (resp.errno == "0") {var comment = resp.data// 拼接内容var comment_html = ""comment_html += '<div class="comment_list">'comment_html += '<div class="person_pic fl">'if (comment.user.avatar_url) {comment_html += '<img src="' + comment.user.avatar_url + '" alt="用户图标">'}else {comment_html += '<img src="../../static/news/images/person01.png" alt="用户图标">'}comment_html += '</div>'comment_html += '<div class="user_name fl">' + comment.user.nick_name + '</div>'comment_html += '<div class="comment_text fl">'comment_html += comment.contentcomment_html += '</div>'comment_html += '<div class="reply_text_con fl">'comment_html += '<div class="user_name2">' + comment.parent.user.nick_name + '</div>'comment_html += '<div class="reply_text">'comment_html += comment.parent.contentcomment_html += '</div>'comment_html += '</div>'comment_html += '<div class="comment_time fl">' + comment.create_time + '</div>'comment_html += '<a href="javascript:;" class="comment_up fr" data-commentid="' + comment.id + '" data-newsid="' + comment.news_id + '">赞</a>'comment_html += '<a href="javascript:;" class="comment_reply fr">回复</a>'comment_html += '<form class="reply_form fl" data-commentid="' + comment.id + '" data-newsid="' + news_id + '">'comment_html += '<textarea class="reply_input"></textarea>'comment_html += '<input type="button" value="回复" class="reply_sub fr">'comment_html += '<input type="reset" name="" value="取消" class="reply_cancel fr">'comment_html += '</form>'comment_html += '</div>'$(".comment_list_con").prepend(comment_html)// 请空输入框$this.prev().val('')// 关闭$this.parent().hide()//更新评论数量updateCommentCount();}else {alert(resp.errmsg)}}})}})

详情页-获取用户对评论的赞

@news_bp.route('/<int:news_id>')
@user_login_data
def news_detail(news_id):# 1.根据新闻编号,查询新闻对象try:news = News.query.get(news_id)except Exception as e:current_app.logger.error(e)return jsonify(errno=RET.DBERR, errmsg='获取新闻失败')# 2.如果新闻对象不存在,直接抛出状态码异常if not news:abort(404)# 3.获取前6条热门新闻try:click_news = News.query.order_by(News.clicks.desc()).limit(6).all()except Exception as e:current_app.logger.error(e)# 4.将热门新闻对象列表,转成字典列表click_news_list = []for item_news in click_news:click_news_list.append(item_news.to_dict())# 5.判断用户是否收藏过该新闻is_collected = False# 用户需要登录, 并且该新闻在用户收藏过的新闻列表中if g.user:if news in g.user.collection_news:is_collected = True# 6.查询数据库中,该新闻的所有评论内容try:comments = Comment.query.filter(Comment.news_id == news_id).order_by(Comment.create_time.desc()).all()except Exception as e:current_app.logger.error(e)return jsonify(errno=RET.DBERR, errmsg='获取评论失败')# 6.1用户点赞过的评论编号try:# 6.1.1用户点过的所有赞commentlikes = []if g.user:commentlikes =CommentLike.query.filter(CommentLike.user_id == g.user.id).all()# 6.1.2获取用户所有点赞过的评论编号mylike_comment_ids = []for commentLike in commentlikes:mylike_comment_ids.append(commentLike.comment_id)except Exception as e:current_app.logger.error(e)return jsonify(errno=RET.DBERR, errmsg='获取点赞失败')# 7.将评论的对象列表,转成字典列表comments_list = []for comment in comments:# 将评论转成字典comm_dict = comment.to_dict()comments_list.append(comm_dict)# 添加is_like记录点赞comm_dict['is_like'] = False# 判断用户是否对评论点过赞if g.user and comment.id in mylike_comment_ids:comm_dict['is_like'] = Truedata = {"news_info": news.to_dict(),"user_info": g.user.to_dict() if g.user else "","news_list": click_news_list,"is_collected": is_collected,"comments": comments_list}return render_template('news/detail.html', data=data)

详情页-获取的点赞评论前端渲染

   <div class="comment_list_con">{# 遍历所有的评论 #}{% for comment in data.comments %}<div class="comment_list"><div class="person_pic fl">{# 判断是否有用户头像 #}{% if comment.user.avatar_url %}<img src="{{ comment.user.avatar_url }}" alt="用户图标">{% else %}<img src="../../static/news/images/worm.jpg" alt="用户图标">{% endif %}</div><div class="user_name fl">{{ comment.user.nick_name }}</div><div class="comment_text fl">{{ comment.content }}</div>{# 判断是否有父评论 #}{% if comment.parent %}<div class="reply_text_con fl"><div class="user_name2">{{ comment.parent.user.nick_name }}</div><div class="reply_text">{{ comment.parent.content }}</div></div>{% endif %}<div class="comment_time fl">{{ comment.create_time }}</div>{# 处理点赞 #}<a href="javascript:;" class="comment_up {% if comment.is_like %} has_comment_up {% endif %} fr"data-commentid="{{ comment.id }}" data-likecount="{{ comment.like_count }}">{# 判断评论的数量 #}{% if comment.like_count > 0 %}{{ comment.like_count }}{% else %}赞{% endif %}</a><a href="javascript:;" class="comment_reply fr">回复</a>{# 回复评论的表单 #}<from class="reply_form fl" data-newsid="{{ comment.news_id }}" data-commentid="{{ comment.id }}"><textarea  class="reply_input"></textarea><input type="submit" name="" value="回复" class="reply_sub fr"><input type="reset" name="" value="取消" class="reply_cancel fr"></from></div>{% endfor %}</div>

详情页-点赞接口与js

# 评论点赞
# 请求路径: /news/comment_like
# 请求方式: POST
# 请求参数:news_id,comment_id,action,g.user
# 返回值: errno,errmsg
@news_bp.route('/comment_like', methods=['POST'])
@user_login_data
def comment_like():# 1.判断用户是否登录了if not g.user:return jsonify(errno=RET.NODATA, errmsg='用户未登录')# 2.获取参数comment_id = request.json.get('comment_id')action = request.json.get('action')# 3.为空校验if not all([comment_id, action]):return jsonify(errno=RET.PARAMERR, errmsg='参数不全')# 4.操作类型进行校验if not action in ['add', 'remove']:return jsonify(errno=RET.DATAERR, errmsg='操作类型有误')# 5.通过评论编号查询评论对象,并判断是否存在try:comment = Comment.query.get(comment_id)except Exception as e:current_app.logger.error(e)return jsonify(errno=RET.DBERR, errmsg='获取评论失败')# 建议换行if not comment: return jsonify(errno=RET.NODATA, errmsg='评论不存在')# 6.根据操作类型点赞或者取消点赞try:if action == 'add':# 6.1 判断用户是否有对该评论点过赞comment_like = CommentLike.query.filter(CommentLike.user_id == g.user.id,CommentLike.comment_id == comment_id).first()if not comment_like:# 创建点赞对象comment_like = CommentLike()comment_like.user_id = g.user.idcomment_like.comment_id = comment_id# 添加到数据库中db.session.add(comment_like)# 将该评论的点赞数量 +1db.session.commit()else:# 6.2 判断用户是否有对该评论点过赞comment_like = CommentLike.query.filter(CommentLike.user_id == g.user.id,CommentLike.comment_id == comment_id).first()if comment_like:# 删除点赞对象db.session.delete(comment_like)# 将该评论的点赞数量-1if comment.like_count > 0:comment.like_count -= 1db.session.commit()except Exception as e:current_app.logger.error(e)db.session.rollback()return jsonify(errno=RET.DBERR, errmsg='操作失败')# 7.返回响应return jsonify(errno=RET.OK, errmsg='操作成功')
// 点赞处理if(sHandler.indexOf('comment_up')>=0){var $this = $(this);var action = "add"if(sHandler.indexOf('has_comment_up')>=0){// 如果当前该评论已经是点赞状态,再次点击会进行到此代码块内,代表要取消点赞action = "remove"}//获取到当前点击的标签上面的, 评论编号, 新闻编号var comment_id = $(this).attr("data-commentid")// var news_id = $(this).attr("data-newsid")var params = {"comment_id": comment_id,"action": action,// "news_id": news_id}$.ajax({url: "/news/comment_like",type: "post",contentType: "application/json",headers: {"X-CSRFToken": getCookie("csrf_token")},data: JSON.stringify(params),success: function (resp) {if (resp.errno == "0") {//获取到当前标签中的点赞数量var like_count = $this.attr('data-likecount')//增加安全性校验,如果获取不到data-likecount的值,那么默认设置成0if(like_count == undefined){like_count = 0;}// 更新点赞按钮图标,并加1, 减1操作if (action == "add") {like_count = parseInt(like_count) + 1// 代表是点赞$this.addClass('has_comment_up')}else {like_count = parseInt(like_count) - 1$this.removeClass('has_comment_up')}// 更新点赞数据,重新赋值回去$this.attr('data-likecount', like_count)if (like_count == 0) {$this.html("赞")}else {$this.html(like_count)}}else if (resp.errno == "4101"){$('.login_form_con').show();}else {alert(resp.errmsg)}}})}

Day4

用户中心与资料修改

from flask import render_template
from flask import redirect, g, request, jsonifyfrom . import profile_bp
from info.utils.commons import user_login_data
from info.utils.response_code import RET
from info.models import db# 请求路径: /user/base_info
# 请求方式:GET,POST
# 请求参数:POST请求有参数,nick_name,signature,gender
# 返回值:errno,errmsg
@profile_bp.route('/base_info', methods=['GET', 'POST'])
@user_login_data
def base_info():# 1.判断请求方式,如果是get请求if request.method == 'GET':# 2.携带用户数据,渲染页面if not g.user:# 如果没有登录,重定向到首页redirect('/')return render_template('news/user_base_info.html', user_info=g.user.to_dict())else:# 3.post请求# 4.获取参数nick_name = request.json.get('nick_name')signature = request.json.get('signature')gender = request.json.get('gender')# 5.校验参数,为空校验if not all([nick_name, signature, gender]):return jsonify(errno=RET.PARAMERR, errmsg='参数不全')if not gender in ['MAN', 'WOMAN']:return jsonify(errno=RET.DATAERR, errmsg='性别异常')# 6.修改用户数据g.user.signature = signatureg.user.nick_name = nick_nameg.user.gender = genderdb.session.add(g.user)db.session.commit()# 7.返回响应return jsonify(errno=RET.OK, errmsg='修改成功')@profile_bp.route('/info')
@user_login_data
def user_info():# 1.判断用户是否登录if not g.user:return redirect('/')# 2.携带数据渲染页面data = {'user_info': g.user.to_dict()}return render_template('news/user.html', data=data)

用户头像-上传七牛

七牛配置

# -*- coding: utf-8 -*-
# flake8: noqaimport qiniu.config
from qiniu import Auth, etag, put_data, put_fileaccess_key = ''
secret_key = ''def image_storage(file_data):"""存储图片到七牛服务器:param file_data: 文件二进制码:return:"""q = Auth(access_key, secret_key)bucket_name = 'ihome-python-why2'# # 上传文件到七牛后, 七牛将文件名和文件大小回调给业务服务器。# policy = {#     'callbackUrl': 'http://your.domain.com/callback.php',#     'callbackBody': 'filename=$(fname)&filesize=$(fsize)'# }token = q.upload_token(bucket_name, None, 3600)# localfile = '../static/images/home01.jpg'# ret, info = put_file(token, None, localfile)ret, info = put_data(token, None, file_data)if info.status_code == 200:return ret.get('key')else:raise Exception('上传图片失败')if __name__ == "__main__":with open('../static/images/home01.jpg', 'rb') as f:file_data = f.read()image_storage(file_data)

头像上传逻辑

# 取/设置,用户头像上传
# 请求路径: /user/pic_info
# 请求方式:GET,POST
# 请求参数:无, POST有参数,avatar
# 返回值:GET请求: user_pci_info.html页面,data字典数据, POST请求: errno, errmsg,avatar_url
@profile_bp.route('/pic_info', methods=['GET', 'POST'])
@user_login_data
def pic_info():# 1.判断请求方式,如果是get请求if request.method == 'GET':# 2.携带用户数据,渲染页面return render_template('news/user_pic_info.html', user_info=g.user.to_dict())# 3.如果是post请求# 4.获取参数avatar = request.files.get('avatar')# 5.为空校验if not avatar:return jsonify(errno=RET.PARAMERR, errmsg='图片不能为空')# 6.上传图像,判断图片是否上传成功try:image_name = image_storage(avatar.read())except Exception as e:current_app.logger.error(e)return jsonify(errno=RET.THIRDERR, errmsg='七牛云异常')if not image_name:return jsonify(errno=RET.NODATA, errmsg='图片上传失败')# 7.将图片设置到用户对象g.user.avatar_url = image_name# 8.返回响应data = {'avatar_url': constants.QINIU_DOMIN_PREFIX + image_name}return jsonify(errno=RET.OK, errmsg='上传成功', data=data)

前端提交图片ajax

$(function () {$(".pic_info").submit(function (e) {e.preventDefault()//TODO 上传头像// 上传头像,表单提交和其他提交方式不一样// /*$(this).ajaxSubmit({url: "/user/pic_info",type: "POST",headers: {"X-CSRFToken": getCookie('csrf_token')},success: function (resp) {if (resp.errno == "0") {$(".now_user_pic").attr("src", resp.data.avatar_url)$(".user_center_pic>img", parent.document).attr("src", resp.data.avatar_url)$(".user_login>img", parent.document).attr("src", resp.data.avatar_url)}else {alert(resp.errmsg)}}})// */})
})

提交新闻

function getCookie(name) {var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");return r ? r[1] : undefined;
}$(function () {$(".release_form").submit(function (e) {e.preventDefault()// 发布新闻, ajaxSubmit属于表单提交// /*$(this).ajaxSubmit({//是为了处理富文本(可以有颜色,大小)beforeSubmit: function (request) {// 在提交之前,对参数进行处理for(var i=0; i<request.length; i++) {var item = request[i]if (item["name"] == "content") {item["value"] = tinyMCE.activeEditor.getContent()}}},url: "/user/news_release",type: "POST",headers: {"X-CSRFToken": getCookie('csrf_token')},success: function (resp) {if (resp.errno == "0") {// 选中索引为6的左边单菜单window.parent.fnChangeMenu(6)// 滚动到顶部window.parent.scrollTo(0, 0)}else {alert(resp.errmsg)}}})// */})
})

在这里插入图片描述

用户新闻列表

# 用户新闻列表
# 请求路径: /user/news_list
# 请求方式:GET
# 请求参数:p
# 返回值:GET渲染user_news_list.html页面
@profile_bp.route('/news_list', methods=['GET', 'POST'])
@user_login_data
def news_list():# 1.获取参数, ppage = request.args.get('p')# 2.参数类型转换try:page = int(page)except Exception as e:page = 1# 3.分页查询用户发布的新闻try:paginate = News.query.filter(News.user_id == g.user.id).order_by(News.create_time.desc()).paginate(page, 10, False)except Exception as e:current_app.logger.error(e)return jsonify(errno=RET.DBERR, errmsg='获取新闻失败')# 4.获取分页对象中的属性,总页数,当前页,当前页对象列表totalPage = paginate.pagescurrentPage = paginate.pageitems = paginate.items# 5.将对象列表,转换成字典列表news_list = []for news in items:news_list.append(news.to_dict())# 6.拼接数据,渲染页面data = {'totalPage': totalPage,'currentPage': currentPage,'news_list': news_list}# 7.携带数据,返回响应return render_template('news/user_news_list.html', data=data)

前端

 <ul class="article_list">{# 遍历用户发布的新闻 #}{% for news in data.news_list %}{% if news.status == 0 %}<li><a href="user_news_release.html">{{ news.title }}</a><em class="pass">已通过</em><span>{{ news.create_time }}</span></li>{% elif news.status == 1 %}<li><a href="#">{{ news.title }}</a><em class="review">审核中</em><span>{{ news.create_time }}</span></li>{% else %}<li><a href="#">{{ news.title }}</a><em class="nopass">未通过</em><span>{{ news.create_time }}</span><b>未通过原因:{{ news.reason }}</b></li>{% endif %}{% endfor %}</ul>

在这里插入图片描述

关注与取消关注

# 关注与取消关注
# 请求路径: /news/followed_user
# 请求方式: POST
# 请求参数:user_id,action
# 返回值: errno, errmsg
@news_bp.route('/followed_user', methods=['POST'])
@user_login_data
def followed_user():# 1.判断用户是否登录if not g.user:return jsonify(errno=RET.NODATA, errmsg='用户未登录')# 2.获取参数author_id = request.json.get('user_id')action = request.json.get('action')# 3.校验参数,为空校验if not all([author_id, action]):return jsonify(errno=RET.PARAMERR, errmsg='参数不全')# 4.检验操作类型if not action in ['follow', 'unfollow']:return jsonify(errno=RET.DATAERR, errmsg='操作类型有误')# 5.根据作者编号取出作者对象,判断作者对象是否存在try:author = User.query.get(author_id)except Exception as e:current_app.logger.error(e)return jsonify(errno=RET.DBERR, errmsg='获取作者失败')if not author:return jsonify(errno=RET.NODATA, errmsg='该作者不存在')# 6.根据操作类型,进行关注或者取消if action == 'follow':# 关注# 6.1判断当前用户是否关注了该作者if not g.user in author.followers:author.followers.append(g.user)else:# 取消关注# 6.2 判断当前用户是否关注了该作者if g.user in author.followers:author.followers.remove(g.user)# 7.返回响应return jsonify(errno=RET.OK, errmsg='操作成功')

随后需要添加 文章详情中的后端,当前作者是否被用户所关注

  # 8.判断登录的用户是否关注了新闻作者is_followed = Falseif g.user and news.user:if g.user in news.user.followers:is_followed = Truedata = {"news_info": news.to_dict(),"user_info": g.user.to_dict() if g.user else "","news_list": click_news_list,"is_collected": is_collected,"comments": comments_list,"is_followed": is_followed}return render_template('news/detail.html', data=data)

前端修改关注的显示

 {% if data.news_info.author %}<div class="author_card">{# 判断是否有作者头像 #}{% if data.news_info.author.avatar_url %}<a href="#" class="author_pic"><img src="{{ data.news_info.author.avatar_url }}" alt="author_pic"></a>{% else %}<a href="#" class="author_pic"><img src="../../static/news/images/user_pic.png" alt="author_pic"></a>{% endif %}<a href="#" class="author_name">{{ data.news_info.author.nick_name }}</a><div class="author_resume">{{ data.news_info.author.signature }}</div><div class="writings"><span>总篇数</span><b>{{ data.news_info.author.news_count }}</b></div><div class="follows"><span>粉丝</span><b>{{ data.news_info.author.followers_count }}</b></div><a href="javascript:;" class="focus fr" data-userid="{{ data.news_info.author.id }}" style="display: {% if data.is_followed %} none {% else %} block {% endif %}">关注</a><a href="javascript:;" class="focused fr" data-userid="{{ data.news_info.author.id }}" style="display: {% if data.is_followed %} block {% else %} none {% endif %}"><span class="out">已关注</span><span class="over">取消关注</span></a></div>{% endif %}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_770938.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Flask搭建新闻网站②

文章目录Day5404创建管理员管理员登录用户统计防止用户进入admin页面gunicorn运行项目nginxDocker部署服务器建立docker镜像Day5 404 # 统一返回404页面 index_bp.route(/404) user_login_data def page_not_found():data {"user_info": g.user.to_dict() if g.use…

Django+xadmin实现教育网站系统

文章目录环境配置与项目介绍Django升级2.0 注意的点app管理数据库设计注册model注册app目录5 xadmin搭建后台管理系统5-3 users app 的model注册5-5 xadmin全局配置app.py 定义app后台名称第6章 用户注册功能实现6.1 登录表单验证6-6 session和cookie自动登录机制用户注册发送邮…

Django+xadmin实现教育网站系统②

文章目录第10章 个人中心和全局搜索功能实现全局搜索修改头像第11章 首页、全局功能细节和404以及500页面配置第12章 常见web攻击及防范sql注入12-2 xss攻击原理及防范12-3 csrf攻击与防范第13章 xadmin的进阶开发13-1 userprofile注册以及django的权限管理13-3 model_icon, 只…

视频网站解决带宽问题(总结)

自己搜来的一些方案&#xff0c;汇总下供自己学习吧 1.大带宽是重中之重 所有了解视频类应用的人都知道&#xff0c;视频网站的带宽才是重中之重。在线视频播放网站每天都会产生巨额的流量&#xff0c;每个客户都会占据非常大的带宽。如果带宽不够就会出现用户播放卡顿&#…

php投票网站教程,PHP之投票联系

1.建立数据库表1&#xff1a;DiaoYanTiMu表2&#xff1a;DiaoYanXuanXiang2.页面页面1&#xff1a;投票首页无标题文档#fanhui{ display:none}$db new MySQLi("localhost","root","123","mydb");$sql "select * from diaoyanti…

网站页面左右_建设一个普通的网站需要多少钱?就是一个展示型的公司网站。...

这个问题在行业内是没有准确定义的&#xff0c;每一个建站公司在面对不同的客户需求&#xff0c;都会有不同的报价模式&#xff0c;而影响价格的因素有很多&#xff0c;但无疑建站成员所拥有的“宝贵经验”往往是最贵的&#xff0c;这也是建站公司相互报价差距巨大的原因。要想…

java页面加速_为你的网站加速

我的博客刚成立也是不久&#xff0c;所以现在我关注了很多中小博客站点&#xff0c;发现很多站点打开速度很慢&#xff0c;甚至有一些网站出现打不开的情况。网站运行不稳定&#xff0c;可能和使用的服务器有关系&#xff0c;因为很多人都图方便&#xff0c;为了不备案直接使用…

linux 重启命令nginxed,Nginx转发,部署网站相关linux命令

进入目录cd /etc/nginx/sites-available进入文件defaultsudo vim default;编辑a鼠标右键粘贴退出编辑Esc保存:wq重启Nginx服务sudo service nginx restart清空default里面的内容sudo sh -c encho "" >default创建manage-front文件&#xff0c;并复制cib-front到ma…

电子病历模板编辑器_这几个邮件模板网站,帮助提升工作效率

AUTOKLOSE: 一些免费的邮件正文模板。Autopilot Templates:ree customer journey templates for marketing automationBEE TEMPLATES for GMAIL: 可编辑Gmail邮件模板。COLD EMAIL TEMPLATE: 一系列营销邮件模板。Contactually: 不知道邮件内容怎么写&#xff1f;参考下这些邮件…

关于ssm框架的外文文献及译文_使用彩云小译,翻译外文网站实现双语对照

彩云小译扩展&#xff0c;实现外语网页的翻译功能&#xff0c;一段原文一段译文&#xff0c;让查阅外文资料可以随心所欲。整理&排版 | idea君 &#xff0c;预计阅读时间 | 3分钟 文章意在学习交流分享&#xff0c;如有侵权请联系删除 封面&#xff1a;http://www.pexels.c…

网站index.php怎么关联其余,thinkphp隐藏index.php/home并允许访问其他模块的实现方法...

想要达成的效果很简单&#xff0c;我有两个模块&#xff0c;Home、Wechat。http://localhost/index.php/home/index/index 缩短为&#xff1a; http://localhost/index/indexhttp://localhost/index.php/wechat/index/index 缩短为&#xff1a; http://localhost/wechat/index/…

php5.2.8升级,UWA2.X通用建站升级程序

UWA2.X通用建站升级程序是一款基于PHP和MySQL开发的通用建站系统&#xff0c;程序简洁、灵活而具备强大的扩展性&#xff0c;将是您轻松建站的首选利器。采用XML名字空间风格核心模板&#xff1a;模板全 部使用文件形式保存&#xff0c;对用户设计模板、网站升级转移均提供很大…

google android开发者网站,谷歌上线 Fuchsia OS 开发者网站

原标题&#xff1a;谷歌上线 Fuchsia OS 开发者网站谷歌自研的操作系统 Fuchsia OS 又有新动作了。据了解&#xff0c;谷歌近日悄悄地上线了 Fuchsia OS 的开发者网站 https://fuchsia.dev/。谷歌表示&#xff0c;上线 fuchsia.dev 是为了让开发者更好地参与 Fuchsia OS 的开发…

如何自制网页服务器,如何自己制作网站?如何制作自己的网页?

如何自己制作网站?如何制作自己的网页?首先&#xff0c;你是非开发者&#xff0c;你需要知道做一个网页要采取哪些步骤。下面一起来看看吧!简单来说&#xff0c;网页制作需要的内容如下:页面设计、前端开发、后端开发(如果只是简单的介绍页面或者是不经常更改的页面)&#xf…

我的世界服务器换披风的网站,我的世界正版披风怎么换|或

【我的世界评测】我的世界正版披风怎么换。那下面给大家分享的则是我的世界正版中更换披风的教程哦~那到底怎么更换披风呢&#xff1f;那下面就给大家详细的介绍一下吧&#xff01;如果你有心仪的作品或者心得分享的话&#xff0c;欢迎来游戏园投稿&#xff0c;大家可以点击>…

计算机安全可信站点,怎样看网站是否安全?教你从地址栏上分辨网站是否真安全...

当网民有SSL证书保护的加密页面时&#xff0c;地址栏网址也会由“http”自动变成“https”。如同金色安全锁标记一样&#xff0c;我们此时提交的信息得到了安全加密保护。不知道平时大家在日常上网时有没有发现观察过有的网站开头是http&#xff0c;而有的则是https。为何会有这…

帮程序员减压放松的 10 个良心网站

同学们工作之余&#xff0c;不妨放下微博跟朋友圈&#xff0c;来这10个网站感受一下看着就醉了的情境&#xff1a;「念完往上一推音乐键&#xff0c;我往后一靠&#xff0c;潮乎乎的软皮耳机里头&#xff0c;音乐排山倒海。」今天推荐的网站&#xff0c;利用代入感强的图片与音…

来,了解一下90年代的网站

来自&#xff1a;www.sohu.com/a/240853435_66877020 年对于互联网来说是很长的一段时间&#xff0c;网页设计在此期间也走过了很长的路&#xff0c;我们现在回头看&#xff0c;几乎不敢相信我们曾经设计过这种东西&#xff01;▎1. Penny JuicePenny Juice 是一款为儿童制作的…

网站 HTTP 升级 HTTPS 完全配置手册

作者&#xff1a;葡萄城技术团队链接&#xff1a;https://my.oschina.net/powertoolsteam/blog/1862967昨天&#xff0c;所有使用Google Chrome稳定版的用户迎来了v68正式版首个版本的发布&#xff0c;详细版本号为v68.0.3440.75&#xff0c;上一个正式版v67.0.3396.99发布于6月…

来膜拜下 Google 的全球化网站架构

这是 Google SRE 工程师在2018年5月的一篇分享。本文大致的介绍了 Google 整个网站的 infrastructure&#xff0c;以及代码发布流程。而更详细的细节&#xff0c;可以阅读 Google 出的《Site Reliability Engineering》这本书。原视频 Google Tech Talk 的链接&#xff1a;http…