6.2 - BBS + BLOG系统
一、简介
博客系统开发:
1.注册,登录,首页
2.个人站点,分组:(分类,标签,归档)
3.文章详细页
4.点赞,踩灭
5.评论楼,评论树
6.后台管理,发布文章,文件上传
7.BeautifulSoup
8.日志
数据库 models.py 注册 /reg/
上传头像 request.FILES.get('avatar') 登录 /login/
随机验证码 /get_valid_img/ 首页 /index/ 个人站点
分类,标签,归档 /blog/egon/ 文章详细页 /blog/egon/articles/2/ 点赞,踩灭 /blog/poll/
ajax的post 事务 评论楼,评论树 /blog/comment/
根评论,子评论
render显示,ajax显示 后台管理,发布文章 /backend/index/
新建APP
认证装饰器
编辑器(KindEditor)
文件上传 /media/article_imgs/... 防止XSS攻击
BeautifulSoup
二、数据库
知识点:
1.继承AbstractUser
目的:为了使用用户认证组件 auth User
配置:AUTH_USER_MODEL = "blog.UserInfo" class UserInfo(AbstractUser):
... 2.中介模型
多对多,第三张表自己生成。
class Article(models.Model):
...
tags = models.ManyToManyField(to='Tag', through='Article2Tag', through_fields=('article', 'tag')) class Article2Tag(models.Model):
...
class Meta: # 联合唯一
unique_together = [
('article', 'tag'),
] 3.联合唯一
class ArticleUpDown(models.Model):
nid = models.AutoField(primary_key=True)
user = models.ForeignKey("UserInfo", null=True, on_delete=models.CASCADE)
article = models.ForeignKey('Article', null=True, on_delete=models.CASCADE) class Meta: # 联合唯一
unique_together = [
('user', 'article'),
]
from django.db import models
from django.contrib.auth.models import AbstractUser class UserInfo(AbstractUser):
"""
用户信息
"""
nid = models.AutoField(primary_key=True)
telephone = models.CharField(max_length=11, null=True, unique=True)
avatar = models.FileField(upload_to='avatars/', default='avatars/default.png')
create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True) blog = models.OneToOneField(to='Blog', to_field='nid', null=True, on_delete=models.CASCADE) def __str__(self):
return self.username class Blog(models.Model):
"""
博客信息
"""
nid = models.AutoField(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) 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', on_delete=models.CASCADE) def __str__(self):
return self.title 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', on_delete=models.CASCADE) def __str__(self):
return self.title class Article(models.Model):
"""
文章信息
comment_count up_count down_count 为了查询时,效率高。
"""
nid = models.AutoField(primary_key=True)
title = models.CharField(max_length=50, verbose_name='文章标题')
desc = models.CharField(max_length=255, verbose_name='文章描述')
create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True) comment_count = models.IntegerField(default=0)
up_count = models.IntegerField(default=0)
down_count = models.IntegerField(default=0) user = models.ForeignKey(verbose_name='作者', to='UserInfo', to_field='nid', on_delete=models.CASCADE)
category = models.ForeignKey(to='Category', to_field='nid', null=True, on_delete=models.CASCADE)
tags = models.ManyToManyField(to='Tag', through='Article2Tag', through_fields=('article', 'tag')) def __str__(self):
return self.title class ArticleDetail(models.Model):
"""
文章详细表
"""
nid = models.AutoField(primary_key=True)
content = models.TextField()
article = models.OneToOneField(to='Article', to_field='nid', on_delete=models.CASCADE) class Article2Tag(models.Model):
"""
多对多, 文章、标签的第三张表
"""
nid = models.AutoField(primary_key=True)
article = models.ForeignKey(verbose_name='文章', to='Article', to_field='nid', on_delete=models.CASCADE)
tag = models.ForeignKey(verbose_name='标签', to='Tag', to_field='nid', on_delete=models.CASCADE) class Meta:
unique_together = [
('article', 'tag'),
] def __str__(self):
return self.article.title + '--' + self.tag.title class ArticleUpDown(models.Model):
"""
点赞,踩灭表
"""
nid = models.AutoField(primary_key=True)
user = models.ForeignKey("UserInfo", null=True, on_delete=models.CASCADE)
article = models.ForeignKey('Article', null=True, on_delete=models.CASCADE)
is_up = models.BooleanField(default=True) class Meta:
unique_together = [
('user', 'article'),
] class Comment(models.Model):
"""
评论表
"""
nid = models.AutoField(primary_key=True)
user = models.ForeignKey(verbose_name='评论者', to='UserInfo', to_field='nid', on_delete=models.CASCADE)
article = models.ForeignKey(verbose_name='评论文章', to='Article', to_field='nid', on_delete=models.CASCADE)
content = models.CharField(verbose_name='评论内容', max_length=255)
create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True) parent_comment = models.ForeignKey('self', null=True, on_delete=models.CASCADE) def __str__(self):
return self.content
models.py
三、admin
from django.contrib import admin # Register your models here. from blog.models import * admin.site.register(UserInfo)
admin.site.register(Blog)
admin.site.register(Category)
admin.site.register(Tag)
admin.site.register(Article)
admin.site.register(ArticleDetail)
admin.site.register(Article2Tag)
admin.site.register(ArticleUpDown)
admin.site.register(Comment)
http://127.0.0.1:8020/admin/
四、注册
知识点:
1.form组件
class RegForm(forms.Form):pass
局部钩子 全局钩子 2.上传头像 avatar
图像预览
var reader = new FileReader();
上传文件
formdata = new FormData(); 3.用户文件配置
avatar = models.FileField(upload_to='avatars/', default='avatars/default.png')
MEDIA_ROOT = os.path.join(BASE_DIR, 'blog', 'media')
MEDIA_URL = '/media/'
re_path(r'media/(?P<path>.*)$',serve,{'document_root':settings.MEDIA_ROOT})
五、登录
知识点:
1.验证码
随机生成5个字符,0-9 a-z A-Z pip install pillow
from PIL import Image, ImageDraw, ImageFont
image = Image.new() 在内存中生成图片直接返回
from io import BytesIO
f = BytesIO() 2.request.session['valid_str'] = valid_str
存在session中,为了之后登录,验证是否通过 3.验证码点击刷新:
$('#valid_img').click(function () {
$(this)[0].src += '?'
}); 4.认证组件
valid_str = request.session.get('valid_str')
if valid_str.upper() == valid_code.upper():
user = auth.authenticate(username = user, password = pwd)
if user:
auth.login(request, user)
六、首页
知识点:
1.bootstrap搭建页面 2.导航条
登录: username / 注销
未登录: 登录 / 注册 3.for循环
{% for article in article_list %}
{% endfor %}
七、个人站点
知识点:
1.文章列表,分类列表,标签列表,日期归档列表
文章列表: /blog/egon/
分类列表: /blog/egon/cate/python
标签列表: /blog/egon/tag/生活
日期归档列表: /blog/egon/archive/2018-06 2.模板继承
{% extends 'base.html' %} {% block content %}
{% endblock content%}} 3.自定义标签
/blog/templatetags/my_tag.py @register.inclusion_tag('menu.html')
def get_menu(username):
...
return {} # 去渲染 menu.html 4.分组查询 .annotate() / extra()应用
多表分组
tag_list = Tag.objects.filter(blog=blog).annotate(
count = Count('article')).values_list('title', 'count') 单表分组 / DATE_FORMAT() / extra()
date_list = Article.objects.filter(user=user).extra(
select={"create_ym": "DATE_FORMAT(create_time,'%%Y-%%m')"}).values('create_ym').annotate(
c = Count('nid')).values_list('create_ym', 'c') 5. 时间、区域配置
TIME_ZONE = 'Asia/Shanghai'
USE_TZ = False
八、文章详细页
知识点:
1.模板继承
article = Article.objects.filter(pk=article_id).first()
{% extends 'base.html' %}
{% block content %}
...
{{ article.articledetail.content|safe }}
{% endblock content %}
九、点赞、踩灭
知识点:
1.ajax的post
var csrfmiddlewaretoken = $('input[name="csrfmiddlewaretoken"]').val(); 2.事务
try: # article_id 与 user_id 联合唯一 所有使用 try ...
with transaction.atomic():
ArticleUpDown.objects.create(is_up=is_up, article_id=article_id, user_id=user_id)
...
Article.objects.filter(pk=article_id).update(up_count=F('up_count')+1) except Exception as e:
... 3.F查询:
Article.objects.filter(pk=article_id).update(up_count=F('up_count')+1)
十、评论楼、评论树
知识点:
1.提交根评论
2.显示根评论
--- render显示
--- ajax显示
3.提交子评论
4.显示子评论
--- render显示
--- ajax显示
评论楼
评论树
1.ajax提交评论
post (csrfmiddlewaretoken)
pid = "" 根评论
pid = value 子评论 2.回复事件
@alex
val ="@" + $(this).attr('username')+ '\n'; 3.事务
with transaction.atomic():
...
多个orm sql操作! 4.F查询,更新
Article.objects.filter(pk=article_id).update(comment_count=F("comment_count")+1)
评论树:
5.js匿名函数
(function(){})() 6.ajax get方式获取comment_list
$.each(comment_list,function(index,comment)){
...
s = '...'
if(pid){ //子评论
$('#'+pid).append(s)
}else{ //根评论
$('.comment_tree').append(s)
}
} 7.JsonResponse() 返回 non-dict objects 需要 safe=False
def get_comment_tree(request, article_id):
ret = list(Comment.objects.filter(article_id=article_id).values(
'pk', 'content', 'parent_comment_id', 'user__username').order_by('nid')) return JsonResponse(ret, safe=False)
十一、后台管理、KindEditor、BeautifulSoup
知识点:
1.新建APP(backend)
settings:
INSTALLED_APPS = [..., 'backend.apps.BackendConfig',] 2.url分配
re_path(r'backend/', include(('backend.urls', 'backend'))), 3.认证装饰器
@login_required
settings:
LOGIN_URL = '/login/' 4.static配置
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'blog', 'static'),
os.path.join(BASE_DIR, 'backend', 'static'),
] 5.编辑器(KindEditor)
<textarea name="article_con" id="article_box" cols="30" rows="10"></textarea>
<script src="/static/kindeditor/kindeditor-all.js"></script>
KindEditor.ready(function (k) {
window.editor = k.create('#article_box', {
...
...
uploadJson: 'upload_img/',
extraFileUploadParams: {"csrfmiddlewaretoken":$('input[name="csrfmiddlewaretoken"]').val()},
filePostName: 'img'
})
}) 6.文件上传
用户文件存在 /media/article_imgs/...
media_path = settings.MEDIA_ROOT
path = os.path.join(media_path, 'article_imgs', img_obj.name)
返回json
img_obj = request.FILES.get('img')
res = {
"url": "/media/article_imgs/"+img_obj.name,
"error": 0
}
return HttpResponse(json.dumps(res)) 7.发布文章
防止XSS攻击 BeautifulSoup,对网页,解析数据 article_con = request.POST.get('article_con')
soup = BeautifulSoup(article_con, 'html.parser') # 过滤script, 删除了所有的script标签
for tag in soup.find_all():
if tag.name == 'script':
tag.decompose() # soup.prettify() == str(soup)
return redirect(reverse('backend:index'))
十二、code
https://github.com/alice-bj/cnblog
结构:
cnblog
├── backend
│ ├── static
│ │ ├── css
│ │ │ ├── backend.css
│ │ ├── js
│ │ │ ├── add_article.js
│ │ │ ├── jquery-3.2.1.js
│ │ │ └── jquery-3.2.1.min.js
│ │ └── kindeditor
│ │ ├── kindeditor-all.js
│ │ ├── kindeditor-all-min.js
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── blog
│ ├── admin.py
│ ├── apps.py
│ ├── media
│ │ ├── article_imgs
│ │ │ ├── girl.jpg
│ │ │ ├── jiqimao.gif
│ │ │ ├── jiqimao.jpg
│ │ │ └── lufei.jpg
│ │ ├── avatars
│ │ │ ├── girl.jpg
│ │ │ ├── lufei.jpg
│ ├── models.py
│ ├── myforms.py
│ ├── settings.py
│ ├── static
│ │ ├── bootstrap-3.3.7
│ │ │ ├── css
│ │ │ │ ├── bootstrap.css
│ │ │ ├── fonts
│ │ │ └── js
│ │ │ ├── bootstrap.js
│ │ │ ├── bootstrap.min.js
│ │ ├── css
│ │ │ ├── article_detail.css
│ │ │ ├── login.css
│ │ │ └── reg.css
│ │ ├── font
│ │ │ └── kumo.ttf
│ │ ├── img
│ │ │ ├── default.png
│ │ │ ├── downdown.gif
│ │ │ ├── icon_form.gif
│ │ │ └── upup.gif
│ │ ├── js
│ │ │ ├── article_detail.js
│ │ │ ├── jquery-3.2.1.js
│ │ │ ├── jquery-3.2.1.min.js
│ │ │ ├── login.js
│ │ │ └── reg.js
│ │ └── theme
│ │ ├── egon.css
│ │ └── yuan.css
│ ├── templatetags
│ │ ├── my_tags.py
│ ├── tests.py
│ ├── urls.py
│ ├── valid_img.py
│ └── views.py
├── cnblog
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── log
│ ├── cnblog_collect.log
│ ├── cnblog_err.log
│ ├── cnblog_info.log
├── manage.py
└── templates
├── add_article.html
├── article_detail.html
├── backend.html
├── base.html
├── homesite.html
├── index.html
├── login.html
├── menu.html
└── reg.html
账号:
egon egon1234 / yuan yuan1234 / alex alex1234
6.2 - BBS + BLOG系统的更多相关文章
- Django学习笔记(20)——BBS+Blog项目开发(4)Django如何使用Bootstrap
本文学习如何通过Django使用Bootstrap.其实在之前好几个Django项目中已经尝试使用过了Bootstrap,而且都留有学习记录,我已经大概有了一个大的框架,那么本文就从头再走一遍流程,其 ...
- Django学习笔记(18)——BBS+Blog项目开发(2)主体思路及流程
这篇博客主要完成一个BBS+Blog项目,那么主要是模仿博客园的博客思路,使用Django框架进行练习. 准备:项目需求分析 在做一个项目的时候,我们首先做的就是谈清楚项目需求,功能需求,然后才开始写 ...
- Django学习笔记(17)——BBS+Blog项目开发(1)验证码功能的实现
本文主要学习验证码功能的实现,为了项目BBS+Blog项目打下基础. 为了防止机器人频繁登陆网站或者破坏分子恶意登陆,很多用户登录和注册系统都提供了图形验证码功能. 验证码(CAPTCHA)是“Com ...
- SpringNote01.基于SpringMVC-Hibernate的Blog系统
最近,在学习Spring,做这样一个简单的blog系统,主要是让自己动手练习使用Spring,熟练的使用才干进一步的深入学习.该项目使用Maven构建,使用git进行代码管理,通过这样一个小项目,熟悉 ...
- 一个JavaWeb搭建的开源Blog系统,整合SSM框架
搬砖有暇,捣鼓了一个简单的Blog系统(项目地址https://github.com/lenve/JavaEETest/tree/master/MyBlog),适合以下人群学习: 1.已经掌握了jsp ...
- Django学习笔记(19)——BBS+Blog项目开发(3)细节知识点补充
本文将BBS+Blog项目开发中所需要的细节知识点进行补充,其中内容包括KindEditor编辑器的使用,BeautifulSoup 模块及其防XSS攻击,Django中admin管理工具的使用,me ...
- Java,面试题,简历,Linux,大数据,常用开发工具类,API文档,电子书,各种思维导图资源,百度网盘资源,BBS论坛系统 ERP管理系统 OA办公自动化管理系统 车辆管理系统 各种后台管理系统
Java,面试题,简历,Linux,大数据,常用开发工具类,API文档,电子书,各种思维导图资源,百度网盘资源BBS论坛系统 ERP管理系统 OA办公自动化管理系统 车辆管理系统 家庭理财系统 各种后 ...
- go-zero 实战之 blog 系统
go-zero 实战项目:blog 本文以 blog 的网站后台为例,着重介绍一下如何使用 go-zero 开发 blog 的用户模块. 本文涉及的所有资料都已上传 github 仓库 kougazh ...
- 用django搭建一个简易blog系统(翻译)(四)
12. Create the templates 你需要做三件事来去掉TemplateDoesNotExist错误 第一件,创建下面目录 * netmag/netmag/templates * net ...
随机推荐
- Windows版变色龙
打包安装版本更新源地址: http://www.insanelymac.com/forum/files/file/59-chameleon-22-svn/ 一.使用方法:1.安装Windows版变色龙 ...
- 跟着百度学PHP[9]-session会话
参考:http://www.w3school.com.cn/php/php_sessions.asp session变量用于存储有关用户的会话的信息,或更改用户会话的设置,session变量保存的信息 ...
- jquery post 同步异步总结
最近在测试,发现有些效果不对,最后发现是post的执行顺序问题,所以研究了下,写了以下总结 1.post被请求多次,解决方法: 连接加入随机数 rand=""+Math.rando ...
- hadoop杂记-为什么会有Map-reduce v2 (Yarn)
转自:http://www.cnblogs.com/LeftNotEasy/archive/2012/02/18/why-yarn.html 前言: 有一段时间没有写博客了(发现这是我博客最常见的开头 ...
- 【转】【Linux】grep命令详解
简介 grep (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它 ...
- android jni log
在编写的jni时,经常需要输出打印信息进行调试,而C中printf在jni中没有效果,这时就需要使用NDK提供的函数. 1. jni中包含头文件 #include <android/log.h& ...
- 【BZOJ】1025: [SCOI2009]游戏(置换群+dp+特殊的技巧+lcm)
http://www.lydsy.com/JudgeOnline/problem.php?id=1025 首先根据置换群可得 $$排数=lcm\{A_i, A_i表示循环节长度\}, \sum_{i= ...
- 一些 JS页面的 调用方式init()
//初始化.... var initAccManPage=function() { //初始化... var initChangeBtn = function(){ $("#btnChang ...
- React Native开发技术
http://www.lcode.org/react-native-week-issue22/
- server.xml详解
http://www.cnblogs.com/gugnv/archive/2012/02/01/2334187.html http://blog.csdn.net/weinianjie1/articl ...