zoukankan      html  css  js  c++  java
  • BLOG总结

    1.登录http://www.cnblogs.com/shaojiafeng/p/7868195.html

    2.注册

    - urls
     
        -前端页面中写 username ,password,password,email,头像
         
         
        -form组件创建注册页面
            -widget的作用是,如果不加widget生成的前端标签是原生的input框,加上之后会变成渲染之后的
            -eg:username,password,repeat_pwd,email
                class RegForm(forms.Form):
                    email = forms.EmailField(widget=widgets.EmailInput(
                        attrs={"class": "form-control", "placeholder": "email"}
                    ))
                ....还有username,password,repeat_pwd
                如果form中有这些字段,则可以在前端页面中{{form_obj.username}},{{form_obj.password}}这样的方式取到值
                 
            -验证每个字段
                - clean_username(self):(用到了局部钩子)
                    cleaned_data它代表的是一个字典
                    -ret=models.UserInfo.objects.filter(username=self.cleaned_data.get("username"))
                     
                        if not ret:  #校验字段
                            return self.cleaned_data.get("username")
                        else:
                            raise ValidationError("用户名已注册")
                        -检查数据库中是否有username
                        -如果没有,验证的那个字段,如果有这个username,则返回cleaned_data取到的值,如果已经存在该用户,就走ValidationError,显示error信息
                         
                                     
                - clean_password(self):(用到了局部钩子)
                 
                    -同上方法验证,但需要注意,这个判断密码不能全是数字
                     
                def clean_validCode(self):(用到全局钩子)
     
                 
        -前端注册页面
            -上一步在后端上传的form对象渲染了username,password,email
             
            -生成头像
                -<img src="/static/img/default.png" alt="" id="avatar_img">
                -<input type="file" class="form-control" id="avatar_file">
                (生成一个默认的灰色框头像,如用户点击上传头像,此时应该吧图片遮到上传的文件上面,
                这里还有让parent设置成相对定位,children设置绝对定位,还有一点,应该不让灰色框隐藏,
                而是让他的透明度为0)
             
            -头像预览
                -找到头像标签,用到change事件,用一个变量去接受当前拿到的文件,然后对去到该文件的路径,让他付给this.result
             
                    $("#avatar_file").change(function () {
     
                    var ele_file=$(this)[0].files[0];  //拿到当前点击的文件
                    var reader=new FileReader();      //创建一个新对象
                    reader.readAsDataURL(ele_file);  
                    reader.onload=function (){
                        $("#avatar_img")[0].src=this.result
                    }
                    });
     
             
            - Ajax提交数据
                -使用formdata是因为里面有二进制文件
                - 上传二进制文件引入 FormData()
                - FormData()对象追加键值对
                    -$("#avatar_file")[0].files[0]) # jquery转DOM对象,取files对象最近一次上传的文件
                     
                    $.ajax({
                    url:"/reg/",
                    type:"POST",
                    data:formdata,
                    contentType:false,
                    processData:false,
                    headers:{"X-CSRFToken":$.cookie('csrftoken')},  //为了避免Forbedent禁止
                    success:function (data) {
                        console.log(data);
                        var data=JSON.parse(data);
     
                        //能拿到user代表注册成功,跳转到登录页面
                        if (data.user){
                            location.href="/login/"
                        }
                         
                        //反之
                         
                        else{
                        console.log(data.errorsList);
     
     
                        $.each(data.errorsList,function (i,j) {
                            console.log(i,j);
     
                            $span=$("<span>");
                            $span.addClass("pull-right").css("color","red");
                            $span.html(j[0]);
                            $("#id_"+i).after($span).parent().addClass("has-error");
     
                            if (i=="__all__"){
                                $("#id_repeat_pwd").after($span)
                            }
                        })
                    }
                     
                        注释:i为出错form组件字段、j为报错
                            each循环报错信息、新建span标签,给其增加样式(右漂浮,红色)
                            span的内容为报错信息
                            给出错的input标签后边添加span标签,并使其父级标签has-error
                            如果i使__all__:将报错添加到重新输入密码后边的span中
         
                     
                     
                 
        -后端注册(views中)  
            -判断是否是is_ajax请求
            -接收从前端提交过来的数据
            -form验证
                实例化对象,然后进行校验,将校验的结果和数据库进行匹配验证,获取校验结果,cleaned_data是一个字典的形式,
                如果校验失败,则走errors错误信息的列表
             
                 
                 form_obj=forms.RegForm(request.POST)  #接收从前端提交来的数据,规则和数据放在一起
                 
                if form_obj.is_valid():(开始校验,并获取校验结果)
                    username = form_obj.cleaned_data["username"]
                    password = form_obj.cleaned_data["password"]
                    email = form_obj.cleaned_data.get("email")
                    avatar_img = request.FILES.get("avatar_img")
                    ................
     
            -setting.py 如果只在这里设置 不在前端设置 用户接收不到文件
                    MEDIA_ROOT=os.path.join(BASE_DIR,"app01","media")
                    MEDIA_URL="/media/"
     
     
            -urls.py
                    # media 配置
                    from django.views.static import serve
                    from blog import  settings
                    url(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),
    

    3.个人博客(以查询为中心)

    1.head_title
    	2.左侧菜单
    		-个人信息
    			-头像
    			-昵称
    		
    		#查询当前用户的所有文章
    			article_list=models.Article.object.filter(user=current_user)
    		
    		-分类归档
    			from django.db.models import Count, Sum
    			category_list = models.Category.objects.all().filter(blog=current_blog).annotate(
    				c=Count("article__nid")).values_list("title", "c")
    		-标签归档
    			tag_list = models.Tag.objects.all().filter(blog=current_blog).annotate(c=Count("article__nid")).values_list("title",
                
    		-日期归档
    			date_list = models.Article.objects.all().extra(
    				select={"filter_create_date": "strftime('%%Y/%%m',create_time)"}).values_list("filter_create_date").annotate(
    				Count("nid"))
    		
    		
    	3.内容部分是个人所有文章的渲染
    		此处渲染的是文章title和文章摘要,发表日期,评论,点赞,阅读数
    		用到for循环去取,因为title是可点击进入的,所以用<a>
    			-<div class="article_title"><a href="/blog/{{ current_user.username }}/articles/{{ article.nid }}">{{ article.title }}</a></div>
    			如上,需要先分配url,让其跳转到/blog/下再跟其name等...
    			
    		-还有一点需要注意的是:发表时间的渲染需要过滤date。eg:(发表于 <span>{{ article.create_time|date:"Y-m-d" }}</span>  )
    

    4.个人博客——文章的详细内容

    -首先点击文章的标题,应该跳转到文章页里面,但是个人博客页的title和左侧菜单应该不变,此处用到继承
    	
    	1.让(article_detail)页面去继承(homeSite)d的title和左侧菜单
    		-{% extends "homeSite.html" %}
    		
    	2.在前端页面中渲染文章标题和文章内容
    		-标题:<h3 class="text-center">{{ article_obj.title }}</h3>
            -内容:<div class="article_con">{{ article_obj.articledetail.content|safe }}</div>
    			-渲染文章内容时,应该让在博客园的HTML代码编辑器中渲染之后的标签页代码写入admin中,为了让去显示全部信息,必须在后面加(|safe)
    

    5.文章页的点赞

    通过点击“赞”  触发click事件,发送ajax请求,来完成点击一次,可以自加一的操作
    	
    	1.在前端页面渲染点赞按钮,将点赞按钮图片保存到/static/img  中
    		-此处需要注意的是urls中的路由分发
    			urlpatterns = [
    				url(r'^poll/$', views.poll),
    				]
    		以上渲染的代码,通过form打包给button,通过ajax去提交
    	2.前端页面中ajax
    		$.ajax({
    			url:"/blog/poll/",
    			type:"post",
    			data:{
    				csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val(),
    				article_id:"{{ article_obj.nid }}"  #文章的对象
    			},
    			success:function(data){
    				var data=JSON.parse(data);   // pollResponse
                     if (data.state){
                         var val=parseInt($("#digg_count").html())+1;
                          $("#digg_count").html(val)
                     }
                     else if (data.is_repeat){
                            $(".diggnum_error").html("重复提交").css("color","red")
                     }
    			}
    
    		})
    	
    	
    	
    	
    	3.后端中:
    		def poll(request):
    			#创建一条记录
    			user_id=request.user.nid
    			article_id=request.POST.get("article_id")
    			
    			articleUp = models.ArticleUp.objects.create(user_id=user_id, article_id=article_id)
    		
    			#找到article_id,在之前的基础上加1.(此处需要引入F)
    			from django.db.models import F
    
    	在views.py中:
    	//从数据库过滤出点赞表的对象,如果有这个对象,就让他自加一,如果没有这个对象,先创建一个对象,让给他自加一
    	其中用到,try异常处理,限制不能让用户点击两次赞
    	
    	
    	
    	
    		def poll(request):
    
    		from django.db.models import F
    		#创建一条记录
    		user_id=request.user.nid
    		article_id=request.POST.get("article_id")
    
    		pollResponse={"state":True,"is_repeat":None} //作为是否重复提交的判断
    		
    		if models.ArticleUp.objects.filter(user_id=user_id, article_id=article_id):
    			//从数据库过滤出点赞表的对象
    			pollResponse["state"]=False
    			pollResponse["is_repeat"]=True
    
    		else:
    
    			try:
    
    				articleUp = models.ArticleUp.objects.create(user_id=user_id, article_id=article_id)
    				models.Article.objects.filter(nid=article_id).update(up_count=F("up_count") + 1)
    			except:
    
    				pollResponse["state"] = False
    
    		import json
    
    		return HttpResponse(json.dumps(pollResponse))
    

    6. 实现ajax文章评论

    1.给文章评论,点击评论按钮,实现ajax提交
    		-前端页面中找到提交按钮,绑定click事件
    		-在urls中添加路由:url(r'^comment/$', views.comment),
    		-在后端中,先取出数据
    			-文章主键号:article_id = request.POST.get("article_id")
    			-评论内容:comment_content = request.POST.get("comment_content")
    			-user_id:user_id = request.user.nid
    		-在前端中渲染出来头像,评论内容
    		
    	2.实现ajax子评论
    		点击“回复”按钮,给文章的评论进行评论
    			-views中提交评论
    				-锚点
    				-$(".comment_list").on("click",".reply_comment_btn",function (){}//找到标签,绑定事件
    				-添加子评论,必须拿到父评论的id
    					-parent_comment_id = $(this).attr("comment_id")
    			-前端中渲染
    				// 回复按钮
    				var  parent_comment_id=null;
    				$(".comment_list").on("click",".reply_comment_btn",function () {
    					// 文本框中显示父评论的名字
    					var parent_comment_username = $(this).attr("conmment_username");
    					$("#comment_con").val("@" + parent_comment_username + "
    ");
    
    					//  获取父评论的comment_id
    					parent_comment_id = $(this).attr("comment_id")
    				})
    

    文章评论前端代码实现:

    {% extends "homeSite.html" %}
    
    {% block content %}
    
        <div class="article_region">
            <div class="row">
                <h3 class="text-center">{{ article_obj.title }}</h3>
                <div class="article_con">{{ article_obj.articledetail.content|safe }}</div>
            </div>
        </div>
    
        <div class="upup row">
    
            <div class="downdown pull-right">
                <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
            </div>
    
            <div class="diggit pull-right">
                <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
            </div>
        </div>
        <span class="diggnum_error pull-right"></span>
    
        <div class="had_comment_region">
            <h5>已发表评论:</h5>
            <div class="comment_list">
            {% for comment in comment_list %}
    
                <div class="comment_item">
                <div class="row">
                    <div class="col-md-6">
                        <img src="{{ comment.user.avatar.url }}" alt="" width="30" height="30">
                        <a href="/blog/{{ comment.user.username }}">{{ comment.user.username }}</a>发表于 {{ comment.create_time|date:"Y-m-d H:i" }}
    
                    </div>
                    <div class="pull-right">
                        <a href="#comment_con" class="reply_comment_btn" comment_id="{{ comment.nid }}" conmment_username="{{ comment.user.username }}">回复</a>
                        <a href="">支持</a>
                    </div>
                </div>
                <div style="background-color: palegoldenrod">
                         {% if comment.parent_comment_id %}
                           @<a href="">{{ comment.parent_comment.user.username }}</a> :&nbsp;&nbsp;&nbsp;{{ comment.parent_comment.content }}
                          {% endif %}
                     </div>
                </div>
    
                {{ comment.content }}
                 <hr>
            {% endfor %}
    
            </div>
        </div>
    
    
    
        <div class="subComment_region">
            <h4>发表评论</h4>
            <p>昵称:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50" value="{{ request.user.username }}"></p>
            <p>评论内容:</p>
    
            <form action="">
                {% csrf_token %}
            <p><textarea name="" id="comment_con" cols="50" rows="10"></textarea></p>
            <input type="button" value="提交评论" class="btn btn-default commentBtn">
        </form>
    
        </div>
    
    
        <script>
            //实现ajax点赞
            $(".diggit").click(function () {
    
             $.ajax({
                 url:"/blog/poll/",
                 type:"post",
                 data:{
                     csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val(),
                     article_id:"{{ article_obj.nid }}"
                 },
                 success:function (data) {
                     var data=JSON.parse(data);   // pollResponse
                     if (data.state){
                         var val=parseInt($("#digg_count").html())+1;
                          $("#digg_count").html(val)
                     }
                     else if (data.is_repeat){
                            $(".diggnum_error").html("重复提交").css("color","red")
                     }
                 }
             })
         })
    
    
             // 实现ajax文章评论
        $(".commentBtn").click(function () {
            var content;
            if(parent_comment_id){
                var index=$("#comment_con").val().indexOf("
    ");     // 子评论
                content= $("#comment_con").val().slice(index+1)
            }else {
                content=$("#comment_con").val()
            }
    
            $.ajax({
                url:"/blog/comment/",
                type:"POST",
                data:{
                     csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val(),
                     article_id:"{{ article_obj.nid }}",
                     comment_content:content,
                     parent_comment_id:parent_comment_id
    
    
                },
                success:function (data) {
    
                    console.log(data.create_time.slice(0,19));
    
                    s='<div class="comment_item" style="border-bottom: 1px solid grey"><div class="row"> <div class="col-md-6"> <img src="{{ request.user.avatar.url}}" alt="" width="30" height="30"> <a href="/blog/{{ request.user.username }}">{{ request.user.username }}</a> 发表于 '+data.create_time.slice(0,19)+' </div> <div class="pull-right"> <a href="#comment_con" class="reply_comment_btn">回复</a> <a href="">支持</a> </div> </div> <div>'+content+' </div> </div>'
    
                    $(".comment_list").append(s);
    
                    $("#comment_con").val("")
                }
            })
    
    
        });
    
          // 实现ajax子评论
    
        // 回复按钮
        var  parent_comment_id=null;
        $(".comment_list").on("click",".reply_comment_btn",function () {
            // 文本框中显示父评论的名字
            var parent_comment_username = $(this).attr("conmment_username");
            $("#comment_con").val("@" + parent_comment_username + "
    ");
    
            //  获取父评论的comment_id
            parent_comment_id = $(this).attr("comment_id")
    
    
        })
        
        </script>
        
    {% endblock %}
    article_detail.html

    文章评论后端实现:

    def comment(request):
        article_id = request.POST.get("article_id")
        comment_content = request.POST.get("comment_content")
        user_id = request.user.nid
    
        commentResponse = {}
        # print(request.POST.get("parent_comment_id"), "=======")
    
        if request.POST.get("parent_comment_id"):  # 处理子评论
            with transaction.atomic():
                pid = request.POST.get("parent_comment_id")
                comment_obj = models.Comment.objects.create(article_id=article_id, user_id=user_id, content=comment_content,
                                                            parent_comment_id=pid)
                commentResponse["create_time"] = str(comment_obj.create_time)
    
        else:  # 处理的文章评论,即根评论
            with transaction.atomic():
    
                comment_obj = models.Comment.objects.create(article_id=article_id, user_id=user_id, content=comment_content)
                models.Article.objects.filter(nid=article_id).update(comment_count=F("comment_count") + 1)
                commentResponse["create_time"] = str(comment_obj.create_time)
                print(commentResponse["create_time"])
        from django.http import JsonResponse
        return JsonResponse(commentResponse)
    views.py

     7.后台管理

    在后台管理页面中可以添加文章,编辑,删除
    添加文章,插件-- kindeditor编辑器的使用

       (1).url的分配:

    url(r'^backend/addArticle/$', views.addArticle),
    url(r'^backend/$', views.backendIndex),
    

     (2).前端页面:addArticle.html 

    -{% extends "backendIndex.html" %}  添加文章页面中得继承后台管理的head和左侧栏
    	-在addArticle.html页面中利用kindeditor编辑器添加文章
    		-用form提交
    			-标题的渲染:<div>
    							<label for="title">标题:</label>
    							<p>{{ article_form.title }}</p>
    						</div>
    			-内容的渲染:
    						<div>
    							<label for="title">内容:</label>
    							<p>{{ article_form.content }}</p>
    						</div>
    						
    			-别忘了还有提交摁钮呦:<p><input type="submit" value="submit"></p>
    			
    		-kindeditor编辑器的插入:
    			-textarea:目的是让textarea的空白框变成kindeditor带有各色功能的编辑框
    			-引入kindeditor:引入的是js文件,用<script>
    				-<script src="/static/kindeditor/kindeditor-all.js"></script>
    				
    			-http://kindeditor.net/demo.php   #用法均可上该网址参考
    			-<script>
    				KindEditor.ready(function(K) {
    						window.editor = K.create('#id_content',{
    								"600px",
    								height:"500px",
    								resizeType:0,
    								uploadJson:"/uploadFile/",
    								extraFileUploadParams:{
    									csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val(),
    							   }
    						});
    				})
    
    			</script>	
    

     (3).views中: 

    def addArticle(request):
    		"""添加文章页"""
    	
    		#如果是post请求,实例化创建一个对象,如果是is_valid(),就去form验证title和content,
    		#    然后创建一个content_obj对象
    	    if request.method=="POST":
            article_form = ArticleForm(request.POST)
            if article_form.is_valid():
                title=article_form.cleaned_data.get("title")
                content=article_form.cleaned_data.get("content")
                article_obj=models.Article.objects.create(title=title,desc=content[0:30],create_time=datetime.datetime.now(),user=request.user)
                models.ArticleDetail.objects.create(content=content,article=article_obj)
            else:
                pass
    
            return HttpResponse("添加成功")
    
        article_form=ArticleForm()
        return render(request,"addArticle.html",{"article_form":article_form})
    	
    
    
    
    
    
    
    	def uploadFile(request):	
    	
    		"""添加文章页的上传文件及图片"""
    		file_obj=request.FILES.get("imgFile")  #拼接一个本地的路径,将图片下载下来
    		file_name=file_obj.name    #用file_obj_name这个属性可以直接从对列中取出组合格名字
    
    		from django.conf import settings
    		import os
    		path=os.path.join(settings.MEDIA_ROOT,"article_uploads",file_name)
    		
    		with open(path,"wb")as f:
    			for i  in file_obj.chunks():   #chunks: 64*2**10
    				f.write(i)
    
    		response={
    			"error":0,  #标识一个状态
    			"url":"/media/article_uploads/"+file_name+"/"   #图片预览的路径
    		}
    		import json
    		return HttpResponse(json.dumps(response))
    

     (4).xss组件

    在添加文章内容时,添加的图片,或者文字内容,在前端页面中渲染不出来,所有用xss组件进行过滤处理,此处过滤相当于白名单处理,就是valid_dict中有的值都可以在前端页面中渲染出来。
    使用到bs4模块(pip install bs4)
    from bs4 import BeautifulSoup

    def filter_xss(html_str):
    
        valid_dict = {"p": ["id", "class"], "div": ["id", "class"],"img":["src","alt"]}	
    
    	from bs4 import BeautifulSoup
    
        soup = BeautifulSoup(html_str, "html.parser")  # soup  ----->  document
    
        ######### 改成dict
        for ele in soup.find_all():
            # 过滤非法标签
            if ele.name not in valid_dict:
                ele.decompose()
            # 过滤非法属性
    
            else:
                attrs = ele.attrs  # p {"id":12,"class":"d1","egon":"dog"}
                l = []
                for k in attrs:
                    if k not in valid_dict[ele.name]:
                        l.append(k)
    
                for i in l:
                    del attrs[i]
    
        print(soup)
    
        return soup.decode()
    

      

    有一种能力,是持续不断的努力
  • 相关阅读:
    你没听过的乔布斯语录:苹果如果没这么独,可能更成功
    关于Apache mod_rewrite的中文配置、使用和语法介绍(实现URL重写和防盗链功能)
    与调试器共舞
    libxml2.dylb 导致<libxml/tree.h> 老是找不到头文件
    国家气象局提供的天气预报接口(完整Json接口)
    dSYM 文件分析工具
    总结
    1-22
    【图论】
    好像要开始图论了....但搜索还剩了点....
  • 原文地址:https://www.cnblogs.com/shaojiafeng/p/7896961.html
Copyright © 2011-2022 走看看