python自动化开发-[第二十二天]-bbs多级评论、点赞、上传文件
今日概要:
1、related_name和related_query_name的区别
2、through_fields的用途
3、django的事务提交
4、点赞的动画效果
5、多级评论的原理
6、上传文件
7、request.post用法
8、如果保留原来的页面
一、related_name和related_query_name的区别
related_name,用于定义反向关联时候,使用的字段名称
related_query_name 用于反向查询related_query_name + _set进行查询
例子:
class A: title = models.CharField() obj = models.A.objects.get(id=1) obj.b_set.all() obj.xxxxxx_set.all() # related_query_name='xxxxxx' obj.uuuu.all() # related_name='uuuu' obj.x obj.u class B: xx ..xx fk1 = models.ForignKey(related_name='x') fk2 = models.ManyToMany(related_name='u') models.B.objects.filter(fk__title='xx')
二、through_fields的用途
through_fields = (在关系表中与当前表建立FK关系的字段名称,在关系表中与目标表建立的FK关系字段名称)
例子:
likes = models.ManyToManyField(to='UserInfo',through="Like",through_fields=('new','user')) #当前表是new表
三、django的事务提交
保持两条sql的同时正确才进行插入动作
from django.db import transaction with transaction.atomic(): models.Like.objects.create(nnew_id=new_id,uuser_id=uid) models.News.objects.filter(id=new_id).update(like_count=F('like_count') + 1) response.code = 999
返回值封装:
class BaseResponse(object): def __init__(self): self.status = False self.data = None self.msg = None def get_dict(self): return self.__dict__ class LikeResponse(BaseResponse): def __init__(self): self.code = 0 super(LikeResponse,self).__init__() json.dumps(对象.__dict__) json.dumps(对象.get_dict())
四、点赞的动画效果
*在ajax中操作回调函数中的 $(this)已经不是原来的$(this)
解决方法:通过一个变量来传递
应用内容:css中的position:fixed,absolute,relative setInterval:定时器
js代码:
$(function () { bindLikeEvent(); }); function bindLikeEvent() { $('.new-like').click(function () { // 获取当前新闻ID var newId = $(this).attr('new-id'); var $this = $(this); $.ajax({ url: '/do_like.html', type: "POST", data: {'newId': newId}, dataType: 'JSON', success:function (arg) { if(arg.status){ var origin = $this.text(); var count = parseInt(origin); if(arg.code == 666){ $this.text(count - 1 ); showLikeCount($this,'-1'); }else if(arg.code == 999){ $this.text(count + 1 ); showLikeCount($this,'+1'); } }else{ alert(arg.msg); } } }) }) } function showLikeCount($this,text) { var fontSize = 5; var top = 0; var right = 0; var opacity = 1; var tag = document.createElement('span'); tag.innerText = text; tag.style.position = "absolute"; tag.style.fontSize = fontSize + "px"; tag.style.top = top + "px"; tag.style.right = right + "px"; tag.opacity = opacity; $this.after(tag); var obj = setInterval(function () { fontSize += 5 ; top -= 5; right -= 5 ; opacity -= 0.1 ; tag.style.fontSize = fontSize + "px"; tag.style.top = top + "px"; tag.style.right = right + "px"; tag.style.opacity = opacity; if (opacity <= 0 ){ clearInterval(obj); tag.remove() } },100) } </script>
五、多级评论的原理
知识点:字典和列表,通过引用赋值,一个修改全部都改变
递归
#!/usr/bin/python # -*- coding:utf-8 -*- def build_comment_data(li): dic = {} #定义一个空字典dic for item in li: item['children'] = [] #列表字典中新增一个key叫children,value为空 dic[item['id']] = item #给空字典dic赋值 key是列表中字典中的id,value是列表字典 result = [] #定义一个空列表,存最后的结果 for item in li: #item是li列表中的每一行字典 pid = item['parent_id'] #pid是取每一行字典中parent_id的值 if pid: #如果每一行字典中parent_id有值 dic[pid]['children'].append(item) #则找到字典中pid的那一行,把item加到children里 else: result.append(item) #否则把parent_id没有值的加到result列表中 # for i in result: # print(i) return result def build_comment_tree(com_list1): tpl = """ <div class="item> <div class="title">{0}:{1}</div> <div class="body>{2}</div> </div> """ #这里的{0}{1}{2}都是占位符 html="" # print(com_list1) # for i in com_list1: # print(i) for item in com_list1: if not item['children']: #如果字典中没有children html += tpl.format(item['user'],item['content'],"") #format给占位符传值,第三个值为空 else: html += tpl.format(item['user'], item['content'], build_comment_tree(item['children'])) #如果有子children则把build_comment_tree函数自己再执行一遍,把孩子传进去(孩子也是一个完整的字典) return html def comment_list(): li = [ {'id': 1, 'user': '银秋良', 'content': '灌我鸟事', 'parent_id': None}, {'id': 2, 'user': '银秋良', 'content': '管我鸟事', 'parent_id': None}, {'id': 3, 'user': '型谱', 'content': '你个文盲', 'parent_id': 1}, {'id': 4, 'user': '详解', 'content': '好羡慕你们这些没脸的人呀', 'parent_id': 2}, {'id': 5, 'user': '银秋良', 'content': '你是流氓', 'parent_id': 3}, {'id': 6, 'user': '银秋良', 'content': '你冷库无情', 'parent_id': 5}, {'id': 7, 'user': '银秋良', 'content': '你才冷酷无情', 'parent_id': 4}, {'id': 8, 'user': '银秋良', 'content': '你无理取闹', 'parent_id': 4}, ] com_list = build_comment_data(li) html = build_comment_tree(com_list) print(html) if __name__ == '__main__': comment_list()
知识回顾:
l = [1,2,4,5,6] #迭代器 for i in l: #迭代器对象 # 迭代器出现报错 l.__iter__() next()取到空的情况,迭代器对象不会 for j in l: print(i)
引用类型应用:
li = [ {'user':'xxx','pwd':'xxx','id':1,"children":[],'parent_id':None}, {'user':'xxx','pwd':'xxx','id':2,"children":[],'parent_id':None}, {'user':'xxx','pwd':'xxx','id':3,"children":[],'parent_id':1}, {'user':'xxx','pwd':'xxx','id':4,"children":[],'parent_id':2}, {'user':'xxx','pwd':'xxx','id':5,"children":[],'parent_id':1}, {'user':'xxx','pwd':'xxx','id':6,"children":[],'parent_id':3}, ] #结果: # result = [ # {'user':'xxx','pwd':'xxx','id':1,"children":[{'user':'xxx','pwd':'xxx','id':3,"children":[ {'user':'xxx','pwd':'xxx','id':6,"children":[],'parent_id':3},],'parent_id':1},{'user':'xxx','pwd':'xxx','id':5,"children":[],'parent_id':1},],'parent_id':None}, # {'user':'xxx','pwd':'xxx','id':2,"children":[{'user':'xxx','pwd':'xxx','id':4,"children":[],'parent_id':2},],'parent_id':None}, # ] dict = {} for i in li: dict[i['id']] = i a = [] for k,v in dict.items(): if v['parent_id']: dict[v['parent_id']]["children"].append(v) else: a.append(v) print(a)
javascript实现多级评论:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .hide { display: none; } .body{ margin-left: 30px; } </style> </head> <body> <h1>多级评论</h1> <a id="a1" href="#" onclick="myClick()">点我</a> {# {{ comment_list | safe }}#} <script src="/static/jquery-3.2.1.js"></script> <script> function my_iter(arg) { var h = ""; $.each(arg,function (k,v) { if (v['children']){ h += '<div class="item"><div class="title">' + v['user'] + ':' + v['content'] + '</div> <div class="body">' + my_iter(v['children']) + '</div></div>' }else{ h += '<div class="item"><div class="title">' + v['user'] + ':' + v['content'] + '</div><div class="body"></div></div>' } }); return h } $(function () { $('body').on('click',".title",function () { if ($(this).next().hasClass('hide')){ $(this).next().removeClass('hide') }else{ $(this).next().addClass('hide') } }) }); function myClick() { $.ajax({ url:'/comment', type:"POST", data:"1", dataType:"JSON", success:function (arg) { console.log(my_iter(arg)); $('#a1').after(my_iter(arg)) } }) } </script> </body> </html>
六、上传文件
- 基于FormData
- 缺点,兼容性不好
- 优点,Ajax直接发送
- 伪Ajax,兼容性更好
- iframe,天生局部刷新
- form,天生整个页面刷新
七、request.post用法
- 如何通过python代码发送post数据? URL: http://127.0.0.1:8003/asset.html 客户端: import requests # response = requests.get('http://127.0.0.1:8003/asset.html') # print(response.text) data_dict = { 'k1':'v1', 'k2':'v2' } # content-type: application/x-www-form-urlencoded # response = requests.post('http://127.0.0.1:8003/asset.html',data=data_dict) # print(response.text) # content-type: appcation/json response = requests.post('http://127.0.0.1:8003/asset.html',json=data_dict) print(response.text) 服务端Django: from django.views.decorators.csrf import csrf_exempt,csrf_protect @csrf_exempt def asset(request): if request.method == "GET": return HttpResponse('收到:GET') else: print(request.POST) print(request.body) return HttpResponse('收到:POST')
八、如果保留原来的页面
request.GET from django.http.request import QueryDict 要点: POST,不要写action
例子:
def host_list(request): print(request.GET,type(request.GET)) # request.GET._mutable = True obj = QueryDict(mutable=True) obj['_zhaofengfeng'] = request.GET.urlencode() # page=10&id=1 url_param = obj.urlencode() hosts = ['c1.com','c2.com','c3.com'] return render(request,'host_list.html',{'hosts':hosts,'url_param':url_param}) def add_host(request): if request.method == "GET": return render(request,'add.html') else: url_params = request.GET.get('_zhaofengfeng') host = request.POST.get('hostname') url ="/host_list.html?"+url_params return redirect(url)