登录功能(图片验证码)
注册功能(上传头像),基于forms
首页()
个人站点(个人样式不同,分类,标签,归档过滤)
文章内容
kafka:消息队列
rebbitmg(流量削峰)
点赞点彩
评论功能:公评论,子评论
后台管理
发布文章(富文本编辑器的使用,防止XSS攻击,XSS跨站脚本攻击,csrf跨站请求伪造)
用户表
一对多的关系一旦确定,关联字段要写在多的一方
博客表(和用户表是一对一) -分类表:一对多 -跟标签:一对多
文章表 -跟用户表:一对多
分类表(和文章表一对多)
标签表(和文章表是多对多,一个文章对多个标签,一个标签对应多个文章)
点赞、点踩表 -跟用户表: 一对多 -跟文章表:一对多
评论表 -跟用户表:一对多 -跟文章表:一对多:一个文章中多个评论对应的是一个表中的多个数据
__str__ 就是print
print就是调用里面的__str__方法
?
?
唯一联合:一个用户只能给一片文章点赞
unique_together = ((‘user‘,‘article‘),)
生成随机颜色
def get_random_color():
    return (random.randint(0,255),random.randint(0,255),random.randint(0,255))
?
方式一:返回固定图片
with open(‘static/img/code.png‘,‘rb‘) as f:
    data = f.read()
return Httpresponse(data)
?
方式二:自动生图片,需要借助第三方模块pillow 图像处理的模块
新生成一张图(保存在硬盘中)
img = Image.new(‘RGB‘,(350,40),get_random_color())
把图片保存起来
with open(‘static/img/code.png‘,‘wb‘) as f:
    img.save(f)
打开返回
with open(‘/static/img/‘,‘rb‘) as f:
    data = f.read()
return HttpResponse(data)
?
方式三:不把文件保存在硬盘中,保存在内存中
新生成一张图片
img = Image.new(‘RGB‘,(350,40),get_random_color())
生成Byteio对象
f = BytesIO()
把文件保存到对象中
img.save(f,‘png‘)
把文件从对象中取出来
f.getvalue()
return HttpResponse(f.getvalue())
?
方法四:在图片上写文件,并保存到内存中
img = Image.new(‘RGB‘,(350,40),get_rnadom_color())
写文字,生成一个字体对象
font = ImageFont.truetype(‘/static/font/kumo.ttf‘,34)
调用方法 返回一个画板对象
draw = ImageDraw.Draw(img)
draw.text((0,10),‘python‘,font=font)
?
f = BytesIO()
img.save(f,‘png‘)
return HttpResponse(f.getvalue())
?
?
for i in range(5):
    num = str(random.randint(0,9))
    up_chr=str(chr(random.randint(65,90)))
    lower_chr = str(chr(random.randint(97,122)))
从三个字符任选
ss = random.choice([num,up_chr,lower_chr])
draw.text((20+i*50,5),ss,font=font,fill=get_random_color())
?
?
画点和线
    width = 320
    height = 35
    for i in range(10):
        x1 = random.randint(0, width)
        x2 = random.randint(0, width)
        y1 = random.randint(0, height)
        y2 = random.randint(0, height)
        # 在图片上画线
        draw.line((x1, y1, x2, y2), fill=get_random_color())
        
    for i in range(100):
        # 画点
        draw.point([random.randint(0, width), random.randint(0, height)], fill=get_random_color())
        x = random.randint(0, width)
    #   y = random.randint(0, height)
    # 画弧形
    draw.arc((x, y, x + 4, y + 4), 0, 90, fill=get_random_color())
?
from django.db import models
from django.contrib.auth.models import AbstractUser
?
?
class UserInfo(AbstractUser):
    nid = models.AutoField(primary_key=True)
    # 头像:FileField文件(varchar类型),default:默认值,upload_to上传的路径
    avatar = models.FileField(upload_to=‘avatar/‘, default=‘avatar/default.png‘)
    #跟blog表一对一
    #OneToOneField本质就是ForeignKey,只不过有个唯一性约束
    blog = models.OneToOneField(to=‘Blog‘, to_field=‘nid‘,null=True)
    # blog = models.ForeignKey(to=‘Blog‘, to_field=‘nid‘,null=True,unique=True)
?
    class Meta:
        # db_table=‘xxxx‘
        # 在admin中显示的表名
        verbose_name=‘用户表‘
        #去掉  用户表  后的s
        verbose_name_plural = verbose_name
?
class Blog(models.Model):
    nid = models.AutoField(primary_key=True)
    #站点名称
    title = models.CharField(max_length=64)
    #站点副标题
    site_name = models.CharField(max_length=32)
    #不同人不同主题
    theme = models.CharField(max_length=64)
    def __str__(self):
        return self.site_name
#分类表
class Category(models.Model):
    nid = models.AutoField(primary_key=True)
    #分类名称
    title = models.CharField(max_length=64)
    #跟博客是一对多的关系,关联字段写在多的一方
    #to  是跟哪个表关联   to_field跟表中的哪个字段做关联, null=True 表示可以为空
    blog = models.ForeignKey(to=‘Blog‘, to_field=‘nid‘, null=True)
    def __str__(self):
        return self.title
?
class Tag(models.Model):
    nid = models.AutoField(primary_key=True)
    #标签名字
    title = models.CharField(max_length=64)
    # 跟博客是一对多的关系,关联字段写在多的一方
    blog = models.ForeignKey(to=‘Blog‘, to_field=‘nid‘, null=True)
    def __str__(self):
        return self.title
?
class Article(models.Model):
    nid = models.AutoField(primary_key=True)
    #verbose_name在admin中显示该字段的中文
    title = models.CharField(max_length=64,verbose_name=‘文章标题‘)
    #文章摘要
    desc = models.CharField(max_length=255)
    #文章内容  大文本
    content = models.TextField()
    #DateTimeField 年月日时分秒(注意跟datafield的区别)
    #auto_now_add=True:插入数据会存入当前时间
    #auto_now=True  修改数据会存入当前时间
    create_time = models.DateTimeField(auto_now_add=True)
    # commit_num=models.IntegerField(default=0)
    # up_num=models.IntegerField(default=0)
    # down_num=models.IntegerField(default=0)