目前本项目已经上线,可以直接在GEEK浏览本项目效果:http://blog.huangyongchi.com/

全新的项目源码地址:https://github.com/hyyc554/YcBlog

1.项目需求

  • 基于ajax和用户认证组件实现登录验证
  • 基于ajax和form组件实现注册功能
  • 系统首页文章列表的渲染
  • 个人站点页面设计
  • 文章详细页的继承
  • 点赞与踩灭
  • 评论功能
  • 富文本编辑器的使用
  • 防止xss攻击

2.项目详情

2.1 数据库设计

核心代码:

1.继承AbstractUser
2.中介模型
3.联合唯一
            

from django.db import models

# Create your models here.


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_name = models.CharField(verbose_name='站点名称', max_length=64)
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):
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)
content = models.TextField()

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 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):
v = self.article.title + "---" + self.tag.title
return v


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 = [
('article', 'user'),
]


class Comment(models.Model):
"""

评论表

"""
nid = models.AutoField(primary_key=True)
article = models.ForeignKey(verbose_name='评论文章', to='Article', to_field='nid', on_delete=models.CASCADE)
user = models.ForeignKey(verbose_name='评论者', to='UserInfo', 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

2.2 站点管理

核心代码:

from django.contrib import admin

# Register your models here.
from blog import models

admin.site.register(models.UserInfo)
admin.site.register(models.Article)
admin.site.register(models.Article2Tag)
admin.site.register(models.ArticleUpDown)
admin.site.register(models.Blog)
admin.site.register(models.Category)
admin.site.register(models.Comment)
admin.site.register(models.Tag)
 

2.3 注册

核心代码:

1.form组件

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})

2.4 登录

核心代码:

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)
 
 

2.5 网站首页

核心代码:

1.bootstrap搭建页面

2.导航条
登录: username / 注销
未登录: 登录 / 注册

3.for循环
{% for article in article_list %}
{% endfor %}

网页底部分页器:

2.6 个人站点

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

2.7 文章详情

核心代码:

1.模板继承
article = Article.objects.filter(pk=article_id).first()
{% extends 'base.html' %}
{% block content %}
...
{{ article.articledetail.content|safe }}
{% endblock content %}

2.8 后台管理

核心代码:

1.支持文章编辑
2.支持富文本编辑器(支持渲染已有文章)
3.支持删除文章
4.防止Xss攻击(基于BS4)
# 防止xss攻击,过滤script标签
soup = BeautifulSoup(content, "html.parser")
for tag in soup.find_all():

if tag.name == "script":
tag.decompose()

2.9 批量建立测试数据

核心代码:

1.定制建立测试数据
2.初始化得到100条用户信息,以及为100个客户分别添加文章、博客的详细信息
 
def supreme(request):
"""
这是数据初始化视图,将会生成99条测试数据,用户名为管理员输入的字符后,加1_99.
密码为管理员填入的密码
:param request:
:return:
"""
tag_title = ['BASIC', 'C',
'C++', 'PASCAL', 'FORTRAN', 'LISP', 'Prolog', 'CLIPS', 'OpenCyc', 'Fazzy', 'Python', 'PHP', 'Ruby',
'Lua']
category_titles = ['非技术区',
'软件测试',
'代码与软件发布',
'计算机图形学',
'游戏开发',
'程序人生',
'求职面试',
'读书区',
'转载区',
'Windows',
'翻译区',
'开源研究',
'Flex']
userlist = []
bolglist = []
article_list = []
tag_list = []
cat_list = []
article2tag_list = []

if request.is_ajax():

form = UserForm(request.POST)
response = {'user': None, 'msg': None}
if form.is_valid():

response['user'] = form.cleaned_data.get('user')
# 生成一条用户记录
user = form.cleaned_data.get('user')

pwd = form.cleaned_data.get('pwd')
email = form.cleaned_data.get('email')
avatar_obj = request.FILES.get('avatar')
extra = {}
if avatar_obj:
extra['avatar'] = avatar_obj
with transaction.atomic():
for i in range(1, 100):
Blog.objects.create(title='blog%s' % i)

UserInfo.objects.create_user(username=user + str(i), password=pwd, email=email, **extra)

UserInfo.objects.filter(username=user + str(i)).update(blog_id=i)

for title in tag_title:
tag_list.append(Tag(title=title, blog_id=i))

for cat in category_titles:
cat_list.append(Category(title=cat, blog_id=i))
import random
for c in range(1, 7):
with open('/home/hyc/PycharmProjects/cnblog/static/superme/%s.txt' % c, 'r',
encoding='utf-8') as f:
content = f.read()

soup = BeautifulSoup(content, "html.parser")
for tag in soup.find_all():
if tag.name == "script":
tag.decompose()
desc = soup.text[0:150] + "..."
c_id = 13 * (i - 1) + random.randrange(1, 9)

article_list.append(
Article(desc=desc, title='article%s' % c, content=content, user_id=i, category_id=c_id))

Category.objects.bulk_create(cat_list)
Tag.objects.bulk_create(tag_list)
Article.objects.bulk_create(article_list)

else:
response['msg'] = form.errors
return JsonResponse(response)

my_from = UserForm

return render(request, 'supreme.html', {'from': my_from})

3.源码链接:

https://github.com/hyyc554/BBS_blog

BBS+Blog项目开发的更多相关文章

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

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

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

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

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

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

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

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

  5. 项目实战:BBS+Blog项目开发

    01-博客系统之功能需求 02-博客系统之表结构设计1 03-博客系统之表结构设计2 04-博客系统之表结构设计3 05-博客系统之表结构设计4 06-博客系统之表机构设计5 07-博客系统之创建系统 ...

  6. BBS+Blog项目流程及补充知识点

    项目流程: 1. 产品需求 (1)基于用户认证组件和Ajax实现登陆验证(图片验证码) (2)基于forms组件和Ajax实现注册功能 (3)设计系统首页(文章列表渲染) (4)设计个人站点页面 (5 ...

  7. BBS+Blog项目代码

    项目目录结构: cnblog/ |-- blog/(APP) |-- migrations(其中文件略) |-- templatetags/ |-- my_tags.py |-- utils/ |-- ...

  8. Django项目开发,XSS攻击,图片防盗链,图片验证码,kindeditor编辑器

    目录 一.Django项目开发 1. 项目开发流程 2. auth模块的补充 (1)django的admin可视化管理页面 (2)将admin可视化管理页面的模型表显示成中文 (3)auth模块的用户 ...

  9. Django学习day14BBS项目开发1.0

    每日测验 """ 1.简述auth模块功能 2.简述项目开发流程 3.简述bbs表设计 """ 内容回顾 auth模块 "&quo ...

随机推荐

  1. 一种特殊的 jpg 图片: MagickProfileImage() sRGB.icc

    原图,在 ps, 浏览器中显示这样: 在 ps 中另存为 web... [转换成 sRGB]选项没有勾选: 在 ps 中另存为 web... 勾选[转换成 sRGB]选项: 用 ImageMaigck ...

  2. c/c++学习系列之memset()函数

    [转载] memset 函数是内存赋值函数,用来给某一块内存空间进行赋值的: 包含在<string.h>头文件中,可以用它对一片内存空间逐字节进行初始化: 原型为 : void *mems ...

  3. 09--STL关联容器(map/multimap)

    一:map/multimap的简介 map是标准的关联式容器,一个map是一个键值对序列,即(key,value)对.它提供基于key的快速检索能力. map中key值是唯一的.集合中的元素按一定的顺 ...

  4. 第四节:跨域请求的解决方案和WebApi特有的处理方式

    一. 简介 前言: 跨域问题发生在Javascript发起Ajax调用,其根本原因是因为浏览器对于这种请求,所给予的权限是较低的,通常只允许调用本域中的资源, 除非目标服务器明确地告知它允许跨域调用. ...

  5. 第十四节: EF的三种模式(四) 之 原生正宗的 CodeFirst模式的默认约定

    一. 简介 1. 正宗的CodeFirst模式是不含有edmx模型,需要手动创建实体.创建EF上下文,然后生成通过代码来自动映射生成数据库. 2. 旨在:忘记SQL.忘记数据库. 3. 三类配置:On ...

  6. 还在用Json完成Ajax,改用Beetl吧

    原文链接:https://blog.csdn.net/xiandafu/article/details/44216905 作者:Beetl作者,闲大赋 浏览器通过AJAX,服务器返回json数据,无刷 ...

  7. sed追加文本-sed脚本追加文本

    input为sed输入文件,内容如下: [root@node1 gitlab-test-]# cat inppu.txt aa bb cc dd 追加文本: 1.匹配  aa 行之后追加文本 We a ...

  8. H - 栀子花开

    这是一个栀子花开的季节,也是一个离别的季节,四年一千多个日日夜夜,那校园的角角落落,留下了我们沉思的身影:那上百次的成绩排名表,印证了我们深深浅浅不断进步的轨迹,但是这些进步都离不开老师的谆谆教诲. ...

  9. kafka_2.11-2.1.0测试

    kafka测试启动创建topic ./kafka-topics.sh --create --zookeeper dip005:2181,dip006:2181,dip007 --replication ...

  10. git使用随笔

    详细:https://blog.csdn.net/qq_31117191/article/details/77141825   git是分为三部分,一部分是你自己的文件,另外一个是缓存区,最后一个是本 ...