zoukankan      html  css  js  c++  java
  • 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>
    
  • 相关阅读:
    《构建之法》第1.2.3章读后感以及《硅谷传奇》观后感
    算复利条件下等额还款金额
    统计实验数据
    单利计算与复利计算程序
    了解和熟悉操作系统
    0302思考并回答一些问题
    sae storage 使用uploadify插件进行文件批量上传
    PHP页面之间跳转方法总结
    js获取每个按键的ASCII值
    C#文件的拆分与合并操作示例
  • 原文地址:https://www.cnblogs.com/hz2lxt/p/13091018.html
Copyright © 2011-2022 走看看