day72 bbs项目☞登录注册

一、表创建及同步

from django.db import models
from django.contrib.auth.models import AbstractUser

# 用户信息表
class UserInfo(AbstractUser):
    # 新增phone,avatar,create_time,blog字段
    phone = models.BigIntegerField()
    avatar = models.ImageField(upload_to='avatar/',default='avatar/default.png')
    create_time = models.DateTimeField(auto_now_add=True)
    blog = models.OneToOneField(to='Blog',null=True)

# 个人站点表
class Blog(models.Model):
    # 创建站点标题,名称,样式
    site_title = models.CharField(max_length=32)
    site_name =models.CharField(max_length=32)
    # 存放的只是样式的路径
    site_theme = models.CharField(max_length=254)

# 分类表
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=254)
    content = models.TextField()
    create_time = models.DateField(auto_now_add=True)
    # 总点赞
    up_num = models.IntegerField(default=0)
    # 总点踩
    dowm_num = models.IntegerField(default=0)
    # 总评论
    comment_num = models.IntegerField(default=0)
    # 和分类的一对多关系
    category = models.ForeignKey(to='Category',null=True)
    # 和站点的一对多关系
    blog = models.ForeignKey(to='Blog')
    # 和标签的多对多关系
    tag = 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 UpAndDowm(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=32)
    comment_time = models.DateField(auto_now_add=True)
    parent = models.ForeignKey(to='self',null=True)


二、注册功能

注册功能要注意的点:

  1. forms验证数据
  2. views内对不同请求和不同类型数据的处理
  3. 前端对后端响应数据的处理
  4. 前端对头像文件的处理

views.py

def register(request):
    form_obj = forms.MyRegForm()
    if request.method == 'POST':
        # 这个dic用来存储数据状态,如果成功直接跳转url,如果失败展示errors,这个逻辑在前端书写
        back_dic = {'code':1000,'url':''}
        # 前端传来的formdata对象会直接把普通数据分配到request.POST中,把文件对象分配到request.FILES内
        # 实例化form对象,把我们的普通数据都传进去
        form_obj = forms.MyRegForm(request.POST)
        # 判断数据是否合法
        if form_obj.is_valid():
            # 获取头像文件
            file_obj = request.FILES.get('avatar')
            form_obj.cleaned_data.pop('password_again')
            cleaned_data = form_obj.cleaned_data
            # 这里没有头像也没关系,我们在设计表的时候头像就已经有一个默认值了
            if file_obj:
                cleaned_data['avatar'] = file_obj
            # 因为cleaned_data是一个字典,所以可以通过**打散数据成xx=xx的形式,灵活运用
            models.UserInfo.objects.create_user(**cleaned_data)
            back_dic['url']='/login'
        else:
            back_dic['code']=2000
            # 如果数据有误需要在前端展示错误信息
            back_dic['msg'] = form_obj.errors
        return JsonResponse(back_dic)

forms.py

from django import forms

from app01 import models

class MyRegForm(forms.Form):
    username = forms.CharField(label='用户名',min_length=3,max_length=8,
                               error_messages={
                                   'max_length':'8个字符太多了!',
                                   'min_length':'3个字符太少了!',
                                    'required':'不能为空!'
                               },
                               widget=forms.widgets.TextInput(attrs={'class':'form-control'})
                               )
    password = forms.CharField(label='密码',max_length=8,min_length=3,
                               error_messages={
                                   'max_length':'8个字符太多了!',
                                   'min_length':'3个字符太少了!',
                                   'required':'不能为空!'
                               },
                               widget=forms.widgets.PasswordInput(attrs={'class':'form-control'})
                               )
    password_again = forms.CharField(label='再次确认密码',max_length=8,min_length=3,
                                     error_messages={
                                         'max_length':'8个字符太多了!',
                                         'min_length':'3个字符太少了!',
                                         'required':'不能为空'
                                     },
                                     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')
        obj = models.UserInfo.objects.filter(username=username)
        if obj :
            self.add_error('username','用户名已存在!')
        return username

    def clean(self):
        password = self.cleaned_data.get('password')
        password_again = self.cleaned_data.get('password_again')
        if password != password_again:
            self.add_error('password_again','两次密码不一致')
        return self.cleaned_data

register.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <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>
{% load static %}
<div class="container-fluid">
    <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 class="form-group">
                 <<! form.auto_id可以获取当前标签的id>>
                        <label for="{{ form.auto_id }}">{{ form.label }}</label>
                        {{ form }}
                        <span style="color: red" class="pull-right"></span>
                    </div>
                {% endfor %}

               <div class="form-group">
                   
            <<! 这里要注意在label内部点击任何东西都会跳转到for指定的标签内!!!!!>>
                    <label for="myfile">头像
                        {% load static %}
                        <img src="{% static 'img/default.png' %}" id='myimg' alt="" width="100" style="margin-left: 10px">
                    </label>
                    <input type="file" id="myfile" name="avatar" style="display: none" >
                </div>
                    <input type="button" class="btn btn-primary pull-right" value="注册" id="id_commit">
            </form>
        </div>

    </div>
</div>

<script>
    $('#myfile').change(function () {
        // 生成一个文件阅读器对象,可以用来读取文件内容
        let myFileReaderObj = new FileReader();
        // 获取文件对象
        let fileObj = $(this)[0].files[0];
        // 把文件对象交给文件阅读器处理,这里的返回结果是文件的二进制数据
        // 异步操作,所以我们要等他加载完毕再执行后面的代码
        myFileReaderObj.readAsDataURL(fileObj);
        myFileReaderObj.onload = function () {
            $('#myimg').attr('src',myFileReaderObj.result)
        }
    })
    $('#id_commit').click(function () {
        // 通过formdata对象发送ajax对象
        let formDataObj = new FormData();
        // 通过each循环的serializeArray方法,得到的index是索引,obj是具体的对象,重要方法
        $.each($('#myform').serializeArray(),function (index,obj) {
            formDataObj.append(obj.name,obj.value)
        });
        formDataObj.append('avator',$('#myfile')[0].files[0])
        $.ajax({
            url:'',
            type:'post',
            data:formDataObj,
            contentType:false,
            processData:false,
            success:function (args) {
                if (args.code==1000){
                    window.location.href = args.url
                }else {
                    // 如果状态码没对上说明有错误数据
                    // 要把错误信息展示到对应标签
                    $.each(args.msg,function (index,obj) {
                     // 因为forms创建的标签的id都是id_字段名
                        let targetId = '#id_' + index;
                        $(targetId).next().text(obj[0]).parent().addClass('has-error')

                    })
                }
            }
        })
    })
    // 给所有input框绑定获取焦点事件
    $('input').focus(function () {
        $(this).next().text('').parent().removeClass('has-error')
    })
</script>
</body>
</html>

二、登录页面搭建

这里只实现了登录页面的搭建并没有写后端验证登录

views.py

from PIL import Image,ImageDraw,ImageFont
"""
Image:生成图片
ImageDraw:能够在图片上乱涂乱画
ImageFont:控制字体样式
"""
from io import BytesIO
"""
内存管理器模块
BytesIO:临时帮你存储数据 返回的时候数据是二进制
StringIO:临时帮你存储数据 返回的时候数据是字符串
"""
import random
# Create your views here.

# 登录功能
def login(request):
    return render(request,'login.html')

# 产生rgb随机颜色
def get_random():
    return random.randint(0,255),random.randint(0,255),random.randint(0,255)

# 获取验证码
def get_code(request):
    # 方式一:直接打开文件
    # with open(r'static/img/default.png','rb') as f:
    #     data = f.read()
    # return HttpResponse(data)

    # 推导步骤2:利用pillow模块动态产生图片
    # img_obj = Image.new('RGB',(430,35),'green')
    # img_obj = Image.new('RGB',(430,35),get_random())
    # # 先将图片对象保存起来
    # with open('xxx.png','wb') as f:
    #     img_obj.save(f,'png')
    # # 再将图片对象读取出来
    # with open('xxx.png','rb') as f:
    #     data = f.read()
    # return HttpResponse(data)

    # 推导步骤3:文件存储繁琐IO操作效率低  借助于内存管理器模块
    # img_obj = Image.new('RGB', (430, 35), get_random())
    # io_obj = BytesIO()  # 生成一个内存管理器对象  你可以看成是文件句柄
    # img_obj.save(io_obj,'png')
    # return HttpResponse(io_obj.getvalue())  # 从内存管理器中读取二进制的图片数据返回给前端

    # 最终成型
    # 产生一个随机颜色的图片
    img_obj = Image.new('RGB',(620,37),get_random())
    # 产生一个画笔对象
    img_draw = ImageDraw.Draw(img_obj)
    # 设置字体样式,大小
    img_font = ImageFont.truetype('static/font/111.ttf',28)

    # 产生5位随机验证码
    code=''
    for i in range(5):
        random_upper = chr(random.randint(65,90))
        random_lower = chr(random.randint(97,122))
        random_int = chr(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
    request.session['code'] = code
    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>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <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-fluid">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <h1 class="text-center">登录页面</h1>
            <div class="form-group">
                <label for="">用户名</label>
                <input type="text" name="username" class="form-control">
            </div>
            <div class="form-group">
                <label for="">密码</label>
                <input type="text" name="password" class="form-control">
            </div>

            <div class="form-group">
                <label for="">验证码</label>
                 <div class="row">
                    <div class="col-md-6">
                        <input type="text" class="form-control">
                    </div>
                    <div class="col-md-6">
                        <img src="/get_code/" alt="" width="620px" height="37px" id="myimg">
                    </div>
                 </div>
            </div>
            <input type="button" class="btn btn-success" value="登录">
        </div>

    </div>

</div>
<script>
    $('#myimg').click(function () {
        let src = $(this).attr('src')
        $(this).attr('src',src += '?')
    })
</script>
</body>
</html>
posted @ 2020-06-11 08:18  lxttt521  阅读(159)  评论(0编辑  收藏  举报