精华内容
下载资源
问答
  • 2019-09-24 20:52:21

    开发步骤:
    管理模板修复
    确定项目:
    项目目标-业务目标
    业务分析:(完全分析透了,再下一步)
    业务框架
    框架的子业务细节
    业务的细节指标(细节要求)
    数据库分析:
    开发框架分析:类组织关系
    用户界面处理:
    开发过程:
    业务难点的时序:-业务闭环,生命周期,分阶段的一套较难业务.Zara软件

    项目一:
    项目目标-业务目标:
    1.内部文档权限管理
    2.文档分享评价
    3.文档筛查
    4.版本管理
    业务框架:+细节+更深的描述
    登录管理:
    权限管理:
    登录权限:安全,角色,加密,保证唯一性,不允许注册,内部添加,默认密码,邮箱(发邮件),电话(发短信)
    用户名:电话
    密码:md5加密
    验证码:4~6位数字加字母
    提示用户名或密码错误和验证码错误

    文件权限:上传(短时间删除权限,防止误上传,或者加作废状态);修改;查看(可限时查看,比如两个月内查看,历史文档不允许查看;);下载;评论(上级对下级),收藏
    情景:不允许随便看,随便下载()
    系统权限-管理员
    操作员管理:
    日志管理:
    系统设置-组织架构(上下级安排):
    上下级管理程序
    日志,文件,评论
    文件管理:存放为主
    上传:
    批量上传
    误上传处理(删除问题)
    版本管理
    日志管理
    只能新增
    修改:版本递增(一个小时内的作为一个版本),修改时间(简单会话的管理);上个版本回滚;;内部上传按钮,版本替换
    查看:支持txt,excel,word,pdf,图片(全部只读,不能复制,图片化处理,浏览器不能直接通过地址获取,控制器排查,后台查看需要验证码,一旦查看只能用一次,图片显示出来验证码就失效);禁止右键,禁止缓存
    下载:浏览器不能直接通过地址下载(即时授权,即时下载)

    通知管理:
    文件增改
    内部公告:
    全公司,部门,指定人员,指定角色
    自动生成,人工生成
    评论通知
    websocket
    日志管理:
    日志登记:
    按文件,部门,人员,时间,操作
    日志查看问题
    查看自身
    管理查看全部
    日志统计:
    文件版本统计
    部门文件活度统计
    个人统计
    查看处理:用户查看,界面等处理
    评论管理:
    文件评论
    小论坛
    管理员禁用–管理员/发布人查看全部

    数据库分析
    主表:
    操作员
    文档表
    评论
    日志
    公告
    副表:
    部门表
    角色(权限)
    文档类型
    业务表:
    文件版本表
    其他表:
    权限
    角色权限表

    操作员表,全部不为空 fm_operator
    id int 自动递增
    姓名username varchar 16
    密码(md5)userpass varchar 128
    电话-登录使用tel varchar 16
    角色(权限) roleid 角色表关联键 int
    部门 departmentid int
    离职禁用(0正常,1禁用)status int
    comments 备注 varchar 255

    文件表fm_document
    id int
    文档名称docname varchar 255
    文档类型doctypeid int
    部门departmentid int
    最新文档地址lastpath(一点击文档直接就到最后一个文件,经常访问用,文档类型上加上有效期) varchar255
    最新版本号lastversion varchar 32
    查出来最后时间(限时访问,控制不能往前翻查太久)lasttime datetime
    创建日期createdate varchar 32
    operatorid int
    状态0 正常1禁用 还有禁止更新,锁定等,暂时先两个 status int
    comments varchar255 文档介绍

    文档表类型 fm_document_type
    id int11
    类型名称 typename varchar255
    事件处理模式 每周 每月 每年 自定义mode int11 0不限1自定义2当天3当周456
    startdate varchar32 有效起始日期
    enddate varchar32 截止日期
    comments varchar255

    fm_department 部门表
    id int 11
    departmentname varchar16 部门名称

    fm_discuss评论表
    id int 11
    fieldid varchar16 文件id
    date varchar32 日期
    operator int 评论人
    info text 评论信息
    status int 状态 0正常 1隐藏 2阻止()

    fm_log日志表 (建议变成切面,可以先暂时忽略,但是切得方法尽量规则,容易找)
    id
    date varchar 32 日期时间
    departmentid varchar 部门id
    operatorid 人员id
    fieldid 文件id
    日志类型optiontype 0新增 1修改 23456
    描述 info varchar 64 提示信息
    status int 64 日志状态(暂无) 0正常 销毁用的
    公告表fm_notice
    id
    date 日期
    sendtype 通知类型0全公司 1部门 2角色 3指定
    departmentid 部门id
    operatorids 指定人员列表 格式12,45,232,544,2323
    operatorid 发布人/发生源,有可能是系统
    roleid 角色id
    createtype 生成类型 0系统 1手工
    tltle 小标题
    info 内容
    url 地址(点击公告时,有则触发)
    status 状态 0正常 1隐藏 (发布人可隐藏)

    角色表fm_role 角色和权限1对多 一个人只能有一个角色(有增删改查)
    id int 11
    rolename varchar32 角色名称
    key varchar 16 判别key 格式 user

    权限表 fm_power(没有增删改查)
    id int 11
    powername varchar32 权限名称
    key varchar 32(shiro用) 判别key 格式:: (manager:user:add)
    parentid int 默认0为根权限 上级权限id (权限树列表使用)
    角色权限关联表fm_role_power
    id
    角色 roleid
    权限powerid

    文件版本表fm_document_file
    id int 11
    createdate varchar 16 文件更新,创建新文件,复制一份
    lasttime(因为一小时之内不更新) datetime 最后修改日期
    version varchar 16 版本
    path varchar 16 文件路径

    增删改查的表:operator,评论,公告,部门,角色,文档类型,角色权限,评论(没有删,修改状态) 日志(没有界面,只有增)
    权限处理:shiro 注解模式
    类组织关系:

    列录入:
    录入列
    userpass 后续补充赋值的
    createdate 后台运算赋值的
    operatorid 后台会话来赋值
    studentcount 触发器修改||运算累加
    可选列(不是每次必须录入的),后台判断赋值
    统计列(根本不录入),统计时计算自动赋值,辅助统计

    更多相关内容
  • Java+MySQL实现评论功能设计开发

    万次阅读 多人点赞 2018-08-13 09:39:52
    Java+MySQL实现评论功能设计开发 一、背景 项目初始版本上线,有时间写点东西记录一下项目中的心得体会,通过这个项目学习了很多,要写下来的有很多,先从评论功能开始吧。由于项目需要增加评论功能,之前并无此...

                                                    Java+MySQL实现评论功能设计开发

    一、背景

          项目初始版本上线,有时间写点东西记录一下项目中的心得体会,通过这个项目学习了很多,要写下来的有很多,先从评论功能开始吧。由于项目需要增加评论功能,之前并无此方面的经验,因此项目开始的一段时间都在寻思着如何进行评论功能的设计。上网搜索一波发现有很多优秀的第三方评论插件可以使用,本来准备直接采用的,但是心里始终有点疙瘩,可能是评论数据放在别人那里不放心的原因,或可能是想一探这些评论系统的究竟,因此最终决定自行设计开发这么一套评论功能。效果截图如下所示,采用的是MySQL数据库,编程语言用的Java。(更多内容,可参阅程序员在旅途)

    二、评论系统的概述:

           评论功能是用户表达对某一主题的想法的很好的一种方式,优秀的评论系统能很好地提高社区的活跃度。各大主流网站也都提供了相应的评论支持。比如:贴吧,新闻类门户网站(APP),UC浏览器等等。

          各大网站侧重点不同,对评论功能的要求就不一样,设计出来的评论系统自然就不一样。可能会有:①只可以进行评论,不可以回复,②既可以进行评论,也可以进行回复,然后在这个基础上可能会增加一些额外的功能,比如评论的折叠,审核,优选等。另外,一个良好的UI显示也是非常重要的,能给用户一个直观的视觉上的体验也是评论功能不可或缺的一个要素,毕竟用户都是具有很强的审美能力的,用户的使用体验决定了项目的需求。

          对于本项目,设计的是,既可以评论,也可以进行回复,评论和回复分开存储。在显示上,评论和回复显示的位置不同,回复相较于评论向右靠一些,这样,看起来比较舒适,当然也可以设置成其他的样式。评论会显示评论者头像,回复不会。

          评论的管理:后台系统应该具备基本的评论管理功能,比如:删除,折叠,优选,排序。这些功能的实现依赖于数据库表的设计,所以,在开始设计的时候,要想清楚自己的项目需要哪些功能。

    三、数据库表的设计:

         本评论功能采用评论和回复分离的方式进行存储,一共设计了两张表,一张用户评论表(comment),一张针对评论的回复表(comment_reply)。评论表主要保存对文章或者回答的评论,回复表保存对每一条评论的回复。

          评论表(comment)如下图:主要包括了:评论ID(作为回复表的主键),回答(文章)ID,评论者ID,评论内容,点赞数,评论时间,审核状态

         评论回复表(comment_reply)如下图:主要包括了:评论ID,用户ID,被回复人ID,回复内容,点赞数,回复时间。

          两张表通过comment_id联系起来(并没有设置主外键,主要是不想维护起来太麻烦),获取某一答案的评论及回复步骤:根据answer_id找到所有的评论,然后,遍历所有的评论,根据comment_id查询到所有的回复(评论者的基本信息,例如头像,名称等需要额外查询)。需要注意的是,在评论和回复数据较多的情况下做好分页处理。

    四、程序的实现: 

          采用Java语言进行编程的实现,使用的SSM框架。主要的功能代码如下所示(因为项目有通知功能,看的时候可以略过这部分,跟单纯的评论功能没有太大关系,但是一般要有通知,后面有时间会写站内通知的设计与开发博客):

       4.1 添加评论代码如下:(获取到评论相关的参数,然后进行向数据库表插入)

    public int addComment(Comment comment) {
    	try {
    		Answer commentAnswer = answerMapper.selectByPrimaryKey(comment.getAnswerId());
    		Long commentId = IDUtils.genItemId();//评论ID
    		Date createtime = new Date();
    		//1,填补comment对象的其他参数,进行插入
    		comment.setCommentId(commentId);
    		comment.setState(1);//状态: 0 待审核,1通过,2不通过
    		comment.setPraseCount(0);//一开始插入的点赞数设置为0
    		comment.setCreatetime(createtime);
    		comment.setUpdatetime(createtime);
    		commentMapper.insert(comment);//插入comment记录
    		//2,跟新Answer的相关一条数据,提示评论数+1
    		commentAnswer.setCommentNum((commentAnswer.getCommentNum()==null?0:commentAnswer.getCommentNum()) + 1);
    		answerMapper.updateByPrimaryKeySelective(commentAnswer);
    		//3,向提醒表插一条数据。这条评论是发给谁的,通知表里面的userId就是谁
    		if (comment.getUserId() != commentAnswer.getUserId()) { //自己评论自己不会有通知
    			Remind remind = new Remind();
    			remind.setRemindId(commentId);
    			remind.setUserId(commentAnswer.getUserId());
    			remind.setFromUserId(comment.getUserId());
    			//commentType:1评论回答,2评论别人的评论,3关注,4支持,5反对,6添加回答
    			remind.setRemindType(1);
    			//已读:0否,1是
    			remind.setReadStatus(0);//否
    			remind.setCreatetime(createtime);
    			//插入通知内容,以json的形式存储
    			RemindContent remindComment = new RemindContent();
    			remindComment.setContentId(commentAnswer.getAnswerId());
    			remind.setContent(JsonUtils.objectToJson(remindComment));//通知内容。回答问题的Id
    			remindMapper.insert(remind);
    		}
    		//返回1代表成功
    		return 1;
    	} catch (Exception e) {
    		e.printStackTrace();
    		return 2;
    	}
    }

     4.2 添加回复代码:(前台会传来评论的ID,然后,封装成回复对象进行插入,一个评论ID会对应很多回复)

    public int addCommentReply(CommentReply commentReply) {
        Long commentId = IDUtils.genItemId();//评论ID
        Date createtime = new Date();
    	commentReply.setPraseCount(0);
    	commentReply.setCreatetime(createtime);
    	int retVal = commentReplyMapper.insert(commentReply);
    	  
        //3,向提醒表插一条数据。这条评论是发给谁的,通知表里面的userId就是谁
    	if (commentReply.getReplyuserId() != commentReply.getUserId()) {
    	    Remind remind = new Remind();
    		remind.setRemindId(commentId);
    	    remind.setUserId(commentReply.getReplyuserId());
    		remind.setFromUserId(commentReply.getUserId());
    		//commentType:1评论回答,2评论别人的评论,3关注,4支持,5反对,6添加回答
    		remind.setRemindType(2);
    		//已读:0是,1否
    		remind.setReadStatus(1);
    		remind.setCreatetime(createtime);
    		remind.setContent(commentReply.getCommentId()+"");
    		remindMapper.insert(remind);
    	}
    	return retVal;
    }

     4.3获取某一回答的评论和回复(评论分页返回,但是回复没有分页,后面会优化,使用的是pagehelper插件):

    public PageBean<CommentStatus> listAnswerComments(Long answerId,Integer pageNum,Integer pageSize) {
    try {
    	CommentExample commentExample = new CommentExample();
    	commentExample.setOrderByClause("createtime DESC");
    	Criteria commentCriteria = commentExample.createCriteria();
    	commentCriteria.andAnswerIdEqualTo(answerId);
    	PageHelper.startPage(pageNum, pageSize);
    	List<Comment> commentList = commentMapper.selectByExampleWithBLOBs(commentExample);//获取具有分页结果的评论数据
    	List<CommentStatus> commentStatusList = new ArrayList<>();
    	for (Comment comment : commentList) {
    		CommentStatus commentStatus = new CommentStatus(); //评论返回的具体对象
    			
    		CommentReplyExample example = new CommentReplyExample();
    		com.pn.mini.model.CommentReplyExample.Criteria criteria = example.createCriteria();
    		criteria.andCommentIdEqualTo(comment.getCommentId());
    		List<CommentReply> commentReplyList = commentReplyMapper.selectByExample(example);
    		List<CommentReplyStatus> commentReplyStatusList = new ArrayList<>();
    		for (CommentReply commentReply2 : commentReplyList) {
    			UserBaseInfo commentUser = userBaseInfoMapper.selectByPrimaryKey(commentReply2.getUserId());
    			UserBaseInfo commentReplyUser = userBaseInfoMapper.selectByPrimaryKey(commentReply2.getReplyuserId());
    			CommentReplyStatus commentReplyStatus = new CommentReplyStatus();
    			commentReplyStatus.setCommentId(commentReply2.getCommentId());
    			commentReplyStatus.setContent(commentReply2.getContent());
    			commentReplyStatus.setCreatetime(commentReply2.getCreatetime());
    			commentReplyStatus.setPraseCount(commentReply2.getPraseCount());
    			commentReplyStatus.setReplyuserId(commentReply2.getReplyuserId());
    			commentReplyStatus.setReplyuserName(commentReplyUser.getUserName());
    			commentReplyStatus.setUserId(commentUser.getUserId());
    			commentReplyStatus.setUserName(commentUser.getUserName());
    			commentReplyStatusList.add(commentReplyStatus);
    		}
    		UserBaseInfo commentUserBaseInfo = userBaseInfoMapper.selectByPrimaryKey(comment.getUserId());
    		CommentIntegrate commentIntegrate = new CommentIntegrate();
    		commentIntegrate.setAnswerId(comment.getAnswerId());
    		commentIntegrate.setAvatar(commentUserBaseInfo.getAvatar());
    		commentIntegrate.setCommentId(comment.getCommentId());
    		commentIntegrate.setContent(comment.getContent());
    		commentIntegrate.setCreatetime(comment.getCreatetime());
    		commentIntegrate.setPraseCount(comment.getPraseCount());
    		commentIntegrate.setState(comment.getState());
    		commentIntegrate.setUpdatetime(comment.getUpdatetime());
    		commentIntegrate.setUserId(comment.getUserId());
    		commentIntegrate.setUserName(commentUserBaseInfo.getUserName());
    		//拼接一条评论的返回对象
    		commentStatus.setCommentIntegrate(commentIntegrate);
    		commentStatus.setCommentReplyStatusList(commentReplyStatusList);
    		commentStatusList.add(commentStatus);
    	}
    	PageBean<CommentStatus> recCommentItemBean = null;//接口返回的对象
    	PageInfo<Comment> pageInfo = new PageInfo<>(commentList);
    	recCommentItemBean = new PageBean<>(commentStatusList);
    	recCommentItemBean.setDataList(commentStatusList);
    	recCommentItemBean.setPageNum(pageInfo.getPageNum());
    	recCommentItemBean.setPages(pageInfo.getPages());
    	recCommentItemBean.setPageSize(pageInfo.getPageSize());
    	recCommentItemBean.setSize(pageInfo.getSize());		 
        recCommentItemBean.setTotal(pageInfo.getTotal());
    	return recCommentItemBean;
    			
    	} catch (Exception e) {
    		e.printStackTrace(); //出现异常返回null,controller根据此判断此处调用是否成功
    		return null;
    	}	
    }

     4.4  优化思考:

       ① 回复没有分页返回,回复数据量大的时候需要分页,在在获取回复的时候分页一下即可。

       ② 获取一条信息,需要再去查询用户表,获取用户的信息,这样就会导致获取一条回答的评论和回复需要查询N次数据表,思考的是增加冗余字段(用户名,用户头像),然后减少这方面的查询开销,当用户头像和名称更改的时候,同步更改这里面的数据,但是一般用户的这方面信息更改较少,总的来说,增加这个冗余字段还是能很大程度提高效率的。

      ③优化后的数据库表如下(忽略hot_value这样的字段,不同项目有不同需求):

    五:总结与反思(后续优化的方向):

           虽然评论功能开发完毕,在目前也可以正常的使用,待使用程序的用户的增加,流量的扩大后仍需要继续优化,不然在用户的使用体验上可能会很糟糕,尤其是当数据量大的时候,用户访问可能会感觉到有些慢。不足之处其一:在于获取评论的回复,每次读取数据的时候,需要遍历每一条评论,然后去查找这个评论下的所有回复,之后返回这些数据,这样就会造成获取一片文章的评论需要多次查找数据库,效率就会很低,下一步准备从数据库设计和程序实现两个方面去思考如何优化;其二在于:所有文章的评论都在一张表里面,评论的回复也都在一张表里面,这样就会导致表的条目很多,下一步优化的思路集中于分表操作,具体的实现还在思考中。。。。

         评论功能的设计还有很多需要优化的地方,欢迎对这方面有了解的小伙伴一起交流。

    展开全文
  • 评论系统--开发总结

    千次阅读 热门讨论 2018-04-09 11:05:21
    目前为止,做了两三个项目,有涉及教育的、论坛的、CMS的,每个项目里都有用到评论这个功能,所以我就想把评论这一块,单独拿出来,做成一个组件化的模块。既节约了开发的工作,还能让自己对这个模块的功能有...

    前言

    目前为止,做了两三个项目,有涉及教育的、论坛的、CMS的,每个项目里都有用到评论这个功能,所以我就想把评论这一块,单独拿出来,做成一个组件化的模块。既节约了开发的工作,还能让自己对这个模块的功能有更进一步的理解。
    因为目前我主要是用tp框架在做开发,所以以下相关实例会以tp框架的语法来呈现。但其实核心方法部分我个人是觉得有所不足的,没有把关联模型的功能给利用起来。这块是我下一版更新的时候会实现的部分。
    正文部分,主要会给大家讲讲目前接触到的评论系统的几种模式,分析他们各自的优劣势,并提供一个数据表设计以及数据提取的思路,希望对大家能够有所帮助。如有不当之处,也欢迎大家拍砖指正。

    评论系统

    常见的评论系统主要有三种:楼中楼模式流模式引用模式 (都是我自己起的名字),下面集中介绍这三种的优劣势以及实现方法。

    一、楼中楼模式

    所谓楼中楼模式,就是每条评论占一楼,针对该评论的所有回复都在该楼里展现,比如百度贴吧、简书的评论系统。
    这里写图片描述
    优势:回复评论的内容集中展现,易于了解评论引发的对话。
    劣势:内容过多时需要做分页处理,较为复杂。
    数据表设计:

    • id(自增主键)
    • target_id (评论主题的id,可根据需要修改为article_id、course_id等等)
    • parent_id(主评论id)
    • reply_uid (记录被评论的用户id,回复主评论时可以0)
    • uid(发表评论的用户id)
    • content (评论内容)
    • 其他字段… (时间、状态等)

    后端业务逻辑:

    /**
     * @desc 获取主评论列表
     */
    public function getMainCommentList($page, $limit)
    {
        $count = Db::name('comment')->where('target_id', $target_id)->where('parent_id', 0)->count('id');
        if (!$count) {
            $data = [
                'count' => 0,
                'list' => []
            ];
            return $data;
        }
        $list = Db::name('comment')->where('target_id', $target_id)->where('parent_id', 0);
        if ($page && $limit) {
            $list = $list->page($page,$limit);
        }
        $list = $list->select();
        foreach ($list as $key => $value) {
            $list[$key]['reply'] = $this->getReplyCommentList($value['parent_id'], 1, 5); //设置取5条记录
        }
        $data = [
            'count' => $count,
            'list' => $list
        ];
        return $data;
    }
    
    /**
     * @desc 获取评论的回复内容
     */
    public function getReplyCommentList($parent_id, $page = null, $limit = null)
    {
        //获取回复的总数
        $count = Db::name('comment')->where('parent_id', $parent_id)->count('id');
        $list = Db::name('comment')->alias('a')->where('a.parent_id', $parent_id)
            ->join('user u1', 'a.uid = u1.id')
            ->join('user u2', 'a.reply_uid = u2.id', 'LEFT')
            ->field('a.id, a.parent_id, a.content, a,uid, a.reply_uid,
            u1.username, u2.username as reply_username'); //还有时间等字段
        if ($page && $limit) {
            $list = $list->page($page, $limit);
        }
        $list = $list->select(); //还需按照时间字段排序
    }

    二、流模式

    流模式,顾名思义,展现形式类似于信息流,不管是评论还是回复,每条信息都占一层,比如laravel-china社区的评论系统。
    这里写图片描述
    优势: 逻辑简单,实现较为容易
    劣势: 对话内容不能集中呈现,不便于了解对话内容。
    数据表设计:

    • id(自增主键)
    • target_id (评论主题的id,可根据需要修改为article_id、course_id等等)
    • reply_uid (记录被评论的用户id,回复主评论时可以0)
    • uid(发表评论的用户id)
    • content (评论内容)
    • 其他字段… (时间、状态等)

    后端业务逻辑

    public function getCommentList($target_id, $page, $limit)
    {
        $count = Db::name('comment')->where('target_id',$target_id)->count('id');
        if (!$count) {
            $data = [
                'count' => 0,
                'list' => []
            ];
            return $data;
        }
    
        $list = Db::name('comment')->alias('a')->where('target_id', $target_id)
            ->join('user u1', 'a.uid = u1.id')
            ->join('user u2', 'a.reply_uid = u2.id')
            ->field('a.id, a.uid, a.reply_uid, a.content, u1.username, u2.username as reply_username');
        if ($page && $limit) {
            $list = $list->page($page, $limit);
        }
        $list = $list->select(); //需加上按时间排序
        $data = [
            'count' => $count,
            'list' => $list
        ];
        return $data;
    }

    三、引用模式

    引用模式与流模式相似,只是回复的内容发布时会带上引用的内容。
    这里写图片描述
    优势:可以理解回复针对的是哪条评论,有助于了解对话内容。实现相对容易。
    劣势:与流模式相似,不能完整呈现整个对话内容。
    通过分析优劣势可以发现,引用模式是介于楼中楼以及流模式之间的一个折中方案。
    数据表设计:

    • id(自增主键)
    • target_id (评论主题的id,可根据需要修改为article_id、course_id等等)
    • reply_id(被评论的评论id,主评论为0)
    • uid(发表评论的用户id)
    • content (评论内容)
    • 其他字段… (时间、状态等)

    后端业务逻辑:

    获取评论列表可以通过左连接评论表,获取引用评论的用户信息和评论等内容。再做简单的分页处理就可以了。

    /**
     * @desc 获取评论列表
     */
    public function getCommentList($target_id, $page = null, $limit = null)
    {
        //获取评论条数统计
        $count = Db::name('comment')->where('target_id', $target_id)->count('id');
        if (!$count) {
            $data = [
                'count' => 0,
                'list' => []
            ];
            return $data;
        }
        //分页获取评论列表数据,同时获取引用的评论数据
        $list = Db::name('comment')->alias('a')->where('a.target_id', $target_id)
            ->join('comment b', 'b.parent_id = a.id', 'LEFT')
            ->join('user u1', 'a.uid = u1.id')
            ->join('user u2', 'b.uid = u2.id')
            ->field('a.id, a.target_id, a.content, a.uid, u1.username,
             b.content as quote_content, b.uid as quote_uid, u2.username as quote_username') //还有时间等字段
        if ($page && $limit) {
            $list = $list->page($page,$limit);
        }
        $list = $list->select();
        $data = [
            'count' => $count,
            'list' => $list
        ];
        return $data;
    }

    以上是针对三种评论模式的初步总结,对于样式部分还没有进行整理,等完成博客项目后,会把前端样式的部分也加上。而对于以上的内容,如有不足之处,希望大家提出指导。

    展开全文
  • django开发个人博客系统

    万次阅读 多人点赞 2019-02-18 22:08:37
    项目简介 运行平台:windows Python版本:3.4 Django版本:2.0 数据库工具:sqlite 开发工具:Pycharm+sublime-text ...写在开头:这是我第一次使用Django进行web开发,...虽然本项目名为信息资源型系统,但是其实...

    目录

    前言
    项目预览
    项目版本
    项目构思
    项目实战
         登录子系统
         后台美化
    完整项目获取
    尾言

    前言

        当初是在2018年写下的这篇文章,那时的django更新到了版本2.0,使用人数还是比较少的,网上的教程大多也很少。而现在随着python web框架的流行,越来越多人开始接触到了django这门技术。如今,django已经更新到了版本3.0,添加了支持异步等重要特性,但是这些特性和本篇文章基本无关。写下这篇文章的初衷是为了让刚接触django框架的童鞋可以入门上手一个项目,了解如何快速搭建一个项目,毕竟python web的优势便是快速易上手嘛【最近接触了springboot后的感触】。如今再次更新这篇博文(2020-2月),希望能够给予大家入门一定的帮助。
        
        
    p.s:其实建立一个web项目需要处理的事情比较杂,我就按照我的建立习惯给大家写下这篇教程。
    另外,本项目是我在重新写时完整重新搭建,所以一定可以跑通,我会写的比较仔细一点,如果你能耐心看完,必定有所收获。
    【-------------------------原创不易,请勿侵权------------------------------------------------------------------】

    项目预览

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
        
        

    项目版本

    运行平台:windows
    Python版本:3.7
    Django版本:3.0
    数据库工具:sqlite
    开发工具:Pycharm+vscode
    依赖:pillow,django-simpleui,django_summernote
        
        

    项目构思

        个人博客系统属于一个非常小型的项目,不会存在高并发的情况,同时注册用户主要也就是为了评论博客内容,其实用户账号安全性也可以完全不用考虑。项目采取前后端分离的形式进行开发,前后端信息交互多数采取ajax形式(按理说动态更新页面比较友好交互,但是为了让大家感受一下这两种方式,在登录这一块采取静态跳转)。剩下的部分一次性在这里写下来大家也不一定能看的很明白,在建立项目的过程中再给大家介绍。
        
        

    项目实战

    请先下载静态文件 下载连接:https://pan.baidu.com/s/1Er2S63MThOfzhlbuUkTEkw 之后替换相应的文件

    我们首先给我们的项目起个名字:Ericam
        
    (1)利用命令行创建项目。
        

    django-admin startproject Ericam
    

        
    (2)创建APP
        
    解释一下:项目中会存在登录子系统,博文管理子系统等,这些子系统每个都可以作为一个app,如此分离方便日后开发维护。但是作为一个入门项目,便不如此麻烦了。我们在整个项目只建立一个app。
    由于我们准备搭建的是一个博客系统,所以就给这个APP起名为:blog
        
    在命令行下继续输入

    python manage.py startapp blog
    

        
    此时文件目录结构:
    在这里插入图片描述
        
    介绍一下各个文件的用处
    在这里插入图片描述
        
    删除test.py,新建一个urls.py文件
    在这里插入图片描述
    为什么需要两个urls.py文件呢?方便分层管理,类似于一级目录,二级目录。
        
        
    (3)注册app并配置静态文件目录
    在这里插入图片描述
        
    在settings.py文件里添加如下内容
        

    # 配置静态文件目录
    STATICFILES_DIRS = [
            os.path.join(BASE_DIR, 'static'),
        ]
    

        
    【静态文件:css,js和图片文件等,我们在这里配置了文件目录路径】
    此时运行项目,用浏览器访问 http://127.0.0.1:8000/
    在这里插入图片描述
    出现一个小火箭代表我们的项目搭建成功了。
        
        
    (4)
    新建文件夹,如下所示(建议直接将static文件夹复制过来,本博客不会讲解css以及js):
    在这里插入图片描述
    (所有html文件存放于templates文件夹下)
    新建index_unlog.html文件【作为首页,未登录时显示的页面】
    我们先简单测试一下,给大家展示一下django如何通过view.py视图层显示html页面。
    在index_unlog.html里:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>首页</title>
    </head>
    <body>
        个人博客系统测试
    </body>
    </html>
    

    在views.py文件里:

    def index_unlog(request):
        return render(request,'index_unlog.html')
    

    最后我们添加一下路由地址,在与settings.py同级目录的urls.py:

    urlpatterns = [
        path('admin/', admin.site.urls),
        path('blog/',include('blog.urls')),
        path('',views.index_unlog,name='index_unlog')
    ]
    

    在新建的urls.py文件【以后我加个标号2代表该文件】里添加如下内容:

    app_name = 'blog'
    urlpatterns = [
    ]
    

    ps:在pycharm里按alt+enter可以添加未引入的类包。
    此时刷新项目,用浏览器访问 http://127.0.0.1:8000/

    在这里插入图片描述

    搞懂了每个文件的大致作用,我们便可以开始正式开发博客系统啦。
    我们按照模块化进行开发。
        
        
        

    登录子系统开发

    (1)首页(未登录)-编写index_unlog.html
        

    {% load static %}
    <html lang="zh">
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta name="author" content="Ericam_">
    
        <!-- CSS -->
    	<title>Ericam_blog</title>
    	<link rel="shortcut icon" href="{% static 'images/gt_favicon.png' %}">
    	<link rel="stylesheet" media="screen" href="http://fonts.googleapis.com/css?family=Open+Sans:300,400,700">
    	<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
    	<link rel="stylesheet" href="{% static 'css/font-awesome.min.css' %}">
    	<!-- Custom styles for our template -->
    	<link rel="stylesheet" href="{% static 'css/bootstrap-theme.css'%}"  >
    	<link rel="stylesheet" href="{% static 'css/log.css'%}">
    	<link rel="stylesheet" href="{% static 'css/blog.css'%}">
    	</head>
    
    
    <body class="back">
      <!--导航栏-->
    	<div class="navbar navbar-inverse navbar-fixed-top headroom" >
    		<div class="container">
    			<div class="navbar-header">
    				<!-- Button for smallest screens -->
    				<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"><span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button>
    				<a class="navbar-brand"><img src="{%static 'css/images/lo.png'%}" alt="Progressus HTML5 template"></a>
    			</div>
    			<div class="nav navbar-nav navbar-right">
    								<!--在这里填写登录提交  1-->
    			</div>
    		</div>
    	</div>
    
    	  <center>
        <div class="container" style="padding-top:300px;min-height:800px">
          <div class="row">,.
            <p class="lead"><font color="white"">个人博客系统,尽情的享用吧(〃'▽'〃)</font></p>
            <p class="tagline"><font color="white">如果您有优秀的建议,欢迎投递哦</font></p>
    							<!--在这里填写登录提交  2-->
          </div>
        </div>
    	</center>
    
    
       <footer id="footer" class="top-space">
    		<div class="footer2">
    			<div class="container">
    				<p class="text-center">Copyright &copy; 2020, Ericam_blog</p>
    			</div>
    		</div>
      </footer>
    </body>
    </html>
    

    第一句话{%load static%}代表引入静态文件(css,js等)
    img,css,js等文件的引用与下述语句类似:

     <link rel="stylesheet" href="{%static 'css/log.css' %}">
    

    此时打开浏览器查看效果:
    在这里插入图片描述
        
        
    (2)登录页-login.html
        

    {%load static%}
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>登录</title>
        <link rel="shortcut icon" href="{% static 'images/gt_favicon.png' %}">
        <link rel="stylesheet" href="{%static 'css/log.css' %}">
        <link rel="stylesheet" href="{%static 'css/semantic.css' %}">
        <link rel="stylesheet" href="{% static 'css/font-awesome.min.css' %}">
    </head>
    <body class="login">
        <div class="ui center aligned grid" style="margin-top: 200px">
            <div class="ui six wide column">
                <h1 class="ui teal header">Ericam blog-登录</h1>
                <div class="ui segment">
                    <div class="ui content">
        <form class="ui large form" method="post" action="{%url 'login'%}">
          <div class="ui stacked segment">
            <div class="field">
              <div class="ui left icon input">
                <input type="text" name="username" placeholder="请输入用户名">
              </div>
            </div>
            <div class="field">
              <div class="ui left icon input">
                <input type="password" name="password" placeholder="请输入密码">
              </div>
            </div>
            {{ error }}<br>
            <a class="pull-right field" >忘记密码</a>
            <button class="ui fluid large teal button" type="submit">登陆</button>
          </div>
    
          <div class="ui error message"></div>
        </form>
    
        <div class="ui message">
          New to us? <a>注册</a>
        </div>
                    </div>
                </div>
            </div>
        </div>
    </body>
    </html>
    

        
    添加路由信息:
        

    urlpatterns = [
        path('admin/', admin.site.urls),
        path('blog/',include('blog.urls')),
        path('',views.index_unlog,name='index_unlog'),
        path('login',views.login,name='login')
    ]
    

        
    添加视图层views.py内容:
        

    def login(request):
        return render(request,'login.html')
    

        
    此时预览:
        
    在这里插入图片描述
        
    在index_unlog.html里添加内容:

    	<!--在这里填写登录提交  1-->
    <a class="btn" href="{% url 'login' %}">登录 / 注册</a></li>
    
        <!--在这里填写登录提交  2-->
    <p><a class="btn btn-action btn-lg" role="button" href="{% url 'login' %}">START NOW</a></p>
    

        
    为了实现登录功能,我们首先需要构造一个用户表
        
    打开models.py文件

    from django.db import models
    from django.contrib import  admin
    from django.urls import reverse
    from django.utils.timezone import now
    
    # Create your models here.
    
    class User(models.Model):
        username = models.CharField(max_length = 50)
        password = models.CharField(max_length = 200)
        nickname = models.CharField(max_length = 50,default='匿名')
        email = models.EmailField()
        created_time = models.CharField(max_length=50,default=now)
        comment_num = models.PositiveIntegerField(verbose_name='评论数', default=0)
        avatar = models.ImageField(upload_to = 'media', default="media/default.png")
    
        def __str__(self):
            return self.username
    
        def comment(self):
            self.comment_num += 1
            self.save(update_fields=['comment_num'])
    
        def comment_del(self):
            self.comment_num -= 1
            self.save(update_fields=['comment_num'])
    
    class UserAdmin(admin.ModelAdmin):
        list_display = ('username','email')
    #修饰器
    

    然后打开命令行

    python manage.py makemigrations
    python manage.py migrate
    

    这便生成了sqlite数据库文件
    在这里插入图片描述
    通过sqliteStudio打开浏览:
    在这里插入图片描述
        
    在views.py文件里编写登录逻辑

    def login(request):
        if request.method == 'POST':
            user_name = request.POST.get('username','')
            pass_word = request.POST.get('password','')
            user = User.objects.filter(username=user_name)  #查看数据库里是否有该用户名
            if user:#如果存在
                user = User.objects.get(username = user_name)#读取该用户信息
                if pass_word==user.password:#检查密码是否匹配
                    request.session['IS_LOGIN'] = True
                    request.session['nickname'] = user.nickname
                    request.session['username'] = user_name
                    return render(request,'index.html',{'user':user})
                else:
                    return render(request,'login.html',{'error': '密码错误!'})
            else:
                return render(request, 'login.html', {'error': '用户名不存在!'})
        else:
            return render(request,'login.html')
    

    因为我们需要记录cookies,所以我们打开settings.py文件,注释该语句
    在这里插入图片描述
    此时登录功能已经实现了。登录成功我们希望页面进行跳转,所以我们需要新建一个index.html

    {% load static %}
    <html lang="zh">
      <head>
        <meta charset="utf-8">
        <title>首页-Ericamblog</title>
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta name="author" content="Ericam_">
    
        <!-- CSS -->
    	<link rel="shortcut icon" href="{% static 'images/gt_favicon.png' %}">
    	<link rel="stylesheet" media="screen" href="http://fonts.googleapis.com/css?family=Open+Sans:300,400,700">
    	<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
    	<link rel="stylesheet" href="{% static 'css/font-awesome.min.css' %}">
    	<!-- Custom styles for our template -->
    	<link rel="stylesheet" href="{% static 'css/bootstrap-theme.css'%}" media="screen" >
    	<link rel="stylesheet" href="{% static 'css/blog.css' %}">
    	<link rel="stylesheet" href="{% static 'css/log.css' %}">
    </head>
    
    <body class="back">
      <script src = "E:/bootstrap/bootstrap-3.3.7-dist/bootstrap-3.3.7-dist/js/jquery.min.js"></script>
      <!--导航栏-->
    	<div class="navbar navbar-inverse navbar-fixed-top headroom" >
    		<div class="container">
    			<div class="container-fluid">
    			  <div class="navbar-header">
    				<!-- Button for smallest screens -->
    				  <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"><span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button>
    				  <a class="navbar-brand"><img src="{%static 'css/images/lo.png'%}" alt="Progressus HTML5 template"></a>
    			  </div>
    
            <ul class="nav navbar-nav navbar-right">
                <li><a><font size="4" color="white">{{user.nickname}}</font></a></li>
                <li><a href="{%url 'index_unlog'%}"><i class="fa fa-sighout"></i><font size="4">注销</font></a></li>
            </ul>
        </div>
    	</div>
    </div>
    
    	  <center>
        <div class="container" style="padding-top:300px;min-height:800px">
          <div class="row">,.
            <p class="lead"><font color="white"">Easy-Download,这里有好多好多资源喔,尽情的享用吧(〃'▽'〃)</font></p>
            <p class="tagline"><font color="white">如果您有优秀的资源,欢迎投递哦</font></p>
            <p><a class="btn btn-action btn-lg" role="button" href="#">START NOW</a></p>
          </div>
        </div>
    	</center>
    
       <footer id="footer" class="top-space">
    		<div class="footer2">
    			<div class="container">
    				<p class="text-center">Copyright &copy; 2020, Ericamblog</p>
    			</div>
    		</div>
      </footer>
    </body>
    </html>
    

    views.py

    def logsuccess(request):
        return render(request,'index.html')
    

    添加路由信息

    urlpatterns = [
        path('admin/', admin.site.urls),
        path('blog/',include('blog.urls')),
        path('',views.index_unlog,name='index_unlog'),
        path('login',views.login,name='login'),
        path('/log',views.logsuccess,name='login-success')
    ]
    

    手动在数据库中添加一个用户信息
    在这里插入图片描述
    我们进行预览
    在这里插入图片描述
        
        
    完成了登录验证功能后,我们就需要添加注册功能,因为刚才用户的信息是我们手动在数据库内添加的,正常情况下应该是前端页面将内容发送给后端,后端经过处理存储在数据库内。
        
        
    注册模块
        
        
    (1)views.py

    def register(request):
        if request.method =='POST':
            user_name = request.POST.get('username','')
            pass_word_1 = request.POST.get('password_1','')
            pass_word_2 = request.POST.get('password_2','')
            nick_name = request.POST.get('nickname','')
            email = request.POST.get('email','')
            avatar = request.FILES.get('avatar')
            if User.objects.filter(username = user_name):
                return render(request,'register.html',{'error':'用户已存在'})
                #将表单写入数据库
            if(pass_word_1 != pass_word_2):
                return render(request, 'register.html', {'error': '两次密码请输入一致'})
            user = User()
            if avatar:
                user.avatar = 'media/' + user_name + '.png'
                img = Image.open(avatar)
                size = img.size
                print(size)
                # 因为是要圆形,所以需要正方形的图片
                r2 = min(size[0], size[1])
                if size[0] != size[1]:
                    img = img.resize((r2, r2), Image.ANTIALIAS)
                # 最后生成圆的半径
                r3 = int(r2/2)
                img_circle = Image.new('RGBA', (r3 * 2, r3 * 2), (255, 255, 255, 0))
                pima = img.load()  # 像素的访问对象
                pimb = img_circle.load()
                r = float(r2 / 2)  # 圆心横坐标
                for i in range(r2):
                    for j in range(r2):
                        lx = abs(i - r)  # 到圆心距离的横坐标
                        ly = abs(j - r)  # 到圆心距离的纵坐标
                        l = (pow(lx, 2) + pow(ly, 2)) ** 0.5  # 三角函数 半径
    
                        if l < r3:
                            pimb[i - (r - r3), j - (r - r3)] = pima[i, j]
                img_circle.save('blog/static/media/'+user_name+'.png')
            user.username = user_name
            user.password = pass_word_1
            user.email = email
            user.nickname = nick_name
            user.save()
                #返回注册成功页面
            return render(request,'index_unlog.html')
        else:
            return render(request,'register.html')
    

        
        
    代码含义很好理解,就是将前端提交的信息以user对象存储到数据库中,中间一部分代码是将用户提交的头像切割成圆形(无需理解)
        
        
    (2)添加路由信息

    urlpatterns = [
        path('admin/', admin.site.urls),
        path('blog/',include('blog.urls')),
        path('',views.index_unlog,name='index_unlog'),
        path('login',views.login,name='login'),
        path('log',views.logsuccess,name='login-success'),
        path('register',views.register,name='register')
    ]
    

    (3)添加register.html

    {%load static%}
    <!DOCTYPE html>
    <html lang="zh-hans">
    <head>
        <meta charset="UTF-8">
        <title>注册</title>
        <link rel="shortcut icon" href="{% static 'images/gt_favicon.png' %}">
        <link rel="stylesheet" href="{%static 'css/log.css' %}">
        <link rel="stylesheet" href="{%static 'css/semantic.css' %}">
    </head>
    <body class="register">
        <div class="ui center aligned grid" style="margin-top: 200px">
            <div class="ui six wide column">
                <h1 class="ui teal header"><font color="black">EricamBlog-用户注册</font></h1>
                <div class="ui segment">
                    <div class="ui content">
                        <form class="ui form" method="post" action="{%url 'register'%}"  enctype="multipart/form-data">
                            <div class="field">
                                <input type="text" name="username" placeholder="请输入用户名"><br>
                            </div>
                            <div class="field">
                                <input type="password" name="password_1" placeholder="请输入密码"><br>
                            </div>
                            <div class="field">
                                <input type="password" name="password_2" placeholder="请确认密码"><br>
                            </div>
                            <div class="field">
                                <input type="text" name="nickname" placeholder="请输入昵称"><br>
                            </div>
                            <div class="field">
                                <input type="text" name="email" placeholder="请输入邮箱"><br>
                            </div>
                            <div>头像<input type="file" name="avatar"></div>
                            {{ error }}<br>
                            <button class="ui fluid large teal button" type="submit">注册</button>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </body>
    </html>
    

        
        
    现在注册模块已经完成了,但是刚才我们在编写登录页面时没有添加对于注册页面的超链接跳转,现在需要进行添加。
    在login.html里修改如下内容:
    在这里插入图片描述
    此时注册功能已经完成,大家可以自行测试。
        
        
    接下来我们再来添加忘记密码模块。
    正常情况下,忘记密码时应该发送邮件给邮箱,邮箱确认后再填写新密码。这里为了简易操作,便忽略。
    (1)添加views.py内容

    def forget_password(request):
        if request.method == 'POST':
            user_name = request.POST.get('username','')
            email = request.POST.get('email','')
            user = User.objects.filter(username = user_name)
            if user:
                user = User.objects.get(username = user_name)
                if(user.email == email):
                    request.session['user_name'] = user_name
                    return render(request,'reset.html')
                else:
                    return render(request,'forget.html',{'error':'您的用户名和邮箱不匹配!'})
            else:
                return render(request,'forget.html',{'error':'请输入正确的用户名'})
        else:
            return  render(request,'forget.html')
    
    def reset(request):
        if request.method == 'POST':
            pass_word1 = request.POST.get('password1','')
            pass_word2 = request.POST.get('password2','')
            user_name = request.session['user_name']
            user = User.objects.get(username = user_name)
            if pass_word1 == pass_word2:
                user.password = pass_word1
                user.save()
                return render(request,'login.html')
            else:
                return render(request,'reset.html', {'error': '两次密码输入不一致!'})
        else:
            return render(request,'reset.html')
    

    (2)添加forget.html和reset.html
    forget.html

    {%load static%}
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>忘记密码</title>
        <link rel="stylesheet" href="{%static 'css/log.css' %}">
        <link rel="stylesheet" href="{%static 'css/semantic.css' %}">
    </head>
    <body class="forget">
        <div class="ui center aligned grid" style="margin-top: 200px">
            <div class="ui six wide column">
                <h1 class="ui teal header">Ericam blog-忘记密码</h1>
                <div class="ui segment">
                    <div class="ui content">
                        <form class="ui form" method="post" action="{%url 'forget'%}">
                            <div class="field">
                                <input type="text" name="username" placeholder="请输入用户名"><br>
                            </div>
                            <div class="field">
                                <input type="text" name="email" placeholder="请输入邮箱"><br>
                            </div>
                            {{ error }}<br>
                            <button class="ui fluid large teal button" type="submit">下一步</button>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </body>
    </html>
    

        
        
    reset.html

    {%load static%}
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>重置密码</title>
        <link rel="shortcut icon" href="{% static 'images/gt_favicon.png' %}">
        <link rel="stylesheet" href="{%static 'css/semantic.css' %}">
        <link rel="stylesheet" href="{%static 'css/log.css' %}">
    </head>
    <body class="reset">
        <div class="ui center aligned grid" style="margin-top: 200px">
            <div class="ui six wide column">
                <h1 class="ui teal header">Ericam blog-重置密码</h1>
                <div class="ui segment">
                    <div class="ui content">
                        <form class="ui form" method="post" action="{%url 'reset'%}">
                            <div class="field">
                                <input type="password" name="password1" placeholder="请输入新密码"><br>
                            </div>
                            <div class="field">
                                <input type="password" name="password2" placeholder="请确认新密码"><br>
                            </div>
                            {{ error }}<br>
                            <button class="ui fluid large teal button" type="submit">确认修改</button>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </body>
    </html>
    

        
        
    (3)添加路由

    urlpatterns = [
        path('admin/', admin.site.urls),
        path('blog/',include('blog.urls')),
        path('',views.index_unlog,name='index_unlog'),
        path('login',views.login,name='login'),
        path('log',views.logsuccess,name='login-success'),
        path('register',views.register,name='register'),
        path('forget',views.forget_password,name='forget'),
        path('reset',views.reset,name='reset')
    ]
    

        
        
    到了这里忘记密码功能已经完成,最后我们还需要添加一下超链接跳转
    打开login.html文件,修改:
    在这里插入图片描述
        
        
    【至此,登录子系统已经全部完成】

    后台美化

    django默认自带后台管理系统
    创建一个超级管理员账户:

    python manage.py createsuperuser
    

    访问:http://127.0.0.1:8000/admin/
    在这里插入图片描述
    接下来我们对后台进行美化

    pip install django-simpleui
    pip install django_summernote
    

    然后在settings.py添加:

    INSTALLED_APPS = [
        "simpleui",   #添加内容,一定要加在admin前
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'blog',
        'django_summernote'#后台富文本
    ]
    
    SUMMERNOTE_CONFIG = {
        # Using SummernoteWidget - iframe mode
        'iframe': True,  # or set False to use SummernoteInplaceWidget - no iframe mode
    
        # Using Summernote Air-mode
        'airMode': False,
    
        # Use native HTML tags (`<b>`, `<i>`, ...) instead of style attributes
        'styleWithSpan': False,
    
        # Change editor size
        'width': '80%',
        'height': '480',
    
        # Use proper language setting automatically (default)
        'lang': 'zh-CN',
    }
    

    刷新,重新进入admin页面:
    在这里插入图片描述
    给后台添加注册,方便管理数据内容:
    修改admin.py文件

    from django.contrib import admin
    from blog.models import Article,User,Category,Tag,ArticleComment,Message
    from django_summernote.admin import SummernoteModelAdmin
    
    # Register your models here.
    class PostAdmin(SummernoteModelAdmin):
        summernote_fields = ('content')  # 给content字段添加富文本
        list_display = ['article_id', 'title', 'created_time']
        search_fields = ['title']  # 搜索框
        list_filter = ['created_time']  # 过滤器
    
    #ass ArticleAdmin(admin.ModelAdmin):
    class CommentAdmin(admin.ModelAdmin):
        list_display = ['username', 'body', 'title']
        search_fields = ['title']  # 搜索框
    
    
    admin.site.register(Article, PostAdmin)
    admin.site.register(Category)
    admin.site.register(Tag)
    admin.site.register(User)
    admin.site.register(ArticleComment,CommentAdmin)
    

    修改models.py文件(完整版):

    from django.db import models
    from django.contrib import  admin
    from django.urls import reverse
    from django.utils.timezone import now
    
    
    #---------------------------------用户---------------------------------------
    class User(models.Model):
        username = models.CharField(max_length = 50)
        password = models.CharField(max_length = 200)
        nickname = models.CharField(max_length = 50,default='匿名')
        email = models.EmailField()
        created_time = models.CharField(max_length=50,default=now)
        comment_num = models.PositiveIntegerField(verbose_name='评论数', default=0)   #评论数
        avatar = models.ImageField(upload_to = 'media', default="media/default.png")  #用户头像
    
        def __str__(self):
            return self.username
    
        def comment(self):
            self.comment_num += 1
            self.save(update_fields=['comment_num'])
    
        def comment_del(self):
            self.comment_num -= 1
            self.save(update_fields=['comment_num'])
    
    #---------------------------------文章评论---------------------------------------
    class ArticleComment(models.Model):
        body = models.TextField()
        username = models.CharField(max_length=50)
        userimg = models.CharField(max_length=70)
        nickname = models.CharField(max_length=50,default="匿名")
        createtime = models.DateTimeField(verbose_name='创建时间', default=now)
        article = models.CharField(max_length=50)
        title = models.CharField(max_length=50)
        # 使对象在后台显示更友好
        def __str__(self):
            return self.article
    
        class Meta:
            ordering = ['-createtime']
            verbose_name = '评论'  # 指定后台显示模型名称
            verbose_name_plural = '评论列表'  # 指定后台显示模型复数名称
            db_table = "comment"  # 数据库表名
    
        list_display = ('article', 'body')
    
    #---------------------------------博客文章标签---------------------------------------
    class Tag(models.Model):
        name = models.CharField(verbose_name='标签名', max_length=64)
    
        # 使对象在后台显示更友好
        def __str__(self):
            return self.name
    
        class Meta:
            ordering = ['name']
            verbose_name = '标签名称'  # 指定后台显示模型名称
            verbose_name_plural = '标签列表'  # 指定后台显示模型复数名称
            db_table = "tag"  # 数据库表名
    
    #---------------------------------博客文章分类---------------------------------------
    class Category(models.Model):
        name = models.CharField(verbose_name='类别名称', max_length=64)
    
        class Meta:
            ordering = ['name']
            verbose_name = "类别名称"
            verbose_name_plural = '分类列表'
            db_table = "category"  # 数据库表名
    
        # 使对象在后台显示更友好
        def __str__(self):
            return self.name
    
    #---------------------------------博客文章---------------------------------------
    class Article(models.Model):
        STATUS_CHOICES = (
            ('d', '草稿'),
            ('p', '发表'),
        )
        article_id = models.CharField(verbose_name='标号', max_length=100)
        title = models.CharField(verbose_name='标题', max_length=100)
        content = models.TextField(verbose_name='正文', blank=True, null=True)
        status = models.CharField(verbose_name='状态', max_length=1, choices=STATUS_CHOICES, default='p')
        views = models.PositiveIntegerField(verbose_name='浏览量', default=0)
        created_time = models.DateTimeField(verbose_name='创建时间', default=now)
        category = models.ForeignKey(Category, verbose_name='分类', on_delete=models.CASCADE, blank=False, null=False)
        tags = models.ManyToManyField(Tag, verbose_name='标签集合', blank=True)
    
        # 使对象在后台显示更友好
        def __str__(self):
            return self.title
    
        # 更新浏览量
        def viewed(self):
            self.views += 1
            self.save(update_fields=['views'])
    
        # 下一篇
        def next_article(self):  # id比当前id大,状态为已发布,发布时间不为空
            return Article.objects.filter(id__gt=self.id, status='p', pub_time__isnull=False).first()
    
        # 前一篇
        def prev_article(self):  # id比当前id小,状态为已发布,发布时间不为空
            return Article.objects.filter(id__lt=self.id, status='p', pub_time__isnull=False).first()
    
        class Meta:
            ordering = ['-created_time']  # 按文章创建日期降序
            verbose_name = '文章'  # 指定后台显示模型名称
            verbose_name_plural = '文章列表'  # 指定后台显示模型复数名称
            db_table = 'article'  # 数据库表名
            get_latest_by = 'created_time'
    
    

    记得使用python manage.py migrate进行生成数据库文件。
    此时访问后台:
    在这里插入图片描述
    写文章时富文本工具也加载了出来:
    在这里插入图片描述

    完整项目获取

    重构了代码,同时更新了博客内容,关键难点已经写下来了。
    如果有问题欢迎在评论区提问。
    如果想要获取完整项目,请扫码赞助该项目。
    获取方式:扫码赞助9.9,留言邮箱地址。
    在这里插入图片描述

    尾言

    其他子模块和该模块大同小异,暂时就不写了。
    其中评论提交和删除采取的是ajax交互形式。
    如果大家看了觉得有帮助请点赞,为了大家重新写了这篇文章,同时重构了代码,确保一定能跑通。

     

    展开全文
  • 第三方评论系统 - 学习/实践

    千次阅读 2019-12-27 15:30:29
    使用第三方评论系统完成博客评论功能, 简单便捷. 2.学习/操作 1.介绍 国内的第三方评论系统基本上都歇菜了,我们可以使用墙外的 Disqus 实现博客评论。 Disqus被墙, 你懂得 //如何解决TBD ...
  • STM32嵌入式系统开发实战指南 FreeRTOS与LwIP联合移植 高清电子书,非光盘 需要光盘内容评论留下邮箱
  • STM32嵌入式系统开发实战指南 FreeRTOS与LwIP联合移植 高清电子书,没错,是电子书,不是光盘 绝对不骗人 光盘可以搜索到 如有需要评论留言可发
  • AGVs调度管理系统开发技术框架简介

    千次阅读 2020-04-06 18:42:45
    AGVs管理系统开发技术专题前言关于博主系统框架总览引言一、AGV接口组件二、AGV/AGV模拟器三、交通管理者组件四、运输组织者组件五、信号处理者组件未完待续解释与声明 前言 由于近期受疫情影响,工作之中少了很多...
  • 微信小程序利用云开发实现评论功能 如果喜欢可以给我一个关注。 一.微信小程序,评论功能的实现。 首先我们先布局,一个文章或者是商品,底下是评论, <!-- 商品详情 --> <view> <view class="store...
  • 随着中国各领域信息化建设进程的加快,信息化系统开发、在线协同、新老系统升级迭代、数据迁移等一定会成为企业不得不面临的核心问题。然而,企业信息系统建设是一项系统工程,它要求业务人员必须和开发人员密切合作...
  • python项目之博客系统开发

    千人学习 2017-03-06 10:04:08
    系统由于主站、个人博客、后台管理三部分组成,其中包含Web开发中的知识,如:多级评论、文章点赞、主题定制、iframe伪Ajax、CSRF、防止XSS攻击等,功能齐全并提供基础示例。
  • (01)开发环境准备

    千次阅读 2022-02-06 10:52:46
    环境准备开发环境操作系统开发工具硬件模拟结束 开发环境 工欲善其事必先利其器,开发的第一步当然是准备开发环境 操作系统 为方便开发,建议使用Linux桌面系统,原因有两个: Linux有很多现成的开发工具,安装也...
  • 前言在这一篇博文中,咱们介绍了如何快速的搭建个人的博客网站,但是这个博客网站是基于Github Pages的纯静态网站,自身是不带任何的可交互的元素的,自然也就没有评论系统。但是,对于一个好的博客网站,如果没有...
  • 教学妹开发springboot+vue的博客论坛系统,so esay

    千次阅读 多人点赞 2022-04-21 16:02:27
    快速学习开发,干净又卫生
  • 微信预约小程序怎么制作(在线预约小程序系统开发功能) 一般开发制作微信预约小程序系统的方式有三种。 1,是购买成品的预约小程序系统,功能固定,只需要替换里面内容信息。 2,联系专业的微信小程序开发公司...
  • 让我开发一个基于springboot的活动管理系统! 他非常的着急,事情比较突然。 好吧,我去买了咖啡,熬了两个通宵给赶制出来了! 后来小伙伴用完系统后,他说可以开源给大家一起学习! 果然人人为我,我为人人! ...
  • 首先个人文笔有限,并不是专业写文章的人,同时知识面也比较局限,以下只是个人对这个问题,在日常闲余时间去对这个问题进行的一些探索总结,如...如何开发一个全新的操作系统呢?这个是很大的问题,很多人在很多时候...
  • 欢迎添加微信互相交流学习哦! ... 毕业设计(论文) 题 目 基于PHP的个人博客系统的设计与开发 ...博客作为一种新的生活方式...因此开发一款功能强大,人性化的个人博客系统,必定会有很大的发展。 本网站采用了PHP+My..
  • 您所在位置:网站首页 > 海量文档 > 计算机 > PythonPython程序设计考试系统开发与应用.pdf4页本文档一共被下载:次,您可全文免费在线阅读后下载本文档。 下载提示1.本站不保证该用户上传的文档...
  • 本人目前大四在读,本科阶段最后一门课程要求开发一个可以实际应用的软件,我和队友一致表示想开发一个个人博客系统,实际上在大一学习了web 前后端之后,我一直酝酿着想开发一个博客系统,用于写自己的博客用,但是...
  • 银河麒麟操作系统开发 对于许多人来说,开始软件开发似乎太困难且繁琐的任务。 实际上,您只需要一台计算机并且对软件开发非常感兴趣即可上手。 在这个故事中,我将介绍软件开发的所有基本知识,并介绍一些您以前...
  • 电商系统开发面试

    千次阅读 多人点赞 2018-04-15 14:57:12
    1.描述一下你的项目网上商城是一个综合性的B2B2C平台,类似京东商城。...系统有两个管理后台:商家管理后台和运营商管理后台。 商家申请入驻后,即可获得商家管理后台的使用权限,在商家管理后台...
  • 基于微信小程序的校园论坛系统开发过程

    千次阅读 多人点赞 2021-01-18 20:47:37
    基于微信小程序的校园论坛系统开发过程 微信小程序介绍 首先,我说明下为什么会选择开发微信小程序,而不是去选择开发APP或者一个web网站的论坛系统,原因很简单–没人用。我开发好几个系统发现班级同学不经常用,这...
  • 智能推荐系统开发中的十大要素

    千次阅读 2018-10-25 09:29:26
    对广 大软件开发工程师们来说,能够投身于推荐系统的研发,是一件既有趣又充满挑战的工作。想要成功的开发一套效果良好的推荐系统,有一系列值得重视的关键点, 文本对此进行了总结,具体列举如下。 1 充分运用显式\...
  • Hexo博客集成码云评论系统

    万次阅读 2019-07-25 10:39:00
    giteement系统是基于gitment的源码开发和扩展的 ➡️ https://gitee.com/zhousiwei/giteementgiteement还在继续维护优化中…欢迎小伙伴们加入一起维护 目前实现以下功能: 基于码云的issues来进行评论的,所以需要...
  • 鸿蒙系统是基于linux开发的吗

    千次阅读 2021-06-13 08:58:57
    鸿蒙系统不是基于linux开发的,而是基于微内核开发的。鸿蒙系统是一款基于微内核面向全场景的分布式操作系统;而Linux是一个单内核结构,同时又吸收了微内核的优点,避免了微内核设计上的缺陷,让一切都运行在内核态...
  • 软件开发常见的软件系统总结

    千次阅读 2018-04-26 00:06:14
    工作到现在开发过很多项目,但感觉一直稀里糊涂的,并没有意识到它们之间的关联,或许很多项目之间觉得很想象,但然后就没有然后了。直到,有一天在升级公司的crm,照...1、cms内容管理系统cms是content management...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 205,225
精华内容 82,090
关键字:

评论系统开发