BBS版本一


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就是关联自己表

搭建注册页面




    
    Title
    
    {% load static %}
    
    


    

注册页面

{% csrf_token %}
''' 其中包换头像上传功能 '''

注册功能实现

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

登录页面搭建




    
    Title
    
    {% load static %}
    
    


登录页面

登录功能实现

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

搭建首页项目




    
    Title
    
    {% load static %}
    
    
    




Panel content
Panel content
Panel content
{% for article_obj in article_list %}

{{ article_obj.title }}

{{ article_obj.desc }}

{{ article_obj.blog.userinfo.username }}   {{ article_obj.create_time| date:'Y-m-d H:i:s' }}   ({{ article_obj.up_num }})   ({{ article_obj.down_num }})   ({{ article_obj.comment_num }})

{% endfor %}
Panel content
Panel content
Panel content

首页

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/')

个人站点搭建页面




    
    Title
    
    {% load static %}
    
    
    




Panel heading

...

Panel heading

...

Panel heading

...

{% for article_obj in article_list %}

{{ article_obj.title }}

{{ article_obj.desc }}

posted @ {{ article_obj.create_time| date:'Y-m-d H:i:s' }}   {{ article_obj.blog.userinfo.username }}   点赞({{ article_obj.up_num }})   点踩({{ article_obj.down_num }})   评论({{ article_obj.comment_num }})

{% endfor %}

个人站点实现

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

相关