一、简介

博客系统开发:

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系统的更多相关文章

  1. Django学习笔记(20)——BBS+Blog项目开发(4)Django如何使用Bootstrap

    本文学习如何通过Django使用Bootstrap.其实在之前好几个Django项目中已经尝试使用过了Bootstrap,而且都留有学习记录,我已经大概有了一个大的框架,那么本文就从头再走一遍流程,其 ...

  2. Django学习笔记(18)——BBS+Blog项目开发(2)主体思路及流程

    这篇博客主要完成一个BBS+Blog项目,那么主要是模仿博客园的博客思路,使用Django框架进行练习. 准备:项目需求分析 在做一个项目的时候,我们首先做的就是谈清楚项目需求,功能需求,然后才开始写 ...

  3. Django学习笔记(17)——BBS+Blog项目开发(1)验证码功能的实现

    本文主要学习验证码功能的实现,为了项目BBS+Blog项目打下基础. 为了防止机器人频繁登陆网站或者破坏分子恶意登陆,很多用户登录和注册系统都提供了图形验证码功能. 验证码(CAPTCHA)是“Com ...

  4. SpringNote01.基于SpringMVC-Hibernate的Blog系统

    最近,在学习Spring,做这样一个简单的blog系统,主要是让自己动手练习使用Spring,熟练的使用才干进一步的深入学习.该项目使用Maven构建,使用git进行代码管理,通过这样一个小项目,熟悉 ...

  5. 一个JavaWeb搭建的开源Blog系统,整合SSM框架

    搬砖有暇,捣鼓了一个简单的Blog系统(项目地址https://github.com/lenve/JavaEETest/tree/master/MyBlog),适合以下人群学习: 1.已经掌握了jsp ...

  6. Django学习笔记(19)——BBS+Blog项目开发(3)细节知识点补充

    本文将BBS+Blog项目开发中所需要的细节知识点进行补充,其中内容包括KindEditor编辑器的使用,BeautifulSoup 模块及其防XSS攻击,Django中admin管理工具的使用,me ...

  7. Java,面试题,简历,Linux,大数据,常用开发工具类,API文档,电子书,各种思维导图资源,百度网盘资源,BBS论坛系统 ERP管理系统 OA办公自动化管理系统 车辆管理系统 各种后台管理系统

    Java,面试题,简历,Linux,大数据,常用开发工具类,API文档,电子书,各种思维导图资源,百度网盘资源BBS论坛系统 ERP管理系统 OA办公自动化管理系统 车辆管理系统 家庭理财系统 各种后 ...

  8. go-zero 实战之 blog 系统

    go-zero 实战项目:blog 本文以 blog 的网站后台为例,着重介绍一下如何使用 go-zero 开发 blog 的用户模块. 本文涉及的所有资料都已上传 github 仓库 kougazh ...

  9. 用django搭建一个简易blog系统(翻译)(四)

    12. Create the templates 你需要做三件事来去掉TemplateDoesNotExist错误 第一件,创建下面目录 * netmag/netmag/templates * net ...

随机推荐

  1. AIX中查找端口号和进程

    1.由端口号查找进程 维护系统或检查到不明的端口自然要去查一下这个端口是由哪个进程来监听的windows可以用命令netstat -ano来查端口对应的进程的pid. aix却并不能,aix需要使用下 ...

  2. 本系列love2d示例代码错误集中整理

    3.输入和音乐 音乐不是循环播放的,可以在love.audio.play(music) 之前添加music:setLooping(true)

  3. Android——Activity中的六个主要函数

    Android Activity中的六个主要函数 Android中一个Activity一般都需要实现六个函数: onCreate(), onStart(), onResume(),onPause(), ...

  4. catch signal

    捕抓信号 如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,称为捕抓信号. 除了SIGSTOP和SIGKILL进程能够忽略或捕获其他的全部信号. 注:信号可从两个不同分类角度对信号进行分 ...

  5. Hbase分布式安装部署过程

    系统 Red hat linux 6.4 Hadoop版本 1.2.1 Hbase版本 0.94.16 Hbase的完全分布式安装概述: 1. 配置hosts,确保涉及的主机名均可解析为ip 2. 编 ...

  6. NodeJS与Javascript时代

    如果你一直在关注互联网的相关技术,你应该会有这样一种感觉,web技术正在发生着变革,虽然我们不愿相信,但一个事实已经越来越清晰的摆在了眼前:LAMP组合的时代将要成为历史,在web诞生的二十年间,它影 ...

  7. 转载 Python导入模块的几种姿势

    作为一名新手Python程序员,你首先需要学习的内容之一就是如何导入模块或包.但是我注意到,那些许多年来不时使用Python的人并不是都知道Python的导入机制其实非常灵活.在本文中,我们将探讨以下 ...

  8. 【BZOJ】1610: [Usaco2008 Feb]Line连线游戏(几何)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1610 两种做法,一种计算几何,一种解析几何,但是计算几何的复杂度远远搞出解析集合(虽然精度最高) 计 ...

  9. cpio -H newc参数详解

    -H format 其中个format可以是: ‘bin’ The obsolete binary format. (2147483647 bytes) ‘odc’ The old (POSIX.1) ...

  10. zabbix2.0 添加自定义监控项

    1. key的创建 客户端配置文件如下: root@192.168.100.254:/usr/local/zabbix/sbin# egrep -v "(^#|^$)" ../et ...