zoukankan      html  css  js  c++  java
  • bbs项目

    数据库表设计:models.py

    from django.db import models
    from django.contrib import auth
    from django.contrib.auth.models import AbstractUser
    
    # Create your models here.
    '''
    先写普通字段
    之后在写外键字段
    '''
    
    class UserInfo(AbstractUser):
        phone = models.BigIntegerField(null=True,verbose_name="手机号")
        # 头像
        avatar = models.FileField(upload_to="avatar/",default='avatar/default.png')
        """
        给avatar字段传文件对象 该文件会自动存储到avatar文件夹 然后avatar字段只保存文件路径avatar/default.png
        """
        create_time = models.DateTimeField(auto_now_add=True)
    
        blog = models.OneToOneField(to='Blog',null=True)
    
    
    class Blog(models.Model):
        site_name = models.CharField(max_length=32,verbose_name='站点名称')
        site_title = models.CharField(max_length=32,verbose_name='站点标题')
        # 简单模拟 认识样式内部原理的操作
        site_theme = models.CharField(max_length=64,verbose_name='站点样式')  # 存css/js的文件路径
    
    
    class Category(models.Model):
        name = models.CharField(max_length=32,verbose_name='文章分类')
        blog = models.ForeignKey(to='Blog',null=True)
    
    
    class Tag(models.Model):
        name = models.CharField(max_length=32,verbose_name='文章标签')
        blog = models.ForeignKey(to='Blog',null=True)
        tags = models.ManyToManyField(to='Article',
                                      through='Article2Tag',
                                      through_fields=('tag','article')
                                      )
    
    
    class Article(models.Model):
        title = models.CharField(max_length=64,verbose_name='文章标题')
        desc = models.CharField(max_length=255,verbose_name='文章简介')
        # 文章内容有很多 一般情况下都是使用TextField
        content = models.TextField(verbose_name='文章内容')
        create_time = models.DateTimeField(auto_now_add=True)
    
        # 数据库字段设计优化
        up_num = models.BigIntegerField(default=0,verbose_name='点赞数')
        down_num = models.BigIntegerField(default=0,verbose_name='点踩数')
        comment_num = models.BigIntegerField(default=0,verbose_name='评论数')
    
        # 外键字段
        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() # 传布尔值存0/1
    
    
    class Comment(models.Model):
        user = models.ForeignKey(to='UserInfo')
        article = models.ForeignKey(to='Article')
        content = models.CharField(max_length=255,verbose_name="评论内容")
        create_time = models.DateTimeField(auto_now_add=True,verbose_name='评论时间')
        # 自关联
        parent = models.ForeignKey(to='self',null=True)  # 一定要加null=True,因为有些评论就是根评论

    注册功能

    myforms.py

    from django import forms  # forms组件所需模块
    from app01 import models
    
    
    class MyRegForm(forms.Form):
        username = forms.CharField(label="用户名", max_length=8, min_length=3,
                                   error_messages={
                                       'required': '用户名不能为空',
                                       'max_length': '用户名最多8位',
                                       'min_length': '用户名最少3位',
                                   },
                                   widget=forms.widgets.TextInput(attrs={'class': 'form-control'})
                                   )
    
        password = forms.CharField(label="密码", max_length=8, min_length=3,
                                   error_messages={
                                       'required': '密码不能为空',
                                       'max_length': '密码最多8位',
                                       'min_length': '密码最少3位',
                                   },
                                   widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'})
                                   )
    
        confirm_password = forms.CharField(label="确认密码", max_length=8, min_length=3,
                                           error_messages={
                                               'required': '确认密码不能为空',
                                               'max_length': '确认密码最多8位',
                                               'min_length': '确认密码最少3位',
                                           },
                                           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_exists = models.UserInfo.objects.filter(username=username)
            if is_exists:
                # 提示信息
                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

    views.py

    from django.shortcuts import render, HttpResponse
    from app01.myforms import MyRegForm
    from app01 import models
    from django.http import JsonResponse
    
    
    # Create your views here.
    def register(request):
        form_obj = MyRegForm()
        if request.method == "POST":
            back_dic = {"code": 1000, "msg": ""}
            # 校验数据是否合法
            form_obj = MyRegForm(request.POST)
            if form_obj.is_valid():
                # print(form_obj.cleaned_data)     # {'username': 'alias', 'password': '123', 'confirm_password': '123', 'email': '123@qq.com'}
                clean_data = form_obj.cleaned_data  # 将校验通过的数据字典赋值给一个变量
                clean_data.pop("confirm_password")  # {'username': 'alias', 'password': '123', 'email': '123@qq.com'}
                # 用户头像
                file_obj = request.FILES.get("avatar")
                """针对用户头像一定要判断是否传值 不能直接添加到字典中"""
                if file_obj:
                    clean_data['avatar'] = file_obj
                # 操作数据库保存数据
                models.UserInfo.objects.create_user(**clean_data)
                back_dic["url"] = "/login/"
            else:
                back_dic["code"] = 2000
                back_dic["msg"] = form_obj.errors
            return JsonResponse(back_dic)
    
        return render(request, "register.html", locals())

    register.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <!-- Bootstrap3 核心 CSS 文件 -->
        <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
        <!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
        <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
        <!-- Bootstrap3 核心 JavaScript 文件 -->
        <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
        <!-- font-awesome.min.css图标库4.7版本 -->
        <link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
    </head>
    <body>
    <div class="container-fluid">
        <div class="row">
            <div class="col-md-8 col-md-offset-2">
                <h1 class="text-center">注册</h1>
                <form id="myform">    <!--我们不用form表单提交数据 只是单纯用一下form标签而已-->
                    {% for form in form_obj %}
                        <div class="from-group">
                            <!--form.auto_id获取forms渲染的input框的id-->
                            <label for="{{ form.auto_id }}">{{ form.label }}</label>
                            {{ form }}
                            <span style="color: red" class="pull-right"></span>
                        </div>
                    {% endfor %}
                    <div class="form-group" style="margin-top: 10px">
                        <label for="myfile">头像
                            {% load static %}
                            <img src="{% static "img/default.png" %}" alt="" id="myimg" width="100px" 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 src="{% static "js/mysteup.js" %}/"></script>
    <script>
        // 选择头像实时显示
        $("#myfile").change(function () {
            // 文件阅读器对象
            // 1、先生成一个文件阅读器对象
            let myFileReaderObj = new FileReader();
            // 2、获取用户上传的头像文件
            let fileObj = $(this)[0].files[0];
            // 3、将文件对象交给阅读器对象读取
            myFileReaderObj.readAsDataURL(fileObj);     // 这步操作是异步
            // 4、利用文件阅读器将文件展示到前端页面   修改img的src属性
            // 等待myFileReaderObj文件阅读器加载完毕之后再执行
            myFileReaderObj.onload = function(){
                $("#myimg").attr("src",myFileReaderObj.result)
            }
        });
        $("#id_commit").click(function () {
            // 发送ajax请求  我们发送的数据中即包含普通键值也包含文件
            let formDataObj = new FormData();
            // 添加普通键值对
            // console.log($("#myform").serializeArray())  // [{},{},{},...] 只包含普通键值对
            $.each($("#myform").serializeArray(),function (index,obj) {
                // console.log(index,obj)   // obj = {}
                formDataObj.append(obj.name,obj.value)
            });
            // 添加文件
            formDataObj.append('avatar',$("#myfile")[0].files[0]);
            // 发送ajax请求
            $.ajax({
                url: '',
                type: 'post',
                dataType: 'json',
                data: formDataObj,
    
                contentType: false,
                processData: false,
                success: function (args) {
                    if (args.code == 1000){
                        // 跳转到登录页面
                        window.location.href = args.url
                    }else{
                        // 如何将对应的错误信息提示展示到对应的input框下面,因为用的ajax所以无法像之前在span标签里面写form.errors.0
                        // forms组件渲染的标签的id值都是 id_字段名
                        $.each(args.msg,function (index,obj) {
                            {#console.log(index,obj)  //  username        ["用户名不能为空"]#}
                            let targetId = '#id_' + index;      // input标签
                            {#$(targetId).next().text(obj[0]).parent().addClass('has-error')#}
                            $(targetId).next().text(obj[0]).prev().css("border","solid red")
                        })
                    }
                }
            })
        })
        // 给所有的input框绑定获取焦点事件
        $('input').focus(function () {
            // 将input下面的span标签和input外面的div标签修改内容及属性
            $(this).next().text('').prev().removeAttr("style","");
        })
    </script>
    </body>
    </html>

    登录功能

    views.py

    from django.shortcuts import render, HttpResponse
    from app01.myforms import MyRegForm
    from app01 import models
    from django.http import JsonResponse
    
    
    # Create your views here.
    def register(request):
        form_obj = MyRegForm()
        if request.method == "POST":
            back_dic = {"code": 1000, "msg": ""}
            # 校验数据是否合法
            form_obj = MyRegForm(request.POST)
            if form_obj.is_valid():
                # print(form_obj.cleaned_data)     # {'username': 'alias', 'password': '123', 'confirm_password': '123', 'email': '123@qq.com'}
                clean_data = form_obj.cleaned_data  # 将校验通过的数据字典赋值给一个变量
                clean_data.pop("confirm_password")  # {'username': 'alias', 'password': '123', 'email': '123@qq.com'}
                # 用户头像
                file_obj = request.FILES.get("avatar")
                """针对用户头像一定要判断是否传值 不能直接添加到字典中"""
                if file_obj:
                    clean_data['avatar'] = file_obj
                # 操作数据库保存数据
                models.UserInfo.objects.create_user(**clean_data)
                back_dic["url"] = "/login/"
            else:
                back_dic["code"] = 2000
                back_dic["msg"] = form_obj.errors
            return JsonResponse(back_dic)
    
        return render(request, "register.html", locals())
    
    
    def login(request):
        return render(request, 'login.html')
    
    """
    图片相关的模块
        # pip3 install pillow
    """
    from PIL import Image,ImageDraw,ImageFont,ImageFilter
    """
    Image:生成图片
    ImageDraw:能够在图片上乱涂乱画
    ImageFont:控制字体样式
    ImageFilter:控制图片模糊度
    """
    from io import BytesIO,StringIO
    """
    内存管理器模块
    BytesIO:临时的帮你存储数据 返回的时候数据就是二进制格式
    StringIO:临时的帮你存储数据 返回的时候数据就是字符串格式
    """
    
    import random
    
    def get_random():
        return random.randint(0,255),random.randint(0,255),random.randint(0,255)
    
    def get_code(request):
        # 推导步骤1:直接获取后端现成的图片二进制数据发送给前端
        # with open(r"static/img/111.jpg", "rb") as f:
        #     data = f.read()
        # return HttpResponse(data)
        #
        # 推导步骤2:利用pillow模块动态产生图片(文件存储繁琐IO操作效率低)
        # img_obj = Image.new('RGB', (430, 35), "red")   # 第二个参数图片尺寸(要和前端划定的尺寸一致),第三个参数还可以放三基色参数
        # 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:借助于内存管理模块
        # img_obj = Image.new('RGB', (430, 35), get_random())
        # io_obj = BytesIO()  # 生成一个内存管理器对象,可以看成是文件句柄
        # img_obj.save(io_obj,'png')     # 要指定图片的格式
        # return HttpResponse(io_obj.getvalue())    # io_obj.getvalue()读取出文件,返回的是二进制格式
    
        # 最终步骤:绘制图片验证码
        img_obj = Image.new('RGB', (430, 35), get_random())
        img_draw = ImageDraw.Draw(img_obj)   # 产生一个画笔对象
        img_font = ImageFont.truetype("static/font/222.TTF",30)    # 字体样式,以及字体大小
    
        # 随机验证码  五位数的随机验证码 数字 小写字母 大写字母
        code = ''
        for i in range(5):
            random_upper = chr(random.randint(65,90))
            random_lower = chr(random.randint(97,122))
            random_int = str(random.randint(0,9))
            # 从上面三个里面随机选一个
            tmp = random.choice([random_upper,random_lower,random_int])
            # 将产生的随机字符串写入图片
            """
            为什么一个个写而不是生成好了之后再写
            因为一个个写能够控制每个字体的间隙 而生成好之后再写的话
            间隙就没法控制了
            """
            img_draw.text((i*45+100,-3),tmp,get_random(),img_font)
            # 拼接随机字符串
            code += tmp
        # print(code)
        # 随机验证码在登录的视图函数中需要用到 要比对,所以要找地方存起来且其他视图函数也能拿到(可以放在auth_session表中)
        request.session['code'] = code
        io_obj = BytesIO()
        # img_obj = img_obj.filter(ImageFilter.GaussianBlur)
        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>
        <!-- Bootstrap3 核心 CSS 文件 -->
        <link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
        <!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
        <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
        <!-- Bootstrap3 核心 JavaScript 文件 -->
        <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
        <!-- font-awesome.min.css图标库4.7版本 -->
        <link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
        {% load static %}
    
    </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="username">用户名</label>
                    <input type="text" name="username" id="username" class="form-control">
                </div>
                <div class="form-group">
                    <label for="password">密码</label>
                    <input type="password" name="password" id="password" class="form-control">
                </div>
                <div class="form-group">
                    <label for="">验证码</label>
                    <div class="row">
                        <div class="col-md-6">
                            <input type="text" name="code" id="id_code" class="form-control">
                        </div>
                        <div class="col-md-6">
                            <!--这个页面只要一加载出来,就会朝这个/get_code/路径发get请求-->
                            <img src="/get_code/" alt="" width="430px" height="35px" id="id_img">
                        </div>
                    </div>
                </div>
                <input type="button" class="btn btn-success btn-block" value="登陆">
            </div>
        </div>
    </div>
    <script>
        $("#id_img").click(function () {
            // 1 先获取标签之前的src
            let oldVal = $(this).attr('src');
            $(this).attr('src',oldVal += '?')
        })
    </script>
    </body>
    </html>
  • 相关阅读:
    C#学习之Enum
    Ten MustHave Tools Every Developer Should Download Now
    C#学习之Random
    C#学习之Exception
    WCF Data Contract之KnownType
    ESQL应该注意的地方
    Windows 安全认证是如何进行的?
    十个必备的.NET开发小工具
    c#中判断一个process是32bit还是64bit
    怎么用python和javascript把多张png拼成一个gif
  • 原文地址:https://www.cnblogs.com/baicai37/p/13090631.html
Copyright © 2011-2022 走看看