bbs项目实战

readme:

需求分析

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

根评论子评论的概念
    根评论就是直接评论当前发布的内容的
    子评论是评论别人的评论
        1.xxxxxx
            1.1dddddd
                1.2dddddggg

根评论与子评论是一对多的关系

models:

from django.db import models

# Create your models here.

from django.contrib.auth.models import AbstractUser

class UserInfo(AbstractUser):
    '''
    继承AbstractUser
    扩展
        phone
        avatar
        create_time

    外键字段:
        一对一 个人站点
    '''
    phone = models.BigIntegerField(verbose_name='手机号',null=True)
    avatar = models.FileField(verbose_name='头像',upload_to='avatar/',default='avatar/default.png')
    create_time = models.DateField(verbose_name='创建时间',auto_now_add=True)

    blog = models.ForeignKey(to='Blog',null=True)

class Blog(models.Model):
    '''
    site_name 站点名称
    site_title 站点标题
    site_theme 站点样式
    '''
    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=64)   # 存css/js文件路径


class Categroy(models.Model):
    '''
     name  分类名

    外键字段:
        一对多 个人站点
    '''
    name = models.CharField(verbose_name='文章分类',max_length=10)

    blog = models.ForeignKey(to='Blog',null=True)

class Tag(models.Model):
    '''
     name  分类名

    外键字段:
        一对多 个人站点
    '''
    name = models.CharField(verbose_name='文章标签', max_length=10)

    blog = models.ForeignKey(to='Blog',null=True)

class Article(models.Model):
    '''
        title   文章标题
        desc    文章简介
        content 文章内容
        create_time  发布时间

        数据库字段设计优化
        (虽然下述的三个字段可以从其他表里面跨表查询计算得出,但是频繁跨表效率差)
        up_num        点赞数
        down_num      点踩数
        comment_num   评论数

        外键字段:
        一对多 个人站点
        一对多 文章分类
        多对多 文章标签
    '''

    title = models.CharField(verbose_name='文章标题',max_length=20)
    desc = models.CharField(verbose_name='文章简介', max_length=60)
    content = models.TextField(verbose_name='文章正文')
    create_time = models.DateTimeField(verbose_name='发表时间',auto_now_add=True)
    up_num = models.IntegerField(verbose_name='点赞数',default=0)
    down_num = models.IntegerField(verbose_name='点踩数',default=0)
    comment_num = models.IntegerField(verbose_name='评论数',default=0)

    blog = models.ForeignKey(to='Blog',null=True)
    categroy = models.ForeignKey(to='Categroy',null=True)
    tags = models.ManyToManyField(to='Tag',null=True,through='Article2Tag',through_fields=('article','tag'))     # 这里使用半自动 创建多对多

class Article2Tag(models.Model):
    article = models.ForeignKey(to='Article')
    tag = models.ForeignKey(to='Tag')


class UpAndDown(models.Model):
    '''
    记录哪个用户给哪篇文章点了赞还是点了踩
    user           ForeignKey(to='User')
    article        ForeignKey(to='Article')
    is_up          BooleanField()
    '''
    user = models.ForeignKey(to='UserInfo')
    article = models.ForeignKey(to='Article')
    is_up = models.BooleanField(verbose_name='点赞数')


class Comment(models.Model):
    '''
    记录那个用户给哪篇文章写了哪些评论内容
    user            ForeignKey(to='User')
    article         ForeignKey(to='Article')
    content         CharField()
    comment_time    DateField()
    parent


    根评论子评论的概念
        根评论就是直接评论当前发布的内容的
        子评论是评论别人的评论
            1.xxxxxx
                1.1dddddd
                    1.2dddddggg

    根评论与子评论是一对多的关系
    '''
    user = models.ForeignKey(to='UserInfo')
    article = models.ForeignKey(to='Article')
    content = models.CharField(verbose_name='评论内容',max_length=255)
    comment_time = models.DateField(verbose_name='评论时间',auto_now_add=True)
    # 自关联
    parent = models.ForeignKey(to='self',null=True)   # 写to='Comment'也可以,但是语义不那么明确

forms:

#!/usr/bin/env python 
# -*- coding:utf-8 -*-
# author: Frank  time:2023/2/12

from django import forms
from app01 import models

class MyReg(forms.Form):
    username = forms.CharField(label='用户名',min_length=3,max_length=8,error_messages={
                                    'required':'用户名必填',
                                    'min_length':'用户名最少三位',
                                    'max_length':'用户名最多八位'
                                },
                               widget=forms.widgets.TextInput(attrs={'class':'form-control'}))

    password = forms.CharField(label='密码',min_length=3,max_length=8,error_messages={
                                    'required':'密码必填',
                                    'min_length':'密码最少三位',
                                    'max_length':'密码最多八位'
                                },
                               widget=forms.widgets.PasswordInput(attrs={'class':'form-control'}))

    repassword = forms.CharField(label='确认密码',min_length=3,max_length=8,error_messages={
                                    'required':'确认密码必填',
                                    'min_length':'确认密码最少三位',
                                    'max_length':'确认密码最多八位'
                                },
                               widget=forms.widgets.PasswordInput(attrs={'class':'form-control'}))

    email = forms.EmailField(label='邮箱',error_messages={
                                    'required':'邮箱必填',
                                    'invalid':'邮箱输入不正确'
                                },
                               widget=forms.widgets.EmailInput(attrs={'class':'form-control'}))

    def clean_username(self):
        username = self.cleaned_data.get('username')
        is_exist = models.UserInfo.objects.filter(username=username)
        if is_exist:
            self.add_error('username','用户名已存在')
        return username

    def clean(self):
        password = self.cleaned_data.get('password')
        repassword = self.cleaned_data.get('repassword')

        if password != repassword:
            self.add_error('repassword','两次输入密码不一致!')
        return self.cleaned_data

register.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>register</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css">
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>

<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <h1 class="text-center">注册页面</h1>
            <form id="myform">
                {% csrf_token %}
                {% for form in form_obj %}
                    <div>
                        <label for="">{{ form.label }}</label>
                        {{ form }}
                        <span style="{color: red}">{{ form.errors }}</span>
                    </div>
                {% endfor %}
                <div class="form-group">
                    <label for="myfile">头像
                        {% load static %}
                    <img src="{% static 'img/default.jpg' %}" alt="头像图片" height="80px" id="myimg">
                    </label>
                    <input type="file" id="myfile" style="display: none" name="avatar">

                </div>
                <input type="button" class="btn btn-primary pull-right" value="提交注册" id="mybutton">
            </form>
        </div>
    </div>
</div>

<script>
    $('#myfile').change(function () {
        //1.先生成一个文件阅读器
        var myFileReaderobj = new FileReader();
        //2.获取文件
        var imgfile = $(this)[0].files[0];
        //3.文件阅读器读取文件
        myFileReaderobj.readAsDataURL(imgfile);
        //4.修改图片标签属性
        myFileReaderobj.onload = function () {
            $('#myimg').attr('src',myFileReaderobj.result)
        }

    });
    
    $('#mybutton').click(function () {
        // 我们发送ajax请求 包括键值对和文件
        var formDataObj = new FormData();
        // 首先获取键值对
        $.each($('#myform').serializeArray(),function (index,obj) {     //我这里有index的目的不是要索引,只是因为这里加一个参数代表的是拿索引,两个参数才是索引+对象
            //console.log(index,obj)
            formDataObj.append(obj.name,obj.value)
        });

        // 然后获取文件
        formDataObj.append('avatar',$('#myfile')[0].files[0]);

        console.log(formDataObj)

        // 发送ajax请求
        $.ajax({
            url:"",
            type:'post',
            data:formDataObj,

            // 需要指定两个关键性参数
            contentType:false,
            processData:false,

            success:function (args) {
                alert(args)
            }

        })
    })
</script>

</body>
</html>

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css">
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>

{#这里不用forms组件来写  因为需要填的东西比较少#}
<div class="container">
    <div class="col-md-8 col-md-offset-2 form-group">
        <div class="row"><h1 class="text-center">登录页面</h1>
            <label for="">Username:</label>
            <input type="text" class="form-control" name="username" id="id_username">
            <label for="">Password:</label>
            <input type="password" class="form-control" name="password" id="id_password">
            <input type="button" id="id_button" class="btn btn-primary pull-right" value="登录" style="margin-top: 20px">
            <span style="color: red" class="pull-right"></span>
        </div>

    </div>
</div>

{#发送ajax请求#}
<script>
    $('#id_button').click(function () {
        $.ajax({
            url:'',
            type:'post',
            data:{
                'username' : $('#id_username').val(),
                'password' : $('#id_password').val(),
                'csrfmiddlewaretoken': '{{ csrf_token }}'   //这里记得要加 '' 没有加'',报错404 (Not Found),如果是404的话,首先先考虑下是不是csrf问题
            },

            //两个必选
{#            processType:false,#}
{#            contentType:false,#}

            success:function (args) {
                if(args.code==1000){
                    window.location.href = args.url
                }else{
                    $('#id_button').next().text(args.msg)
                }
            }
        })
    })

</script>

</body>
</html>

home.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css">
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
    <nav class="navbar navbar-inverse">  <!--或者是navbar-inverse换黑色样式-->
      <div class="container-fluid">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">BBS</a>
        </div>

        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
          <ul class="nav navbar-nav">
            <li class="active"><a href="#">博客 <span class="sr-only">(current)</span></a></li>
            <li><a href="#">文章</a></li>
            <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">更多 <span class="caret"></span></a>
              <ul class="dropdown-menu">
                <li><a href="#">Action</a></li>
                <li><a href="#">Another action</a></li>
                <li><a href="#">Something else here</a></li>
                <li role="separator" class="divider"></li>
                <li><a href="#">Separated link</a></li>
                <li role="separator" class="divider"></li>
                <li><a href="#">One more separated link</a></li>
              </ul>
            </li>
          </ul>
          <form class="navbar-form navbar-left">
            <div class="form-group">
              <input type="text" class="form-control" placeholder="Search">
            </div>
            <button type="submit" class="btn btn-default">Submit</button>
          </form>
          <ul class="nav navbar-nav navbar-right">
              {% if request.user.is_authenticated %}
                <li><a href="#">{{ request.user.username }}</a></li>
                <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">更多操作 <span class="caret"></span></a>
              <ul class="dropdown-menu">
                <li><a href="#">修改密码</a></li>
                <li><a href="#">修改头像</a></li>
                <li><a href="#">后台管理</a></li>
                <li role="separator" class="divider"></li>
                <li><a href="#">退出登录</a></li>
              </ul>
            </li>
              {% else %}
                <li><a href="{% url 'login' %}">登录</a></li>    <!--url反向解析-->
                <li><a href="{% url 'reg' %}">注册</a></li>
              {% endif %}



          </ul>
        </div><!-- /.navbar-collapse -->
      </div><!-- /.container-fluid -->
    </nav>
</body>
</html>

views:

from django.shortcuts import render,HttpResponse

from django.http import JsonResponse

from app01 import MyRegForm
from app01 import models

from django.contrib import auth
# Create your views here.




def register(request):
    # 想到用forms组件来写比较方便
    form_obj = MyRegForm.MyReg()

    if request.method == 'POST':
        # 校验数据是否合法
        form_obj = MyRegForm.MyReg(request.POST)

        dict_info = {"code":1000,"msg":''}
        if form_obj.is_valid():
            # print(form_obj.cleaned_data)   {'username': '123', 'password': '', 'repassword': '', 'email': '11@11.com'}
            mydata = form_obj.cleaned_data
            mydata.pop('repassword')
            # print(request.FILES.get('avatar'))  # 111.jpg
            # mydata['avatar'] = request.FILES.get()
            avatar_file = request.FILES.get('avatar')
            if avatar_file:
                # 这里要记得判断是否为None,如果直接存数据库的话,none就也存进去了
                mydata['avatar'] = avatar_file
            models.UserInfo.objects.create_user(**mydata)
            dict_info['url'] = '/login/'
        else:
            dict_info['code'] = 2000
            dict_info['msg'] = form_obj.errors
        return JsonResponse(dict_info)   # 第一次写的时候这里出错了,多缩进了一格
    return render(request,'register.html',locals())


def login(request):

    if request.method == 'POST':

        dict_info = {'code':1000,'msg':''}

        username = request.POST.get('username')
        password = request.POST.get('password')

        # 校验用户名和密码是否正确
        user_obj = auth.authenticate(request,username=username,password=password)
        if user_obj:
            # 保存用户状态
            auth.login(request,user_obj)
            dict_info['url'] = '/home/'
        else:
            dict_info['code'] = 2000
            dict_info['msg'] = '用户名或密码错误!'
        return JsonResponse(dict_info)

    return render(request,'login.html')


def home(request):
    return render(request,'home.html')
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值