Django基础07-day22
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django基础07-day22相关的知识,希望对你有一定的参考价值。
写在前面
上课第22天,打卡:
武天老师:要过一个开心有趣、精神百倍的人生!
1 s17day22 BBS 2 3 今日内容:BBS 4 - 新闻列表 5 - 点赞 6 - 事务 7 - 小动画 8 - 多级评论 9 - 引用:列表,字典 10 - 递归: 11 - 上传文件 12 - 基于FormData 13 - 伪Ajax,兼容性更好 14 15 - request.GET,意识:跳转回原来页面 16 17 18 内容详细: 19 1. Bug解决 20 related_name,用于定义反向关联时候,使用的字段名称 21 related_query_name 22 23 24 class A: 25 title = models.CharField() 26 obj = models.A.objects.get(id=1) 27 obj.b_set.all() 28 obj.xxxxxx_set.all() # related_query_name=‘xxxxxx‘ 29 obj.uuuu.all() # related_name=‘uuuu‘ 30 31 obj.x 32 obj.u 33 34 class B: 35 xx ..xx 36 fk1 = models.ForignKey(related_name=‘x‘) 37 fk2 = models.ManyToMany(related_name=‘u‘) 38 39 models.B.objects.filter(fk__title=‘xx‘) 40 41 through_fields = (在关系表中与当前表建立FK关系的字段名称,在关系表中与目标表建立的FK关系字段名称) 42 43 2. 点赞 44 - 事务 45 from django.db import transaction 46 with transaction.atomic(): 47 models.Like.objects.create(nnew_id=new_id,uuser_id=uid) 48 models.News.objects.filter(id=new_id).update(like_count=F(‘like_count‘) + 1) 49 response.code = 999 50 - 返回值:封装对象 51 class BaseResponse(object): 52 def __init__(self): 53 self.status = False 54 self.data = None 55 self.msg = None 56 57 def get_dict(self): 58 return self.__dict__ 59 60 61 class LikeResponse(BaseResponse): 62 def __init__(self): 63 self.code = 0 64 super(LikeResponse,self).__init__() 65 66 67 json.dumps(对象.__dict__) 68 json.dumps(对象.get_dict()) 69 70 - 在Ajax操作时候,回调函数中的 $(this)已经不是原来的$(this) 71 72 - css: 73 position:fixed,absolute,relative 74 setInterval:定时器 75 76 3. 评论 77 - 字典,列表,通过引用赋值,一个修改全部都改 78 - 递归 79 80 作业: 81 评论:0 绑定点击事件 82 - 发送Ajax请求: 新闻ID 83 84 - 查询当前新闻ID对应的所有评论 models.xxxx.values() 85 li = [ 86 {‘id‘: 1, ‘user‘: ‘银秋良‘, ‘content‘: ‘灌我鸟事‘, ‘parent_id‘: None}, 87 {‘id‘: 2, ‘user‘: ‘银秋良‘, ‘content‘: ‘管我鸟事‘, ‘parent_id‘: None}, 88 {‘id‘: 3, ‘user‘: ‘型谱‘, ‘content‘: ‘你个文盲‘, ‘parent_id‘: 1}, 89 {‘id‘: 4, ‘user‘: ‘详解‘, ‘content‘: ‘好羡慕你们这些没脸的人呀‘, ‘parent_id‘: 2}, 90 {‘id‘: 5, ‘user‘: ‘银秋良‘, ‘content‘: ‘你是流氓‘, ‘parent_id‘: 3}, 91 {‘id‘: 6, ‘user‘: ‘银秋良‘, ‘content‘: ‘你冷库无情‘, ‘parent_id‘: 5}, 92 {‘id‘: 7, ‘user‘: ‘银秋良‘, ‘content‘: ‘你才冷酷无情‘, ‘parent_id‘: 4}, 93 {‘id‘: 8, ‘user‘: ‘银秋良‘, ‘content‘: ‘你无理取闹‘, ‘parent_id‘: 4}, 94 ] 95 选择: 96 - 数据进行操作并且渲染,返回给用户html 97 - 返回给前端JavaScrip ***** 98 99 应用:菜单 100 101 102 4. 上传文件 103 - 基于FormData 104 - 缺点,兼容性不好 105 - 优点,Ajax直接发送 106 107 - 伪Ajax,兼容性更好 108 - iframe,天生局部刷新 109 - form,天生整个页面刷新 110 111 112 普通POST请求: 113 - Ajax(*) 114 - 伪Ajax 115 上传内文件: 116 - Ajax, FormData 117 - 伪Ajax (*) 118 119 120 5. 其他 121 - 如何通过python代码发送post数据? 122 URL: http://127.0.0.1:8003/asset.html 123 124 125 客户端: 126 import requests 127 128 # response = requests.get(‘http://127.0.0.1:8003/asset.html‘) 129 # print(response.text) 130 data_dict = { 131 ‘k1‘:‘v1‘, 132 ‘k2‘:‘v2‘ 133 } 134 # content-type: application/x-www-form-urlencoded 135 # response = requests.post(‘http://127.0.0.1:8003/asset.html‘,data=data_dict) 136 # print(response.text) 137 138 # content-type: appcation/json 139 response = requests.post(‘http://127.0.0.1:8003/asset.html‘,json=data_dict) 140 print(response.text) 141 142 服务端Django: 143 from django.views.decorators.csrf import csrf_exempt,csrf_protect 144 145 @csrf_exempt 146 def asset(request): 147 if request.method == "GET": 148 return HttpResponse(‘收到:GET‘) 149 else: 150 print(request.POST) 151 print(request.body) 152 return HttpResponse(‘收到:POST‘) 153 154 - 如何保留原来页面条件 155 request.GET 156 from django.http.request import QueryDict 157 要点: 158 POST,不要写action 159 160 本周作业:CMDB 161 1. javascript递归实现多级评论 162 2. CMDB 163 - Agent: 164 采集硬件资产,并且自动汇报到API(一个硬件) 165 主机名:hostname,内存信息 166 response = requests.post(‘http://127.0.0.1:8003/asset.html‘,json=data_dict) 167 print(response.text) 168 - 服务端Django: 169 API: 170 支持为其他系统和用户提供资源:API 171 print(request.body.decode(‘utf-8‘)) 172 173 主机表:主机名,IP... 174 175 内存表: 176 位置 容量 型号 主机ID 177 178 页面: 179 表增删改查(如何保留原来页面条件) 180 181 - 程序左侧菜单:多级评论知识 182 183 184
################ # 2017-09-24 - 课上笔记 ################ """ 十一作业:CMDB - 采集资产,就是一个py文件,执行一个命令,通过正则取结果:{...} - API: http://www.qiyi.domain/xxx.html - POST请求,request.post(API,data={...}) - Django程序 - url:/assert.html --> assert - def assert(request): request.POST 写到数据库 - index.html --> index 展示数据 - 动态的左侧菜单:多级评论 """ """ day22 今日内容: - 新闻列表 - 点赞(2次数据库操作,所以有可能存在脏数据) - 事物 - 点赞+1的小动画 - 多级评论 - Python中的引用(指针) - 递归:深度优先搜索 - 上传文件 - 基于FormData对象 - 伪ajax,兼容性更好 - 分页 - request.GET - 添加完/修改完 跳转回原来的页面 """ 今日内容: - 反查 - related_name 用于定义反向关联是的名称 - related_query_name class A: title = models.CharField() class B: xxxx = xxxx fk1 = models.ForeignKey(related_name=‘xxx‘) fk2 = models.ForeignKey(related_query_name=‘xxx‘) fk3 = models.ManyToMany(related_name=‘xxx‘) - ManyToMany 的 througth_fields 字段是有顺序要求的 - 点赞 - 事物 from django.db import transaction with transaction.atomic(): pass - 返回值 - 面向对象 - base + 继承 - json.dumps(对象.__dict__) - +/-动画 - 在ajax操作时候,回调函数中的 $(this) 已经不是原来的 $(this) - css - position: fixed,absolute,relative - setInterval定时器 - setTimeout 只执行一次 - JS的闭包 """ var obj = setInterval(function () { fontSize =+ 5; top -= 5; right -= 5; opacity -= 0.1; tag.style.fontSize = fontSize + "px"; tag.style.top = top; tag.style.right = right; tag.style.opacity = opacity; // 终止定时器 if(opacity <= 0){ clearInterval(obj); tag.remove(); } },100); """ - 字典和列表的结合查找 li = [ {‘user‘:‘xxx‘,‘pwd‘:‘xxx‘,‘id‘:1}, {‘user‘:‘xxx‘,‘pwd‘:‘xxx‘,‘id‘:2}, {‘user‘:‘xxx‘,‘pwd‘:‘xxx‘,‘id‘:3}, {‘user‘:‘xxx‘,‘pwd‘:‘xxx‘,‘id‘:4}, ] dic = {} for item in li: dic[item[‘id‘]] = item """ 练习题: 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}, ] """ - 多级评论 {{ comment_list|safe }} - 字典,列表 通过引用赋值,一个修改,全部都改; - 递归 和左侧菜单原理是一样的 给评论绑定点击事件 - 发送ajax请求 - 把新闻ID传给后台,查询当前新闻下面的所有评论(models.xxx.objects.values(...)) - 后台渲染HTML,返回给前端 或者 把数据字典返回给前端,让前端来递归生成多级结构 应用:菜单 上传文件并预览 - 基于FormData - 缺点:兼容性不好 - 优点:ajax直接发送 - 伪造发送ajax - iframe标签 天生局部刷新 向其他网址发数据,页面不刷新 - form表单 天生整体刷新 - 如果是普通的POST: - ajax - 伪ajax - 如果是上传文件: - 伪ajax a标签包含input的file标签,同时把input标签的透明度置为0 其他: - 如何通过Python代码发送POST数据? import requests requests.get() requests.post() - 两种发送数据的方式(区别是请求头里的content-type不一样): - data - json -> content-type:application/json (django 不处理这个类型,所以request.POST 是空的,需要去request.body) ‘‘‘ 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) ‘‘‘ - 如何保留原来页面的条件 request.GET request.GET.urlencode() from django.http.request import QueryDict """mutable这个值默认是False,是不允许修改的""" obj = QueryDict(mutable=True) obj[‘xxxxxx‘] = request.GET.urlencode() url_param = obj.urlencode() request.GET.get(‘xxxxxx‘) 要点:发送POST请求的时候不要写action,还会提交到当前页面 作业: - 评论用js递归构造实现多级 - 尝试去做CMDB - agent 收集服务器相关数据,发送到API;用json汇报 - server 提供API给agent,接收数据,然后存储,最后页面展示(表的增删改查,要保留原来地址) - 展示的时候加上左侧菜单 - 菜单扩展: - 默认展开
初始化绑定事件
实时判断剩余可输入字符
<div style="background-color: powderblue; border-radius: 10px ;"> <div class="form-group container-fluid"> <label for="pic_summary">添加描述</label> <textarea class="form-control pic2news-desc" id="pic_summary" name="pic_summary" rows="3" placeholder="描述不能为空"></textarea> </div> <div class="form-group container-fluid"> 您还可以输入<span class="char_notice-pic2news" style="color: red">150</span>个字 </div> </div> $(".pic2news-desc").keyup(function () { var $maxChars = 150;//最多字符数 var $curr = $(".pic2news-desc").val().length; if ($curr < $maxChars){ var $left = $maxChars - $curr; $(".char_notice-pic2news").text($left); } });
鼠标点击图片后左下进行放大
<div class="item-pic"> <img src="{{ news.avatar }}" style="max-height:80px; max-width: 80px;"> </div> .item .item-pic { float: right; width: 10%; max-height: 80px; max-width: 80px; display: inline-block; position: absolute; } .item-pic:active { z-index: 99; } .item-pic:active>img{ transform: scale(2,2); /*transform-origin: 0 0;*/ transform-origin:100% 0; transition: .3s transform; }
好看的 <input type="file" ...> 样式的实现方式
<form id="pic2news-form" method="post" target="iframe4pic" action="/upload_img2/" enctype="multipart/form-data"> {% csrf_token %} <div class="form-group container-fluid"> <label for="upload_img">选择图片</label> <a href="javascript:" id="nice-input-file"> 上传<input type="file" id="upload_img" name="avatar" onchange="auto_submit()"> </a> <p class="help-block">支持jpg、jpeg、gif、png格式,且不超过5MB</p> </div> </form> #nice-input-file{ position: relative; display: inline-block; width: 60px; height: 30px; background-color: darkslateblue; color: white; text-align: center; line-height: 30px; border-radius: 7px; text-decoration: none; } #upload_img { position:absolute; opacity: 0; left: 0; top: 0; right: 0; bottom: 0; }
基于FormData上传文件
<form id="pic2news-form"> {% csrf_token %} <div class="form-group container-fluid"> <label for="upload_img">选择图片</label> <a href="javascript:" id="nice-input-file"> 上传<input type="file" id="upload_img" name="avatar" onchange="auto_upload()"> </a> <p class="help-block">支持jpg、jpeg、gif、png格式,且不超过5MB</p> <div id="pic-preshow" class="be_hidden" style="height: 150px;"></div> </div> <div style="background-color: powderblue; border-radius: 10px ;"> <div class="form-group container-fluid"> <label for="pic_summary">添加描述</label> <textarea class="form-control pic2news-desc" id="pic_summary" name="pic_summary" rows="3" placeholder="描述不能为空"></textarea> </div> <div class="form-group container-fluid"> 您还可以输入<span class="char_notice-pic2news" style="color: red">150</span>个字 </div> </div> <label for="category" class="col-md-2">发布到</label> <div class="col-md-4"> <select class="form-control" name="pic_category" id="pic_category"> {% for category in category_list %} <option>{{ category }}</option> {% endfor %} </select> </div> </form> function auto_upload() { // 获取文件 上传文件 预览 $("#pic-preshow").removeClass(‘be_hidden‘); var formData = new FormData(); formData.append(‘pic‘,$("#upload_img")[0].files[0]); console.log(formData); $.ajax({ url:‘/upload_img/‘, type:‘POST‘, data:formData, headers:{‘X-CSRFToken‘: $.cookie(‘csrftoken‘)}, processData: false, // tell jQuery not to process the data contentType: false, // tell jQuery not to set contentType success:function (ret) { ret = JSON.parse(ret); if (ret.status){ var tag = document.createElement(‘img‘); tag.src = "/" + ret.path; tag.style.maxWidth = "100%"; tag.style.maxHeight = "100%"; $(‘#pic-preshow‘).empty(); $(‘#pic-preshow‘).append(tag); }else { alert(‘预览失败‘); } } }) } $("#pic_publisher").click(function () { var $pic_path = $("#pic-preshow").find("img").attr("src"); if(0 == $("#pic_summary").val().length || typeof($pic_path) == "undefined"){ alert("请确保图片和描述都正确填写!"); }else { $.ajax({ url:‘/new_article/‘, type:‘POST‘, data:{ ‘pic_summary‘:$("#pic_summary").val(), ‘avatar‘:$pic_path, ‘category‘:$("#pic_category").val() }, headers:{‘X-CSRFToken‘: $.cookie(‘csrftoken‘)}, success:function (data) { var dic=JSON.parse(data); if(dic[‘flag‘]){ window.location.href = ‘/index/‘; }else { alert("提交失败,请重试!"); } } }) } }); class UploadView(AuthView,View): def post(self, request, *args, **kwargs): import os,json obj = request.FILES.get(‘pic‘) img_path = os.path.join(‘statics‘, ‘image‘, obj.name) with open(img_path, mode=‘wb‘) as f: for chunk in obj.chunks(): f.write(chunk) data = { ‘status‘: True, ‘path‘: img_path.replace("statics","static") } return HttpResponse(json.dumps(data))
面向对象思想写字典返回给前端
#!/usr/bin/python # -*- coding:utf-8 -*- class BaseResponse(object): def __init__(self): self.status = False self.msg = None self.data = None @property def dict_info(self): return self.__dict__ class LikeResponse(BaseResponse): def __init__(self): self.code = None super(LikeResponse,self).__init__() if __name__ == ‘__main__‘: like = LikeResponse() print(like.dict_info)
基于iframe上传文件
<form id="pic2news-form" method="post" target="iframe4pic" action="/upload_img2/" enctype="multipart/form-data"> {% csrf_token %} <div class="form-group container-fluid"> <label for="upload_img">选择图片</label> <a href="javascript:" id="nice-input-file"> 上传<input type="file" id="upload_img" name="avatar" onchange="auto_submit()"> </a> <p class="help-block">支持jpg、jpeg、gif、png格式,且不超过5MB</p> </div> </form> <iframe id="ifm" name="iframe4pic" onload="successCallback(this);" style="display: none;" ></iframe> <div id="pic-preshow" class="be_hidden" style="height: 150px;"></div> function auto_submit() { console.log(‘auto_submit ...‘); $("#pic2news-form").submit(); } function successCallback(ths){ console.log("successCallback ..."); var response = ths.contentWindow.document.body.innerHTML; response = JSON.parse(response); console.log(response); var img = document.createElement(‘img‘); img.src = "/" + response.data; img.style.maxWidth = "100%"; img.style.maxHeight = "100%"; $("#pic-preshow").removeClass(‘be_hidden‘); $(‘#pic-preshow‘).empty(); $(‘#pic-preshow‘).append(img); } def upload_img2(request): import os response = BaseResponse() try: print("ok") user = request.POST.get(‘user‘) print(user) obj = request.FILES.get(‘avatar‘) print(obj) img_path = os.path.join(‘statics‘, ‘image‘, obj.name) print(">>>>>>>>>",img_path) with open(img_path, mode=‘wb‘) as f: for chunk in obj.chunks(): f.write(chunk) except Exception as e: print("error") response.msg = str(e) print(e) else: response.status = True response.data = img_path.replace("statics","static") return HttpResponse(json.dumps(response.dict_info))
iframe的src属性
# iframe demo <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <input type="text" placeholder="请输入关键字" id="key" /> <input type="button" value="搜索" onclick="searchSB();" /> <div class="container"> <iframe id="im1" src="" style="width: 650px;height: 1000px;"></iframe> <iframe id="im2" src="" style="width: 650px;height: 1000px;"></iframe> </div> <script src="../static/js/jquery-3.2.1.min.js"></script> <script> function searchSB() { var val = $(‘#key‘).val(); alert(val); $(‘#im1‘).attr("src","https://www.baidu.com/s?wd="+val); $(‘#im2‘).attr("src","https://www.sogou.com/web?query="+val); } </script> </body> </html>
Django的 transaction 事务
from django.db.models import F from django.db import transaction class LikeView(AuthView,View): def post(self, request, *args, **kwargs): response = LikeResponse() try: news_id = request.POST.get("news_id") username = request.session.get("user") user_obj = models.UserInfo.objects.filter(username=username).first() like_exist = models.Like.objects.filter(user_id=user_obj.id, news_id=news_id).count() # django的事务:涉及到2次数据库操作,要么一起成功,要么一起失败,避免产生脏数据 with transaction.atomic(): if like_exist: models.Like.objects.filter(user_id=user_obj.id, news_id=news_id).delete() # from django.db.models import F -> F操作实现点赞个数加减1 models.NewsInfo.objects.filter(id=news_id).update(like_count=F(‘like_count‘) - 1) response.code = 1 else: models.Like.objects.create(user_id=user_obj.id,news_id=news_id) models.NewsInfo.objects.filter(id=news_id).update(like_count=F(‘like_count‘)+1) response.code = 0 except Exception as e: response.msg = str(e) print(‘>>>>>>>>> ‘,e) else: response.status = True return HttpResponse(json.dumps(response.dict_info))
根据url爬取网页标题乱码问题
def crawling(request): if ‘GET‘ == request.method: data = {‘title‘: None, ‘desc‘: None, ‘flag‘:False, ‘msg‘:None} url = request.GET.get(‘url‘) try: import requests from bs4 import BeautifulSoup response = requests.get(url) ‘‘‘ ISO-8859-1 需要把这个转换成 utf-8/gbk 否则前端会出现乱码 ‘‘‘ if request.encoding not in [‘gbk‘,‘GB2312‘,‘UTF-8‘,‘utf-8‘]: response.encoding = ‘utf-8‘ soup = BeautifulSoup(response.text, ‘html.parser‘) title = soup.find(‘title‘).text if soup.find(‘meta‘, attrs={‘name‘: ‘description‘}): data[‘desc‘] = soup.find(‘meta‘, attrs={‘name‘: ‘description‘}).get(‘content‘) data[‘title‘] = title data[‘flag‘] = True except Exception as e: data[‘msg‘] = e return HttpResponse(json.dumps(data))
点赞动画
$(function () { bindLikeEvent(); $("#register-form").bootstrapValidator({ message: ‘This value is not valid‘, excluded : [‘:disabled‘],//[‘:disabled‘, ‘:hidden‘, ‘:not(:visible)‘] feedbackIcons: { valid: ‘glyphicon glyphicon-ok‘, invalid: ‘glyphicon glyphicon-remove‘, validating: ‘glyphicon glyphicon-refresh‘ }, fields: { username: {/*键名username和input name值对应*/ message: ‘用户名无效‘, validators: { notEmpty: {/*非空提示*/ message: ‘用户名不能为空‘ }, stringLength: {/*长度提示*/ min: 3, max: 20, message: ‘用户名长度必须在3到20之间‘ }/*最后一个没有逗号*/ } }, password: { message:‘密码无效‘, validators: { notEmpty: { message: ‘密码不能为空‘ }, stringLength: { min: 3, max: 30, message: ‘密码长度必须在3到30之间‘ } } }, email: { validators: { notEmpty: { message: ‘邮箱不能为空‘ }, emailAddress: { message: ‘邮箱格式错误‘ } } } } }) }); function showLikeCount($this,mytext) { var fontSize = 5; var top = 0; var right = 0; var opacity = 1; var tag = document.createElement(‘span‘); tag.innerText = mytext; // 外层div用relative,内层标签用absolute tag.style.position = "absolute"; // 默认大小 tag.style.fontSize = fontSize + "px"; tag.style.top = top + ‘px‘; tag.style.right = right + ‘px‘; tag.style.opacity = opacity; $this.after(tag); // 定时器:每0.1s执行一次,模拟动画效果 // JS的闭包:obj 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); } function bindLikeEvent() { $(".recommend").click(function () { var $news_id = $(this).attr("news-id"); var $this = $(this); $.ajaxSetup({ data: {‘csrfmiddlewaretoken‘:‘{{ csrf_token }}‘} }); $.ajax({ url:‘/do_like/‘, type:‘POST‘, data:{‘news_id‘:$news_id}, success:function (data) { var ret=JSON.parse(data); if(ret.status){ var origin = $this.text(); var count = parseInt(origin); if (0 == ret.code){ $this.text(count+1); showLikeCount($this,"+1"); } else if(1 == ret.code){ $this.text(count-1); showLikeCount($this,"-1"); } }else { alert("点赞操作失败!"+ret.msg); } } }) }); }
添加完/修改完 跳转回原来的页面
# 视图函数 from django.http.request import QueryDict # index的视图函数 def get(self, request, *args, **kwargs): category_list = models.NewsCategory.objects.all() category_id = kwargs.get(‘category_id‘) print(request.GET, type(request.GET)) # <QueryDict: {‘page‘: [‘3‘]}> <class ‘django.http.request.QueryDict‘> print(request.GET.urlencode()) # page = 3 """mutable这个值默认是False,是不允许修改的""" obj = QueryDict(mutable=True) obj[‘_url_parameter‘] = request.GET.urlencode() # page=3 obj[‘prev_path‘] = request.path_info # /category/3/ url_param = obj.urlencode() # 发布新消息的视图函数 def post(self, request, *args, **kwargs): category = request.POST.get("category") category_obj = models.NewsCategory.objects.filter(caption=category).first() author = request.session.get(‘user‘) author_obj = models.UserInfo.objects.filter(username=author).first() url = request.POST.get("link") if url: title = request.POST.get("title") summary = request.POST.get("summary") models.NewsInfo.objects.create(title=title,summary=summary,url=url,category=category_obj,author=author_obj) url_params = request.GET.get(‘_url_parameter‘) url_path = request.GET.get(‘prev_path‘) print("$$$$$$$$$$$$$ ",url_path) print(">>>>> ",url_params) url = url_path + "?" + url_params print("++++++++++++++++ ",request.META) return redirect(url) # index.html # 带上 <a href="/new_article/?{{ url_param }}" class="add-new-msg"> <span class="n1 ico"></span> <span class="n2">发布</span> </a> # new_article.html # form表单里不能写action,这样会提交当前页面 <form method="post"> ... </form>
# index.html {% load staticfiles %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>抽抽屉</title> <link rel="Shortcut Icon" href="{% static "image/header.png" %}"> <link rel="stylesheet" href="{% static "css/bootstrap.css" %}"> <link rel="stylesheet" href="{% static "css/bbs.css" %}"> <script src="{% static "js/jquery-3.2.1.min.js" %}"></script> <script src="{% static "js/bootstrap.js" %}"></script> <script src="{% static "js/bootstrap-select.min.js" %}"></script> <script src="{% static "js/bootstrapValidator.min.js" %}"></script> <script src="{% static "js/jquery.cookie.js" %}"></script> <style> .be_hidden{ display: none; } </style> </head> <body> <div class="header"> <div class="logo"> <img src="{% static "image/logo.png" %}" alt="抽屉logo" title="欢迎来到抽屉新热榜"> </div> <div class="head_btn1"> <ul class="nav nav-pills my_nav"> {% if category_id %} <li><a href="/index/?page=1">全部</a></li> {% else %} <li class="active"><a href="/index/?page=1">全部</a></li> {% endif %} {% for category in category_list %} {% if category.id == category_id %} <li class="active"><a href="/category/{{ category.id }}/?page=1">{{ category.caption }}</a></li> {% else %} <li><a href="/category/{{ category.id }}/?page=1">{{ category.caption }}</a></li> {% endif %} {% endfor %} </ul> </div> <div class="head_btn2"> {% if request.session.user %} <ul class="nav navbar-nav navbar-right"> <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" style="color: white">{{ request.session.user }}<span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">个人主页</a></li> <li><a href="#">设置</a></li> <li><a href="/logout/">登出</a></li> </ul> </li> </ul> {% else %} <ul class="nav2"> <li><a data-toggle="modal" data-target="#register">注册</a></li> <li><a data-toggle="modal" data-target="#login">登录</a></li> </ul> {% endif %} </div> <div class="head_btn3"> <form action="" method="post"> <input class="header_select" type="text"> <a href=""> <span class="select_icon"></span> </a> </form> </div> </div> {% block content %} <div class="page_body"> <div class="main-content"> <div class="content-left"> <div class="content-top-area"> <div class="child-nav"> <a href="" class="active icons" id="hotest">最热</a> <a href="">发现</a> <a href="">人类发布</a> </div> <div class="sort-nav"> <a href="" class="active">即时排序</a> <a href="">24小时</a> <a href="">3天</a> </div> <a href="/new_article/?{{ url_param }}" class="add-new-msg"> <span class="n1 ico"></span> <span class="n2">发布</span> </a> </div> <div class="content-list"> {% load get_domain %} {% for news in news_list %} <div class="item"> <div class="item-body"> <div class="item-title"> <a href="" target="_blank" class="a-link"> {{ news.title }} </a> <span>-{% get_domain news.url %}</span> <a href=""> <span class="item-title-a">{{ news.category }}</span> </a> </div> <div class="item-pic"> <img src="{{ news.avatar }}" style="max-height:80px; max-width: 80px;"> </div> </div> <div class="item-footer"> <div style="display: inline-block; position: relative;"> <a class="recommend" news-id="{{ news.id }}" title="推荐"> <span class="item-icon icon1"></span> <b>{{ news.like_count }}</b> </a> </div> <a href="" class="comment" title="评论"> <span class="item-icon icon2"></span> <b>{{ news.comment_count }}</b> </a> <a href="" class="collection" title="加入私藏"> <span class="item-icon icon3"></span> <b>私藏</b> </a> <a href="" class="from_where"> <span> <img src="" > </span> <b>{{ news.author }}</b> </a> <span class="timestamp"> <a href="" target="_blank"> <b>{{ news.ctime }}</b> </a> <i>入热榜</i> </span> <span class="share-to"> <i>分享到</i> <span class="share-icon"> <a href="" class="icon-sina" title="分享到新浪微博"></a> <a href="" class="icon-douban" title="分享到豆瓣"></a> <a href="" class="icon-qqzone" title="分享到qq空间"></a> <a href="" class="icon-renren" title="分享到人人"></a> </span> </span> </div> </div> {% endfor %} </div> <div class="mypagination"> {{ page_str|safe }} </div> </div> <div class="content-right"> </div> </div> <a href="javascript:scroll(0,0)" target="_self" id="gotop"></a> </div> <div class="content-footer"> <div class="content-footer-div"> <div class="foot-nav"> <a href="" target="_blank">关于我们</a> <span>|</span> <a href="" target="_blank">联系我们</a> <span>|</span> <a href="" target="_blank">服务条款</a> <span>|</span> <a href="" target="_blank">隐私政策</a> <span>|</span> <a href="" target="_blank">抽屉新热榜工具</a> <span>|</span> <a href="" target="_blank">下载客户端</a> <span>|</span> <a href="" target="_blank">意见与反馈</a> <span>|</span> <a href="" target="_blank">友情链接</a> <span>|</span> <a href="" target="_blank">公告</a> <p> © http://www.cnblogs.com/standby/ ®谢绝转载! </p> </div> </div> </div> <div class="modal fade" id="login" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="exampleModalLabel">登录</h4> </div> <div class="modal-body"> <form id="login-form"> {% csrf_token %} <div class="form-group"> <label for="username" class="control-label">用户名:</label> <input type="text" class="form-control" id="username" name="username"> </div> <div class="form-group"> <label for="password" class="control-label">密码:</label> <input type="password" class="form-control" id="password" name="password"> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal">取消</button> <button type="button" class="btn btn-primary to_login">登录</button> </div> </div> </div> </div> <div class="modal fade" id="register" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="exampleModalLabel">注册</h4> </div> <form id="register-form"> {% csrf_token %} <div class="modal-body"> <div class="form-group"> <label for="username" class="control-label">用户名:</label> <input type="text" class="form-control" id="username" name="username"> </div> <div class="form-group"> <label for="password" class="control-label">密码:</label> <input type="password" class="form-control" id="password" name="password"> </div> <div class="form-group"> <label for="email" class="control-label">邮件:</label> <input type="email" class="form-control" id="email" name="email"> </div> </div> <div class="modal-footer"> <button type="submit" class="btn btn-primary to_add_user">添加</button> <button type="button" class="btn btn-default" data-dismiss="modal">取消</button> </div> </form> </div> </div> </div> </body> <script> $(function () { bindLikeEvent(); $("#register-form").bootstrapValidator({ message: ‘This value is not valid‘, excluded : [‘:disabled‘],//[‘:disabled‘, ‘:hidden‘, ‘:not(:visible)‘] feedbackIcons: { valid: ‘glyphicon glyphicon-ok‘, invalid: ‘glyphicon glyphicon-remove‘, validating: ‘glyphicon glyphicon-refresh‘ }, fields: { username: {/*键名username和input name值对应*/ message: ‘用户名无效‘, validators: { notEmpty: {/*非空提示*/ message: ‘用户名不能为空‘ }, stringLength: {/*长度提示*/ min: 3, max: 20, message: ‘用户名长度必须在3到20之间‘ }/*最后一个没有逗号*/ } }, password: { message:‘密码无效‘, validators: { notEmpty: { message: ‘密码不能为空‘ }, stringLength: { min: 3, max: 30, message: ‘密码长度必须在3到30之间‘ } } }, email: { validators: { notEmpty: { message: ‘邮箱不能为空‘ }, emailAddress: { message: ‘邮箱格式错误‘ } } } } }) }); function showLikeCount($this,mytext) { var fontSize = 5; var top = 0; var right = 0; var opacity = 1; var tag = document.createElement(‘span‘); tag.innerText = mytext; // 外层div用relative,内层标签用absolute tag.style.position = "absolute"; // 默认大小 tag.style.fontSize = fontSize + "px"; tag.style.top = top + ‘px‘; tag.style.right = right + ‘px‘; tag.style.opacity = opacity; $this.after(tag); // 定时器:每0.1s执行一次,模拟动画效果 // JS的闭包:obj 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); } function bindLikeEvent() { $(".recommend").click(function () { var $news_id = $(this).attr("news-id"); var $this = $(this); $.ajaxSetup({ data: {‘csrfmiddlewaretoken‘:‘{{ csrf_token }}‘} }); $.ajax({ url:‘/do_like/‘, type:‘POST‘, data:{‘news_id‘:$news_id}, success:function (data) { var ret=JSON.parse(data); if(ret.status){ var origin = $this.text(); var count = parseInt(origin); if (0 == ret.code){ $this.text(count+1); showLikeCount($this,"+1"); } else if(1 == ret.code){ $this.text(count-1); showLikeCount($this,"-1"); } }else { alert("点赞操作失败!"+ret.msg); } } }) }); } $(".to_add_user").click(function () { $.ajaxSetup({ data: {csrfmiddlewaretoken: ‘{{ csrf_token }}‘} }); $.ajax({ url:"/register/", type:"POST", data:$(‘#register-form‘).serialize(), success:function (data) { var dic=JSON.parse(data); if(dic["flag"]){ alert(dic["msg"]); } else { alert(dic["msg"]); } } }); $(this).attr("data-dismiss","modal"); }); $(".to_login").click(function () { $.ajaxSetup({ data: {csrfmiddlewaretoken: ‘{{ csrf_token }}‘} }); $.ajax({ url:"/login/", type:"POST", data:$(‘#login-form‘).serialize(), success:function (data) { var dic=JSON.parse(data); if(dic["flag"]){ alert(dic["msg"]); } else { alert(dic["msg"]); } window.location.href = ‘/index/‘; } }); $(this).attr("data-dismiss","modal"); }); </script> {% endblock %} </html>
# new_article.html {% extends "index.html" %} {% block content %} <div class="col-sm-8 col-lg-offset-2" style="padding-top: 100px;"> <ul class="nav nav-tabs article_type"> <li class="active" relation="url2news"><a href="javascript:">连接</a></li> <li relation="text2news"><a href="javascript:">文字</a></li> <li relation="pic2news"><a href="javascript:">图片</a></li> </ul> </div> <div class="col-sm-8 col-lg-offset-2" style="padding-top: 20px;"> <div id="url2news"> <form method="post"> {% csrf_token %} <div class="form-group"> <div class="col-sm-12"> <label for="link" >添加链接</label> </div> <div class="col-sm-10"> <input type="text" class="form-control" id="link" name="link" placeholder="http://"> </div> <button type="button" class="btn btn-info col-md-2" id="get_title">获取标题</button> </div> <div class="form-group container-fluid"> <label for="title">标题</label> <input type="text" class="form-control" id="title" name="title" placeholder=""> </div> <div class="form-group container-fluid"> <label for="summary">添加摘要(选填)</label> <textarea class="form-control" id="summary" name="summary" rows="3"></textarea> </div> <div class="form-group"> <label for="category" class="col-md-2">发布到</label> <div class="col-md-4"> <select class="form-control" name="category" id="category"> {% for category in category_list %} <option>{{ category }}</option> {% endfor %} </select> </div> <div class="col-md-3 col-lg-offset-3"> <button type="button" class="btn btn-default" id="empty_btn">清空</button> <button type="submit" class="btn btn-success" id="publisher">发布</button> </div> </div> </form> </div> <div id="text2news" class="be_hidden"> <form action=""> {% csrf_token %} <div style="background-color: powderblue; border-radius: 10px ;"> <div class="form-group container-fluid"> <label for="summary">添加文字</label> <textarea class="form-control text2news-desc" id="summary" name="summary" rows="3"></textarea> </div> <div class="form-group container-fluid"> 您还可以输入<span class="char_notice-text2news" style="color: red">150</span>个字 </div> </div> <div class="form-group"> <label for="category" class="col-md-2">发布到</label> <div class="col-md-4"> <select class="form-control" name="category" id="category"> {% for category in category_list %} <option>{{ category }}</option> {% endfor %} </select> </div> <div class="col-md-3 col-lg-offset-3"> <button type="button" class="btn btn-default" id="empty_btn">清空</button> <button type="submit" class="btn btn-success" id="publisher">发布</button> </div> </div> </form> </div> <div id="pic2news" class="be_hidden"> <form id="pic2news-form" method="post" target="iframe4pic" action="/upload_img2/" enctype="multipart/form-data"> {% csrf_token %} <div class="form-group container-fluid"> <label for="upload_img">选择图片</label> <a href="javascript:" id="nice-input-file"> 上传<input type="file" id="upload_img" name="avatar" onchange="auto_submit()"> </a> <p class="help-block">支持jpg、jpeg、gif、png格式,且不超过5MB</p> </div> </form> <iframe id="ifm" name="iframe4pic" onload="successCallback(this);" style="display: none;" ></iframe> <div id="pic-preshow" class="be_hidden" style="height: 150px;"></div> <div style="background-color: powderblue; border-radius: 10px ;"> <div class="form-group container-fluid"> <label for="pic_summary">添加描述</label> <textarea class="form-control pic2news-desc" id="pic_summary" name="pic_summary" rows="3" placeholder="描述不能为空"></textarea> </div> <div class="form-group container-fluid"> 您还可以输入<span class="char_notice-pic2news" style="color: red">150</span>个字 </div> </div> <label for="category" class="col-md-2">发布到</label> <div class="col-md-4"> <select class="form-control" name="pic_category" id="pic_category"> {% for category in category_list %} <option>{{ category }}</option> {% endfor %} </select> </div> <div class="col-md-3 col-lg-offset-3"> <button type="button" class="btn btn-default" id="pic_empty_btn">清空</button> <button type="submit" class="btn btn-success" id="pic_publisher">发布</button> </div> </div> </div> <script> function myValidator() { $("#pic2news-form").bootstrapValidator({ message: ‘This value is not valid‘, excluded : [‘:disabled‘],//[‘:disabled‘, ‘:hidden‘, ‘:not(:visible)‘] feedbackIcons: { valid: ‘glyphicon glyphicon-ok‘, invalid: ‘glyphicon glyphicon-remove‘, validating: ‘glyphicon glyphicon-refresh‘ }, fields: { pic_summary: { message: ‘图片描述不能为空‘, validators: { notEmpty: {/*非空提示*/ message: ‘图片描述不能为空‘ }, stringLength: {/*长度提示*/ min: 1, max: 150, message: ‘图片描述字数必须在1到150之间‘ } } } } }) } $(function () { {# myValidator();#} }); function auto_submit() { console.log(‘auto_submit ...‘); $("#pic2news-form").submit(); } function successCallback(ths){ console.log("successCallback ..."); var response = ths.contentWindow.document.body.innerHTML; response = JSON.parse(response); console.log(response); var img = document.createElement(‘img‘); img.src = "/" + response.data; img.style.maxWidth = "100%"; img.style.maxHeight = "100%"; $("#pic-preshow").removeClass(‘be_hidden‘); $(‘#pic-preshow‘).empty(); $(‘#pic-preshow‘).append(img); } $("#pic_publisher").click(function () { var $pic_path = $("#pic-preshow").find("img").attr("src"); if(0 == $("#pic_summary").val().length || typeof($pic_path) == "undefined"){ alert("请确保图片和描述都正确填写!"); }else { $.ajax({ url:‘/new_article/‘, type:‘POST‘, data:{ ‘pic_summary‘:$("#pic_summary").val(), ‘avatar‘:$pic_path, ‘category‘:$("#pic_category").val() }, headers:{‘X-CSRFToken‘: $.cookie(‘csrftoken‘)}, success:function (data) { var dic=JSON.parse(data); if(dic[‘flag‘]){ window.location.href = ‘/index/‘; }else { alert("提交失败,请重试!"); } } }) } }); // tab切换 $(".article_type li").click(function () { $(this).siblings().removeClass(‘active‘); $(this).addClass(‘active‘); // alert($(this).children().eq(0).attr(‘id‘)); // 更改 category_manage 对应的 content 显示 // 通过在 li 标签里埋了一个自定义属性,对应到content里面id值 var $id_val = $(this).attr("relation"); var $sel = "#" + $id_val; // 拼接字符串 $($sel).removeClass(‘be_hidden‘); $($sel).siblings().addClass(‘be_hidden‘); }); $("#get_title").click(function () { $.ajaxSetup({ data: {csrfmiddlewaretoken: ‘{{ csrf_token }}‘} }); $.ajax({ url:"/crawling/", type:"GET", data:{‘url‘:$(‘#link‘).val()}, success:function (data) { var dic=JSON.parse(data); if(dic["flag"]){ $("#title").val(dic[‘title‘]); $(‘#summary‘).val(dic[‘desc‘]); } else { alert(dic["msg"]); } } }); }); $("#empty_btn").click(function () { $("#link").val(""); $("#title").val(""); $("#summary").val(""); }); $("#pic_empty_btn").click(function () { $("#pic_summary").val(""); $("#pic-preshow").addClass(‘be_hidden‘); $(".char_notice-pic2news").text(150); myValidator(); }); $(".text2news-desc").keyup(function () { var $maxChars = 150;//最多字符数 var $curr = $(".text2news-desc").val().length; if ($curr < $maxChars){ var $left = $maxChars - $curr; $(".char_notice-text2news").text($left); } }); $(".pic2news-desc").keyup(function () { var $maxChars = 150;//最多字符数 var $curr = $(".pic2news-desc").val().length; if ($curr < $maxChars){ var $left = $maxChars - $curr; $(".char_notice-pic2news").text($left); } }); </script> {% endblock %}
# bbs.css * { margin: 0; padding: 0; } .be_hidden { display: none; } #nice-input-file{ position: relative; display: inline-block; width: 60px; height: 30px; background-color: darkslateblue; color: white; text-align: center; line-height: 30px; border-radius: 7px; text-decoration: none; } #upload_img { position:absolute; opacity: 0; left: 0; top: 0; right: 0; bottom: 0; } .header { top: 0; left: 0; position: fixed; z-index: 1000; width: 100%; height: 44px; background-color: #2459a2; } .my_nav li,.nav2 li { display: inline-block; font-size: 12px; line-height: 44px; } .my_nav li a { text-decoration: none; color: #c0cddf; height: 43px; padding: 0 12px 0 12px; display: inline-block; } .nav2 li a { text-decoration: none; color: white; height: 43px; padding: 0 20px 0 20px; display: inline-block; } .my_nav li a:hover { color: yellow; background-color: #396bb3; } .my_nav li:active { color: black; background-color: #396bb3; } .nav2 li a:hover,a:active { color: white; background-color: #396bb3; } /*.nav li a:visited {*/ /*color: white;*/ /*background-color: #204982;*/ /*}*/ .logo { line-height: 44px; margin-top: 0; float: left; margin-left: 170px; width: 25%; /*vertical-align: middle;*/ } .head_btn1 { /*border: 1px solid mediumvioletred;*/ margin-left: -200px; float: left; width: 30%; } .head_btn2 { /*border: 1px solid yellow;*/ float: left; width: 10%; margin-left: 170px; } .head_btn3 { /*border: 1px solid red;*/ float: right; width: 24%; } .head_btn3 input{ width: 120px; height: 30px; margin-top: 7px; /*margin-left: -120px;*/ float: left; border-style: none; /*background-color: #f4f4f4;*/ background-color: rgb(244, 244, 244); } .head_btn3 input:focus { background-color: white; } .head_btn3 a { display: inline-block; width: 30px; height: 30px; background-color: #f4f4f4; float: left; margin-top: 7px; border-left: 1px solid lightgray; } .select_icon { display: block; width: 11px; height: 12px; /*border: 1px solid red;*/ background-image: url(‘../image/icon.png‘); /*background-position-x: 0px;*/ /*background-position-y: -197px;*/ background-position: 0 -197px; background-repeat: no-repeat; margin-top: 9px; margin-left:9px; } .page_body { background-color: #ededed; padding-top: 44px; } .main-content { background-color: white; display: block; /*border: 1px solid red;*/ width: 1008px; height: 2696px; margin-top: 0; margin-left: 166.5px; margin-right: 106.5px; } .content-left { /*border: 1px solid blue;*/ float: left; width: 69.5%; height: 2696px; } .content-right { /*border: 1px solid green;*/ float: right; width: 30%; height: 2696px; background-image: url(‘../image/wld.png‘); background-repeat: repeat; } .content-top-area { /*border: 1px solid crimson;*/ width: 94%; height: 20px; margin-top: 37px; margin-left: 3%; margin-right: 3%; /*border-bottom: 1px solid lightgray;*/ border-bottom: 1px solid #dce7f4; } .content-top-area a { text-decoration: none; } .child-nav { float: left; /*border: 1px solid red;*/ width: 190.5px; height: 42px; margin-top: -25px; } .icons { background: url(‘../image/tip.png‘) no-repeat 0 0; } .child-nav .active { background-position: 0 -299px; color: #333; text-decoration: none; } .child-nav a { display: inline-block; width: 60px; height: 26px; line-height: 26px; margin-top: 3px; margin-bottom: 13px; color: #369; font-size: 12px; font-weight: 700; text-align: center; } .child-nav a:active #hotest { text-decoration: none; } .child-nav a:active { background: url(‘../image/tip.png‘) no-repeat 0 0; background-position: 0 -299px; color: #333; text-decoration: none; } .child-nav a:hover, .sort-nav a:hover { text-decoration: underline; } .sort-nav { float: left; /*border: 1px solid blue;*/ width: 141.17px; height: 20px; margin-left: 180px; margin-top: -20px; } .sort-nav a { display: inline-block; margin-left: 5px; color: #390; text-align: center; font-size: 5px; /*word-wrap: break-word;*/ /*word-break: break-all;*/ } .sort-nav .active { color: #b4b4b4; } .add-new-msg { float: right; background-color: #84a42b; border: 1px solid #8aab30; color: #fff; display: inline-block; height: 30px; line-height: 30px; text-align: center; width: 134px; font-size: 15px; margin-top: -25px; } .ico { background: url(‘../image/icon.png‘) no-repeat 0 0; } .n1 { height: 12px; width: 11px; background-position: 0 -184px; display: inline-block; } .n2 { font-weight: 400; margin-left: 8px; } /*.right_pic {*/ /*width: 100%;*/ /*height: 500px;*/ /*background-repeat: repeat;*/ /*}*/ .content-list { } .item { /*border: 1px solid red;*/ width: 94%; margin-top: 0; margin-left: 3%; margin-right: 3%; border-bottom: 1px solid #dce7f4; padding-top: 10px; padding-bottom: 10px; } .item .item-title { float: left; width: 90%; margin-bottom: 40px; } .item .item-pic { float: right; width: 10%; max-height: 80px; max-width: 80px; display: inline-block; position: absolute; } .item-pic:active { z-index: 99; } .item-pic:active>img{ transform: scale(2,2); /*transform-origin: 0 0;*/ transform-origin:100% 0; transition: .3s transform; } .item .item-title .a-link { text-decoration: none; } .item .item-title .a-link:hover { text-decoration: underline; } .item span { display: inline-block; } .item-body { /*border: 1px solid blue;*/ overflow: hidden; /*子div撑起父div*/ } .item-footer { /*border: 1px solid rebeccapurple;*/ } .item-title .item-title-a { text-decoration: underline; } .item-footer a{ margin-right: 10px; text-decoration: none; } .item-footer a:hover b{ text-decoration: underline; color: #369; } .item-footer b { color: #99aecb; margin-left: 7px; font-size: 14px; font-weight: 700; margin-top: 10px; } .item-footer .item-icon { background: url(‘../image/icon_18_118.png‘) no-repeat 0 0; vertical-align: bottom; /*让icon和文本水平对齐*/ } .item-footer .icon1 { background-position: 0 -40px; width: 18px; height: 18px; } .item-footer a:hover .icon1{ background-position: 0 0; } .item-footer .icon2 { background-position: 0 -100px; width: 18px; height: 18px; } .item-footer a:hover .icon2 { background-position: 0 -80px; } .item-footer .icon3 { background-position: 0 -160px; width: 18px; height: 18px; } .item-footer a:hover .icon3 { background-position: 0 -140px; } .timestamp b { color: #e59373; margin-left: 0; vertical-align: 0; font-weight: 400; margin-right: -18px; } .item-footer .share-to { display: none; color: #ccc; margin-top: -2px; } .item-footer i { font-style: normal; vertical-align: bottom; font-size: 14px; color: #cccccc; } .item-footer .share-to .share-icon a { background: url(‘../image/share_icon_.png‘) no-repeat 0 0; width: 13px; height: 13px; display: inline-block; _display: inline; margin-right: 7px; margin-top: 2px; } .item:hover .item-footer .share-to{ display: inline-block; } .share-to .share-icon a.icon-sina { background-position: 0 0; width: 17px; height: 14px; } .share-to .share-icon a.icon-sina:hover { background-position: 0 -90px; width: 17px; height: 14px; } .share-to .share-icon a.icon-douban { background-position: 0 -15px; } .share-to .share-icon a.icon-douban:hover { background-position: 0 -105px; } .share-to .share-icon a.icon-qqzone { background-position: 0 -30px; width: 16px; height: 14px; } .share-to .share-icon a.icon-qqzone:hover { background-position: 0 -120px; width: 16px; height: 14px; } .share-to .share-icon a.icon-renren { background-position: 0 -60px; } .share-to .share-icon a.icon-renren:hover { background-position: 0 -151px; } .ret_top a { width: 80px; height: 50px; background-color: darkgray; /*opacity: 0.9;*/ text-align: center; line-height: 50px; position: fixed; bottom: 20px; right: 20px; color: blue; } #gotop { background: url(‘../image/back_to_top.png‘) 0 0 no-repeat; bottom: 30px; left: 90%; cursor: pointer; height: 38px; width: 38px; position: fixed; z-index: 2; } .page_num { margin-top: 20px; /*border: 1px solid red;*/ width: 94%; margin-left: 3%; margin-right: 3%; overflow: hidden; clear: both; border-bottom: 1px solid #dce7f4; } .page_num ul { margin-top: 20px; margin-bottom: 80px; } .page_num ul li { display: inline; float: left; margin-left: 10px; } .page_num ul li span { float: left; color: #369; height: 34px; line-height: 34px; text-align: center; width: 34px; border: 1px solid #e1e1e1; } .page_num ul li a { float: left; color: #369; height: 34px; line-height: 34px; text-align: center; width: 34px; border: 1px solid #e1e1e1; text-decoration: none; border-radius: 4px; } .page_num ul li a.next_page { margin-right: 9px; width: 77px; font-weight: 400; } .page_num ul li span.page_now { font-weight: 700; color: #333; border: none; } .page_num ul li a:hover { color: #fff; background-color: #369; border: 1px solid #369; } .content-footer { background-color: #ededed; } /*.content-footer:before {*/ /*float: left;*/ /*border: 1px solid mediumvioletred;*/ /*height: 50px;*/ /*width: 10%;*/ /*!*clear: both;*!*/ /*content: "";*/ /*}*/ /*.content-footer:after {*/ /*float: right;*/ /*border: 1px solid blue;*/ /*height: 50px;*/ /*width: 10%;*/ /*!*clear: both;*!*/ /*content: "";*/ /*}*/ .content-footer-div:before { float: left; /*border: 1px solid mediumvioletred;*/ height: 50px; width: 2%; /*clear: both;*/ content: ""; } .content-footer-div:after { float: right; /*border: 1px solid blue;*/ height: 50px; width: 2%; /*clear: both;*/ content: ""; } .content-footer-div { /*border: 1px solid red;*/ /*float: left;*/ /*width: 79%;*/ width: 1008px; margin-left: 166.5px; margin-right: 106.5px; background-color: white; text-align: center; /*border-top: 1px solid #ccdcef;*/ position: relative; padding-top: 30px; padding-bottom: 100px; } .foot-nav { /*border: 1px solid mediumvioletred;*/ padding-top: 15px; border-top: 2px solid #dce7f4; float: left; width: 95%; } .content-footer-div a { text-decoration: none; } .content-footer-div a:hover { text-decoration: underline; } .content-footer-div .foot-nav span { color: #5681ab; display: inline-block; height: 15px; overflow: hidden; } .content-footer-div p { margin-top: 10px; text-align: center; color: darkgray; } .mypagination a{ display: inline-block; padding: 5px 8px; background-color: darkslateblue; margin: 5px; color: white; } .mypagination a.active{ background-color: green; }
# urls.py from django.conf.urls import url from django.contrib import admin from bbs import views from bbs import forms urlpatterns = [ url(r‘^admin/‘, admin.site.urls), url(r‘^index/‘, views.IndexView.as_view()), url(r‘^category/(?P<category_id>\\d+)/‘, views.IndexView.as_view()), url(r‘^register/‘, views.RegisterView.as_view()), url(r‘^login/‘, views.IndexView.as_view()), url(r‘^logout/‘, views.logout), url(r‘^new_article/‘, views.NewArticleView.as_view()), url(r‘^crawling/‘, views.crawling), url(r‘^do_like/‘, views.LikeView.as_view()), url(r‘^comment_show/‘, views.comment_tree), url(r‘^upload_img/‘, views.UploadView.as_view()), url(r‘^upload_img2/‘, views.upload_img2), url(r‘^iframe/‘, views.iframe), url(r‘^iframe2/‘, views.iframe2), # url(r‘^‘, views.IndexView.as_view()), ]
# models.py from django.db import models # Create your models here. class UserInfo(models.Model): """用户表""" username = models.CharField(max_length=32) password = models.CharField(max_length=64) email = models.CharField(max_length=32,null=True) def __str__(self): return self.username class NewsCategory(models.Model): """新闻类型表""" caption = models.CharField(max_length=16) def __str__(self): return self.caption class NewsInfo(models.Model): """新闻表""" title = models.CharField(max_length=32,verbose_name="标题") summary = models.CharField(max_length=255,verbose_name="简介",null=True) url = models.CharField(max_length=255,verbose_name="URL",null=True) avatar = models.CharField(max_length=255,verbose_name="文章配图",null=True) ctime = models.DateTimeField(auto_now_add=True,verbose_name=‘创建时间‘) category = models.ForeignKey(to="NewsCategory",verbose_name="类别") author = models.ForeignKey(to="UserInfo",verbose_name="作者") # 点赞和评论时,记着更新like_count,comment_count。自增1/自减1: F 实现 like_count = models.IntegerField(default=0) comment_count = models.IntegerField(default=0) def __str__(self): return self.title class Comment(models.Model): """评论记录表""" content = models.CharField(max_length=255,verbose_name="评论内容") user = models.ForeignKey(to="UserInfo",verbose_name="评论者") news = models.ForeignKey(to="NewsInfo",verbose_name="评论的文章") ctime = models.DateTimeField(auto_now_add=True,verbose_name=‘评论时间‘) """多级评论需要 自关联""" parent = models.ForeignKey("Comment",related_name="pid",null=True,blank=True) def __str__(self): return self.content class Like(models.Model): """点赞记录表""" user = models.ForeignKey(to="UserInfo",verbose_name="点赞者") news = models.ForeignKey(to="NewsInfo",verbose_name="点赞的文章") ctime = models.DateTimeField(auto_now_add=True,verbose_name="点赞时间") # 建立联合唯一索引,限定每个用户给每篇文章只能点赞一次 class Meta: unique_together = [ (‘user‘,‘news‘), ]
# views.py from django.shortcuts import render,HttpResponse,redirect # Create your views here. import re import json from bbs import models from django.forms import Form from django.forms import fields from django.forms import widgets from django.views import View from django.db.models import F from django.db import transaction from common import md5 from common.my_response import BaseResponse from common.my_response import LikeResponse from common.paginator import Paginator from django.http.request import QueryDict class AuthView(object): def dispatch(self, request, *args, **kwargs): if request.session.get(‘user‘): response = super(AuthView,self).dispatch(request, *args, **kwargs) return response else: return redirect(‘/login/‘) class IndexView(View): def get(self, request, *args, **kwargs): category_list = models.NewsCategory.objects.all() category_id = kwargs.get(‘category_id‘) print(request.GET, type(request.GET)) # <QueryDict: {‘page‘: [‘3‘]}> <class ‘django.http.request.QueryDict‘> print(request.GET.urlencode()) # page = 3 """mutable这个值默认是False,是不允许修改的""" obj = QueryDict(mutable=True) obj[‘_url_parameter‘] = request.GET.urlencode() # page=3 obj[‘prev_path‘] = request.path_info # /category/3/ url_param = obj.urlencode() print(url_param) # _url_parameter=page%3D3 """这样在跳转到发布新文章的页面的时候就会:http://127.0.0.1:8000/new_article/?_url_parameter=page%3D3""" # 前端请求的url:http://127.0.0.1:8001/index/?page=2 current_page = request.GET.get(‘page‘) # 初开始访问的是 http://127.0.0.1:8001/index 所以要做判断 if not current_page: current_page = 1 else: current_page = int(current_page) if category_id: category_id = int(category_id) all_count = models.NewsInfo.objects.filter(**kwargs).count() pager = Paginator(all_count=all_count, current_page=current_page, base_url=request.path_info) news_list = models.NewsInfo.objects.filter(**kwargs)[pager.start:pager.end] else: # 首先获得数据总条数 all_count = models.NewsInfo.objects.all().count() pager = Paginator(all_count=all_count, current_page=current_page, base_url=request.path_info) # 通过切片的形式从数据库中拿到对应页数的items news_list = models.NewsInfo.objects.all()[pager.start:pager.end] page_str = pager.page_html return render(request, ‘index.html‘, locals()) def post(self, request, *args, **kwargs): response = {‘flag‘: False, ‘msg‘: None} username = request.POST.get(‘username‘) password = request.POST.get(‘password‘) obj = models.UserInfo.objects.filter(username=username, password=md5.encrypt(password)).first() if obj: request.session[‘user‘] = username request.session.set_expiry(3600) response[‘flag‘] = True response[‘msg‘] = username + "登录成功" else: response[‘flag‘] = False response[‘msg‘] = "用户名或密码错误" # return render(request,‘index.html‘,locals()) return HttpResponse(json.dumps(response)) class RegisterView(View): def post(self, request, *args, **kwargs): response = {‘flag‘: False, ‘msg‘: None} username = request.POST.get(‘username‘) password = request.POST.get(‘password‘) if len(password) >= 3 and len(password) < 30 and len(username) >= 3 and len(username) < 20: email = request.POST.get(‘email‘) patten = re.compile("[\\w!#$%&‘*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&‘*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[\\w](?:[\\w-]*[\\w])?") if re.match(patten,email): models.UserInfo.objects.create(username=username,password=md5.encrypt(password),email=email) else: models.UserInfo.objects.create(username=username, password=md5.encrypt(password)) response[‘flag‘] = True response[‘msg‘] = "注册成功!" else: response[‘msg‘] = "注册失败!用户名密码长度不符合规定。" return HttpResponse(json.dumps(response)) def logout(request): # 用户登出后清空session request.session.clear() return redirect(‘/index/‘) class NewArticleView(AuthView,View): def get(self, request, *args, **kwargs): category_list = models.NewsCategory.objects.all() return render(request,‘new_article.html‘,locals()) def post(self, request, *args, **kwargs): category = request.POST.get("category") category_obj = models.NewsCategory.objects.filter(caption=category).first() author = request.session.get(‘user‘) author_obj = models.UserInfo.objects.filter(username=author).first() url = request.POST.get("link") if url: title = request.POST.get("title") summary = request.POST.get("summary") models.NewsInfo.objects.create(title=title,summary=summary,url=url,category=category_obj,author=author_obj) url_params = request.GET.get(‘_url_parameter‘) url_path = request.GET.get(‘prev_path‘) print("$$$$$$$$$$$$$ ",url_path) print(">>>>> ",url_params) url = url_path + "?" + url_params print("++++++++++++++++ ",request.META) return redirect(url) # return redirect(‘/index/‘) else: ret = {‘flag‘:False,‘msg‘:None} title = request.POST.get("pic_summary") avatar = request.POST.get(‘avatar‘) try: models.NewsInfo.objects.create(title=title, avatar=avatar, category=category_obj, author=author_obj) except Exception as e: ret[‘msg‘] = e else: ret[‘flag‘] = True return HttpResponse(json.dumps(ret)) def crawling(request): if ‘GET‘ == request.method: data = {‘title‘: None, ‘desc‘: None, ‘flag‘:False, ‘msg‘:None} url = request.GET.get(‘url‘) try: import requests from bs4 import BeautifulSoup response = requests.get(url) ‘‘‘ ISO-8859-1 需要把这个转换成 utf-8/gbk 否则前端会出现乱码 ‘‘‘ if request.encoding not in [‘gbk‘,‘GB2312‘,‘UTF-8‘,‘utf-8‘]: response.encoding = ‘utf-8‘ soup = BeautifulSoup(response.text, ‘html.parser‘) title = soup.find(‘title‘).text if soup.find(‘meta‘, attrs={‘name‘: ‘description‘}): data[‘desc‘] = soup.find(‘meta‘, attrs={‘name‘: ‘description‘}).get(‘content‘) data[‘title‘] = title data[‘flag‘] = True except Exception as e: data[‘msg‘] = e return HttpResponse(json.dumps(data)) class LikeView(AuthView,View): def post(self, request, *args, **kwargs): response = LikeResponse() try: news_id = request.POST.get("news_id") username = request.session.get("user") user_obj = models.UserInfo.objects.filter(username=username).first() like_exist = models.Like.objects.filter(user_id=user_obj.id, news_id=news_id).count() # django的事务:涉及到2次数据库操作,要么一起成功,要么一起失败,避免产生脏数据 with transaction.atomic(): if like_exist: models.Like.objects.filter(user_id=user_obj.id, news_id=news_id).delete() # from django.db.models import F -> F操作实现点赞个数加减1 models.NewsInfo.objects.filter(id=news_id).update(like_count=F(‘like_count‘) - 1) response.code = 1 else: models.Like.objects.create(user_id=user_obj.id,news_id=news_id) models.NewsInfo.objects.filter(id=news_id).update(like_count=F(‘like_count‘)+1) response.code = 0 except Exception as e: response.msg = str(e) print(‘>>>>>>>>> ‘,e) else: response.status = True return HttpResponse(json.dumps(response.dict_info)) def get_comment_list(li): dic = {} for item in li: item["children"] = [] dic[item["id"]] = item result = [] for item in li: pid = item[‘parent_id‘] if pid: dic[item["parent_id"]]["children"].append(item) else: result.append(item) return result def get_comment_tree(result): """ {‘parent_id‘: None, ‘content‘: ‘灌我鸟事‘, ‘id‘: 1, ‘user‘: ‘银秋良‘, ‘children‘: [{‘parent_id‘: 1, ‘content‘: ‘你个文盲‘, ‘id‘: 3, ‘user‘: ‘型谱‘, ‘children‘: [{‘parent_id‘: 3, ‘content‘: ‘你是流氓‘, ‘id‘: 5, ‘user‘: ‘银秋良‘, ‘children‘: [{‘parent_id‘: 5, ‘content‘: ‘你冷库无情‘, ‘id‘: 6, ‘user‘: ‘银秋良‘, ‘children‘: []}]}]}]} {‘parent_id‘: None, ‘content‘: ‘管我鸟事‘, ‘id‘: 2, ‘user‘: ‘银秋良‘, ‘children‘: [{‘parent_id‘: 2, ‘content‘: ‘好羡慕你们这些没脸的人呀‘, ‘id‘: 4, ‘user‘: ‘详解‘, ‘children‘: [{‘parent_id‘: 4, ‘content‘: ‘你才冷酷无情‘, ‘id‘: 7, ‘user‘: ‘银秋良‘, ‘children‘: []}, {‘parent_id‘: 4, ‘content‘: ‘你无理取闹‘, ‘id‘: 8, ‘user‘: ‘银秋良‘, ‘children‘: []}]}]} """ tpl = """ <div class="item"> <div class="title">{0}:{1} <a href="">回复</a></div> <div class="body">{2}</div> </div> """ html = "" """递归遍历所有子评论""" for item in result: if not item["children"]: html += tpl.format(item["user"],item["content"],"") else: html += tpl.format(item["user"],item["content"],get_comment_tree(item["children"])) return html def comment_tree(request): 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}, ] result = get_comment_list(li) html = get_comment_tree(result) return render(request,‘demo.html‘,locals()) from django.views.decorators.csrf import csrf_protect,csrf_exempt class UploadView(AuthView,View): def post(self, request, *args, **kwargs): import os,json obj = request.FILES.get(‘pic‘) img_path = os.path.join(‘statics‘, ‘image‘, obj.name) with open(img_path, mode=‘wb‘) as f: for chunk in obj.chunks(): f.write(chunk) data = { ‘status‘: True, ‘path‘: img_path.replace("statics","static") } return HttpResponse(json.dumps(data)) def iframe(request): return render(request,‘iframe_test.html‘) def iframe2(request): return render(request, ‘iframe_demo.html‘) def upload_img2(request): print("?????????????????????") import os response = BaseResponse() try: print("ok") user = request.POST.get(‘user‘) print(user) obj = request.FILES.get(‘avatar‘) print(obj) img_path = os.path.join(‘statics‘, ‘image‘, obj.name) print(">>>>>>>>>",img_path) with open(img_path, mode=‘wb‘) as f: for chunk in obj.chunks(): f.write(chunk) except Exception as e: print("error") response.msg = str(e) print(e) else: response.status = True response.data = img_path.replace("statics","static") return HttpResponse(json.dumps(response.dict_info))
# 自定义templatetags from django import template from django.utils.safestring import mark_safe register = template.Library() @register.simple_tag def get_domain(url): from urllib import parse domain = parse.urlparse(url) return domain.netloc
# md5.py def encrypt(pwd): import hashlib obj = hashlib.md5() obj.update(pwd.encode(‘utf-8‘)) data = obj.hexdigest() return data
# my_response.py class BaseResponse(object): def __init__(self): self.status = False self.msg = None self.data = None @property def dict_info(self): return self.__dict__ class LikeResponse(BaseResponse): def __init__(self): self.code = None super(LikeResponse,self).__init__() if __name__ == ‘__main__‘: like = LikeResponse() print(like.dict_info)
# paginator.py class Paginator(object): def __init__(self,all_count,current_page,base_url,per_page=10,per_page_count=11): """ 分页组件的初始化 :param all_count: 数据的总条数 :param current_page: 当前页码 :param base_url: 基础url :param per_page: 每页显示的条目数 :param per_page_count: 显示的页码数 """ self.all_count = all_count self.current_page = current_page self.base_url = base_url self.per_page = per_page self.per_page_count = per_page_count # 计算得出真实的页码数 pager_count, remainder = divmod(self.all_count, self.per_page) if 0 != remainder: pager_count += 1 self.pager_count = pager_count # 默认每次显示11个页码(除上一页、下一页、首页和尾页之外)并且让当前选择页码始终居中 self.half_per_page_count = int(self.per_page_count / 2) @property def start(self): """ 数据条目的起始索引 # x -> items_per_page*(x-1) ~ items_per_page*x :return: """ return self.per_page * (self.current_page - 1) @property def end(self): """ 数据条目的结束索引 # x -> items_per_page*(x-1) ~ items_per_page*x :return: """ return self.per_page * self.current_page @property def page_html(self): # 获取正确的开始页码和结束页码 # 判断真实的页码数是否超过 per_page_count if self.pager_count > self.per_page_count: # 如果当前页 < half_per_page_count if self.current_page <= self.half_per_page_count: pager_start = 1 pager_end = self.per_page_count # 如果当前页码 大于 half_per_page_count 并且 小于 pager_count - half_per_page_count elif self.current_page <= self.pager_count - self.half_per_page_count: pager_start = self.current_page - self.half_per_page_count pager_end = self.current_page + self.half_per_page_count # 如果当前页码大于 pager_count - half_per_page_count else: pager_start = self.pager_count - self.per_page_count + 1 pager_end = self.pager_count else: pager_start = 1 pager_end = self.pager_count page_list = [] first_page = ‘<a href="{}?page=1">首页</a>‘.format(self.base_url) page_list.append(first_page) if self.current_page > 1: prev = ‘<a href="{}?page={}">上一页</a>‘.format(self.base_url,self.current_page - 1) else: prev = ‘<a href="javascript:void(0)" disabled="true">上一页</a>‘ page_list.append(prev) # 循环生成HTML for i in range(pager_start, pager_end + 1): if i == self.current_page: tpl = ‘<a class="active" href="{}?page={}">{}</a>‘.format(self.base_url,i, i) else: tpl = ‘<a href="{}?page={}">{}</a>‘.format(self.base_url,i, i) page_list.append(tpl) if self.current_page < self.pager_count: nex = ‘<a href="{}?page={}">下一页</a>‘.format(self.base_url,self.current_page + 1) else: nex = ‘<a href="javascript:void(0)" disabled="true">下一页</a>‘.format(self.current_page + 1) page_list.append(nex) last_page = ‘<a href="{}?page={}">尾页</a>‘.format(self.base_url,self.pager_count) page_list.append(last_page) page_str = "".join(page_list) return page_str
# 目录结构 D:\\soft\\work\\Python_17\\day21\\s17day21_bbs_iframe>tree /F 卷 NewDisk 的文件夹 PATH 列表 卷序列号为 2E8B-8205 D:. │ db.sqlite3 │ manage.py │ ├─.idea │ │ dataSources.local.xml │ │ dataSources.xml │ │ misc.xml │ │ modules.xml │ │ s17day21_bbs.iml │ │ workspace.xml │ │ │ ├─dataSources │ │ │ 423d494f-02d5-44bf-b89f-561d5803cd88.xml │ │ │ │ │ └─423d494f-02d5-44bf-b89f-561d5803cd88 │ │ │ storage.xml │ │ │ │ │ ├─_metadata_ │ │ │ metadata │ │ │ metadata.keystream │ │ │ metadata.keystream.len │ │ │ metadata.len │ │ │ metadata.values.at │ │ │ metadata_i │ │ │ metadata_i.len │ │ │ │ │ ├─_src_ │ │ └─_staging_ │ └─inspectionProfiles │ profiles_settings.xml │ ├─bbs │ │ admin.py │ │ apps.py │ │ forms.py │ │ models.py │ │ tests.py │ │ views.py │ │ __init__.py │ │ │ ├─migrations │ │ │ 0001_initial.py │ │ │ 0002_auto_20170923_2220.py │ │ │ 0003_auto_20170925_2359.py │ │ │ __init__.py │ │ │ │ │ └─__pycache__ │ │ 0001_initial.cpython-35.pyc │ │ 0002_auto_20170923_2220.cpython-35.pyc │ │ 0003_auto_20170925_2359.cpython-35.pyc │ │ __init__.cpython-35.pyc │ │ │ ├─templatetags │ │ │ get_domain.py │ │ │ │ │ └─__pycache__ │ │ get_domain.cpython-35.pyc │ │ │ └─__pycache__ │ admin.cpython-35.pyc │ apps.cpython-35.pyc │ forms.cpython-35.pyc │ models.cpython-35.pyc │ views.cpython-35.pyc │ __init__.cpython-35.pyc │ ├─common │ │ md5.py │ │ my_response.py │ │ paginator.py │ │ │ └─__pycache__ │ md5.cpython-35.pyc │ my_response.cpython-35.pyc │ paginator.cpython-35.pyc │ ├─s17day21_bbs │ │ settings.py │ │ urls.py │ │ wsgi.py │ │ __init__.py │ │ │ └─__pycache__ │ settings.cpython-35.pyc │ urls.cpython-35.pyc │ wsgi.cpython-35.pyc │ __init__.cpython-35.pyc │ ├─statics │ ├─css │ │ bbs.css │ │ bootstrap-select.min.css │ │ bootstrap-theme.css │ │ bootstrap-theme.css.map │ │ bootstrap-theme.min.css │ │ bootstrap-theme.min.css.map │ │ bootstrap.css │ │ bootstrap.css.map │ │ bootstrap.min.css │ │ bootstrap.min.css.map │ │ bootstrapValidator.min.css │ │ │ ├─fonts │ │ glyphicons-halflings-regular.eot ...... │ │ │ ├─image │ │ 1.jpg ...... │ │ │ └─js │ bootstrap-select.js.map │ bootstrap-select.min.js │ bootstrap.js │ bootstrap.min.js │ bootstrapValidator.min.js │ city_info.js │ jquery-3.2.1.js │ jquery-3.2.1.min.js │ jquery.cookie.js │ npm.js │ └─templates demo.html iframe_demo.html iframe_test.html index.html new_article.html tab_demo.html test.html D:\\soft\\work\\Python_17\\day21\\s17day21_bbs_iframe>
以上是关于Django基础07-day22的主要内容,如果未能解决你的问题,请参考以下文章
django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE的解决办法(转)(代码片段
django.core.exceptions.ImproperlyConfigured: Requested setting DEFAULT_INDEX_TABLESPACE的解决办法(转)(代码片段