使用Vue+Django+Ant Design做一个留言评论模块 1.总览
留言的展示参考网络上参见的格式,如掘金社区:
一共分为两层,子孙留言都在第二层中
最终效果如下:
接下是数据库的表结构,如下所示:
有一张user表和留言表,关系为一对多,留言表有父留言字段的id,和自身有一个一对多的关系,建表语句如下:
CREATE TABLE `message` ( `id` int NOT NULL AUTO_INCREMENT, `date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `content` text NOT NULL, `parent_msg_id` int DEFAULT NULL, `user_id` int NOT NULL, PRIMARY KEY (`id`), KEY `user_id` (`user_id`), KEY `message_ibfk_1` (`parent_msg_id`), CONSTRAINT `message_ibfk_1` FOREIGN KEY (`parent_msg_id`) REFERENCES `message` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `message_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8 CREATE TABLE `user` ( `id` int NOT NULL AUTO_INCREMENT, `username` varchar(255) NOT NULL, `password` varchar(255) NOT NULL, `identity` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `username` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 2.后台接口 2.1获取留言接口在Django的views.py中定义两个接口,一个负责提供留言内容,一个负责插入留言,如下:
# 获取留言信息 @require_http_methods(['GET']) def findAllMsg(request): response = {} try: sql = ''' SELECT msg1.*, user.username, msg2.username AS parent_msg_username FROM message msg1 LEFT JOIN (SELECT m.id, user.username FROM message m LEFT JOIN USER ON m.user_id = user.id )AS msg2 ON msg1.parent_msg_id = msg2.id LEFT JOIN USER ON msg1.user_id = user.id ORDER BY msg1.date DESC; ''' with connection.cursor() as cursor: cursor.execute(sql) response['messages'] = sortMsg(cursor) response['status_code'] = 200 except Exception as e: response['status_code'] = 500 response['error'] = e return JsonResponse(response)先来看看这个sql能查出些什么东西:
上面接口中的sorMsg()函数用于整理留言信息,使子留言和父留言能对应起来,算法实现如下:
# 整理留言信息返回格式 def sortMsg(cursor): list = [] allMsg = dictfetchall(cursor) for i in range(len(allMsg)): tmpParent = allMsg[i] tmpChild = [] # 如果没有属于根评论,则搜索该评论下的所有子评论 if tmpParent.get('parent_msg_id') == None: tmpChild = bfs(tmpParent, allMsg) # 如果是子评论则跳过,子评论最终会出现在根评论的子节点中 else: continue tmpParent['children'] = tmpChild # 格式化时间 tmpParent['date'] = datetime.datetime.strftime(tmpParent['date'], '%Y-%m-%d %H:%M:%S') list.append(tmpParent) return list # 搜索一条留言的所有子留言,广度优先 import queue def bfs(parent, allMsg): childrenList = [] q = queue.Queue() q.put(parent) while(not q.empty()): tmpChild = q.get() for i in range(len(allMsg)): if allMsg[i]['parent_msg_id'] is not None and allMsg[i]['parent_msg_id'] == tmpChild['id']: childrenList.append(allMsg[i]) q.put(allMsg[i]) # 子留言列表按时间降序排序 childrenList = sorted(childrenList, key = lambda d: d['date'], reverse = True) # 格式化日期格式 for item in childrenList: item['date'] = datetime.datetime.strftime(item['date'], '%Y-%m-%d %H:%M:%S') return childrenList用postman测试接口,得到的json格式如下:
{ "messages": [ { "id": 12, "date": "2020-05-31 12:19:43", "content": "你好啊,太棒了", "parent_msg_id": null, "user_id": 5, "username": "wangwu", "parent_msg_username": null, "children": [] }, { "id": 11, "date": "2020-05-31 12:18:55", "content": "的时刻层6666666632\n2面的思考名称看到什么材料是isdafjoisdjiojildsc", "parent_msg_id": null, "user_id": 3, "username": "zhangsan", "parent_msg_username": null, "children": [] }, { "id": 5, "date": "2020-05-29 19:09:33", "content": "发的发射点发吖方吖是发是呵等方5爱的非4阿瑟东方 发", "parent_msg_id": null, "user_id": 4, "username": "lisi", "parent_msg_username": null, "children": [ { "id": 13, "date": "2020-05-31 12:20:12", "content": "号好好好矮好矮好矮好好", "parent_msg_id": 5, "user_id": 6, "username": "zhaoliu", "parent_msg_username": "lisi" } ] }, { "id": 1, "date": "2020-05-29 19:06:21", "content": "fasfdsafas法阿萨德方吖65阿瑟东方5是的发", "parent_msg_id": null, "user_id": 1, "username": "student", "parent_msg_username": null, "children": [ { "id": 7, "date": "2020-05-29 19:29:29", "content": "hfhf2h22h222223232", "parent_msg_id": 6, "user_id": 1, "username": "student", "parent_msg_username": "zhaoliu" }, { "id": 6, "date": "2020-05-29 19:09:56", "content": "而离开离开邻居哦i据哦i报价哦v保健品45465", "parent_msg_id": 4, "user_id": 6, "username": "zhaoliu", "parent_msg_username": "mike" }, { "id": 4, "date": "2020-05-29 19:09:14", "content": "发送端非场地萨擦手d5asd32 1dads\r\ndsac十多次ds出错", "parent_msg_id": 2, "user_id": 8, "username": "mike", "parent_msg_username": "lisi" }, { "id": 3, "date": "2020-05-29 19:08:56", "content": "奋发恶法撒打发士大夫士大夫是大 大师傅撒", "parent_msg_id": 2, "user_id": 2, "username": "teacher", "parent_msg_username": "lisi" }, { "id": 2, "date": "2020-05-29 19:08:41", "content": "fasdfasdf发生的法撒旦飞洒多发点房地产", "parent_msg_id": 1, "user_id": 4, "username": "lisi", "parent_msg_username": "student" } ] } ], "status_code": 200 }这个就是前台所要的内容了。