zoukankan      html  css  js  c++  java
  • django框架前后端混合项目之表设计、数据库及form组件等相关内容-77

    1 auth组件:django内置的一套用户,认证系统本质是一个app(admin,auth)
    2 方法
    	-authenticate(username=lqz,password=123,phone=12222)
        -login:写了session,把当前登录用户写入了request.user    request.user.print_name()
        -logout:退出
        -is_authenticate :判断用户是否登录(视图,模板)
        -login_require:登录认证装饰器(基于session的)
        -creat_user/superuser:直接存表,密码是明文,借助这俩方法创建用户
        -check_password:通过明文密码校验
        -set_password:一定要记住保存
        -is_staff,is_active,is_superuser(User对象的属性,表中的字段)
        -扩展auth_user表:一对一,继承(在setting中配置)
        
    3 多对多关系,第三张表的创建
    	-手动创建:book  author  没有直接的关联字段
        -中介模型:手动创建中间表,book和author写上关联字段
        	-authors=models.ManyToManyField(to='Author',through='AuthorToBook',through_fields=('book_id','author_id'))
            -基于对象的跨表查询:正常使用
            -基于双下滑下的连表查询:正常使用
            -book.authors.add,set,remove,clear (不能用了,  AuthorToBook:表)
       	-自动创建第三张表
        	
    

    1 项目开发流程

    1 互联网项目(产品经理提需求),传统行业项目(客户提需求)
    
    2 项目开发流程
    	-需求分析(组长,项目经理,产品经理)
        -原型设计(产品经理)
        -美工UI切图
        -设计程序,数据库(上面连个跟设计数据库可以同步操作)
        -分任务开发(张三写用户相关,李四写订单相关),多人协同开发(git,svn)
     	-过了三个月所有任务开发完了
        -测试(专门的测试)
        -上线
    3 项目开发模式
    	-瀑布模式:
        -敏捷开发:
        
        
    4 博客项目需求
    	-多人博客
        -博客首页
        -登录:图片验证码
        -注册:上传头像
        -自己有自己的个人站点(根据分类,标签,时间,过滤文章)
        -自己的后台管理
        	-发表博客(富文本编辑器,xss攻击处理)
            -查看,删除
        -文章分类
        -随笔档案
        -文章标签
        -文章
        -文章详情
        -评论(根评论,子评论)
        -点赞点踩
        
    

    2 bbs项目表设计

    # 表设计(8张)
        1 用户表:UserInfo表
        2 博客表:Blog表
        3 分类表:Category
        4 标签表:Tag
        5 文章:Article(文章和详情一个表)
        6 评论:Commit 
        7 点赞点踩表:UpAndDown
    
    # 表关系
    	见图
        
    # 表中字段
        1 用户表:UserInfo表(通过继承auth_user扩展)
        	-telephone
            -avatar(头像)
            -blog  关联字段
        2 博客表:Blog表
        	-site_title
            -site_name
            -site_style
        3 分类表:Category
        	-name
            -blog
        4 标签表:Tag
        	-name
            -blog
        5 文章:Article(文章和详情一个表)
        	-title
            -desc
            -content
            -create_time
            -blog
            -category
            -tag(在数据没有字段)
            -#最后更新时间
        6 评论:Commit 
        	-user
            -article
            -create_time
            -content
        7 点赞点踩表:UpAndDown
        	-user
            -article
            -is_up
            -create_time
    
          
        # 假设加一张关注表
        user
        atricle
        create_time
    	
    

    3 数据库表创建及同步

    # 根评论和子评论分析
    id   user  articel   content                   commit
    1     1     1         写的真好                     null
    2     1     2         写的真烂                     null
    3     2     2         你放屁,人家写的很好            2
    4     1     2         你怎么骂人呢?                 3
    5     2     2         就骂你怎么了                   4
    6     3     2         你这个嘴太碎了                 2
    7     4     2         碎嘴子                        2
    
    
    
    from django.db import models
    
    from django.contrib.auth.models import AbstractUser
    
    
    class UserInfo(AbstractUser):
        phone = models.CharField(max_length=32)
        # upload_to文件上传以后存放的路径
        # FileField本质是varchar类型
        # 坑()
        avatar = models.FileField(upload_to='avatar/', default='avatar/default.png')
        blog = models.OneToOneField(to='Blog',on_delete=models.CASCADE)
    
    
    class Blog(models.Model):
        site_title = models.CharField(max_length=32)
        site_name = models.CharField(max_length=32)
        # 每个人样式不同(文件地址)
        site_style = models.CharField(max_length=32)
    
    
    class Tag(models.Model):
        name = models.CharField(max_length=32)
        blog = models.ForeignKey(to='Blog',on_delete=models.CASCADE)
    
    
    class Category(models.Model):
        name = models.CharField(max_length=32)
        blog = models.ForeignKey(to='Blog',on_delete=models.CASCADE)
    
    
    class Article(models.Model):
        title = models.CharField(max_length=32)
        desc = models.CharField(max_length=128)
        # 大文本
        content = models.TextField()
        create_time = models.DateTimeField(auto_now_add=True)
    
        # 关联关系
        blog = models.ForeignKey(to='Blog',on_delete=models.CASCADE)
        category = models.ForeignKey(to='Category',on_delete=models.CASCADE)
        # 多对多关系
        tag = models.ManyToManyField(to='Tag', through='TagToArticle', through_fields=('article', 'tag'))
    
    
    class TagToArticle(models.Model):
        tag = models.ForeignKey(to='Tag',on_delete=models.CASCADE)
        article = models.ForeignKey(to='Article',on_delete=models.CASCADE)
    
    
    class UpAndDown(models.Model):
        user = models.ForeignKey(to='UserInfo',on_delete=models.CASCADE)
        article = models.ForeignKey(to='Article',on_delete=models.CASCADE)
        # 实质存的时候,是0和1
        is_up = models.BooleanField()
        create_time = models.DateTimeField(auto_now_add=True)
    
    
    class Commit(models.Model):
        user = models.ForeignKey(to='UserInfo',on_delete=models.CASCADE)
        article = models.ForeignKey(to='Article',on_delete=models.CASCADE)
        content = models.CharField(max_length=256)
        create_time = models.DateTimeField(auto_now_add=True)
    
        # 存父评论的id号
        # commit_id=models.IntegerField()
        # commit=models.ForeignKey(to='Commit')
        # 自关联(不能叫表明小写)
        commit_id=models.ForeignKey(to='self',on_delete=models.CASCADE)
    
    
    
        # 踩了两个坑
        avatar = models.FileField(upload_to='avatar/', default='avatar/default.png')
        commit_id=models.ForeignKey(to='self',on_delete=models.CASCADE)
        
       # 迁移(两条命令)
    

    4 注册form组件编写

    1 用户名,密码,            修改个人信息:邮箱,手机号,头像
    2 用户名,密码,邮箱,头像
    
    
    from django import forms
    from django.forms import widgets
    
    from blog import models
    from django.forms import ValidationError
    
    
    class RegisterForm(forms.Form):
        username = forms.CharField(required=True, max_length=18, min_length=3, label='用户名',
                                   error_messages={'required': '该字段必填',
                                                   'max_length': '最大长度为18',
                                                   'min_length': '最短为3'},
                                   widget=widgets.TextInput(attrs={'class': 'form-control'}))
        password = forms.CharField(required=True, max_length=18, min_length=3, label='密码',
                                   error_messages={'required': '该字段必填',
                                                   'max_length': '最大长度为18',
                                                   'min_length': '最短为3'},
                                   widget=widgets.PasswordInput(attrs={'class': 'form-control'}))
        re_password = forms.CharField(required=True, max_length=18, min_length=3, label='确认密码',
                                      error_messages={'required': '该字段必填',
                                                      'max_length': '最大长度为18',
                                                      'min_length': '最短为3'},
                                      widget=widgets.PasswordInput(attrs={'class': 'form-control'}))
        email = forms.EmailField(required=True, label='邮箱',
                                 error_messages={'required': '该字段必填'},
                                 widget=widgets.EmailInput(attrs={'class': 'form-control'}))
    
        # 用户名如果存在了,就不能注册
        def clean_username(self):
            username = self.cleaned_data.get('username')
            # 去数据库查询
            user = models.UserInfo.objects.filter(username=username).count()
            if user:  # 不合法
                raise ValidationError('用户名已经存在')
            else:
                return username
    
        # 校验两次密码是否一致
        def clean(self):
            password = self.cleaned_data.get('password')
            re_password = self.cleaned_data.get('re_password')
            if re_password == password:
                return self.cleaned_data
            else:
                raise ValidationError('两次密码不一致')
    
    
    

    5 注册功能页面搭建

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
        <script src="/static/jquery-3.3.1/jquery-3.3.1.min.js"></script>
        <title>注册</title>
    </head>
    <body>
    <div class="container-fluid">
        <div class="row">
            <h1 class="text-center">注册功能</h1>
            <div class="col-md-6 col-md-offset-3">
    
                <form id="form">
                {% csrf_token %}
                    {% for foo in form %}
                        <div class="form-group">
                            <label for="{{ foo.auto_id }}">{{ foo.label }}</label>
                            {{ foo }}
                        </div>
                    {% endfor %}
                    <div class="form-group">
                        <label for="id_myfile">头像
                            <img src="/static/img/default.png" alt="" id="id_img" height="80" width="80"
                                 style="margin-left: 10px">
                        </label>
    
                        <input type="file" name="myfile" id="id_myfile" style="display: none">
                    </div>
                    <div class="text-center">
                        {#注意这个坑#}
                        <input type="button" value="注册" id="id_submit" class="btn btn-danger">
                    </div>
                </form>
            </div>
        </div>
    </div>
    </body>
    
    <script>
        //放文件的标签发生变化,我们把文件搞出来,放到img标签中
        $("#id_myfile").change(function () {
            //借助于文件阅读器
            const filereader = new FileReader()
            //把图片读到filereader对象中
            //$('#id_myfile')[0].files[0]
            filereader.readAsDataURL($('#id_myfile')[0].files[0])
            //$('#id_img').attr('src','https://account.cnblogs.com/images/registersideimg.png')
            //$('#id_img').attr('src',filereader.result) //这样不行,文件没读完
            filereader.onload = function () {
                //文件完全读到文件阅读器以后,再执行
                $('#id_img').attr('src', filereader.result)
            }
        })
    
        $("#id_submit").click(function () {
            var formdata = new FormData()
            formdata.append('avatar', $('#id_myfile')[0].files[0])
            //第一种方式:
            /*
            formdata.append('username', $('#id_name').val())
            formdata.append('password', $('#id_password').val())
            formdata.append('re_password', $('#id_re_password').val())
            formdata.append('email', $('#id_email').val())
             */
            //第二种方式:
            var ser = $('#form').serializeArray()
            //[{name:name,value:lqz}, {name:password],value:123}, {name:re_password],value:123}, {name:email],value:123@qq.com}]
            //console.log(ser)
    
            $.each(ser, function (k, v) {
                //console.log(v.name)
                //console.log(v.value)
                formdata.append(v.name, v.value)
            })
    
            $.ajax({
                url: '/register/',
                method: 'post',
                processData: false,
                contentType: false,
                data: formdata,
                success: function (data) {
                    if (data.code == 100) {
                        console.log(data.msg)
                        //js控制的跳转
                        location.href=data.url
                    } else {
                        //有错误,需要渲染页面
                    }
                }
    
            })
    
    
        })
    
    </script>
    </html>
    

    6 头像实时显示

    $("#id_myfile").change(function () {
        //借助于文件阅读器
        const filereader = new FileReader()
        //把图片读到filereader对象中
        //$('#id_myfile')[0].files[0]
        filereader.readAsDataURL($('#id_myfile')[0].files[0])
        //$('#id_img').attr('src','https://account.cnblogs.com/images/registersideimg.png')
        //$('#id_img').attr('src',filereader.result) //这样不行,文件没读完
        filereader.onload = function () {
            //文件完全读到文件阅读器以后,再执行
            $('#id_img').attr('src', filereader.result)
        }
    })
    

    7 注册功能完成

    后端

    def register(request):
        if request.method == 'GET':
            form = RegisterForm()
            return render(request, 'register.html', context={'form': form})
        elif request.method == 'POST':
            # 校验数据是否合法
            res = {'code': 100, 'msg': '注册成功'}
            form = RegisterForm(data=request.POST)
            if form.is_valid():
    
                # 保存到数据库
                data = form.cleaned_data  # {username:lqz,password:123,re_password:123,email:3@qq.com}
                data.pop('re_password')# {username:lqz,password:123,email:3@qq.com}
                file=request.FILES.get('avatar')
                if file:
                    data['avatar']=file # {username:lqz,password:123,email:3@qq.com,'avatar':文件对象}
                print(data)
                models.UserInfo.objects.create_user(**data)
                # res['url']='/index/'
                res['url']='http://www.baidu.com'
                '''
                FileField自动干了这个事
                with open('media/avatar/%s'%file.name,'wb') as f:
                    for line in file:
                        f.write(line)
                path='media/avatar/%s'%file.name
            
                '''
                # models.UserInfo.objects.create_user(username=username,password=password,email=email,avatar=path)
                # 返回,会被ajax接收到
                return JsonResponse(res)
            else:
                # 数据校验不通过
                res['code'] = 101  # 101表示注册失败
                res['msg'] = '数据验证失败'
                res['error'] = form.errors
                return JsonResponse(res)
    

    前端

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
        <script src="/static/jquery-3.3.1/jquery-3.3.1.min.js"></script>
        <title>注册</title>
    </head>
    <body>
    <div class="container-fluid">
        <div class="row">
            <h1 class="text-center">注册功能</h1>
            <div class="col-md-6 col-md-offset-3">
    
                <form id="form">
                {% csrf_token %}
                    {% for foo in form %}
                        <div class="form-group">
                            <label for="{{ foo.auto_id }}">{{ foo.label }}</label>
                            {{ foo }}
                        </div>
                    {% endfor %}
                    <div class="form-group">
                        <label for="id_myfile">头像
                            <img src="/static/img/default.png" alt="" id="id_img" height="80" width="80"
                                 style="margin-left: 10px">
                        </label>
    
                        <input type="file" name="myfile" id="id_myfile" style="display: none">
                    </div>
                    <div class="text-center">
                        {#注意这个坑#}
                        <input type="button" value="注册" id="id_submit" class="btn btn-danger">
                    </div>
                </form>
            </div>
        </div>
    </div>
    </body>
    
    <script>
        //放文件的标签发生变化,我们把文件搞出来,放到img标签中
        $("#id_myfile").change(function () {
            //借助于文件阅读器
            const filereader = new FileReader()
            //把图片读到filereader对象中
            //$('#id_myfile')[0].files[0]
            filereader.readAsDataURL($('#id_myfile')[0].files[0])
            //$('#id_img').attr('src','https://account.cnblogs.com/images/registersideimg.png')
            //$('#id_img').attr('src',filereader.result) //这样不行,文件没读完
            filereader.onload = function () {
                //文件完全读到文件阅读器以后,再执行
                $('#id_img').attr('src', filereader.result)
            }
        })
    
        $("#id_submit").click(function () {
            var formdata = new FormData()
            formdata.append('avatar', $('#id_myfile')[0].files[0])
            //第一种方式:
            /*
            formdata.append('username', $('#id_name').val())
            formdata.append('password', $('#id_password').val())
            formdata.append('re_password', $('#id_re_password').val())
            formdata.append('email', $('#id_email').val())
             */
            //第二种方式:
            var ser = $('#form').serializeArray()
            //[{name:name,value:lqz}, {name:password],value:123}, {name:re_password],value:123}, {name:email],value:123@qq.com}]
            //console.log(ser)
    
            $.each(ser, function (k, v) {
                //console.log(v.name)
                //console.log(v.value)
                formdata.append(v.name, v.value)
            })
    
            $.ajax({
                url: '/register/',
                method: 'post',
                processData: false,
                contentType: false,
                data: formdata,
                success: function (data) {
                    if (data.code == 100) {
                        console.log(data.msg)
                        //js控制的跳转
                        location.href=data.url
                    } else {
                        //有错误,需要渲染页面
                    }
                }
    
            })
    
    
        })
    
    </script>
    </html>
    
  • 相关阅读:
    css文字和背景色渐变色
    雪碧图定位
    js操作链接url
    93服务器上获取json数据
    this的区别
    绩效项目总结
    【ASP.NET MVC 学习笔记】- 05 依赖注入工具Ninject
    【ASP.NET MVC 学习笔记】- 04 依赖注入(DI)
    【ASP.NET MVC 学习笔记】- 03 Razor语法
    【ASP.NET MVC 学习笔记】- 02 Attribute
  • 原文地址:https://www.cnblogs.com/usherwang/p/14204920.html
Copyright © 2011-2022 走看看