博客系统项目整理:
一:创建表:
models代码:
from django.db import models from django.contrib.auth.models import AbstractUser class UserInfo(AbstractUser): '''用户信息表''' nid = models.AutoField(primary_key=True) nickname = models.CharField(max_length=32,verbose_name="昵称",unique=True,null=True,blank=True) tel = models.CharField(max_length=11, verbose_name='电话',unique=True, null=True,blank=True) avatar = models.FileField(verbose_name="头像",upload_to="avatar",default="/avatar/default.png") create_time = models.DateTimeField(verbose_name="创建时间",auto_now_add=True) class Meta: verbose_name_plural = "用户信息表" def __str__(self): return self.username class Article(models.Model): ''' 文章表 ''' title = models.CharField(max_length=64,verbose_name="文章标题") summary = models.CharField(max_length=244, verbose_name="文章概要") create_time = models.DateTimeField(verbose_name="创建时间",auto_now_add=True) update_time = models.DateTimeField(verbose_name="修改时间",auto_now=True) poll_count = models.IntegerField(verbose_name="点赞数",default=0) comment_count = models.IntegerField(verbose_name="评论数",default=0) read_count = models.IntegerField(verbose_name="阅读数",default=0) # is_essence = models.BooleanField(verbose_name="是否精华",default=0) # is_top = models.BooleanField(verbose_name="是否置顶",default=0) user = models.ForeignKey(to="UserInfo",verbose_name="所属作者",null=True,blank=True) classify = models.ForeignKey(to="Classfication",verbose_name="所属类别",null=True,blank=True) tags = models.ManyToManyField(to="Tag",through="Article2tag",through_fields=('article', 'tag'),verbose_name="所属标签") site_article_category = models.ForeignKey(to="SiteArticleCategory", null=True,verbose_name="文章分类") class Meta: verbose_name_plural = "文章表" def __str__(self): return self.title class Article_detail(models.Model): '''文章细节表''' article = models.OneToOneField(to="Article",verbose_name="所属文章") content = models.TextField(verbose_name="文章内容") class Meta: verbose_name_plural = "文章细节表" class Tag(models.Model): '''标签表''' name = models.CharField(max_length=32,verbose_name="标签名") blog = models.ForeignKey(to="Blog",verbose_name="所属博客") def __str__(self): return self.name class Meta: verbose_name_plural = "标签表" class Article2tag(models.Model): article = models.ForeignKey(verbose_name="文章",to="Article") tag = models.ForeignKey(verbose_name="标签",to="Tag") class Meta: '''联合唯一''' unique_together = [ ("article","tag") ] class Comment(models.Model): '''评论表''' time = models.DateTimeField(verbose_name="评论时间",auto_now_add=True) content = models.CharField(max_length=265,verbose_name="评论内容") up_count = models.IntegerField(default=0) user = models.ForeignKey(to="UserInfo",verbose_name="评论人",null=True,blank=True) article = models.ForeignKey(to="Article",verbose_name="评论文章",null=True,blank=True) farther_comment = models.ForeignKey(to="Comment",verbose_name="父级评论",null=True,blank=True) # farther_comment = models.ForeignKey("self",verbose_name="父级评论",null=True,blank=True) class Meta: verbose_name_plural = "评论表" class Article_poll(models.Model): '''文章点赞表''' time = models.DateTimeField(verbose_name="点赞时间",auto_now_add=True) article = models.ForeignKey(to="Article",verbose_name="点赞文章",null=True,blank=True) #一个文章可以有多个赞 user = models.ForeignKey(to="UserInfo",verbose_name="点赞人",null=True,blank=True) # is_positive = models.BooleanField(default=1,verbose_name="点赞或踩") class Meta: '''联合唯一''' unique_together = ("user", "article",) verbose_name_plural = "文章点赞表" class Comment_poll(models.Model): '''评论点赞表''' time=models.DateTimeField(verbose_name="点赞时间",auto_now_add=True) # is_positive = models.BooleanField(verbose_name="点赞或踩",default=1) user = models.ForeignKey(to="UserInfo",verbose_name="点赞用户",null=True,blank=True) comment = models.ForeignKey(to="Comment",verbose_name="点赞所属评论",null=True,blank=True) #一个评论可以有多个赞 class Meta: '''联合唯一''' unique_together = ("user","comment",) verbose_name_plural = "评论点赞表" class Blog(models.Model): '''个人站点表''' title = models.CharField(max_length=32,verbose_name="个人博客标题") url = models.CharField(max_length=64,verbose_name="路径",unique=True) theme = models.CharField(max_length=32,verbose_name="博客主题") user = models.OneToOneField(to="UserInfo", verbose_name="所属用户") class Meta: verbose_name_plural = "个人站点表Blog" def __str__(self): return self.title class Classfication(models.Model): '''博主个人文章分类表''' title = models.CharField(max_length=32, verbose_name="分类标题") blog = models.ForeignKey(to="Blog",verbose_name="所属博客") def __str__(self): return self.title class Meta: verbose_name_plural = "分类表" #与文章表关联,属于博客全局的分类 class SiteCategory(models.Model): """ 博客主页分类,父 """ name=models.CharField(max_length=32) def __str__(self): return self.name class Meta: verbose_name_plural = "博客主页分类,父" class SiteArticleCategory(models.Model): """ 博客主页分类,子 """ name=models.CharField(max_length=32) site_category=models.ForeignKey("SiteCategory") def __str__(self): return self.name class Meta: verbose_name_plural = "博客主页分类,子"
admin:
from django.contrib import admin # Register your models here. from . import models admin.site.register(models.UserInfo) admin.site.register(models.Article) admin.site.register(models.Article_detail) admin.site.register(models.Tag) admin.site.register(models.Article2tag) admin.site.register(models.Comment) admin.site.register(models.Article_poll) admin.site.register(models.Comment_poll) admin.site.register(models.Blog) admin.site.register(models.Classfication) admin.site.register(models.SiteCategory) admin.site.register(models.SiteArticleCategory)
配置---引用:
#配置 settings: AUTH_USER_MODEL = "app01.UserInfo" #引用from django.contrib.auth.models import AbstractUser from django.db import models from django.conf import settings from django.contrib.auth.models import AbstractUser
表关系:
博客系统表关系整理; 1:创建用户信息表(UserInfo):-----------继承了AbstractUser(配置 settings: AUTH_USER_MODEL = "app01.UserInfo") ----------(from django.contrib.auth.models import AbstractUser) 主键(ID) 昵称(nickname) 电话(tel) 邮箱(email) 头像(avatar) 创建时间(create_time) 2:创建文章表(Acticle) 文章标题(title) 文章概要(summary) 创建时间(create_time) 修改时间(updata_time) 点赞数(poll_count) 评论数(comment_count) 阅读数(read_count) 作者(user)-------------------------------与信息表(Userinfo)是一对多的关系 所属类别(classify)-----------------------与分类表(Classify)是一对多的关系 标签(tag)--------------------------------与标签表(Tag)是多对多的关系,过滤关系,一篇文章只能有一层与标签的关系,不可重复。 博客的类,固定字段只有选择的权限(type_choices) 3文章详细表(Article_detail) 所属文章(article)------------------------与文章表是(Article)是一对一的关系 文章内容(content) 4标签表(Tag) 标签名(name) 所属博客(blog)----------------------------与博客表是一对多的关系 5博客和标签的关系表(Article2tag)--------------自己创建方便后面添加字段 文章(article)-----------------------------与文章表(Article)是多对一的关系 标签(tag)---------------------------------与标签表(Tag)是多对一的关系 6:评论表 评论时间(time) 评论内容(content) 评论人(user)------------------------------与用户信息表(UserInfo)是多对一的关系 评论文章(article)-------------------------与文章表(Acticle)是多对一的关系 父级评论(father_comment)------------------自关联(可以评论别人的评论) 7:文章点赞表(Article_poll) 点赞时间(time) 点赞文章(article)-------------------------与文章表(Acticle)是多对一的关系 点赞人(user)------------------------------与用户表(UserInfo)是多对一的关系 8:评论点赞表(Comment_poll) 点赞时间(time) 点赞用户(user)----------------------------与用户信息表(UserInfo)是多对一的关系 点赞所属评论(comment)---------------------与评论表(Comment)是多对一的关系 9:博客表(Blog) 个人博客标题(title) 路径(url) theme(博客主题) user(所属用户)----------------------------与用户信息表是(UserInfo)是一对一的关系 10:博主个人文章分类表(Classfication) 分类标题(title) 所属博客(blog)----------------------------与博客表是(Blog)是多对一的关系
二:登录:
界面显示
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale"> <title>博客系统首页</title> <script src="/static/jquery-3.2.1.min.js"></script> <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css"> <style> .hides{ display: none; } </style> </head> <body> <nav class="navbar navbar-inverse primary"> <div class="container"> <a class="navbar-brand" href="#">博客园</a> <div id="bs-example-navbar-collapse-9" class="collapse navbar-collapse"> <ul class="nav navbar-nav navbar-right"> {% if request.user.is_authenticated %} <li><a href="">{{request.userinfo.uaername}}<span class="glyphicon glyphicon-user"></span></a></li> <li><a href="/log_out/">注销</a></li> <li><a href="/#/">修改密码</a></li> {% else %} <li><a href="/login/">登录</a></li> <li><a href="/register/">注册</a></li> {% endif %} </ul> <form class="navbar-form navbar-right"> <input type="text" class="form-control" placeholder="搜索"> </form> </div> </div> </nav> <div class="container"> <div class="row col-md-3"> <div class="panel panel-primary"> <div class="panel-body"> 网站分类 </div> <div class="panel-footer"> {% for site in site_list %} <div class="panel panel-primary"> <div class="panel-heading cate_title">{{site.name}}</div> <div class="panel-body hides"> {% for sitearticlecategory in site.sitearticlecategory_set.all %} <p><a href="/site/{{sitearticlecategory.name}}">{{sitearticlecategory.name}}</a></p> {% endfor %} </div> </div> {% endfor %} </div> </div> </div> <div class="col-md-6"> <div class=" article_list"> {% for article in article_list %} <div><a href="">{{article.title}}</a></div> <div class="row"> <div class="avatar col-md-2"> <a href="{% url 'aaa' article.user.username %}"><img src="{{article.user.avatar.url}}" alt="" width="80px" height="80px"></a> </div> <div class="summary col-md-10" > <p>{{article.summary}}</p> </div> </div> <div class="article_info row">   <a href="/app01/{{ article.user.username }}"><b>{{article.user.username}}</b></a>   发布与:{{article.create_time|date:"Y-m-d H:i"}}   <a href=""><span class="glyphicon glyphicon-comment"></span>评论({{article.comment_count}})</a>   <a href=""><span class="glyphicon glyphicon-thumbs-up"></span>点赞({{article.poll_count}})</a>   <a href=""><span class="glyphicon glyphicon-share-alt"></span>阅读({{article.read_count}})</a> </div> <hr> {% endfor %} </div> </div> <div class="col-md-3"> <div class="panel panel-default"> <div class="panel-body"> Panel content </div> <div class="panel-footer">Panel footer</div> </div> <div class="panel panel-default"> <div class="panel-body"> Panel content </div> <div class="panel-footer">Panel footer</div> </div> <div class="panel panel-default"> <div class="panel-body"> Panel content </div> <div class="panel-footer">Panel footer</div> </div> </div> </div> <script> $(".cate_title").mouseover(function () { $(this).next().slideDown(300) }).parent().mouseleave(function () { $(this).children(".panel-footer").slideUp(300) }); {# $(".cate_title").mouseenter(function () {#} {# $(this).next().slideDown(300)#} {# });#} {# $(".panel-footer").mouseleave(function () {#} {# $(this).next().slideUp(300)#} {# });#} </script> </b
导入:
url
url(r'^get_authCode_img/', views.get_authCode_img), url(r'^login/$',views.login),
前端页面的实现:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale"> <title>博客系统首页</title> <script src="/static/jquery-3.2.1.min.js"></script> <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css"> <style> .hides{ display: none; } </style> </head> <body> <nav class="navbar navbar-inverse primary"> <div class="container"> <a class="navbar-brand" href="#">博客园</a> <div id="bs-example-navbar-collapse-9" class="collapse navbar-collapse"> <ul class="nav navbar-nav navbar-right"> {% if request.user.is_authenticated %} <li><a href="">{{request.userinfo.uaername}}<span class="glyphicon glyphicon-user"></span></a></li> <li><a href="/log_out/">注销</a></li> <li><a href="/#/">修改密码</a></li> {% else %} <li><a href="/login/">登录</a></li> <li><a href="/register/">注册</a></li> {% endif %} </ul> <form class="navbar-form navbar-right"> <input type="text" class="form-control" placeholder="搜索"> </form> </div> </div> </nav> <div class="container"> <div class="row col-md-3"> <div class="panel panel-primary"> <div class="panel-body"> 网站分类 </div> <div class="panel-footer"> {% for site in site_list %} <div class="panel panel-primary"> <div class="panel-heading cate_title">{{site.name}}</div> <div class="panel-body hides"> {% for sitearticlecategory in site.sitearticlecategory_set.all %} <p><a href="/site/{{sitearticlecategory.name}}">{{sitearticlecategory.name}}</a></p> {% endfor %} </div> </div> {% endfor %} </div> </div> </div> <div class="col-md-6"> <div class=" article_list"> {% for article in article_list %} <div><a href="">{{article.title}}</a></div> <div class="row"> <div class="avatar col-md-2"> <a href="{% url 'aaa' article.user.username %}"><img src="{{article.user.avatar.url}}" alt="" width="80px" height="80px"></a> </div> <div class="summary col-md-10" > <p>{{article.summary}}</p> </div> </div> <div class="article_info row">   <a href="/app01/{{ article.user.username }}"><b>{{article.user.username}}</b></a>   发布与:{{article.create_time|date:"Y-m-d H:i"}}   <a href=""><span class="glyphicon glyphicon-comment"></span>评论({{article.comment_count}})</a>   <a href=""><span class="glyphicon glyphicon-thumbs-up"></span>点赞({{article.poll_count}})</a>   <a href=""><span class="glyphicon glyphicon-share-alt"></span>阅读({{article.read_count}})</a> </div> <hr> {% endfor %} </div> </div> <div class="col-md-3"> <div class="panel panel-default"> <div class="panel-body"> Panel content </div> <div class="panel-footer">Panel footer</div> </div> <div class="panel panel-default"> <div class="panel-body"> Panel content </div> <div class="panel-footer">Panel footer</div> </div> <div class="panel panel-default"> <div class="panel-body"> Panel content </div> <div class="panel-footer">Panel footer</div> </div> </div> </div> <script> $(".cate_title").mouseover(function () { $(this).next().slideDown(300) }).parent().mouseleave(function () { $(this).children(".panel-footer").slideUp(300) }); {# $(".cate_title").mouseenter(function () {#} {# $(this).next().slideDown(300)#} {# });#} {# $(".panel-footer").mouseleave(function () {#} {# $(this).next().slideUp(300)#} {# });#} </script> </body> </
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="description" content=""> <meta name="author" content=""> <title>用户登录页面</title> <link href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css" rel="stylesheet"> <link rel="stylesheet" href="/static/css/login.css"> <script src="/static/jquery-3.2.1.min.js"></script> <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script> </head> <body> <div class="container"> <div class="row col-md-4 col-lg-offset-4 container"> <form method=post> {% csrf_token %} <h1 class="form-signin-heading col-lg-offset-4 text-primary"><b>请登录:</b></h1> <hr> <div> <label for="username">用户名:</label> <p class="username"><input id="username" class="form-control" placeholder="用户名" type="text" name="username"></p> </div> <div> <label for="password">密码:</label> <p class="password"><input id="password" class="form-control" placeholder="密码" type="password" name="password"></p> </div> <div> <label for="auth_code">验证码:</label> <p class="auth_code"><input id="auth_code" class="form-control" placeholder="验证码" type="text" name="auth_code"></p> </div> <div> <img class="auth_code_img" src="/get_authCode_img/" style="200px;height:50px"> {# <a class="refresh">看不清</a>#} </div> <hr> <input type="button" value="登录" class="btn btn-lg btn-primary pull-left" id="subBtn"><span class="error"></span> <a href="/register/"> <input type="button" value="注册" class="btn btn-lg btn-primary pull-right" id=""></a> </form> </div> </div> <script> //登录 $("#subBtn").click(function () { $.ajax({ url:"/login/", type:"POST", data:{ "username":$("#username").val(), "password":$("#password").val(), "auth_code":$("#auth_code").val(), "csrfmiddlewaretoken":$("[name='csrfmiddlewaretoken']").val() }, success:function (data) { console.log(data); var response=JSON.parse(data); if (response["is_login"]){ location.href="/index/" } else { $(".error").html(response["error_msg"]).css("color","red") } } }) }); // 验证码刷新 $(".auth_code_img").click(function () { $(this)[0].src+="?" }) </script> </body> </html>
后端代码:
登录 def login(request): if request.is_ajax(): login_response = {"is_login": False, "error_msg": None} # 定义一个字典 username = request.POST.get("username") # 取到用户名 password = request.POST.get("password") # 取到密码 auth_code = request.POST.get("auth_code") # 取到验证码 if auth_code.upper() == request.session.get("auth_code").upper(): # 从session中获取验证码,判断是否正确 # print(username, password, '==========') user = auth.authenticate(username=username, password=password) print(user) # 通过auth模块获取用户名密码 if user: # 正确,判断用户名和密码是否正确 login_response["is_login"] = True auth.login(request, user) else: login_response["error_msg"] = "用户名或密码不正确" # 前端显示用户名或密码错误 else: login_response["error_msg"] = '验证码不正确' # 前端显示验证码错误 return HttpResponse(json.dumps(login_response)) # 返回 return render(request, "login.html") # 若不是Ajax访问方式,返回登录页面重新登录
验证码:
# 登录 def login(request): if request.is_ajax(): login_response = {"is_login": False, "error_msg": None} # 定义一个字典 username = request.POST.get("username") # 取到用户名 password = request.POST.get("password") # 取到密码 auth_code = request.POST.get("auth_code") # 取到验证码 if auth_code.upper() == request.session.get("auth_code").upper(): # 从session中获取验证码,判断是否正确 # print(username, password, '==========') user = auth.authenticate(username=username, password=password) print(user) # 通过auth模块获取用户名密码 if user: # 正确,判断用户名和密码是否正确 login_response["is_login"] = True auth.login(request, user) else: login_response["error_msg"] = "用户名或密码不正确" # 前端显示用户名或密码错误 else: login_response["error_msg"] = '验证码不正确' # 前端显示验证码错误 return HttpResponse(json.dumps(login_response)) # 返回 return render(request, "login.html") # 若不是Ajax访问方式,返回登录页面重新登录
验证码刷新:
// 验证码刷新 $(".auth_code_img").click(function () { $(this)[0].src+="?" })
注销:
#注销 def log_out(request): auth.logout(request) return redirect("/login/")
css代码:
.container{ margin-top:20px; }
请求流程:
流程:
1:客户端-----------发送(第一次get请求)-------------客户端返回一个Html页面(登录页面) 2:验证码-----------src(url再次请求服务端)----------服务端执行验证码函数,生成验证码保存在session中 3:用户输入内容----点击提交发送ajax请求---(Post)----服务端从request中拿到ajax请求信息。 4:从session中取出取出验证码和--ajax中的信息进行匹配。 5:匹配成功---------进行下一步验证,失败返回错误信息,在Html页面渲染。 6:通过auth模块获取用户名密码,判断用户名和密码是否和数据库中的相同。 7:若相同,写入定义的字典中。 一“is_login”:true-----保存在session中,跳转到首页 8:若不相同,返回登录页面,渲染错误信息。
1,用ajax提交数据 $(".log_btn").click(function(){ $.ajax({ url:url路径 type:访问状态 headers: {"X-CSRFToken":
$.cookie('csrftoken')},#跨站请求访问 返回的数据 data:{ 字典名:$(".字段标识名").val() } 接收数据 sussecc:funsess(data){ 函数 } }) }
2、图片刷新(写在sussecc函数中) 原理:给图片绑定一个点击事件:每次给src+?就会再次发送一次get请求,就起到了刷星的作用 dom对象 $(".validCode_img")
.click(function () { $(this)[0].src+="?";
随机验证码:
方式一:将图片导入静态文件,用文件句柄打开图片返回给前端进行渲染
方式二:导入PIL模块,利用Image生成一张图片保存后,用文件举兵打开,返回前端
方式三:导入PIL、IO模块,还是利用Image生成图片,但是这次没有将图片保存到磁盘而是将图片利用IO模块中的BytesIO暂时的保存到内存中,用BytesIO句柄打开,返回到前端。
方式四:对方式三进行优化,加上了random模块可以让图片随机生成,加上随机的5个字符,基本的验证码就显示出来了
因为随机码是用for循环生成的先将它放入一个列表中,人后将列表转换 为字符串,存入session中便于做对比,接收前端发过来的数据,包括用 户名密码以及验证码三条数据,先拿session中保存的验证码与前段发来 的验证码进行匹配验证,如果匹配成功则进行用户名密码的匹配匹配成功 则登录成功
def get_authCode_img(request): #方式一 # import os # path = os.path.join(settings.BASE_DIR, "static", "img", "a.jpg") # with open(path, "rb") as f: # data = f.read() # return HttpResponse(data) # 方式2: # from PIL import Image # img=Image.new(mode="RGB",size=(120,40),color="green") # f=open("validCode.png","wb") # img.save(f,"png") # with open("validCode.png","rb") as f: # data=f.read() # return HttpResponse(data) # 方式3: # from io import BytesIO # from PIL import Image # img = Image.new(mode="RGB", size=(120, 40), color="blue") # f=BytesIO() # img.save(f,"png") # data=f.getvalue() # return HttpResponse(data) # 方式4 : from io import BytesIO import random from PIL import Image,ImageDraw,ImageFont img = Image.new(mode="RGB", size=(120, 40), color=(random.randint(0,255),random.randint(0,255),random.randint(0,255))) draw=ImageDraw.Draw(img,"RGB") font=ImageFont.truetype("static/font/kumo.ttf",25) valid_list=[] for i in range(5): random_num=str(random.randint(0,9)) random_lower_zimu=chr(random.randint(65,90)) random_upper_zimu=chr(random.randint(97,122)) random_char=random.choice([random_num,random_lower_zimu,random_upper_zimu]) draw.text([5+i*24,10],random_char,(random.randint(0,255),random.randint(0,255),random.randint(0,255)),font=font) valid_list.append(random_char) f=BytesIO() img.save(f,"png") data=f.getvalue() valid_str="".join(valid_list) print(valid_str) request.session["Keep_auth_code"]=valid_str #将验证码写入session中 return HttpResponse(data)
三:注册:
页面
form组件:
#! usr/bin/env python # -*- coding: utf-8 -*- from django import forms from django.forms import fields from django.forms import widgets,ValidationError from app01 import models from django.core.validators import RegexValidator class RegisterForm(forms.Form): """注册Form组件""" username = forms.CharField( required=True, min_length=3, max_length=8, error_messages={ 'required': '用户不能为空', 'min_length': '用户长度不能小于3', 'max_length': '用户长度不能大于8', },widget=widgets.TextInput(attrs={'placeholder': '用户名:', 'class': 'form-control'})) password = fields.CharField( required=True, min_length=3, max_length=8, error_messages={ 'required': '密码不能为空', 'min_length': '密码长度不能小于3', 'max_length': '密码长度不能大于8', # 'invalid': '密码格式错误', }, # validators=[RegexValidator('d+', '只能是数字')], widget=widgets.PasswordInput(attrs={'placeholder': '密码:', 'class': 'form-control'})) confirm_password = fields.CharField( required=True, min_length=3, max_length=8, error_messages={ 'required': '确认密码不能为空', 'min_length': '确认密码长度不能小于3', 'max_length': '确认密码长度不能大于8', }, widget=widgets.PasswordInput(attrs={'placeholder': '确认密码:', 'class': 'form-control'})) email = fields.EmailField( required=True, error_messages={ 'required':'邮箱不能为空', 'invalid':'邮箱格式错误'}, widget=widgets.EmailInput(attrs={'placeholder':'邮箱:','class':'form-control'})) def clean_username(self): """用户名""" ret = models.UserInfo.objects.filter(username=self.cleaned_data.get("username")) if not ret: return self.cleaned_data.get("username") else: raise ValidationError("用户名已注册") def clean_password(self): """密码""" data = self.cleaned_data.get("password") if not data.isdigit(): return self.cleaned_data.get("password") else: raise ValidationError("密码不能全是数字") # def clean_auth_code(self): # if self.cleaned_data.get("auth_code")==self.request.session.get("auth_code"): # return self.cleaned_data.get("auth_code") # else: # raise ValidationError("验证码错误") def clean(self): if self.cleaned_data.get("password")==self.cleaned_data.get("confirm_password"): return self.cleaned_data else: raise ValidationError("两次密码不一致") def __init__(self,request,*args,**kwargs): super().__init__(*args,**kwargs) self.request=request
前端页面显示:
from django.shortcuts import render, HttpResponse, redirect from app01.forms import * from app01 import forms from app01 import models from django.db.models import Count import json from django.contrib import auth # 登录 def login(request): if request.is_ajax(): login_response = {"is_login": False, "error_msg": None} # 定义一个字典 username = request.POST.get("username") # 取到用户名 password = request.POST.get("password") # 取到密码 auth_code = request.POST.get("auth_code") # 取到验证码 if auth_code.upper() == request.session.get("auth_code").upper(): # 从session中获取验证码,判断是否正确 # print(username, password, '==========') user = auth.authenticate(username=username, password=password) print(user) # 通过auth模块获取用户名密码 if user: # 正确,判断用户名和密码是否正确 login_response["is_login"] = True auth.login(request, user) else: login_response["error_msg"] = "用户名或密码不正确" # 前端显示用户名或密码错误 else: login_response["error_msg"] = '验证码不正确' # 前端显示验证码错误 return HttpResponse(json.dumps(login_response)) # 返回 return render(request, "login.html") # 若不是Ajax访问方式,返回登录页面重新登录 # 验证码 def get_authCode_img(request): from io import BytesIO import random from PIL import Image, ImageDraw, ImageFont img = Image.new(mode="RGB", size=(120, 40), color=(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))) draw = ImageDraw.Draw(img, "RGB") font = ImageFont.truetype("static/font/kumo.ttf", 25) valid_list = [] for i in range(5): random_num = str(random.randint(0, 9)) random_lower_zimu = chr(random.randint(65, 90)) random_upper_zimu = chr(random.randint(97, 122)) random_char = random.choice([random_num, random_lower_zimu, random_upper_zimu]) draw.text([5 + i * 24, 10], random_char, (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)), font=font) valid_list.append(random_char) f = BytesIO() img.save(f, "png") data = f.getvalue() valid_str = "".join(valid_list) print(valid_str) request.session["auth_code"] = valid_str # 将验证码写入session中 return HttpResponse(data) #注销 def log_out(request): auth.logout(request) return redirect("/login/") # 注册 def register(request): if request.is_ajax(): form_obj = forms.RegisterForm(request,request.POST) print("---------") print(form_obj.is_valid()) regResponse = {"user": None, "errorsList": None} if form_obj.is_valid(): print("000000") username = form_obj.cleaned_data["username"] password = form_obj.cleaned_data["password"] # nickname = form_obj.cleaned_data["nickname"] # tel = form_obj.cleaned_data["tel"] email = form_obj.cleaned_data.get("email") avatar_img = request.FILES.get("avatar_img") user_obj = models.UserInfo.objects.create_user(username=username, password=password,email=email,avatar=avatar_img) regResponse["user"] = user_obj.username else: print("111") regResponse["errorsList"] = form_obj.errors print(regResponse) return HttpResponse(json.dumps(regResponse)) form_obj= forms.RegisterForm(request) return render(request, "register.html", {"form_obj": form_obj}) # 主页 def index(request,*args,**kwargs): if kwargs: article_list = models.Article.objects.filter(site_article_category__name=kwargs.get("site_article_category"))#查找点击的类的文章 else: article_list = models.Article.objects.all() site_list = models.SiteCategory.objects.all() return render(request, "index.html",{"article_list":article_list,"site_list":site_list}) #个人主页 def homeSite(request,username,**kwargs): # print(kwargs) # print(username) """点击文章用户名或,头像跳转的此页""" current_user = models.UserInfo.objects.filter(username=username).first()#获取当前用户 # current_blog = current_user.blog#获取当前博客 if not current_user: return render(request,"notFound.html") current_blog = current_user.blog # 获取当前博客 #查询当前文章 article_list=models.Article.objects.filter(user=current_user) #查询 当前用户的分类归档 classfication_list=models.Classfication.objects.all().filter(blog=current_blog).annotate(c=Count("article__id")).values_list("title","c") #查询当前用户的标签归档 tag_list=models.Tag.objects.all().filter(blog=current_blog).annotate(c=Count("article__id")).values_list("name","c") #查询当前用户的标签归档 date_list = models.Article.objects.filter(user=current_user).extra( select={"filter_create_date": "strftime('%%Y/%%m',create_time)"}).values_list("filter_create_date").annotate(Count("id")) if kwargs: if kwargs.get("condition")=="classify": print(kwargs.get("condition")) article_list = models.Article.objects.filter(user=current_user,classify__title=kwargs.get("para")) # article_list = models.Article.objects.filter(user=current_user, category__title=kwargs.get("para")) elif kwargs.get("condition")=="tag": article_list = models.Article.objects.filter(user=current_user,tags__name=kwargs.get("para")) elif kwargs.get("condition")=="date": year,month=kwargs.get("para").aplit("/") article_list = models.Article.objects.filter(user=current_user,create_time__year=year,create_time__month=month) return render(request,"homeSite.html", locals()) #具体文章详细 def contentsArticle(request,username,article_id): """点击文章标题,跳转到此页""" current_user = models.UserInfo.objects.filter(username=username).first() # 获取当前用户 current_blog = current_user.blog#获取当前博客 if not current_user: return render(request, "notFound.html") # 查询当前文章 article_list = models.Article.objects.filter(user=current_user) # 查询 当前用户的分类归档 classfication_list = models.Classfication.objects.all().filter(blog=current_blog).annotate( c=Count("article__id")).values_list("title", "c") # 查询当前用户的标签归档 tag_list = models.Tag.objects.all().filter(blog=current_blog).annotate(c=Count("article__id")).values_list("name", "c") # 查询当前用户的标签归档 date_list = models.Article.objects.filter(user=current_user).extra( select={"filter_create_date": "strftime('%%Y/%%m',create_time)"}).values_list("filter_create_date").annotate( Count("id")) article_obj = models.Article.objects.filter(id=article_id).first() return render(request,"contents_article.html",loca
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>用户注册页面</title> <link href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css" rel="stylesheet"> <link href="/static/css/register.css" rel="stylesheet"> <script src="/static/jquery-3.2.1.min.js"></script> <script src="/static/js/jquery.cookie.js"></script> </head> <body> <div class="container"> <div class="row col-md-4 col-lg-offset-4"> <form> {% csrf_token %} <h2 class="form-signin-heading col-lg-offset-3 text-info">请您注册:</h2> <div class="form-group"> <label for="username">用户名:</label> <p>{{ form_obj.username }} {{ form_obj.errors.username.0 }}</p> </div> <div class="form-group"> <label for="password">密码:</label> <p>{{ form_obj.password }} {{ form_obj.errors.password.0 }}</p> </div> <div class="form-group"> <label for="confirm_password">确认密码:</label> <p>{{ form_obj.confirm_password }} {{ form_obj.errors.confirm_password.0 }}</p> </div> {# <div class="form-group">#} {# <label for="nickname">昵称:</label>#} {# <p>{{ form_obj.nickname }} {{ form_obj.errors.nickname.0 }}</p>#} {# </div>#} {# <div class="form-group">#} {# <label for="tel">电话:</label>#} {# <p>{{ form_obj.tel }} {{ form_obj.errors.tel.0 }}</p>#} {# </div>#} <div class="form-group"> <label for="email">邮箱:</label> <p>{{ form_obj.email }} {{ form_obj.errors.email.0 }}</p> </div> <div class="form-group avatar"> <label for="avatar">头像</label> <img src="/static/img/default.png" alt="" id="avatar_img"> <input type="file" id="avatar_file"> </div > <div class="col-lg-offset-5"> <input type="button" value="提交" class="btn btn-primary" id="avatar_Btn"><span class="error"></span> </div> </form> </div> </div> <script> $("#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 } }); $("#avatar_Btn").click(function () { var formdata = new FormData(); formdata.append("username", $("#id_username").val()); formdata.append("password", $("#id_password").val()); formdata.append("confirm_password", $("#id_confirm_password").val()); {# formdata.append("nickname", $("#id_nickname").val());#} {# formdata.append("tel", $("#id_tel").val());#} formdata.append("email", $("#id_email").val()); formdata.append("avatar_img",$("#id_avatar_img").val()); $.ajax({ url: "/register/", type: "POST", data: formdata, contentType: false, processData: false, headers:{"X-CSRFToken":$.cookie('csrftoken')}, success: function (data) { console.log(data); var data = JSON.parse(data); if (data.user) { location.href = "/login/" } //全局钩子的错误提示 else { console.log(data.errorsList); $(".pull-right").html("").parent().removeClass("has-error");//去除第一次错误信息 $.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");//找到当前错误的input框 if (i=="__all__"){ $("#id_confirm_password").after($span) } }) } } }) }) </script> </body> </html>
后端代码:
def register(request): if request.is_ajax(): form_obj = forms.RegisterForm(request,request.POST) print("---------") print(form_obj.is_valid()) regResponse = {"user": None, "errorsList": None} if form_obj.is_valid(): print("000000") username = form_obj.cleaned_data["username"] password = form_obj.cleaned_data["password"] # nickname = form_obj.cleaned_data["nickname"] # tel = form_obj.cleaned_data["tel"] email = form_obj.cleaned_data.get("email") avatar_img = request.FILES.get("avatar_img") user_obj = models.UserInfo.objects.create_user(username=username, password=password,email=email,avatar=avatar_img) regResponse["user"] = user_obj.username else: print("111") regResponse["errorsList"] = form_obj.errors print(regResponse) return HttpResponse(json.dumps(regResponse)) form_obj= forms.RegisterForm(request) return render(request, "register.html", {"form_obj": form_obj})
css代码:
.container{ margin-top:50px; } .avatar{ position: relative; 60px; height: 60px; } #avatar_img,#avatar_file{ position: absolute; top:0; left: 40px; 60px; height: 60px; } #avatar_file{ opacity: 0; }
头像预览JS:
/** * Created by pc on 2017-11-21. */ //头像预览 $("#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 } }); $("#avatar_Btn").click(function () { var formdata = new FormData(); formdata.append("username", $("#id_username")).val(); formdata.append("password", $("#id_password")).val(); formdata.append("confirm_password", $("#id_confirm_password")).val(); formdata.append("nickname", $("#id_nickname")).val(); formdata.append("tel", $("#id_tel")).val(); formdata.append("email", $("#id_email")).val(); formdata.append("avatar_img",$("#id_avatar_img")).val(); $.ajax({ url: "/register/", type: "POST", data: formdata, contentType: false, processData: false, header: {"X-CSRFToken": $.cookie('csrftoken')}, success: function (data) { console.log(data); var data = JSON.parse(data); 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) } }) } } }) });
settings配置:
AUTH_USER_MODEL = "app01.UserInfo" STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR,"static"), ] MEDIA_ROOT=os.path.join(BASE_DIR,"app01","media","uploads") MEDIA_URL="/media/"
流程:
注册 1. form组件生成html标签 在RegFrom类中继承From这个类, 利用这个类的方法,生成input标签,在这个类中可设置,标签的属性 - username - password - email 2. 利用后端传来的form在前端生成html标签 第一次get请求时后返回RegFrom类实例化的对象, 前端生成- username,- password,- emai,- avatar对应的四个标签 显示图片: - 图片和上传文件折叠 - 作用:上传文件覆盖图片,透明度为零 用户点击图片其实点击上传文件 -把 - 把上传文件和图片的父亲标签设置为相对路径 设置长宽,自己 - 图片预览 - 用户点击上传文件 上传文件的标签发生变化,会触发change事件 - 取到用户上传的文件 var ele_file = this.files[0]; - 创建FileReader()对象4 - 把上传文件的对象的路径写入FileReader()对象,结果为FileReader().result - FileReader()加载onload事件,把FileReader().result结果写入到img标签 3. 用户提交数据 用户通过ajav提交数据: 如果要传二进制的数据必须要用FormData打包 在传二进制的时候必须要到的参数 -------contentType:false, ------processData:false, -----headers:{"X-CSRFToken":$.cookie('csrftoken')},防止跨站请求 --用FormData打包数据 var formdata=new FormData(); formdata.append("username",$("#id_username").val()); --通过data把数据传到后台函数 4.验证数据 post请求走Regfrom函数 -有错误利用RegForm 的钩子返回错误,----》 有错误将错误信息用键值对保存到errorst中 没有错误将前端拿到的数据放入cleaned_data中 注册函数中判断form_obj.is_valid对象是否正确 ---正确则获取数据写入数据库---返回一个状态 regResponse["user"]=user_obj.username-----给前端 ---错误则获取数据写入数据库---返回一个状太regResponse["errorsList"]=form_obj.errors-----给前端 后台函数利用form_obj.cleaned_data拿到数据 5、前端用ajax接收处理错误信息 $.each(data.errorsList,function (i,j) { {# controls.log(data.errorsList)#} {# console.log(i,j);#} // i j ------- username ["用户名不能为空"] ------- password ["密码不能为空"] ------- repeat_pwd ["验证密码不能为空"] ------- email ["邮箱不能为空"] $span=$("<span>"); $span.addClass("pull-right").css("color","red"); --------{# 添加一个span标签#} $span.html(j[0]); --------{#把log的值j写入span中#} $("#id_"+i).after($span).parent().addClass("has-error") -------#id_"+i找到当前的错误的input框 -------parent().addClass("has-error")给错误的input框加一个红色的颜色 if (i=="__all__"){ $("#id_repeat_pwd").after($span) -------全局钩子的错误信息 } })
四:博客主页:
页面:
前端代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale"> <title>{{username}}博客首页</title> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css"> <link rel="stylesheet" href="/static/css/homeSite.css"> <script src="/static/jquery-3.2.1.min.js"></script> <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script> </head> <body> <div class="MenuBar"> <div class="heeder"> <div class="leftbutton"> <span class="abuttn">{{current_user.username}}</span> <a href="" class="abuttn">博客园</a> </div> <div class="key-search"> <form action="/" method="post"> <a href="#" class="i"> <span class="ico"></span> </a> </form> </div> <div class="rightbutton"> <a href="" class="abuttn">首页</a> <a href="" class="abuttn">新随笔</a> <a href="" class="abuttn">联系</a> <a href="" class="abuttn">订阅</a> <a href="" class="abuttn">管理</a> </div> </div> </div> <div class="container homeSite"> <div class="row"> <div class="col-md-3 userinfo"> <div class="well well-lg "> <h4 class="col-lg-offset-3">个人信息</h4> <p>---------------------------------------------</p> <p><img src="{{current_user.avatar.url}}" alt="" width="100px" height="100px" class="img-circle"></p> <p>昵称:    <span>{{current_user.username}}</span></p> <p>园龄:</p> <p>粉丝:</p> <p>关注:</p> <a href="">+关注</a> </div> <div class="panel panel-primary"> <div class="panel-heading"><b>分类归档</b></div> <div class="panel-body"> {% for classfication in classfication_list %} <p><a href="/app01/{{ current_user.username }}/classify/{{classfication.0}}">{{classfication.0}}({{classfication.1}})</a></p> {# <p>{{ classfication }}</p>#} {% endfor %} </div> <div class="panel-heading"><b>标签归档</b></div> <div class="panel-body"> {% for tag in tag_list %} <p><a href="/app01/{{current_user.username}}/tag/{{tag.0}}">{{tag.0}}({{tag.1}})</a></p> {% endfor %} </div> <div class="panel-heading"><b>日期归档</b></div> <div class="panel-body"> {% for date in date_list %} <p><a href="/app01/{{current_user.username}}/date/{{date.0}}">{{date.0}}({{date.1}})</a></p> {% endfor %} </div> </div> </div> {# 文章#} <div class="col-md-9 articleinfo"> {% block content %} {% for article in article_list %} <div class="well well-lg "> <div class="col-lg-offset-9"> <h4>{{article.create_time|date:"Y年m月d日"}}</h4> </div> <p>---------------------------------------------------------------------------------------------------------------------------------------------------------------------------</p> <h3><a href="/app01/{{current_user.username}}/article/{{article.id}}"><b>{{article.title}}</b></a></h3> <hr> <div class="summary"> <p>{{article.summary}}<span><a href="">阅读全文</a></span></p> </div> <hr> <div class="col-lg-offset-5 info"> 发表于:<span>{{article.create_time|date:"Y-m-d H:i"}}</span>   评论:<span>({{article.comment_count}})</span>   点赞:<span>({{article.poll_count}})</span>   阅读:<span>({{article.read_count}})</span>     <span><a href="">编辑</a></span> </div> </div> {% endfor %} {% endblock %} </div> </div> </div> </body> </html>
后端代码:
def index(request,*args,**kwargs): if kwargs: article_list = models.Article.objects.filter(site_article_category__name=kwargs.get("site_article_category"))#查找点击的类的文章 else: article_list = models.Article.objects.all() site_list = models.SiteCategory.objects.all() return render(request, "index.html",{"article_list":article_list,"site_list":site_list})
1:在url中写主页路由
url(r'^index', views.index)
url(r'^index', views.index),#主页
2:创建视图函数,从数据库取出数据,返回到前端。
-------找到文章表,取出文章对象,返回。
-------找到网站分类表,取出分类对象,返回。
def index(request,*args,**kwargs): if kwargs: article_list = models.Article.objects.filter(site_article_category__name=kwargs.get("site_article_category"))#查找点击的类的文章 else: article_list = models.Article.objects.all() site_list = models.SiteCategory.objects.all() return render(request, "index.html",{"article_list":article_list,"site_list":site_list})
3:返回到主页html进行渲染:
1:-----拿到文章对象用for标签循环,{{.文章内容}}进行渲染。
<div class="col-md-6"> <div class=" article_list"> {% for article in article_list %} <div><a href="">{{article.title}}</a></div> <div class="row"> <div class="avatar col-md-2"> <a href="{% url 'aaa' article.user.username %}"><img src="{{article.user.avatar.url}}" alt="" width="80px" height="80px"></a> </div> <div class="summary col-md-10" > <p>{{article.summary}}</p> </div> </div> <div class="article_info row">   <a href="/app01/{{ article.user.username }}"><b>{{article.user.username}}</b></a>   发布与:{{article.create_time|date:"Y-m-d H:i"}}   <a href=""><span class="glyphicon glyphicon-comment"></span>评论({{article.comment_count}})</a>   <a href=""><span class="glyphicon glyphicon-thumbs-up"></span>点赞({{article.poll_count}})</a>   <a href=""><span class="glyphicon glyphicon-share-alt"></span>阅读({{article.read_count}})</a> </div> <hr> {% endfor %} </div>
2:-----拿到分类对象用for标签循环,{{.网站分类,父}}进行渲染。
3:-----拿到网站分类对象,{{.(反向查询,表名_set).网站分类,子}}进行渲染。
<div class="row col-md-3"> <div class="panel panel-primary"> <div class="panel-body"> 网站分类 </div> <div class="panel-footer"> {% for site in site_list %} <div class="panel panel-primary"> <div class="panel-heading cate_title">{{site.name}}</div> <div class="panel-body hides"> {% for sitearticlecategory in site.sitearticlecategory_set.all %} <p><a href="/site/{{sitearticlecategory.name}}">{{sitearticlecategory.name}}</a></p> {% endfor %} </div> </div> {% endfor %} </div> </div> </div>
4:JQ做动态折叠效果,鼠标悬浮展开,鼠标移开折叠。
1:-----选择器找到网站分类,给他绑定一个(悬浮)事件,当触发这个事件(鼠标悬浮),执行function,$(this)找到选择器对象,执行展开事件。
2:-----选择器找到网站分类的父级,给他绑定一个(悬浮)执行function,$(this)找到选择器对象,执行折叠事件事件。
$(".cate_title").mouseover(function () { $(this).next().slideDown(300) }).parent().mouseleave(function () { $(this).children(".panel-footer").slideUp(300) });
5:点击网站分类,子分类,查找到这个分类下的所有文章。
-------分类渲染在<a>标签中,给他一个url,鼠标点击,------走urls进行路由匹配--------找url的视图函数--------进行查找
a标签:---------/site/{{网站分类,name}}
url:------------以site开头,有名分组(接收点击的分类),按关键字传参.*匹配所有,返回一个键值对,返回到视图函数。
url(r'^site/(?P<site_article_category>.*)/$', views.index),
url(r'^site/(?P<site_article_category>.*)/$', views.index),
视图函数--------**kwargs接收键值对,判断kwargs,判断正确,进行网站查询,否则查询所有文章。
查询------------找到文章表,过滤(反向查询按字段)出文章的网站分类,子分类 =kwargs传过来的分类,返回到前端进行渲染。
article_list = models.Article.objects.filter(site_article_category__name=kwargs.get("site_article_category"))
def index(request,*args,**kwargs): if kwargs: article_list = models.Article.objects.filter(site_article_category__name=kwargs.get("site_article_category"))#查找点击的类的文
首页:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale"> <title>博客系统首页</title> <script src="/static/jquery-3.2.1.min.js"></script> <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css"> <style> .hides{ display: none; } </style> </head> <body> <nav class="navbar navbar-inverse primary"> <div class="container"> <a class="navbar-brand" href="#">博客园</a> <div id="bs-example-navbar-collapse-9" class="collapse navbar-collapse"> <ul class="nav navbar-nav navbar-right"> {# {% if request.user.is_authenticated %}#} <li><a href=""><span class="glyphicon glyphicon-user">{{request.user.uaername}}</span></a></li> <li><a href="/#/">注销</a></li> <li><a href="/#/">修改密码</a></li> {# {% else %}#} <li><a href="/#/">登录</a></li> <li><a href="/#/">注册</a></li> {# {% endif %}#} </ul> <form class="navbar-form navbar-right"> <input type="text" class="form-control" placeholder="搜索"> </form> </div> </div> </nav> <div class="container"> <div class="row col-md-3"> <div class="panel panel-primary"> <div class="panel-body"> 网站分类 </div> <div class="panel-footer"> {% for site in site_list %} <div class="panel panel-primary"> <div class="panel-heading cate_title">{{site.name}}</div> <div class="panel-body hides"> {% for sitearticlecategory in site.sitearticlecategory_set.all %} <p><a href="/site/{{sitearticlecategory.name}}">{{sitearticlecategory.name}}</a></p> {% endfor %} </div> </div> {% endfor %} </div> </div> </div> <div class="col-md-6"> <div class=" article_list"> {% for article in article_list %} <div><a href="">{{article.title}}</a></div> <div class="row"> <div class="avatar col-md-2"> <a href="{% url 'aaa' article.user.username %}"><img src="{{article.user.avatar.url}}" alt="" width="80px" height="80px"></a> </div> <div class="summary col-md-10" > <p>{{article.summary}}</p> </div> </div> <div class="article_info row">   <a href="/app01/{{ article.user.username }}"><b>{{article.user.username}}</b></a>   发布与:{{article.create_time|date:"Y-m-d H:i"}}   <a href=""><span class="glyphicon glyphicon-comment"></span>评论({{article.comment_count}})</a>   <a href=""><span class="glyphicon glyphicon-thumbs-up"></span>点赞({{article.poll_count}})</a>   <a href=""><span class="glyphicon glyphicon-share-alt"></span>阅读({{article.read_count}})</a> </div> <hr> {% endfor %} </div> </div> <div class="col-md-3"> <div class="panel panel-default"> <div class="panel-body"> Panel content </div> <div class="panel-footer">Panel footer</div> </div> <div class="panel panel-default"> <div class="panel-body"> Panel content </div> <div class="panel-footer">Panel footer</div> </div> <div class="panel panel-default"> <div class="panel-body"> Panel content </div> <div class="panel-footer">Panel footer</div> </div> </div> </div> <script> $(".cate_title").mouseover(function () { $(this).next().slideDown(300) }).parent().mouseleave(function () { $(this).children(".panel-footer").slideUp(300) }); {# $(".cate_title").mouseenter(function () {#} {# $(this).next().slideDown(300)#} {# });#} {# $(".panel-footer").mouseleave(function () {#} {# $(this).next().slideUp(300)#} {# });#} </script> </body> </html>
四:个人博客主页:
页面:
前端代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale"> <title>{{username}}博客首页</title> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css"> <link rel="stylesheet" href="/static/css/homeSite.css"> <script src="/static/jquery-3.2.1.min.js"></script> <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script> </head> <body> <div class="MenuBar"> <div class="heeder"> <div class="leftbutton"> <span class="abuttn">{{current_user.username}}</span> <a href="" class="abuttn">博客园</a> </div> <div class="key-search"> <form action="/" method="post"> <a href="#" class="i"> <span class="ico"></span> </a> </form> </div> <div class="rightbutton"> <a href="" class="abuttn">首页</a> <a href="" class="abuttn">新随笔</a> <a href="" class="abuttn">联系</a> <a href="" class="abuttn">订阅</a> <a href="" class="abuttn">管理</a> </div> </div> </div> <div class="container homeSite"> <div class="row"> <div class="col-md-3 userinfo"> <div class="well well-lg "> <h4 class="col-lg-offset-3">个人信息</h4> <p>---------------------------------------------</p> <p><img src="{{current_user.avatar.url}}" alt="" width="100px" height="100px" class="img-circle"></p> <p>昵称:    <span>{{current_user.username}}</span></p> <p>园龄:</p> <p>粉丝:</p> <p>关注:</p> <a href="">+关注</a> </div> <div class="panel panel-primary"> <div class="panel-heading"><b>分类归档</b></div> <div class="panel-body"> {% for classfication in classfication_list %} <p><a href="/app01/{{ current_user.username }}/classify/{{classfication.0}}">{{classfication.0}}({{classfication.1}})</a></p> {# <p>{{ classfication }}</p>#} {% endfor %} </div> <div class="panel-heading"><b>标签归档</b></div> <div class="panel-body"> {% for tag in tag_list %} <p><a href="/app01/{{current_user.username}}/tag/{{tag.0}}">{{tag.0}}({{tag.1}})</a></p> {% endfor %} </div> <div class="panel-heading"><b>日期归档</b></div> <div class="panel-body"> {% for date in date_list %} <p><a href="/app01/{{current_user.username}}/date/{{date.0}}">{{date.0}}({{date.1}})</a></p> {% endfor %} </div> </div> </div> {# 文章#} <div class="col-md-9 articleinfo"> {% block content %} {% for article in article_list %} <div class="well well-lg "> <div class="col-lg-offset-9"> <h4>{{article.create_time|date:"Y年m月d日"}}</h4> </div> <p>---------------------------------------------------------------------------------------------------------------------------------------------------------------------------</p> <h3><a href="/app01/{{current_user.username}}/article/{{article.id}}"><b>{{article.title}}</b></a></h3> <hr> <div class="summary"> <p>{{article.summary}}<span><a href="">阅读全文</a></span></p> </div> <hr> <div class="col-lg-offset-5 info"> 发表于:<span>{{article.create_time|date:"Y-m-d H:i"}}</span>   评论:<span>({{article.comment_count}})</span>   点赞:<span>({{article.poll_count}})</span>   阅读:<span>({{article.read_count}})</span>     <span><a href="">编辑</a></span> </div> </div> {% endfor %} {% endblock %} </div> </div> </div> </body> </html>
后端代码:
#个人主页 def homeSite(request,username,**kwargs): # print(kwargs) # print(username) """点击文章用户名或,头像跳转的此页""" current_user = models.UserInfo.objects.filter(username=username).first()#获取当前用户 # current_blog = current_user.blog#获取当前博客 if not current_user: return render(request,"notFound.html") current_blog = current_user.blog # 获取当前博客 #查询当前文章 article_list=models.Article.objects.filter(user=current_user) #查询 当前用户的分类归档 classfication_list=models.Classfication.objects.all().filter(blog=current_blog).annotate(c=Count("article__id")).values_list("title","c") #查询当前用户的标签归档 tag_list=models.Tag.objects.all().filter(blog=current_blog).annotate(c=Count("article__id")).values_list("name","c") #查询当前用户的标签归档 date_list = models.Article.objects.filter(user=current_user).extra( select={"filter_create_date": "strftime('%%Y/%%m',create_time)"}).values_list("filter_create_date").annotate(Count("id")) if kwargs: if kwargs.get("condition")=="classify": print(kwargs.get("condition")) article_list = models.Article.objects.filter(user=current_user,classify__title=kwargs.get("para")) # article_list = models.Article.objects.filter(user=current_user, category__title=kwargs.get("para")) elif kwargs.get("condition")=="tag": article_list = models.Article.objects.filter(user=current_user,tags__name=kwargs.get("para")) elif kwargs.get("condition")=="date": year,month=kwargs.get("para").aplit("/") article_list = models.Article.objects.filter(user=current_user,create_time__year=year,create_time__month=month) return render(request,"homeSite.html", locals())
url路由:
from django.conf.urls import include, url from django.contrib import admin from django.views.static import serve from Blog_long import settings from app01 import views urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url(r'^login', views.login), #登录 url(r'^get_authCode_img/', views.get_authCode_img), #验证码 url(r'^log_out',views.log_out), #注销 url(r'^register', views.register), # 注册 url(r'^index', views.index),#主页 # media 配置 url(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}), #首页点击分类查询到属于这个类的文章 url(r'^site/(?P<site_article_category>.*)/$', views.index), #个人站点首页,路由分发 url(r'^app01/', include('app01.urls')), ]
分发路由:
from django.conf.urls import include, url from app01 import views urlpatterns = [ url(r'^(?P<username>.*)/(?P<condition>classify|tag|date)/(?P<para>.*)', views.homeSite), url(r'^(?P<username>.*)/article/(?P<article_id>d+)', views.contentsArticle), url(r'^(?P<username>.*)',views.homeSite,name="aaa"), ]
1:点击首页中的--头像--和--发布人--,跳转到所对应的个人个人博客首页中。
--头像,发布人都渲染在<a>标签中。
--路由分发:以...开头,就映入到某个应用下的urls中进行匹配。
url(r'^app01/', include('app01.urls')),
url(r'^app01/', include('app01.urls')),
--给a标签一个url,点击走----url进行路由匹配,匹配成功走----所对应的视图函数。
url(r'^(?P<username>.*)', views.homeSite,name="aaa"),
<a>标签:----------点击发布人-----发送一个url:以app01/开头,引入到app01下的urls中,当前点击的用户名。进行路由匹配。
"/app01/{{ article.user.username }}"
0
------点击头像-------通过别名,反向解析------找到别名是...的url,替换
------视图函数中也可以用反向解析,原理相同,导入removes,传参数要用args。
{% url 'aaa' article.user.username %}
urls:-------------有名分组,按关键字传参,接收当前点击的用户名,返回到所对应的视图函数中,加别名,用于反向解析。
url(r'^(?P<username>.*)', views.homeSite,name="aaa"),
视图函数:--------接收kwargs键值对,和当前用户名-----查询当前用户名是点击的用户名,的用户信息对象,判断用户信息,如果不是返回错误信息。
--返回个人博客页面,返回用户信息。
查询:------------通过个人用户信息查询到个人个人站点(个人博客)
def homeSite(request,username,**kwargs): current_user = models.UserInfo.objects.filter(username=username).first()#获取当前用户 current_blog = current_user.blog print(current_blog)#获取当前博客 if not current_user: return render(request,"notFound.html") #查询当前文章 article_list=models.Article.objects.filter(user=current_user) #查询 当前用户的分类归档 classfication_list=models.Classfication.objects.all().filter(blog=current_blog).annotate(c=Count("article__id")).values_list("title","c") #查询当前用户的标签归档 tag_list=models.Tag.objects.all().filter(blog=current_blog).annotate(c=Count("article__id")).values_list("name","c") #查询当前用户的标签归档 date_list = models.Article.objects.filter(user=current_user).extra( select={"filter_create_date": "strftime('%%Y/%%m',create_time)"}).values_list("filter_create_date").annotate( Count("id")) if kwargs: if kwargs.get("condition")=="classify": article_list = models.Article.objects.filter(user=username,classify__title=kwargs.get("para")) elif kwargs.get("condition")=="tag": article_list = models.Article.objects.filter(user=username,tags__name=kwargs.get("para")) elif kwargs.get("condition")=="date": year,month=kwargs.get("para").aplit("/") article_list = models.Article.objects.filter(user=username,create_time__year=year,create_time__month=month) return render(request,"homeSite.html", locals())
2:查询当前用户的文章对象-----找到文章表,过滤出user=当前用户的文章,返回到页面进行渲染。
3:拿到用户信息,---------返回到页面渲染个人信息。
4:分类归档
1:-----查询当前用户,个人站点的分类对象-----分组查询到(查询当前用户,个人站点的分类对象)的数目
classfication_list=models.Classfication.objects.all().filter(blog=current_blog).annotate(c=Count("article__id")).values_list("title","c")
2:-----返回到页面进行渲染。
----for循环分类对象,是一个元组,.0拿到分类,.1拿到分类数量。进行渲染。
3:-----点击当前分类------查询到当前分类的文章进行渲染。
----<a>标签-------当前分类渲染在a标签中,点击,发送一个url-----/app01/{{ current_user.username }}/classify/{{classfication.0}}----走urls。
----urls:---------以app01开头,有名分组(当前用户),有名分组(归档方式),有名分组(具体分类)-----返回当前用户名,键值对到---视图函数----走视图函数。
url(r'^(?P<username>.*)/(?P<condition>classify|tag|date)/(?P<para>.*)', views.homeSite),
----视图函数------拿到当前用户名,键值对。
----判断kwargs中有名分组(分类)等不等于归档分类 ----if kwargs.get("condition")=="classify":----判断正确进行查询
----查询,-------查询当前用户个人站点所点击分类的文章。-----返回到页面进行渲染。
----article_list = models.Article.objects.filter(user=username,classify__title=kwargs.get("para"))
5:标签归档-----点击当前标签------查询到当前标签的文章进行渲染。
----<a>标签-------当前分类渲染在a标签中,点击,发送一个url-----/app01/{{ current_user.username }}/tag/{{classfication.0}}----走urls。
----urls:---------以app01开头,有名分组(当前用户),有名分组(归档方式),有名分组(具体标签)-----返回当前用户名,键值对到---视图函数----走视图函数。
url(r'^(?P<username>.*)/(?P<condition>classify|tag|date)/(?P<para>.*)', views.homeSite),
----视图函数------拿到当前用户名,键值对。
----判断kwargs中有名分组(分类)等不等于归档标签 ----if kwargs.get("condition")=="tag":----判断正确进行查询
----查询,-------查询当前用户个人站点所点击标签的文章。-----返回到页面进行渲染。
----article_list = models.Article.objects.filter(user=username,tags__name=kwargs.get("para"))
6:日期归档-----点击当前日期------查询到当前日期的文章进行渲染。
----<a>标签-------当前分类渲染在a标签中,点击,发送一个url-----/app01/{{ current_user.username }}/data/{{classfication.0}}----走urls。
----urls:---------以app01开头,有名分组(当前用户),有名分组(归档方式),有名分组(具体日期)-----返回当前用户名,键值对到---视图函数----走视图函数。
url(r'^(?P<username>.*)/(?P<condition>classify|tag|date)/(?P<para>.*)', views.homeSite),
----视图函数------拿到当前用户名,键值对。
----判断kwargs中有名分组(日期)等不等于归档分类 ----if kwargs.get("condition")=="data":----判断正确进行查询
----查询,-------查询当前用户个人站点所点击标签的文章。-----返回到页面进行渲染。
----获取时间----year,month=kwargs.get("para").aplit("/")
----article_list = models.Article.objects.filter(user=username,create_time__year=year,create_time__month=month)
个人博客首页:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale"> <title>{{username}}博客首页</title> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css"> <link rel="stylesheet" href="/static/css/homeSite.css"> <script src="/static/jquery-3.2.1.min.js"></script> <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script> </head> <body> <div class="MenuBar"> <div class="heeder"> <div class="leftbutton"> <span class="abuttn">{{current_user.username}}</span> <a href="" class="abuttn">博客园</a> </div> <div class="key-search"> <form action="/" method="post"> <a href="#" class="i"> <span class="ico"></span> </a> </form> </div> <div class="rightbutton"> <a href="" class="abuttn">首页</a> <a href="" class="abuttn">新随笔</a> <a href="" class="abuttn">联系</a> <a href="" class="abuttn">订阅</a> <a href="" class="abuttn">管理</a> </div> </div> </div> <div class="container homeSite"> <div class="row"> <div class="col-md-3 userinfo"> <div class="well well-lg "> <h4 class="col-lg-offset-3">个人信息</h4> <p>---------------------------------------------</p> <p><img src="{{current_user.avatar.url}}" alt="" width="100px" height="100px" class="img-circle"></p> <p>昵称:    <span>{{current_user.nickname}}</span></p> <p>园龄:</p> <p>粉丝:</p> <p>关注:</p> <a href="">+关注</a> </div> <div class="panel panel-primary"> <div class="panel-heading"><b>分类归档</b></div> <div class="panel-body"> {% for classfication in classfication_list %} <p><a href="/app01/{{ current_user.username }}/classify/{{classfication.0}}">{{classfication.0}}({{classfication.1}})</a></p> {# <p>{{ classfication }}</p>#} {% endfor %} </div> <div class="panel-heading"><b>标签归档</b></div> <div class="panel-body"> {% for tag in tag_list %} <p><a href="/app01/{{current_user.username}}/tag/{{tag.0}}">{{tag.0}}({{tag.1}})</a></p> {% endfor %} </div> <div class="panel-heading"><b>日期归档</b></div> <div class="panel-body"> {% for date in date_list %} <p><a href="/app01/{{current_user.username}}/date/{{date.0}}">{{date.0}}({{date.1}})</a></p> {% endfor %} </div> </div> </div> {# 文章#} <div class="col-md-9 articleinfo"> {% for article in article_list %} <div class="well well-lg "> <div class="col-lg-offset-9"> <h4>{{article.create_time|date:"Y年m月d日"}}</h4> </div> <p>---------------------------------------------------------------------------------------------------------------------------------------------------------------------------</p> <h3><a href=""><b>{{article.title}}</b></a></h3> <hr> <div class="summary"> <p>{{article.summary}}<span><a href="">阅读全文</a></span></p> </div> <hr> <div class="col-lg-offset-5 info"> 发表于:<span>{{article.create_time|date:"Y-m-d H:i"}}</span>   评论:<span>({{article.comment_count}})</span>   点赞:<span>({{article.poll_count}})</span>   阅读:<span>({{article.read_count}})</span>     <span><a href="">编辑</a></span> </div> </div> {% endfor %} </div> </div> </div> </body> </html>
博客首页-----和-----个人博客首页--流程:
1:在url中写主页路由 url(r'^index', views.index) 2:创建视图函数,从数据库取出数据,返回到前端。 -------找到文章表,取出文章对象,返回。 -------找到网站分类表,取出分类对象,返回。 3:返回到主页html进行渲染: 1:-----拿到文章对象用for标签循环,{{.文章内容}}进行渲染。 2:-----拿到分类对象用for标签循环,{{.网站分类,父}}进行渲染。 3:-----拿到网站分类对象,{{.(反向查询,表名_set).网站分类,子}}进行渲染。 4:JQ做动态折叠效果,鼠标悬浮展开,鼠标移开折叠。 1:-----选择器找到网站分类,给他绑定一个(悬浮)事件,当触发这个事件(鼠标悬浮),执行function,$(this)找到选择器对象,执行展开事件。 2:-----选择器找到网站分类的父级,给他绑定一个(悬浮)执行function,$(this)找到选择器对象,执行折叠事件事件。 $(".cate_title").mouseover(function () { $(this).next().slideDown(300) }).parent().mouseleave(function () { $(this).children(".panel-footer").slideUp(300) }); 5:点击网站分类,子分类,查找到这个分类下的所有文章。 -------分类渲染在<a>标签中,给他一个url,鼠标点击,------走urls进行路由匹配--------找url的视图函数--------进行查找 a标签:---------/site/{{网站分类,name}} url:------------以site开头,有名分组(接收点击的分类),按关键字传参.*匹配所有,返回一个键值对,返回到视图函数。 url(r'^site/(?P<site_article_category>.*)/$', views.index), 视图函数--------**kwargs接收键值对,判断kwargs,判断正确,进行网站查询,否则查询所有文章。 查询------------找到文章表,过滤(反向查询按字段)出文章的网站分类,子分类 =kwargs传过来的分类,返回到前端进行渲染。 article_list = models.Article.objects.filter(site_article_category__name=kwargs.get("site_article_category")) 四:个人博客主页: 1:点击首页中的--头像--和--发布人--,跳转到所对应的个人个人博客首页中。 --头像,发布人都渲染在<a>标签中。 --路由分发:以...开头,就映入到某个应用下的urls中进行匹配。 url(r'^app01/', include('app01.urls')), --给a标签一个url,点击走----url进行路由匹配,匹配成功走----所对应的视图函数。 <a>标签:----------点击发布人-----发送一个url:以app01/开头,引入到app01下的urls中,当前点击的用户名。进行路由匹配。 "/app01/{{ article.user.username }}" 0 ------点击头像-------通过别名,反向解析------找到别名是...的url,替换 ------视图函数中也可以用反向解析,原理相同,导入removes,传参数要用args。 {% url 'aaa' article.user.username %} urls:-------------有名分组,按关键字传参,接收当前点击的用户名,返回到所对应的视图函数中,加别名,用于反向解析。 url(r'^(?P<username>.*)', views.homeSite,name="aaa"), 视图函数:--------接收kwargs键值对,和当前用户名-----查询当前用户名是点击的用户名,的用户信息对象,判断用户信息,如果不是返回错误信息。 --返回个人博客页面,返回用户信息。 查询:------------通过个人用户信息查询到个人个人站点(个人博客) 2:查询当前用户的文章对象-----找到文章表,过滤出user=当前用户的文章,返回到页面进行渲染。 3:拿到用户信息,---------返回到页面渲染个人信息。 4:分类归档 1:-----查询当前用户,个人站点的分类对象-----分组查询到(查询当前用户,个人站点的分类对象)的数目 classfication_list=models.Classfication.objects.all().filter(blog=current_blog).annotate(c=Count("article__id")).values_list("title","c") 2:-----返回到页面进行渲染。 ----for循环分类对象,是一个元组,.0拿到分类,.1拿到分类数量。进行渲染。 3:-----点击当前分类------查询到当前分类的文章进行渲染。 ----<a>标签-------当前分类渲染在a标签中,点击,发送一个url-----/app01/{{ current_user.username }}/classify/{{classfication.0}}----走urls。 ----urls:---------以app01开头,有名分组(当前用户),有名分组(归档方式),有名分组(具体分类)-----返回当前用户名,键值对到---视图函数----走视图函数。 url(r'^(?P<username>.*)/(?P<condition>classify|tag|date)/(?P<para>.*)', views.homeSite), ----视图函数------拿到当前用户名,键值对。 ----判断kwargs中有名分组(分类)等不等于归档分类 ----if kwargs.get("condition")=="classify":----判断正确进行查询 ----查询,-------查询当前用户个人站点所点击分类的文章。-----返回到页面进行渲染。 ----article_list = models.Article.objects.filter(user=username,classify__title=kwargs.get("para")) 5:标签归档-----点击当前标签------查询到当前标签的文章进行渲染。 ----<a>标签-------当前分类渲染在a标签中,点击,发送一个url-----/app01/{{ current_user.username }}/tag/{{classfication.0}}----走urls。 ----urls:---------以app01开头,有名分组(当前用户),有名分组(归档方式),有名分组(具体标签)-----返回当前用户名,键值对到---视图函数----走视图函数。 url(r'^(?P<username>.*)/(?P<condition>classify|tag|date)/(?P<para>.*)', views.homeSite), ----视图函数------拿到当前用户名,键值对。 ----判断kwargs中有名分组(分类)等不等于归档标签 ----if kwargs.get("condition")=="tag":----判断正确进行查询 ----查询,-------查询当前用户个人站点所点击标签的文章。-----返回到页面进行渲染。 ----article_list = models.Article.objects.filter(user=username,tags__name=kwargs.get("para")) 6:日期归档-----点击当前日期------查询到当前日期的文章进行渲染。 ----<a>标签-------当前分类渲染在a标签中,点击,发送一个url-----/app01/{{ current_user.username }}/data/{{classfication.0}}----走urls。 ----urls:---------以app01开头,有名分组(当前用户),有名分组(归档方式),有名分组(具体日期)-----返回当前用户名,键值对到---视图函数----走视图函数。 url(r'^(?P<username>.*)/(?P<condition>classify|tag|date)/(?P<para>.*)', views.homeSite), ----视图函数------拿到当前用户名,键值对。 ----判断kwargs中有名分组(日期)等不等于归档分类 ----if kwargs.get("condition")=="data":----判断正确进行查询 ----查询,-------查询当前用户个人站点所点击标签的文章。-----返回到页面进行渲染。 ----获取时间----year,month=kwargs.get("para").aplit("/") ----article_list = models.Article.objects.filter(user=username,create_time__year=year,create_time__month=month)
五:文章详细(重点:点赞,评论)
解决bug:登录点赞,不登录返回登录页面。
六:后台管理
1:后台页面设计:-----------------给(管理)a标签一个路由:/app01/manage/
url:
url(r'^manage/$',views.manage),
前端代码:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale"> <title>后台管理</title> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css"> <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"> <script src="/static/jquery-3.2.1.min.js"></script> <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script> <script src="/static/kindeditor/kindeditor-all-min.js"></script> </head> <body> <div class="" style="background-color: #2459a2;height: 50px; 100%"> <div class="container"> <a class="navbar-brand" href="#"><b>{{ user.username }}博客园后台管理</b></a> <div id="bs-example-navbar-collapse-9" class="collapse navbar-collapse"> <ul class="nav navbar-nav navbar-right"> <li><a href="/logout/">注销</a></li> <li><a href="/setpassword/">修改密码</a></li> </ul> </div> </div> </div> <p></p> <div class="row col-md-2"> <div class="panel panel-primary "> <div class="panel-heading"><b>操作</b></div> <div class="panel-body"> <div class="panel-footer"><a href="/app01/manage/"><< 文章管理 >></a></div> <div class="panel-footer"><a href=""><< 分类管理 >></a></div> <div class="panel-footer"><a href=""><< 标签管理 >></a></div> <div class="panel-footer"><h2>{{ user }}!</h2></div> </div> </div> </div> <div class="col-md-9 sidebar alert-warning col-lg-offset-1"> {% block manage %} <div class="bs-example" data-example-id="contextual-table"> <table class="table"> <thead> <tr> <th>标题</th> <th>评论数</th> <th>点赞数</th> <th>操作</th> <th>操作</th> <th><a href="/app01/manage/add_article/"> <button class="btn btn-primary">添加</button> </a></th> </tr> </thead> <tbody> {% for article in article_list %} <tr> <td>{{ article.title }}</td> <td>{{ article.comment_count }}</td> <td>{{ article.poll_count }}</td> <td><a href=""> <button class="btn btn-primary">编辑</button> </a></td> <td><a href=""> <button class="btn btn-danger">删除</button> </a></td> </tr> {% endfor %} </tbody> </table> </div> {% endblock %} </div> </body> </html>
后端代码:
def manage(request): if not request.user.is_authenticated(): return redirect("/login/") article_list = models.Article.objects.filter(user=request.user).all() print(article_list) return render(request,"manage.html",{"article_list":article_list})
2:文章管理:
----添加文章:
url:
url(r'^manage/add_article/$',views.add_article),
前端代码:
{% extends "manage.html"%} {% block manage %} {% csrf_token %} <h4>添加文章:</h4> <form action="/app01/manage/add_article/" method="post" novalidate> {% csrf_token %} <div> <label for="title">标题:</label> <p>{{ article_form.title }} {{ article_form.errors.title.0 }}</p> </div> <div> <label for="content">内容:</label> <p>{{ article_form.content }} {{ article_form.errors.content.0 }}</p> </div> <p><button class="btn-sm btn-primary">提交</button></p> </form> <script> KindEditor.ready(function (K) { window.editor = K.create('#id_content', { {# 宽#} "1100px", {# 高#} height: "450px", {# 是否可以拖动#} resizeType: 0, {# 指定上传文件的终端,对应在url,视图函数#} uploadJson: "/uploadFile/", extraFileUploadParams: { csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val() } }); }) </script> {% endblock %}
添加文章Form组件:
#文章From组件 class ArticleFrom(forms.Form): title = forms.CharField( required=True, max_length=20, error_messages={ "required":"不能为空", },widget=widgets.TextInput(attrs={ 'class': 'form-control'})) content = forms.CharField( required=True, error_messages={ "required": "不能为空", },widget=widgets.Textarea(attrs={ 'class': 'form-control'})) def clean_content(self): # 拿到文章内容 html_str=self.cleaned_data.get("content") #调用函数 clean_content=xss_plugin.filter_xss(html_str) self.cleaned_data["content"]=clean_content return self.cleaned_data.get("content")
后端代码:
def add_article(request): if request.method=="POST": article_form = ArticleFrom(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,summary=content[0:30],create_time=datetime.datetime.now(),user=request.user) models.Article_detail.objects.create(content=content,article=article_obj) return HttpResponse("添加成功") else: pass article_form=ArticleFrom return render(request,"add_article.html",{"article_form":article_form})
3:添加kindeditor编辑器
下载:http://kindeditor.net/docs/option.html
编辑器(kindeditor)--------------------------------------http://kindeditor.net/docs/option.html
导入:
引用:
绑定编辑器:
代码:
url:
#编辑器上传文件 url(r'^uploadFile/$', views.uploadFile),
视图函数:-----------------文件预览
4:XSS攻击----用(beautifulsoup4模块实现)
(beautifulsoup4)----------------------------------------http://www.cnblogs.com/yuanchenqi/articles/7617280.html
----下载:
----xss组件:
代码:
from bs4 import BeautifulSoup def filter_xss(html_str): valid_tag_list = ["p", "div", "a", "img", "html", "body", "br", "strong", "b"] valid_dict = {"p": ["id", "class"], "div": ["id", "class"]} 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()
-----from组件 过滤,钩子
代码:
from django import forms from django.forms import fields from django.forms import widgets,ValidationError from app01 import models from app01.plugins import xss_plugin from django.core.validators import RegexValidator #注册Form组件 class RegisterForm(forms.Form): """注册Form组件""" username = forms.CharField( required=True, min_length=3, max_length=8, error_messages={ 'required': '用户不能为空', 'min_length': '用户长度不能小于3', 'max_length': '用户长度不能大于8', },widget=widgets.TextInput(attrs={'placeholder': '用户名:', 'class': 'form-control'})) password = fields.CharField( required=True, min_length=3, max_length=8, error_messages={ 'required': '密码不能为空', 'min_length': '密码长度不能小于3', 'max_length': '密码长度不能大于8', # 'invalid': '密码格式错误', }, # validators=[RegexValidator('d+', '只能是数字')], widget=widgets.PasswordInput(attrs={'placeholder': '密码:', 'class': 'form-control'})) confirm_password = fields.CharField( required=True, min_length=3, max_length=8, error_messages={ 'required': '确认密码不能为空', 'min_length': '确认密码长度不能小于3', 'max_length': '确认密码长度不能大于8', }, widget=widgets.PasswordInput(attrs={'placeholder': '确认密码:', 'class': 'form-control'})) email = fields.EmailField( required=True, error_messages={ 'required':'邮箱不能为空', 'invalid':'邮箱格式错误'}, widget=widgets.EmailInput(attrs={'placeholder':'邮箱:','class':'form-control'})) def clean_username(self): """用户名""" ret = models.UserInfo.objects.filter(username=self.cleaned_data.get("username")) if not ret: return self.cleaned_data.get("username") else: raise ValidationError("用户名已注册") def clean_password(self): """密码""" data = self.cleaned_data.get("password") if not data.isdigit(): return self.cleaned_data.get("password") else: raise ValidationError("密码不能全是数字") # def clean_auth_code(self): # if self.cleaned_data.get("auth_code")==self.request.session.get("auth_code"): # return self.cleaned_data.get("auth_code") # else: # raise ValidationError("验证码错误") def clean(self): if self.cleaned_data.get("password")==self.cleaned_data.get("confirm_password"): return self.cleaned_data else: raise ValidationError("两次密码不一致") def __init__(self,request,*args,**kwargs): super().__init__(*args,**kwargs) self.request=request #文章From组件 class ArticleFrom(forms.Form): title = forms.CharField( required=True, max_length=20, error_messages={ "required":"不能为空", },widget=widgets.TextInput(attrs={ 'class': 'form-control'})) content = forms.CharField( required=True, error_messages={ "required": "不能为空", },widget=widgets.Textarea(attrs={ 'class': 'form-control'})) def clean_content(self): # 拿到文章内容 html_str=self.cleaned_data.get("content") #调用函数 clean_content=xss_plugin.filter_xss(html_str) self.cleaned_data["content"]=clean_content return self.cleaned_data.get("content")