Django—BBS注册页面

 一、数据库表分析

 1、首先是用户表,用户表继承Django自带的auth_user表,目的是可以使用Django封装好的方法,不用自己手动写cookie和session操作,还可以自定义字段

2、个人站点表,和用户是一对一关系,一个用户都有一个站点

3.文章表,字段有标题和内容,并且还应该有文章的分类和标签,文章只能有一个分类,比如说这篇文章是Python,那篇是前端,但是一个文章可以有多个标签,所以应该还有文章分类表(和文章表是一对多的关系),文章标签表(和文章表是一对多的关系)

4.文章分类表

5.文章标签表

6.评论表,和用户是一对一的关系

7.论坛怎么能没有点赞评论,所以加一个点赞点踩表,一个用户一篇文章只能点一次赞或点一次踩,所以是一对多关系

 关系图

二、表的建立

使用的是mysql

from django.db import models
from django.contrib.auth.models import AbstractUser
#导入AbstractUser类,继承之后,Django自带的Auth_user就被替换了
# Create your models here.


class UserInfo(AbstractUser):
    # 自定义字段
    phone = models.CharField(max_length=32)
    avatar = models.FileField(upload_to='avatar/',default='avatar/default.png')
    # 用户上传头像,upload_to是头像保存的位置,default是用户默认的头像
    create_time = models.DateField(auto_now_add=True)
    # 关联个人页表
    blog = models.OneToOneField(to='Blog',null=True)

class Blog(models.Model):
    site_name = models.CharField(max_length=32)
    site_title = models.CharField(max_length=64)
    # 个人站点的样式文件 存该样式文件的路径
    theme = models.CharField(max_length=64)

#种类表
class Category(models.Model):
    name = models.CharField(max_length=32)
    blog = models.ForeignKey(to='Blog', null=True)

#标签表
class Tag(models.Model):
    name = models.CharField(max_length=32)
    blog = models.ForeignKey(to='Blog', null=True)

#文章表
class Article(models.Model):
    title = models.CharField(max_length=32)
    desc = models.CharField(max_length=255)
    # 存大段文本
    content = models.TextField()
    create_time = models.DateField(auto_now_add=True)
    # 文章的评论数,点赞数,点踩数,虽然有评论表,点赞表,点踩表,但是每次获取数据都是一次查询,速度会很慢,所以直接在文章表里添加
    comment_num = models.IntegerField(default=0)
    up_num = models.IntegerField(default=0)
    down_num = models.IntegerField(default=0)
    blog = models.ForeignKey(to='Blog', null=True)
    category = models.ForeignKey(to='Category',null=True)
    tags = models.ManyToManyField(to='Tag',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 = models.ForeignKey(to='UserInfo')
    article = models.ForeignKey(to='Article')
    is_up = models.BooleanField()


class Comment(models.Model):
    user = models.ForeignKey(to='UserInfo')
    article = models.ForeignKey(to='Article')
    content = models.CharField(max_length=255)
    # 自己是自己的外键,回复如果有其他回复,那么他的parent就是第一个楼层,否则默认是null
    parent = models.ForeignKey(to='self',null=True)
models.py

还要在setting文件里:添加你继承AbstractUser的表名

AUTH_USER_MODEL='app01.UserInfo'

执行数据库迁移命令

python manage.py makemigrations
python mange.py migrate

三、注册页面

完成效果:

forms类的创建

from django import forms
from . import models

class MyForm(forms.Form):
    username = forms.CharField(label='用户名',max_length=14,min_length=3,error_messages={
        'max_length':'用户名不能超过14位!',
        'min_length':'用户名不能少于3位!',
        'required':'用户名不能为空!'
    },widget=forms.TextInput(attrs={'class':'form-control'}))
    password = forms.CharField(label='密码', max_length=14, min_length=3, error_messages={
        'max_length': '密码不能超过14位!',
        'min_length': '密码不能少于3位!',
        'required': '密码不能为空!'
    }, widget=forms.PasswordInput(attrs={'class': 'form-control'}))
    confirm_password = forms.CharField(label='确认密码', max_length=14, min_length=3, error_messages={
        'max_length': '确认密码不能超过14位!',
        'min_length': '确认密码不能少于3位!',
        'required': '确认密码不能为空!'
    }, widget=forms.PasswordInput(attrs={'class': 'form-control'}))
    email = forms.EmailField(label='邮箱',error_messages={
        'required':'邮箱不能为空!',
        'invalid':'邮箱格式错误!'
    },widget=forms.EmailInput(attrs={'class':'form-control'}))

    #局部钩子
    def clean_username(self):
        #获取用户传来的已通过form组件验证的username
        username = self.cleaned_data.get('username')
        #在数据库的UserInfo表内的username做匹配,取到对象
        user_obj = models.UserInfo.objects.filter(username=username).first()
        #判断对象存不存在,不存在则创建,存在则返回
        if user_obj:
            self.add_error('username','用户名已存在!')
        return username

    #全局钩子
    def clean(self):
        password = self.cleaned_data.get('password')
        confirm_password = self.cleaned_data.get('confirm_password')
        if not password == confirm_password:
            self.add_error('confirm_password','两次密码不一致!请重新输入!')
        return self.cleaned_data
myforms.py

前端页面的搭建

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
    <script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>
    <style>
        body {
            background-color: #eeeeee;
        }
    </style>

</head>
<body>
<div class="container-fluid">
    <div class="row">
        <div class="col-md-4 col-md-offset-4">
            <h2 class="text-center">注册</h2>
            <hr>
            <form id="myform">
            {% csrf_token %}
                {% for form in form_obj %}
                    <div class="form-group">
                        <label for="{{ form.auto_id }}">{{ form.label }}</label>
                        {{ form }}
                        <span class="errors pull-right" style="color: red"></span>
                    </div>
                {% endfor %}
            </form>
            <div class="form-group">
                <label for="id_myfile">头像
                    <img src="/static/image/default.jpg" alt="" width="60" style="margin-left: 20px" id="id_img">
                </label>
                <input type="file" name="myfile" id="id_myfile" style="display: none">
            </div>
            <button class="pull-right btn btn-primary  btn-block" id="id_submit">注册</button>
        </div>
    </div>
</div>

//背景动态效果 可以直接复制使用 <script type="text/javascript" color="87,0,86" opacity='1' zIndex="-2" count="99" src="//cdn.bootcss.com/canvas-nest.js/1.0.1/canvas-nest.min.js"></script>

后端代码

def register(request):
   #自定义状态码,等会ajax要用到
    respone_code={'code':100,'msg':''}
   #初始化forms组件
    form_obj=myforms.RegForm()

   #渲染注册页面,locals()把from_obj,response_code传到了前端,起码目前是这样
    return render(request,'register.html',locals())

这只是get请求的代码

 上传头像

 //上传头像并替换
    $('#id_myfile').change(function () {
        // 先获取用户上传的文件对象
        let fileObj = this.files[0];
        // 生成一个内置对象
        let fileReader = new FileReader();
        // 将文件对象传递给内置对象
        fileReader.readAsDataURL(fileObj);
        // 将读取出文件对象替换到img标签
        fileReader.onload = function () {  // 等待文件阅读器读取完毕再渲染图片
            $('#id_img').attr('src', fileReader.result)
        }
    });

ajax异步提交

 $('#id_submit').click(function () {
        //生成一个Formdata对象
        let formData = new FormData();
        //$('#myform').serializeArray()是form表单中的所有数据,自动获取form表单中所有input框键值对,用each循环取出来
        $.each($('#myform').serializeArray(), function (index, obj) {
            //只是添加了普通的键值对,文件对象需要你手动添加
            formData.append(obj.name, obj.value)
        });
        {#console.log($('#myform').serializeArray())#}
        //手动添加文件对象
        formData.append('myfile', $('#id_myfile')[0].files[0]);
        $.ajax({
            url: '',
            type: 'post',
            data: formData,
            processData: false, // 告诉浏览器不要处理我的数据
            contentType: false, // 不要用任何的编码,就用我formdata自带的编码格式,django能够自动识别改formdata对象
            success: function (data) {
                if (data.code == 100) {
                    /*跳转到登录界面
                    location.href  获取URL
                    location.href="URL" // 跳转到指定页面
                    location.reload() 重新加载页面*/
                    location.href = data.url
                } else {
                    $.each(data.msg, function (index, obj) {
                        let targetId = '#id_' + index;  //字符串拼接 id_username,id_password...
                        $(targetId).next().html(obj[0]).parent().addClass('has-error')
                    })
                }

            }
        })
    });
    $('input').focus(function () {
        $(this).next().html('').parent().removeClass('has-error')

    })
$('#myform').serializeArray()是form表单中的所有数据,自动获取form表单中所有input框键值对,用each循环取出来

console.log($('#myform').serializeArray())

 post请求发送后端代码

from django.shortcuts import render,HttpResponse
from . import myforms
from . import models
from django.http import JsonResponse
# Create your views here.

#注册
def register(request):
    back_dic = {'code':100,'msg':''}
    #实例化一个form对象
    form_obj = myforms.MyForm()
    if request.method == 'POST':
        form_obj = myforms.MyForm(request.POST)
        if form_obj.is_valid():
            # 拿到通过验证的用户信息字典,里面还有confirm_password
            cleaned_data = form_obj.cleaned_data
            # 由于创建用户不需要confirm_password这个字段,需要删除
            cleaned_data.pop('confirm_password')
            # 获取用户上传的头像文件
            file_obj = request.FILES.get('myfile')
            # 如果用户上传头像,则加入cleaned_data里并已通过创建到用户表里
            if file_obj:
                cleaned_data['avatar'] = file_obj
            #因为我们需要创建的用户信息和值都在cleaned_data里面这里,cleaned_data又是一个字典,可以**打撒成?=?的方法传值
            # 注意的是前端的name的值必须跟数据库里的字段一直才可以**传值
            models.UserInfo.objects.create_user(**cleaned_data)
            back_dic['msg'] = '注册成功'
            back_dic['url'] = '/login/'
        else:
            back_dic['code'] = 101
            back_dic['msg'] = form_obj.errors
        # 因为给前端传的是字典,需要用JsonResponse
        return JsonResponse(back_dic)
    return render(request,'register.html',locals())
原文地址:https://www.cnblogs.com/zhengyuli/p/11054502.html