首页 > 其他分享 >BBS项目

BBS项目

时间:2023-01-02 22:22:32浏览次数:31  
标签:obj name 项目 models True 文章 BBS verbose

目录

BBS

项目开发基本流程

  1. 需求分析
  2. 架构设计
  3. 分组开发
  4. 提交测试
  5. 交付上线

项目分析(表)

bbs项目主要是仿照博客园的页面来设计的。核心就是文章的增删改查

image

  1. 表分析

    首先我们得先确定几个表(表的数量),其次确定表得基础字段,最后确定表的外键字段

    1.用户表
    2.个人站点表
    3.文章表
    4.文章分类表
    5.文章标签表
    6.点赞点踩表
    7.文章评论表
    
  2. 基本字段分析

    用户表

    我们基于auth_user表并扩展额外的字段

    auth_user
    	用户名、密码、邮箱、是否是超级管理员
    基于auth_user表并扩展额外的字段
    	电话表、头像、注册时间
    

    个人站点表

    1.站点名称(kimi/kiki)
    2.站点标题(我博客的The Road of Learning kimi)
    3.站点样式(CSS样式)
    

    文章表

    文章标题、文章简介、文章内容、发布时间
    

    文章分类表

    分类名称
    

    文章标签表

    标签名称
    

    点赞点踩表

    此表是记录哪个用户给哪篇文章点了推荐(赞)反对(踩)
    	用户字段(用户主键):外键字段
        文章字段(文章主键):外键字段
        点赞点踩
    

    文章评论表

    此表是记录哪个用户给哪篇文章评论了什么内容
    用户字段(用户主键):外键字段
    文章字段(文章主键):外键字段
      
    评论内容
    评论时间
    外键字段(自关联)
    
    """
    id	user_id  article_id  content parent_id
    1     1         1         哈哈哈     null
    2     2         1         你笑傻     1
    3     3         1         他疯了     2
    """
    
  3. 外键字段

    用户表
        用户与个人站点时一对一外键关系
        
    个人站点表
    
    文章表
        文章表与个人站点表时一对多外键关系
        文章表与文章分类表时一对多外键关系
        文章与文章标签表时多对多外键关系
        
        文章评论数
        文章点赞数
        文章点踩数
        """ 数据库字段优化设计:我们想统计文章的评论数、点赞数
        通过文章数据跨表查询到文章评论表中对应的数据统计,但是文章需要频繁的展示,每次都跨表查询的话效率极低,基于上述的表述,我们优化处理,只需要在文章表中再创建三个普通字段,之后只需要确保每次操作评论表或者点赞点踩表时同时修改上述的三个普通字段即可"""
        
    文章分类表
        文章分类与个人站点时一对多外键关系
       
    文章标签表
        文章标签与个人站点是一对多外键关系
    

    表关系图如下
    image

项目注册功能

用户注册:利用form组件、modelform组件、ajax组件等编写

1.渲染前端标签
2.校验用户数据
3.展示错误提示
注意:form组件单独开设py文件编写  解耦合!!!

项目登录功能

img标签的src属性

1.直接填写图片地址
2.填写路由,会自动朝该路由发送get请求
如果结果是图片的二进制数据,那么会自动渲染图片

终端下载pillow模块
pip install pillow -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com

项目实操

models.py

from django.db import models
from django.contrib.auth.models import AbstractUser # 要继承auth_user做扩展,引入AbstractUser
""" 要在settings配置一下AUTH_USER_MODEL = 'app01.UserInfo'
"""

class UserInfo(AbstractUser):
    """用户表"""
    phone = models.BigIntegerField(verbose_name='手机号', null=True)
    avatar = models.FileField(upload_to='avatar/', default='avatar/default.jpg', verbose_name='用户头像')
    register_time = models.DateTimeField(verbose_name='注册时间', auto_now_add=True)

    site = models.OneToOneField(to='Site', on_delete=models.CASCADE, null=True)


class Site(models.Model):
    """个人站点表"""
    site_name = models.CharField(verbose_name='站点名称', max_length=32)
    site_title = models.CharField(verbose_name='站点标题', max_length=32)
    site_theme = models.CharField(verbose_name='站点样式', max_length=32, null=True)  # 简单模拟样式文件


class Article(models.Model):
    """文章表"""
    title = models.CharField(verbose_name='文章标题', max_length=32)
    desc = models.CharField(verbose_name='文章简介', max_length=255)
    content = models.TextField(verbose_name='文章内容')
    create_time = models.DateTimeField(verbose_name='创建时间', auto_now_add=True)
    # 三个优化字段
    comment_num = models.IntegerField(verbose_name='评论数', default=0)
    up_num = models.IntegerField(verbose_name='点赞数', default=0)
    down_num = models.IntegerField(verbose_name='点踩数', default=0)

    site = models.ForeignKey(to='Site', on_delete=models.CASCADE, null=True)
    category = models.ForeignKey(to='Category', on_delete=models.CASCADE, null=True)
    tags = models.ManyToManyField(to='Tag',
                                  through='Article2Tag',
                                  through_fields=('article', 'tag'),
                                  null=True
                                  )


class Category(models.Model):
    """文章分类表"""
    name = models.CharField(verbose_name='分类名称', max_length=32)
    site = models.ForeignKey(to='Site', on_delete=models.CASCADE, null=True)


class Tag(models.Model):
    """文章标签表"""
    name = models.CharField(verbose_name='标签名称', max_length=32)
    site = models.ForeignKey(to='Site', on_delete=models.CASCADE, null=True)


class Article2Tag(models.Model):
    article = models.ForeignKey(to='Article', on_delete=models.CASCADE, null=True)
    tag = models.ForeignKey(to='Tag', on_delete=models.CASCADE, null=True)


class UpAndDown(models.Model):
    """文章点赞点踩表"""
    user = models.ForeignKey(to='UserInfo', on_delete=models.CASCADE, null=True)
    article = models.ForeignKey(to='Article', on_delete=models.CASCADE, null=True)
    is_up = models.BooleanField(verbose_name='点赞点踩')  # 传布尔值存 0或者1


class Comment(models.Model):
    """文章评论表"""
    user = models.ForeignKey(to='UserInfo', on_delete=models.CASCADE, null=True)
    article = models.ForeignKey(to='Article', on_delete=models.CASCADE, null=True)
    content = models.TextField(verbose_name='评论内容')
    comment_time = models.DateTimeField(auto_now_add=True, verbose_name='评论时间')
    parent = models.ForeignKey(to='self', on_delete=models.CASCADE, null=True)

注册功能

校验数据利用的是form组件。

views.py

from app01 import myforms  # 引入myforms
from app01 import models  # 引入models
from django.http import JsonResponse  # 引入JsonResponse做数据序列化

# 注册功能
def register_func(request):
    # 前后端ajax交互,通常采用字段作为交互对象
    back_dict = {'code': 10000, 'msg': ''}
    # 1.先产生一个空的form_obj
    form_obj = myform.RegisterForm()
    if request.method == 'POST':
        form_obj = myform.RegisterForm(
            request.POST)  # username password confirm_password email csrfmiddlewaretoken四个键值对
        if form_obj.is_valid():  # 判断是否符合
            clean_data = form_obj.cleaned_data  # 存储符合校验的数据 # username password confirm_password email
            # 将confirm_password键值对移除
            clean_data.pop('confirm_password')  # {# username password  email}
            # 获取用户上传的对象文件
            avatar_obj = request.FILES.get('avatar')  # 用户有可能没有上次,下面的判断必须要的
            if avatar_obj:
                clean_data['avatar'] = avatar_obj  #  {username password  email avatar }
            # 创建用户数据
            models.UserInfo.objects.create_user(**clean_data)  #  上述处理字典的目的就是为了创建数据省事
            back_dict['msg'] = '注册成功'
            back_dict['url'] = '/login/'
            """ 正常业务一般是先写正确的逻辑,后面慢慢添加错误的逻辑"""
        else:
            back_dict['code'] = 10001
            back_dict['msg'] = form_obj.errors
        return JsonResponse(back_dict)

    return render(request, 'registerPage.html', locals())

register.html

本次虽用了form,是为了后面前端的数据反序化,前端提交数据是使用了ajax组件提交数据,本次还给input标签绑定获取焦点事件,移除错误样式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>
    {% load static %}
    <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
    <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>
</head>
<body>
<div class="container">
    <div class="col-md-8 col-md-offset-2">
        <h2 class="text-center">用户注册</h2>
        <form id = 'form'>  <!--不使用form表单提交数据,但是用一下form表单,他有一个序列化功能-->
            {% csrf_token %}
            {% for form in form_obj %}
                <div class="form-group">  <!-- 目的是让多个获取用户数据的标签上下间距更大一点-->
                    <label for="{{ form.auto_id }}">{{ form.label }}</label>  <!--form.auto_id自动获取渲染的标签id值-->
                    {{ form }}
                        <span style="color: red" class="pull-right"></span>
                </div>
            {% endfor %}

        <!--用户头像自己编写相关标签获取-->
            <div class="form-group">
                <label for="myfile">头像
                    <img src="/static/img.jpg" alt="" width="120" id="myimg">  <!-- 把img放在lable里面,因为label和input框已经绑定了-->
                </label>
                <input type="file" id ='myfile' style="display: none" >
            </div>
            <input type="button" id="subBtn" class="btn btn-primary btn-block" value="注册">

        </form>
    </div>
</div>


<script>
    // 1.用户头像的实时展示   >>>这是前端的固定代码
    $('#myfile').change(function (){
        //1.产生一个文件阅读器对象
        let myFileReaderObj = new FileReader();
        // 2.获取用户上传的头像文件
        let fileObj = this.files[0];
        //3.将文件对象交给阅读器对象读取
        myFileReaderObj.readAsDataURL(fileObj)
        //3.等待文件阅读器对象加载完毕之后再修改src
        myFileReaderObj.onload = function (){
            // 4.修改img标签的src属性展示图片
            $('#myimg').attr('src',myFileReaderObj.result)
        }
    })

    // 2.给注册按钮绑定点击事件  发送ajax 携带了文件数据
    $('#subBtn').click(function (){
        // 1.先产生一个内置对象
        let myFormDataObj = new FormData();
        // 2.添加普通数据(单个单个的编写效率极低)
        {#console.log($('#form').serializeArray())  // 可以一次性获取form标签内所有的普通字段数据[{},{},{}]#}
        $.each($('#form').serializeArray(),function (index,dataObj){   //对结果for循环,然后交给后面的函处理
            myFormDataObj.append(dataObj.name,dataObj.value)  // {'name':'','value':''}
        })
        // 3.添加文件数据
        myFormDataObj.append('avatar',$('#myfile')[0].files[0])  //query对象转为标签对象
        //4.发送ajax请求
        $.ajax({
            url:'',
            type:'post',
            data:myFormDataObj,
            contentType:false,
            processData:false,
            success:function (args){
                //  如果code=10000,直接跳转到登录页面,back_dict['url'] = '/login/'
                if(args.code===10000){
                    window.location.href = args.url

                    } else{
                    {#console.log(args.msg)#}
                        let dataObj =args.msg;
                        //如何针对性的渲染错误提示 {'username'}  id_username
                        $.each(dataObj,function(k,msgArray){
                            //拼接标签的id值
                            let eleId='#id_'+ k
                            //根据id查找标签  修改下面的span标签的内容  并给父标签添加错误样式
                            $(eleId).next().text(msgArray[0]).parent().addClass('has-error')
                        })
                    }
                    }
            })
    })


    //3.给所有的input标签绑定获取焦点事件,移除错误样式
    $('input').focus(function (){
        $(this).next().text('').parent().removeClass('has-error')})
</script>
</body>
</html>

登录功能

views.py

# 校验组件一般只在篡创建的时候用到的
def login_func(request):

    return render(request,'loginPage.html')

from PIL import Image,ImageFont,ImageDraw
"""
Image           产生图片
ImageFont       字体样式
ImageDraw       画笔对象
"""
from io import BytesIO,StringIO
"""
BytesIO         在内存中临时存储 读取的时候以bytes格式为准
StringIO        在内存中临时存储 读取的时候以字符串格式为准
"""
import random
def get_random():
    return random.randint(0.255),random.randint(0.255),random.randint(0.255)

def get_code_func(request):
    # 1.推导步骤1:直接读取图片文件返回
    # with open(r'D:\PycharmProjects\BBS\avatar\头像2.png','rb')as f:
    #     data=f.read()
    # return HttpResponse(data)
    # 2.推导步骤2:随机产生图片动态返回  第三方pillow模块
    # img_obj = Image.new('RGB',(350.35),'green')
    # with open(r'xxx.png', 'wb') as f:
    #     img_obj.save(f, 'png')
    # with open(r'xxx.png', 'rb') as f:
    #     data = f.read()
    # return HttpResponse(data)
    # 3.推导步骤3:针对图片的保存与读取做优化 内存管理器
    # img_obj = Image.new('RGB', (350, 35), 'yellow')
    # io_obj = BytesIo()
    # img_obj.save(io_obj,'png')
    # return HttpResponse(io_obj.getvalue())
    # 4.推导步骤4:图片颜色是可以随机变换的
    img_obj = Image.new('RGB', (350, 35), get_random())
    io_obj = BytesIO()
    img_obj.save(io_obj,'png')
    return HttpResponse(io_obj.getvalue())

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>
    {% load static %}
    <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
    <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>
</head>
<body>
    <div class="container">
        <div class="col-md-8 col-md-offset-2">
            <h2 class="text-center">用户登录</h2>
            <div class="form-group">
                <label for="name">用户名</label>
                <input type="text" id="name" class="form-control">
            </div>
            <div class="form-group">
                <label for="password">密码</label>
                <input type="password" id="password" class="form-control">
            </div>
            <div class="form-group">
                <label for="code">验证码</label>
                <div class="row">
                    <div class="col-md-6">
                        <input type="text" id="code" class="form-control">
                    </div>
                    <div class="col-md-6">
                        <img src="/get_code/" alt="" width="350" height="35">
                    </div>
                </div>
            </div>
            <input type="button" class="btn btn-success btn-block" value="登录">
        </div>
    </div>
</body>
</html>

标签:obj,name,项目,models,True,文章,BBS,verbose
From: https://www.cnblogs.com/zhanglanhua/p/17020719.html

相关文章

  • 基于Springboot+SSM框架旅游系统项目开发与设计(附源码资料)-毕业设计
    1.项目简介这是一个Springboot旅游网站管理系统,管理员角色包含以下功能:管理员登录,用户管理,旅游路线管理,旅游景点管理,酒店管理,旅游攻略管理,车票管理,订单管理,数据分......
  • bbs
    项目开发基本流程1.需求分析2.架构设计3.分组开发4.提交测试5.交付上线项目流程仿造博客园项目 核心:文章的增删改查表分析 先确定表的数量再确定表的基础字段......
  • bbs项目
    内容概要主题:仿BBS项目项目开发基本流程项目分析(表)项目注册功能项目登录功能今日内容详细项目开发基本流程1.需求分析2.架构设计3.分组开发4.提交测试......
  • BBS仿博客园
    目录项目开发基本流程一、BBS表设计1.表字段设计1.用户表2.个人站点表3.文章标签表4.文章分类表5.文章表6.点赞点踩表7.文章评论表2.七章表之间的关系1.用户表和个人站点表......
  • django_BBS博客系统练习
    表设计表分析先确认表的数量再确认表的基础字段最后确认表的外键字段1.用户表(基于auth模块设计扩展,手机号,头像,注册时间)fromdjango.contrib.auth.modelsimportAbst......
  • Android网络游戏之神农诀项目开发--视频
    Android网络游戏之神农诀项目开发​   Android作为一款为移动终端打造的开源手机操作平台,其引领破除技术垄断、拥有自主知识产权、降低开发成本之潮流,引起业界的......
  • BBS项目 前期准备及注册、登录部分
    项目开发基本流程1.需求分析2.架构设计3.分组开发4.提交测试5.交付上线创建项目配置环境配置TEMPLATES=[{'BACKEND':'django.template.backends......
  • BBS项目练习
    BBS项目练习此项目是对博客园软件的简单模仿,旨在整合django的知识点。七张信息表用户表(与站点一对一)站点表文章表(与站点一对多)文章分类表文章标签表点赞点踩表......
  • BBS项目
    项目开发基本流程1.需求分析2.架构设计3.分组开发4.提交测试5.交付上线项目流程仿博客园项目 核心:文章的增删改查表分析 先确定表的数量,在确定表的基础字段,最......
  • BBS(仿博客园项目)-基于django框架详解(包含图文)
    BBS项目(仿博客园项目)项目简介使用python中django框架开发类似博客园基本功能的小项目技术:django框架、编程语言(python3.8)、前端基础(bootstarp3.4.1,jQuery3.5.1)、......