1、建表阶段:
关系图:

解释:
这个表总共有十张表: 用户表(userinfo): 建表原因:保存用户的信息。继承了django自带的AbstractUser用户信息表 字段: nickname(昵称) telephone(手机号) avatar(头像) create_time(创建时间) 博主个人站点表(Blog): 建表原因:为了显示个人的所有博客信息 字段: title(个人博客标题) site(个人博客后缀) theme(个人博客主题) user(对应用户)---------和用户表一对一 文章分类表(Category): 建表原因:为了把文章细分成类 字段: title(文章标题) blog(所属博客)---------和博客表多对一 文章表(Article): 建表原因:存储个人文章的信息 字段: title(文章标题) desc(文章描述) read(文章阅读量) comment_count(文章评论量) up_count(文章置顶) down_count(文章置末尾) create_time(文章创建时间) category(文章类型)----和类型表多对一 user(所属用户)--------和用户表多对一 tags(标签)------------和标签表多对多 文章详情表(ArticleDetail): 建表原因:存储个人文章的详细信息 content(文章类容) article(所属文章)----------和文章表示一对一 评论表(Comment): 建表原因:对文章的评论 content(评论类容) create_time(创建时间) up_count(评论量) user(评论者)--------------和用户多对一 article(评论文章)---------和文章表多对一 parent_comment(父级评论)--和自己自关联(为的是能自己评论自己,可以评论别人的评论) 评论点赞表(CommentUp): 建表原因:对评论的点赞 user(点赞的用户)------------和用户表多对一 comment(被点赞评论)----------和评论表多对一 文章点赞表(ArticleUp): 建表原因:对文章的点赞 user(点赞的用户)------------和用户表多对一 comment(被点赞文章)----------和文章表多对一 标签表(Tag): title(标签名称) bolg(所属博客)--------------和博客表多对一 文章和标签第二张表(Article2Tag): 建表原因:为了形成文章和标签的多对多关系,让后期添加数据更方便 article(文章)---------------和文章表多对一 tag(标签)--------------------和标签表多对一
数据库代码实现:
from django.db import models
from django.contrib.auth.models import AbstractUser #admin 表中的有些字段就不会显示
# Create your models here.
class UserInfo(AbstractUser): # settings: AUTH_USER_MODEL = "blog.UserInfo"
"""
用户信息
"""
nid = models.BigAutoField(primary_key=True)
nickname = models.CharField(verbose_name='昵称', max_length=32)
telephone = models.CharField(max_length=11, blank=True, null=True, unique=True, verbose_name='手机号码')
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 Blog(models.Model):
"""
站点信息
"""
nid = models.BigAutoField(primary_key=True)
title = models.CharField(verbose_name='个人博客标题', max_length=64)
site = models.CharField(verbose_name='个人博客后缀', max_length=32, unique=True)
theme = models.CharField(verbose_name='博客主题', max_length=32)
user = models.OneToOneField(to='UserInfo', to_field='nid')
class Meta:
verbose_name_plural = "站点信息表"
def __str__(self):
return self.title
class Category(models.Model):
"""
博主个人文章分类表
"""
nid = models.AutoField(primary_key=True)
title = models.CharField(verbose_name='分类标题', max_length=32)
blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid') #一个站点多个博客
def __str__(self):
return self.title
class Meta:
verbose_name_plural="文章分类表"
class Article(models.Model):
'''
文章表,最主要的一张表
'''
nid = models.BigAutoField(primary_key=True)
title = models.CharField(max_length=50, verbose_name='文章标题')
desc = models.CharField(max_length=255, verbose_name='文章描述') #外键用更加详细的描述
read_count = models.IntegerField(default=0)
comment_count = models.IntegerField(default=0)
up_count = models.IntegerField(default=0)
down_count = models.IntegerField(default=0)
create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True) # auto_now_add 当前的时间
category = models.ForeignKey(verbose_name='文章类型', to='Category', to_field='nid', null=True) #多个文章对应一个类型
user = models.ForeignKey(verbose_name='所属用户', to='UserInfo', to_field='nid') #多个文章对应一个用户
tags = models.ManyToManyField(
to="Tag",
through='Article2Tag',
through_fields=('article', 'tag'),
)
type_choices = [
(1, "编程语言"),
(2, "软件设计"),
(3, "前端"),
(4, "操作系统"),
(5, "数据库"),
]
article_type_id = models.IntegerField(choices=type_choices, default=None)
class Meta:
verbose_name_plural = "文章表"
def __str__(self):
return self.title
class ArticleDetail(models.Model):
"""
文章详细表
"""
nid = models.AutoField(primary_key=True)
content = models.TextField(verbose_name='文章内容', )
article = models.OneToOneField(verbose_name='所属文章', to='Article', to_field='nid') #每个文章的简介只是对应一片文章
class Meta:
verbose_name_plural = "文章详细表"
def __str__(self):
return self.content
class Comment(models.Model):
"""
评论表
"""
nid = models.BigAutoField(primary_key=True)
content = models.CharField(verbose_name='评论内容', max_length=255)
create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
up_count = models.IntegerField(default=0)
user = models.ForeignKey(verbose_name='评论者', to='UserInfo', to_field='nid') #评论表是由多个人组件起来的
article = models.ForeignKey(verbose_name='评论文章', to='Article', to_field='nid') #评论的是文章
parent_comment = models.ForeignKey('self', blank=True, null=True, verbose_name='父级评论') #自关联,父级评论
class Meta:
verbose_name_plural = "评论表"
def __str__(self):
return self.content
class CommentUp(models.Model):
"""
评论点赞表
"""
nid = models.AutoField(primary_key=True)
user = models.ForeignKey('UserInfo', null=True) #用户点赞
comment = models.ForeignKey("Comment", null=True) #对评论点赞
class Meta:
verbose_name_plural = "评论点赞表"
class ArticleUp(models.Model):
"""
文章点赞表
"""
nid = models.AutoField(primary_key=True)
user = models.ForeignKey('UserInfo', null=True) #用户点赞
article = models.ForeignKey("Article", null=True) #文章点赞
class Meta:
verbose_name_plural = "文章点赞表"
class Tag(models.Model):
'''
标签表
'''
nid = models.AutoField(primary_key=True)
title = models.CharField(verbose_name='标签名称', max_length=32)
blog = models.ForeignKey(verbose_name='所属博客', to='Blog', to_field='nid') #多个标签属于一个博客,,
class Meta:
verbose_name_plural = "标签表"
def __str__(self):
return self.title
class Article2Tag(models.Model):
'''
文章标签的第二张表,自己新建的
'''
nid = models.AutoField(primary_key=True)
article = models.ForeignKey(verbose_name='文章', to="Article", to_field='nid') #对应文章
tag = models.ForeignKey(verbose_name='标签', to="Tag", to_field='nid') #对应标签
class Meta:
unique_together = [
('article', 'tag'),
]
2、登录界面的实现:
界面显示:

前段代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>博客登录页面</title>
<link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css/">
</head>
<body>
<div class="container col-md-offset-3 col-sm-6 " >
<div class="panel panel-primary " style="margin-top:80px">
<div class="panel-heading">请登录</div>
<div class="panel-body">
<form class="form-horizontal" method="post">
{% csrf_token %}
<div class="form-group ">
<label for="username" class="col-sm-3 control-label">账号:</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="username" placeholder="账号" >
</div>
</div>
<div class="form-group">
<label for="password" class="col-sm-3 control-label">密码:</label>
<div class="col-sm-8">
<input type="password" class="form-control" id="password" placeholder="密码" >
</div>
</div>
<div class="form-group">
<label for="verify" class="col-sm-3 control-label">验证码:</label>
<div class="col-sm-3">
<input type="text" class="form-control" id="verify" placeholder="验证码">
</div>
<div class="col-md-4">
<img class="validCode_img" src="/get_validCode_img/" alt="" width="200px" height="35px">
</div>
</div>
<div id="qq" class="col-md-offset-4"></div>
<dic class="error"></dic>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="button" class="btn btn-primary login_btn" style="margin-left: 70px">登录</button>
<a href="/reg/" type="button" class="btn btn-info" id="refBtn">注册</a>
</div>
</div>
</form>
</div>
</div></div>
<script src="/static/jquery-3.2.1.js"></script>
<script src="/static/jquery.cookie.js"></script>
<script>
$(".login_btn").click(function () {
$.ajax({
url:"/login/",
type:"POST",
headers: {"X-CSRFToken": $.cookie('csrftoken')},
data:{
"username":$("#username").val(),
"password":$("#password").val(),
"validCode":$("#verify").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")
}
}
});
{#点击图片刷新验证码#}
$(".validCode_img").click(function () {
$(this)[0].src+="?";
})})
</script>
</body>
</html>
后台登录代码示例:
def login(request):
if request.method == "POST":
print(request.POST)
username=request.POST.get("username")
password=request.POST.get("password")
volidCode=request.POST.get("validCode")
login_response={"is_login":False,"error_msg":None}
if volidCode.upper()==request.session.get("keepValidCode").upper(): #对比验证码
user = auth.authenticate(username=username,password=password) #对比账户和密码
if user: #如果user正确
login_response["is_login"]=True #就把login_response的值改为true
auth.login(request,user) #应为继承了uesrinfo的表所以就用
else:
login_response["error_msg"] = "用户名或密码错误"
else:
login_response["error_msg"] = '验证码错误'
import json
return HttpResponse(json.dumps(login_response))
else:
return render(request, "login.html")
后台验证码的代码示例:
def get_validCode_img(request):
from io import BytesIO
import random
#导入的画笔包ImageDraw,字体包ImageFont
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("app01/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["keepValidCode"] = valid_str
return HttpResponse(data)
流程客户端请求服务端的流程图:

流程:
流程: 1、客户端向————(第一次git请求)————>服务端返回登录页 2、延验码-----src(url再次请求服务端)---->服务端执行验证码函数,生成验证码,保存到session中 3、用户输入内容---点击提交发送agax请求---(post)------>服务端从ruquest中去agax请求的信息, 从sessing中取出验证码进行和agax中的信息进行匹配 成功-----进行下一步登录验证 失败-----记录错误信息 | | | | 验证用户信息的状态 用字典的形式保存到login_response | 正确用:"is_login":true保存状态写入session 错误:返回一个字段的字符串 最后 return login_response
使用到的知识点;
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+="?";
3、注册功能实现

代码示例
前端代码示例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>注册页面</title> </head> <script src="/static/jquery-3.2.1.js"></script> <script src="/static/bootstrap-3.3.7/js/bootstrap.js"></script> <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css"> <link rel="stylesheet" href="/static/css/reg.css"> <script src="/static/jquery.cookie.js"></script> <body> <div class="container"> <div class="row"> <div class="col-md-5 col-md-offset-3"> <form> {% csrf_token %} <div class="form-group"> <label for="username">用户名</label> {{ form_obj.username }} </div> <div class="form-group"> <label for="password">密码</label> {{ form_obj.password }} </div> <div class="form-group"> <label for="password">确认密码</label> {{ form_obj.repeat_pwd }} </div> <div class="form-group"> <label for="email">邮箱</label> {{ form_obj.email }} </div> <div class="form-group avatar"> <label for="avatar">头像选择</label> <img src="/static/img/lll.jpg" alt="" id="avatar_img"> <input type="file" class="form-control" id="avatar_file" > </div> <input type="button" value="提交" class="btn btn-primary" id="subBtn"><span class="error"></span> </form> </div> </div> </div> <script> // 头像预览 $("#avatar_file").change(function () { var ele_file = this.files[0]; //this.files var reader=new FileReader(); reader.readAsDataURL(ele_file);//获取当前选择的图片路径 reader.onload=function () { $("#avatar_img")[0].src=this.result } }); {# 提交数据#} $("#subBtn").click(function () { var formdata=new FormData(); formdata.append("username",$("#id_username").val()); formdata.append("password",$("#id_password").val()); formdata.append("repeat_pwd",$("#id_repeat_pwd").val()); formdata.append("email",$("#id_email").val()); formdata.append("avatar_img",$("#avatar_file")[0].files[0]); $.ajax({ url:"/reg/", 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"); //去除前面一次的错误信息 //parent().removeClass("has-error");去除input框的颜色 $.each(data.errorsList,function (i,j) { 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) //全局钩子的错误信息 } }) } } }) }) </script> </body> </html>
后台代码示例:
def reg(request): if request.method == "POST": #若果是post请求 #进入RegForm中验证格式是否错误 form_obj=RegForm(request.POST) regResponse={"user":None,"errorsList":None} # if form_obj.is_valid(): # cleaned_data 正确的信息 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") user_obj=models.UserInfo.objects.create_user(username=username,password=password,email=email,avatar=avatar_img,nickname=username) regResponse["user"]=user_obj.password else: regResponse["errorsList"]=form_obj.errors print("&&&&&&&&&&&&&&&&&&&&",form_obj.errors) print("===================",form_obj.cleaned_data) # #<ul class="errorlist"><li>email<ul class="errorlist"><li>邮箱不能为空</li></ul></li></ul> import json return HttpResponse(json.dumps(regResponse)) else: form_obj=RegForm() return render(request,"reg.html",{"form_obj":form_obj}) #如果是get请求将返回一个页面,并且请from生成的标签返回
后台生成form表单代码
from django import forms from django.forms import widgets,ValidationError from app01 import models class RegForm(forms.Form): #账户 required=TRUE必须要填的 error_messages错误提示信息 username=forms.CharField(max_length=12,min_length=2,required=True, error_messages={"required":"用户名不能为空","min_length":"用户名必须大于五位",}, widget=widgets.TextInput(attrs={"class":"form-control","placeholder":"username"}) ) #密码 password=forms.CharField(min_length=6,required=True, error_messages={"required": "密码不能为空", "max_length": "用户名必须大于五位", }, widget=widgets.PasswordInput( attrs={"class": "form-control", "placeholder": "password"} )) #确认密码 repeat_pwd=forms.CharField(min_length=6, error_messages={"required": "验证密码不能为空", "max_length": "密码名必须大于六位", }, widget=widgets.PasswordInput(attrs={"class": "form-control", "placeholder": "repeat_pwd"} )) # 邮件 email=forms.EmailField(required=True, error_messages={"required": "邮箱不能为空" }, widget=widgets.EmailInput( attrs={"class": "form-control", "placeholder": "email"} )) #用户名的钩子 def clean_username(self): ret=models.UserInfo.objects.filter(username=self.cleaned_data.get("username")) print("****************************>>>>>",self.cleaned_data.get) print ("*****************************") 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(self): if self.cleaned_data.get("password") == self.cleaned_data.get("repeat_pwd"): return self.cleaned_data else: raise ValidationError("两次密码不一致")
代码流程
注册
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)
-------全局钩子的错误信息
}
})
4、博客首页的实现

后台代码示例:
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() cate_list=models.SiteCategory.objects.all() return render(request,"index.html",{"article_list":article_list,"cate_list":cate_list})
前端代码的实现:
<!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=1"> <title>博客首页</title> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css"> <script src="/static/jquery-3.2.1.js"></script> <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.js"></script> <style> .hides { display: none; } </style> <body> <nav class="navbar navbar-inverse"> <div class="container"> <!-- Brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="#">博客园</a> </div> <!-- Collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <li class="active"><a href="#">园子 <span class="sr-only">(current)</span></a></li> <li><a href="#">博文</a></li> <li><a href="#">新闻</a></li> <li><a href="#">收藏</a></li> <li><a href="#">小组</a></li> <li><a href="#">招聘</a></li> </ul> <ul class="nav navbar-nav navbar-right"> {% if request.user.is_authenticated %} <li><a href=""><span class="glyphicon glyphicon-user"></span>{{ request.user.username }}</a></li> <li><a href="/log_out/">注销</a></li> {% else %} <li><a href="/login/">登录</a></li> <li><a href="/reg/">注册</a></li> {% endif %} <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a> <ul class="dropdown-menu"> <li><a href="#">Action</a></li> <li><a href="#">Another action</a></li> <li><a href="#">Something else here</a></li> <li role="separator" class="divider"></li> <li><a href="#">Separated link</a></li> <li role="separator" class="divider"></li> <li><a href="#">One more separated link</a></li> </ul> </li> </ul> </div><!-- /.navbar-collapse --> </div><!-- /.container-fluid --> </nav> <div class="container"> {#左侧菜单部分#} <div class="col-md-2"> <div class="panel panel-default"> <div class="panel-heading">网站分类</div> {% for cate in cate_list %} <div class="panel panel-default "> <div class="panel-heading cate_title "> <div class="panel-body">{{ cate.name }} </div> </div> <div class="panel-body hides"> {% for sitearticlecategory in cate.sitearticlecategory_set.all %} <p><a href="/cate/{{ sitearticlecategory.name }}">{{ sitearticlecategory.name }}</a></p> {% endfor %} </div> </div> {% endfor %} </div> </div> {#文章部分#} <div class="col-md-7"> {% for article in article_list %} <div class="article_itme"> <div class="title"><a href="/blog/{{ article.user.username }}">{{ article.title }}</a></div> <div class="row"> <div class="avatar col-md-2"> <a href="/blog/{{ article.user.username }}"><img src="/media/{{ article.user.avatar }}" alt="" width="70" height="70"></a> </div> <div class="desc col-md-10"><p>{{ article.desc }}</p></div> </div> <div class="row"> <a href="/blog/{{ article.user.username }}" class="name">{{ article.user.username }}</a> <span class="time ">发布于:{{ article.create_time|date:"Y-m-d" }}</span> <a href="" class="glyphicon glyphicon-comment"> 评论:{{ article.comment_count }}</a> <a href="" class="glyphicon glyphicon-thumbs-up"> 点赞:{{ article.comment_count }}</a> </div> <hr> </div> {% endfor %} </div> {#右侧部分#} <div class="col-md-3"> <div class="panel panel-default"> <div class="panel-heading">Panel heading without title</div> <div class="panel-body"> Panel content </div> </div> <div class="panel panel-default"> <div class="panel-heading">Panel heading without title</div> <div class="panel-body"> Panel content </div> </div> <div class="panel panel-default"> <div class="panel-heading">Panel heading without title</div> <div class="panel-body"> Panel content </div> </div> </div> </div> </div> <script> $(".cate_title").mouseover(function () { $(this).next().slideDown(300) }).parent().mouseleave(function () { $(this).children(".panel-body").slideUp(300) }) </script> </body> </html>
逻辑流程:
问题一: 在导入图片的时候需要在url中配置,在查找图片的后面需要加上.url 模块的导入 from django.conf import settings from django.views.static import serve url(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),#配置图片 问题二: 给博客站点的分类下的字分类进行隐藏 .hides { display: none; } 问题三:给分类下的给一个事件,鼠标移动就展开mouseover(鼠标移动事件) $(".cate_title").mouseover(function () { $(this).next().slideDown(300) <script> $(".cate_title").mouseover(function () { $(this).next().slideDown(300) }).parent().mouseleave(function () { $(this).children(".panel-body").slideUp(300) }) </script> 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"))
浙公网安备 33010602011771号