码迷,mamicode.com
首页 > 其他好文 > 详细

Django基础07-day22

时间:2017-10-14 17:01:48      阅读:208      评论:0      收藏:0      [点我收藏+]

标签:enc   ace   dmi   site   delete   copy   absolute   tab切换   pup   

写在前面



上课第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         
武Sir - 笔记

 

 

################
# 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

标签:enc   ace   dmi   site   delete   copy   absolute   tab切换   pup   

原文地址:http://www.cnblogs.com/standby/p/7589055.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!