day15 BBS项目
项目开发流程
- 需求分析
- 项目设计
- 分组开发
- 测试
- 上线
表设计
'''
一个项目中最重要的不是业务逻辑的书写
而是前期的表设计,只要将表设计好了,后续的功能书写才会一帆风顺
'''
# bbs表设计
1.用户表
继承AbstractUser
扩展字段:
phone :电话号码
avatar :用户头像
create_time :创建时间
外键字段:
一对一个人站点表
2.个人站点表
site_name:站点名称
site_title;站点标题
site_theme:站点样式
外键字段:
一对多个人站点
3.文章标签表
name:标签名
外键字段:
一对多个人站点
4.文章分类表
name:分类名
外键字段:
一对多个人站点
5.文章表
title:文章标题
desc:文章简介
content:文章内容
create_time:发布时间
# 数据库字段设计优化(虽然下面的三个字段可以从其他表里面跨表查询计算得出,但是频繁跨表效率比较低下)
'''所以在文章表添加下面的三个字段,添加普通字段同步更新,减少跨表查询次数'''
up_num :点赞数
down_num :点踩数
comment_num :评论数
外键字段:
一对多个人站点
多对多文章标签
一对多文章分类
6.点赞点踩表
记录哪个用户给哪篇文章点了赞还是点了踩
user :用户 ForeignKey(to="User")
article :文章 ForeignKey(to="Article")
is_up :是否点赞 BooleanField()
7.文章评论表
记录哪个用哪个户给哪篇文章写了哪些评论内容
user ForeignKey(to="User")
article ForeignKey(to="Article")
content CharField()
comment_time DateField()
parent ForeignKey(to="Comment",null=True) # 自关联
# parent ForeignKey(to="self",null=True) # orm提供的语法自关联
评论分为根评论和子评论(可以评论别人评论的)
根评论:是评论文章内容的评论
字评论:是回复别人的评论
# 外键关系:是一对多的
创建表字段
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
# 用户表
class UserInfo(AbstractUser):
phone = models.CharField(max_length=32, verbose_name='手机号')
# 头像
avatar = models.FileField(upload_to='static/img', default='static/img/111.png', verbose_name='头像')
'''
给avatar字段传文件对象,该文件会自动存储到avatar文件下,然后avatar字段只保存文件路径
'''
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
# 一对一站点表:用户表和站点表是一对一关系
blog = models.OneToOneField(to='Blog', null=True, verbose_name='关联站点表')
# 站点表
class Blog(models.Model):
site_name = models.CharField(max_length=64, verbose_name='站点名称')
site_title = models.CharField(max_length=64, verbose_name='站点标题')
site_theme = models.CharField(max_length=64, verbose_name='站点主题')
# 标签表
class Tag(models.Model):
name = models.CharField(max_length=32)
# 一对多站点表:标签表和站点表是一对多关系
blog = models.ForeignKey(to='Blog', verbose_name='关联站点表')
# 分类表
class Category(models.Model):
name = models.CharField(max_length=32, verbose_name='分类名称')
# 一对多站点表:分类表和站点表是一对多关系
blog = models.ForeignKey(to='Blog', verbose_name='关联站点表')
# 文章表
class Article(models.Model):
title = models.CharField(max_length=128, verbose_name='文章标题')
desc = models.CharField(max_length=512, verbose_name='文章简介')
content = models.TextField(verbose_name='文章内容')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
# 优化字段
up_num = models.IntegerField(verbose_name='点赞数')
down_num = models.IntegerField(verbose_name='点踩数')
comment_num = models.IntegerField(verbose_name='评论数')
# 外键关系
# 一对多站点表:文章表和站点表是一对多关系
blog = models.ForeignKey(to='Blog', verbose_name='关联站点表')
tags = models.ManyToManyField(to='Tag', through='Article2Tag',
through_fields=('article', 'tag'),
verbose_name='关联第三张表'
)
category = models.ForeignKey(to='Category', verbose_name='关联分类表')
# 自己创建的第三张表,用于扩建字段
class Article2Tag(models.Model):
article = models.ForeignKey(to='Article')
tag = models.ForeignKey(to='Tag')
# 点赞点踩表
class UpAndDown(models.Model):
user = models.ForeignKey(to='UserInfo', verbose_name='关联用户表')
article = models.ForeignKey(to='Article', verbose_name='关联文章表')
is_up = models.BooleanField() # 存的是0/1
# 评论表
class Comment(models.Model):
user = models.ForeignKey(to='UserInfo', verbose_name='关联用户表')
article = models.ForeignKey(to='Article', verbose_name='关联文章表')
content = models.CharField(max_length=512, verbose_name='评论内容')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
# 根评论和子评论一对多的关系,自关联
parent_id = models.ForeignKey(to='self', null=True) # self就是关联自己表
搭建注册页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
{% load static %}
<link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
<script src="{% static 'layer-v3.5.1/layer/layer.js' %}"></script>
</head>
<body>
<div class="container-fluid">
<div class="row">
<h1 class="text-center">注册页面</h1>
<div class="col-md-8 col-md-offset-2">
<form action="">
{% csrf_token %}
<div class="form-group">
<label for="">用户名:</label>
<input type="text" id="username" class="form-control">
</div>
<div class="form-group">
<label for="">密码:</label>
<input type="password" id="pwd" class="form-control">
</div>
<div class="form-group">
<label for="">确认密码:</label>
<input type="password" id="re_pwd" class="form-control">
</div>
<div class="form-group">
<label for="">邮箱:</label>
<input type="text" id="email" class="form-control">
</div>
<div class="form-group">
<label for="myfile">头像:
{% load static %}
<img src="{% static 'img/111.png' %}" alt="" class="img-circle" width="66px" id="myimg">
</label>
<input type="file" id="myfile" class="form-control" style="display: none">
</div>
<input type="button" class="btn btn-block btn-success pull-right" value="注册">
</form>
</div>
</div>
</div>
<script>
// 头像实时展示:借助于文件阅读器
$('#myfile').change(function () {
// 1.借助于文件阅读器
var myFileReadObj = new FileReader();
// 2.获取图片数据
var myImgObj = $('#myfile')[0].files[0];
// 3. 把图片数据交给文件阅读器读取
myFileReadObj.readAsDataURL(myImgObj); // 异步操作,有io
// 3.1 因为是异步操作。先让它加载完在执行后面的
myFileReadObj.onload = function () {
// 4.改变img的src
$('#myimg').attr('src',myFileReadObj.result)
}
});
$('.btn').on('click', function () {
var username = $('#username').val();
// 简单验证
if (!username) {
layer.msg('请输入用户名')
return
}
// 借助于ForData
var formDataObj = new FormData();
// 向formDataObj增加普通数据
formDataObj.append('username', $('#username').val());
formDataObj.append('pwd', $('#pwd').val());
formDataObj.append('re_pwd', $('#re_pwd').val());
formDataObj.append('email', $('#email').val());
// 添加文件数据
formDataObj.append('myfile', $('#myfile')[0].files[0]);
// 发送ajax请求
$.ajax({
url:'',
type:'post',
data:formDataObj,
contentType:false,
processData: false,
success:function (args) {
if (args.code == 200){
layer.msg(args.msg,{icon:1}, function () {
location.href = args.url
})
}else {
layer.msg(args.msg)
}
}
})
})
</script>
</body>
</html>
'''
其中包换头像上传功能
'''
注册功能实现
from django.shortcuts import render, HttpResponse, redirect
from django.http import JsonResponse
from app01 import models
def register(request):
if request.method == 'POST':
# 1.获取用户数据
back_dic = {'code': 200, 'msg': '注册成功'}
username = request.POST.get('username')
pwd = request.POST.get('pwd')
re_pwd = request.POST.get('re_pwd')
email = request.POST.get('email')
avatar = request.FILES.get('myfile')
# 2.验证参数
if not username:
back_dic['code'] = 201
back_dic['msg'] = '用户名必须填写'
return JsonResponse(back_dic)
if not pwd:
back_dic['code'] = 202
back_dic['msg'] = '密码必须填写'
return JsonResponse(back_dic)
if not re_pwd:
back_dic['code'] = 203
back_dic['msg'] = '确认密码必须填写'
return JsonResponse(back_dic)
if not email:
back_dic['code'] = 204
back_dic['msg'] = '邮箱必须填写'
return JsonResponse(back_dic)
res = models.UserInfo.objects.filter(username=username).first()
email_obj = models.UserInfo.objects.filter(email=email).first()
# 判断用户是否存在
if res:
back_dic['code'] = 205
back_dic['msg'] = '用户名已存在'
return JsonResponse(back_dic)
# 判断密码是否一致
if not pwd == re_pwd:
back_dic['code'] = 206
back_dic['msg'] = '密码两次不一致'
return JsonResponse(back_dic)
# 判断邮箱是否已经绑定
if email_obj:
back_dic['code'] = 207
back_dic['msg'] = '邮箱已绑定'
return JsonResponse(back_dic)
# 3.业务逻辑
data_dic = {}
if avatar:
data_dic['avatar'] = avatar
# 给密码加密
import hashlib
m = hashlib.md5()
m.update(pwd.encode('utf-8'))
pwd = m.hexdigest()
data_dic['username'] = username
data_dic['password'] = pwd
data_dic['email'] = email
# 4.存入数据库
models.UserInfo.objects.create(**data_dic) # 利用可变长参数,传入数据
# 5.返回格式化数据
back_dic['url'] = '/login/'
return JsonResponse(back_dic)
return render(request, 'register.html')
登录页面搭建
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
{% load static %}
<link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
<script src="{% static 'layer-v3.5.1/layer/layer.js' %}"></script>
</head>
<body>
<div class="container-fluid">
<div class="row">
<h1 class="text-center">登录页面</h1>
<div class="col-md-8 col-md-offset-2">
<form action="">
<div class="form-group">
<label for="">用户名:</label>
<input type="text" id="username" class="form-control">
</div>
<div class="form-group">
<label for="">密码:</label>
<input type="password" id="password" class="form-control">
</div>
<div class="form-group">
<label for="">验证码:</label>
<div class="row">
<div class="col-md-6">
<input type="text" id="code" class="form-control">
</div>
<div class="col-md-6">
<img src="/get_code/" id="my_img" alt="" style="width: 475px;height: 30px;">
</div>
</div>
</div>
<input type="button" class="btn btn-success btn-block" value="登录">
</form>
</div>
</div>
</div>
<script>
// 点击图片切换验证码
$('#my_img').on('click', function () {
// 拿当前点击图片中的src属性
var old = $(this).attr('src');
// 更换src属性
$(this).attr('src', old += '?')
})
// 给登录按钮绑定点击事件
$('.btn').on('click', function () {
// 获取输入框中的数据
var username = $('#username').val();
var password = $('#password').val();
var code = $('#code').val();
// 发送ajax请求
$.ajax({
url: '',
type: 'post',
data: {'username': username, 'password': password, 'code': code},
success: function (res) {
if (res.code == 200) {
layer.msg(res.msg, {},function () {
location.href = res.url;
});
} else {
layer.msg(res.msg, {icon:2});
}
}
})
})
</script>
</body>
</html>
登录功能实现
def login(request):
if request.method == 'POST':
back_dic = {'code': 200, 'msg': '登录成功'}
# 接收参数
username = request.POST.get('username')
password = request.POST.get('password')
code = request.POST.get('code')
# 验证参数
if not code:
back_dic['code'] = 208
back_dic['msg'] = '验证码必须填写'
return JsonResponse(back_dic)
if request.session.get('code').upper() != code.upper():
back_dic['code'] = 209
back_dic['msg'] = '验证码填写错误'
return JsonResponse(back_dic)
# 业务逻辑
# 给密码加密
import hashlib
m = hashlib.md5()
m.update(password.encode('utf-8'))
password = m.hexdigest()
user_obj = models.UserInfo.objects.filter(username=username, password=password).first()
if not user_obj:
back_dic['code'] = 210
back_dic['msg'] = '用户名或者密码错误'
return JsonResponse(back_dic)
# 保存用户信息
request.session['id'] = user_obj.id
request.session['username'] = user_obj.username
# 返回数据
back_dic['url'] = '/home/'
return JsonResponse(back_dic)
return render(request, 'login.html')
验证码功能
def get_code(request):
# 最终步骤4:写图片验证码
img_obj = Image.new('RGB', (430, 35), get_random())
img_draw = ImageDraw.Draw(img_obj) # 产生一个画笔对象
img_font = ImageFont.truetype('static/font/包图小白体.ttf', 30) # 字体样式 大小
# 随机验证码 五位数的随机验证码 数字 小写字母 大写字母
code = ''
for i in range(4):
random_upper = chr(random.randint(65, 90))
random_lower = chr(random.randint(97, 122))
random_int = str(random.randint(0, 9))
# 从上面三个里面随机选择一个
tmp = random.choice([random_lower, random_upper, random_int])
# 将产生的随机字符串写入到图片上
"""
为什么一个个写而不是生成好了之后再写
因为一个个写能够控制每个字体的间隙 而生成好之后再写的话
间隙就没法控制了
"""
img_draw.text((i * 60 + 60, -2), tmp, get_random(), img_font)
# 拼接随机字符串
code += tmp
print(code)
# 随机验证码在登陆的视图函数里面需要用到 要比对 所以要找地方存起来并且其他视图函数也能拿到
request.session['code'] = code
io_obj = BytesIO()
img_obj.save(io_obj, 'png')
return HttpResponse(io_obj.getvalue())
搭建首页项目
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
{% load static %}
<link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
<script src="{% static 'layer-v3.5.1/layer/layer.js' %}"></script>
<script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>
</head>
<body>
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<!-- 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="#">BBS</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="#">Link</a></li>
<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>
<form class="navbar-form navbar-left">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<ul class="nav navbar-nav navbar-right">
<!--判断session中是否有数据,如果有显示登录用户,如果没有显示登录注册按钮-->
{% if request.session.username %}
<li><a href="#">{{ request.session.username }}</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">更多操作 <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#" data-toggle="modal" data-target="#myModal">修改密码</a></li>
<li><a href="#">后台管理</a></li>
<li><a href="/logout/">退出登录</a></li>
<li role="separator" class="divider"></li>
</ul>
</li>
{% else %}
<li><a href="/register/">注册</a></li>
<li><a href="/login/">登录</a></li>
{% endif %}
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">×</span></button>
<h4 class="modal-title text-center" id="myModalLabel">修改密码</h4>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<div class="form_group">
<label for="">原密码</label>
<input type="password" id="old_password" class="form-control">
</div>
<div class="form_group">
<label for="">新密码</label>
<input type="password" id="new_password" class="form-control">
</div>
<div class="form_group">
<label for="">确认密码</label>
<input type="password" id="re_password" class="form-control">
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary commit">提交</button>
</div>
</div>
</div>
</div>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<div class="container-fluid">
<div class="row">
<div class="col-md-2">
<div class="panel panel-primary">
<div class="panel-body">
Panel content
</div>
<div class="panel-footer">Panel footer</div>
</div>
<div class="panel panel-success">
<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 class="col-md-7">
{% for article_obj in article_list %}
<div class="media">
<h4 class="media-heading"><a href="">{{ article_obj.title }}</a></h4>
<div class="media-left">
<a href="#">
<img class="media-object" width="30" src="/static/img/111.png" alt="...">
</a>
</div>
<div class="media-body">
{{ article_obj.desc }}
</div>
<br>
<div>
<span><a href="">{{ article_obj.blog.userinfo.username }} </a></span>
<span>{{ article_obj.create_time| date:'Y-m-d H:i:s' }} </span>
<span><span class="glyphicon glyphicon-thumbs-up"></span>({{ article_obj.up_num }}) </span>
<span><span class="glyphicon glyphicon-thumbs-down"></span>({{ article_obj.down_num }}) </span>
<span><span class="glyphicon glyphicon-comment"></span>({{ article_obj.comment_num }})</span>
</div>
</div>
<hr>
{% endfor %}
</div>
<div class="col-md-3">
<div class="panel panel-primary">
<div class="panel-body">
Panel content
</div>
<div class="panel-footer">Panel footer</div>
</div>
<div class="panel panel-success">
<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>
</div>
<script>
$('.commit').on('click', function () {
// 获取输入框中的数据
var old_password = $('#old_password').val();
var new_password = $('#new_password').val();
var re_password = $('#re_password').val();
// 发送ajax请求
$.ajax({
url: '/set_password/',
type: 'post',
data: {'old_password': old_password, 'new_password': new_password, 're_password': re_password},
success: function (res) {
if (res.code == 200) {
layer.msg(res.msg, {}, function () {
{#location.href = res.url;#}
location.reload()
});
} else {
layer.msg(res.msg, {icon: 2});
}
}
})
})
</script>
</body>
</html>
首页
def home(request):
article_list = models.Article.objects.all()
return render(request, 'home.html', locals())
修改密码功能
def get_md5(pwd):
import hashlib
m = hashlib.md5()
m.update(pwd.encode('utf-8'))
return m.hexdigest()
def set_password(request):
if request.method == 'POST':
back_dic = {'code': 200, 'msg': '修改密码成功'}
# 获取数据
old_password = request.POST.get('old_password')
new_password = request.POST.get('new_password')
re_password = request.POST.get('re_password')
# 验证参数
old_password = get_md5(old_password)
user_obj = models.UserInfo.objects.filter(username=request.session.get('username'),
password=old_password).first()
if not user_obj:
back_dic['code'] = 211
back_dic['msg'] = '原密码错误'
return JsonResponse(back_dic)
if new_password != re_password:
back_dic['code'] = 212
back_dic['msg'] = '两次密码不一致'
return JsonResponse(back_dic)
# 业务逻辑
new_password = get_md5(new_password)
# 修改数据
models.UserInfo.objects.filter(pk=request.session.get('id')).update(password=new_password)
return JsonResponse(back_dic)
退出登录功能
def logout(request):
request.session.flush()
return redirect('/home/')
个人站点搭建页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
{% load static %}
<link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
<script src="{% static 'layer-v3.5.1/layer/layer.js' %}"></script>
<script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>
</head>
<body>
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<!-- 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="#">BBS</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="#">Link</a></li>
<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>
<form class="navbar-form navbar-left">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<ul class="nav navbar-nav navbar-right">
<!--判断session中是否有数据,如果有显示登录用户,如果没有显示登录注册按钮-->
{% if request.session.username %}
<li><a href="#">{{ request.session.username }}</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">更多操作 <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#" data-toggle="modal" data-target="#myModal">修改密码</a></li>
<li><a href="#">后台管理</a></li>
<li><a href="/logout/">退出登录</a></li>
<li role="separator" class="divider"></li>
</ul>
</li>
{% else %}
<li><a href="/register/">注册</a></li>
<li><a href="/login/">登录</a></li>
{% endif %}
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">×</span></button>
<h4 class="modal-title text-center" id="myModalLabel">修改密码</h4>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<div class="form_group">
<label for="">原密码</label>
<input type="password" id="old_password" class="form-control">
</div>
<div class="form_group">
<label for="">新密码</label>
<input type="password" id="new_password" class="form-control">
</div>
<div class="form_group">
<label for="">确认密码</label>
<input type="password" id="re_password" class="form-control">
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary commit">提交</button>
</div>
</div>
</div>
</div>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<div class="container-fluid">
<div class="row">
<div class="col-md-3">
<div class="panel panel-primary">
<!-- Default panel contents -->
<div class="panel-heading">Panel heading</div>
<div class="panel-body">
<p>...</p>
</div>
</div>
<div class="panel panel-info">
<!-- Default panel contents -->
<div class="panel-heading">Panel heading</div>
<div class="panel-body">
<p>...</p>
</div>
</div>
<div class="panel panel-success">
<!-- Default panel contents -->
<div class="panel-heading">Panel heading</div>
<div class="panel-body">
<p>...</p>
</div>
</div>
</div>
<div class="col-md-9">
{% for article_obj in article_list %}
<div class="media">
<h4 class="media-heading"><a href="">{{ article_obj.title }}</a></h4>
<div class="media-body">
{{ article_obj.desc }}
</div>
<br>
<div class="pull-right">
<span>posted @</span>
<span>{{ article_obj.create_time| date:'Y-m-d H:i:s' }} </span>
<span><a href="">{{ article_obj.blog.userinfo.username }} </a></span>
<span>点赞({{ article_obj.up_num }}) </span>
<span>点踩({{ article_obj.down_num }}) </span>
<span>评论({{ article_obj.comment_num }})</span>
</div>
</div>
<hr>
{% endfor %}
</div>
</div>
</div>
</body>
</html>
个人站点实现
def site(request, username):
# 验证站点名称是否存在
user_obj = models.UserInfo.objects.filter(username=username).first()
if not user_obj:
return render(request, '404.html')
# 查询当前站点的所有文章
blog = user_obj.blog
article_list = models.Article.objects.filter(blog=blog).all()
return render(request, 'site.html', locals())