zoukankan      html  css  js  c++  java
  • 1209 BBS 登录

    上周内容

    bbs项目
    	
    	
    	项目开发流程
    		需求分析
    		
    		架构设计
    		
    		分组开发
    			我们一般情况下都只是作用于这一步
    		
    		各项测试
    
    		交付上线
    			
    	bbs表设计
    		任何一个项目 最最重要的部分都是数据库的表设计
    	
    	用户表
    		继承AbstractUser表  来做额外的字段扩展
    			1.类的继承
    			2.配置文件配置
    				AUTH_USER_MODEL = '应用名.类名'
    		
    		phone
    		avatar
    			upload_to='avatar/'
    		register_time
    		
    		
    		
    	
    	个人站点表
    		站点标题
    		站点名称
    		站点样式
    			模拟
    		
    	
    	文章标签表
    		标签名称
    	
    	文章分类表
    		分类名称
    	
    	文章表
    		文章标题
    		文章简介
    		文章内容
    		文章日期
    		
    		# 数据库优化字段
    		点赞数
    		点踩数
    		评论数
    		
    	
    	点赞点踩表
    		用户id         一对多字段
    		文章id		   一对多字段
    		点赞点踩		1/0
    		
    	
    	评论表
    		用户id			一对多字段
    		文章id			一对多字段
    		评论内容
    		评论时间
    		自关联字段		自己跟自己所在的表关联
    		
    	
    	数据库配置
    		1.配置文件
    		2.__init__文件
    	
    	数据库迁移命令
    		python3 manage.py makemigrations	
    		python3 manage.py migrate
    	
    	注册功能
    		只要是注册功能一般都有一定的校验规则
    		
    		我们利用forms组件 来完成注册的校验
    			用户名
    				label
    				error_messages
    					required
    					invalid
    				widget
    				validators
    			密码
    			确认密码
    			邮箱
    			
    			钩子函数
    				校验用户名是否已存在
    			
    				校验两次密码是否一致
    		
    		一旦你的项目特别庞大 需要用到很多forms组件 
    		那么你可以单独的将所有forms组件放到一个py文件中或者一个文件下
    		然后针对不同的功能开设不同的py文件
    			单独的py文件
    		
    			文件夹
    				1.py
    				2.py
    				3.py
    				4.py
    			
    	注册功能使用的是ajax做后端交互
    	但是我们用的了form标签
    		因为form标签有一个自动序列化普通键值对的功能
    		可以方便的将普通键值对循环添加到formdata对象中
    	
    	label标签在跟input有绑定关系的前提下
    	内部无论放什么对象 点击都能够是对应的input框聚焦
    	
    	img标签src属性可以放的值
    		1.图片的地址
    		2.图片的二进制数据
    		3.后端url   自动朝该url发送get请求
    	
    	实时展示用户选择的头像
    		利用内置对象fileReader
    			文件阅读器在读取文件的时候 是一个异步io操作
    			所以你在渲染img标签的时候一定要等待文件阅读器加载完毕之后再渲染
    			等待...加载完毕
    				onload
    				window.onload = function(){}
    				fileReader.onload = function(){}
    	发送ajax请求
    		1.ajax提交数据基本语法
    		2.ajax发送文件需要借助于内置对象formdata
    			ajax发送formdata对象
    			需要制定两个参数都为false
    				processData
    				contentType
    	后端正常的业务逻辑无需多说
    	
    	
    	一旦报错之后前端如何对应的渲染相应的信息
    		1.你需要研究form组件渲染的input框的id值的特点
    			id_字段名
    		2.你又发现返回的报错信息 键就是一个个的字段名
    			自己手动拼接处input框的id值
    			然后利用DOM操作 来操作span标签以及div标签
    	
    	最后为了功能的健壮性
    		给所有的input设置获取焦点事件
    			自动移除报错信息和报错的样式
    		
    	
    	控制字体样式的文件都是以.ttf结尾
    	
    	
    	
    	
    本周
    	bbs结束
    
    今日内容
    	登录功能
    	
    	首页搭建
    	
    	导航条用户功能
    	
    	admin后台管理
    
    下周安排(15d~22d)
    	vue前端框架   3~5d
    	django restframework(******)
    	路飞项目
    	git
    	celery
    	项目上线
    

    今日内容

    url.py

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        # 注册功能
        url(r'^register/',views.register,name='register'),
        # 登录功能
        url(r'^login/',views.login,name='login'),
        # 验证码图片
        url(r'^get_code/',views.get_code,name='code'),
        # 首页搭建
        url(r'^home/',views.home,name='home'),
        # 退出登录
        url(r'^logout/',views.logout,name='logout'),
        # 修改密码
        url(r'^set_password/',views.set_password,name='set_pwd')
    ]
    

    views.py

    from django.shortcuts import render,HttpResponse,redirect,reverse
    from app01 import  myform
    from app01 import  models
    from django.http import JsonResponse
    # 验证码相关
    from PIL import Image, ImageDraw, ImageFont
    from io import BytesIO, StringIO
    # auth模块校验密码
    from django.contrib import auth
    from django.contrib.auth.decorators import login_required
    
    # Create your views here.
    def register(request):
        # 生成一个空的forms对象
        form_obj = myform.MyRegForm()
    
        if request.method == 'POST':
            back_dic = {'code':1000,'msg':''}
    
            # 对用户提交的数据先进行校验 forms
                # 直接使用forms组件的校验方法,校验整个的数据字典
            form_obj = myform.MyRegForm(request.POST)
            if form_obj.is_valid():
                # 如果数据校验结果正确
                clean_data = form_obj.cleaned_data   # 获取正确的数据 4个键值对
                # 将确认密码的键值对弹出,只剩余三个便于创建用户
                clean_data.pop('confirm_password')
                # 获取用户上传的文件
                file_obj = request.FILES.get('avatar')
                # 判断文件是否存在,用户是否上传,如果没有上传才会设置default头像
                if file_obj:
                    clean_data['avatar'] = file_obj     # 四个键值对
                # 自动创建,使用**直接打散关键字参数
                models.Userinfo.objects.create_user(**clean_data)
                # 添加成功界面信息,及跳转
                back_dic['msg'] = '注册成功'
                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):
        if request.method == 'POST':
            back_dic = {'code':1000,'msg':''}
            username = request.POST.get('username')
            password = request.POST.get('password')
            code = request.POST.get('code')
            # 1.先校验验证码是否正确 忽略大小写
            if request.session.get('code').upper() == code.upper():
                # 2.校验用户名密码是否正确 利用auth模块
                user_obj = auth.authenticate(request,username=username,password=password)
                if user_obj:
                    # 3.保存用户登录状态
                    auth.login(request,user_obj)
    # 就可以在任意位置通过request.user获取到当前登录对象 并且 request.user.is_authenticated()判断当前用户是否登录
                    # 返回前端信息,并定向主页
                    back_dic['msg'] = '登录成功'
                    back_dic['url'] = '/home/'
                else:
                    back_dic['code'] = 2000
                    back_dic['msg'] = '用户名或密码错误'
            else:
                back_dic['code'] = 3000
                back_dic['msg'] = '验证错误'
            # 返回给前端字典数据
            return JsonResponse(back_dic)
        return render(request,'login.html')
    
    
    import random
    # 给验证码的图片添加随机颜色
    def get_random():
        return random.randint(0,255),random.randint(0,255),random.randint(0,255)
    
    
    # 图片验证码相关
    def get_code(request):
        # 推导步骤一:直接发送后端存在的图片
            # img标签可以直接返回二进制数据进行显示
        # with open(r'static/img/02b02.jpg.jpg','rb') as f:
        #     data = f.read()
        # return HttpResponse(data)
    
        # 推导步骤二 利用pillow模块自动生成图片
        '''
        from PIL import Image,ImageDraw,ImageFont
        Image       生成图片
        ImageDraw   在图片上写字
        ImageFont   控制字体的样式'''
        # 生成图片对象
        # img_obj = Image.new('RGB',(360,35),'red')     直接放文件的颜色
        # img_obj = Image.new('RGB',(360,35),get_random())   # 放rgb模式(255,23,232)
        # # 利用文件操作先保存下来
        # with open('xxx.png','wb') as f:
        #     img_obj.save(f,'png')
        # # 然后利用文件操作将图片数据读取并发送
        # with open(r'xxx.png','rb') as f:
        #     data = f.read()
        # return HttpResponse(data)
    
        # 推导步骤三  临时存储数据并且能够随时取出的地方
        '''内存管理模块
        from io import BytesIO,StringIO
        BytesIO     保存数据(并且在获取的时候,是以二进制的方式给你)
        StringIO    保存数据(以字符串的形式给你)
        '''
        # img_obj = Image.new('RGB',(360,35),get_random())
        #     # # 先生成一个io对象
        #     # io_obj = BytesIO()    # 可以将对象当做是文件的句柄
        #     # # 存储数据
        #     # img_obj.save(io_obj,'png')
        #     # # getvalue获取二进制的数据
        #     # return HttpResponse(io_obj.getvalue())
    
        # 推导步骤四     在图片上写字
        img_obj = Image.new('RGB',(360,35),get_random())
        # 将生成好的图片对象交给imageDraw
        img_draw = ImageDraw.Draw(img_obj)  # 生成一个画笔对象
        # 字体样式,将ttf格式字体,及字体的大小 设置
        img_font = ImageFont.truetype('static/fonts/1.ttf',30)
        # 产生一个随机验证码  大小写英文加数字 五位,每一位都可以是大小写数据
        code= ''
        for i in range(5):
            # chr 根据数字对应字符编码的英文
            upper_str = chr(random.randint(65,90))
            lower_str = chr(random.randint(97,122))
            random_int = str(random.randint(0,9))
            # 随机选取一个字符
            tmp = random.choice([upper_str,random_int,lower_str])
            # 向图片中写入一个((x轴,y轴)坐标,文本,图片北京,字体样式)
            img_draw.text((i*60+60,0),tmp,get_random(),img_font)
            # 存储写的字
            code += tmp
        print(code)
        # 这个验证码后面的其他视图函可能用得上,找到地方保存,并且这个地方的全局视图函数都可以访问
        request.session['code'] = code
        # 图片保存
        io_obj = BytesIO()
        img_obj.save(io_obj,'png')
        return HttpResponse(io_obj.getvalue())
    
    
    # 首页的搭建
    def home(request):
        return render(request,'home.html',locals())
    
    
    # 退出登录
    @login_required
    def logout(request):
        # 退出登录
        auth.logout(request)
        # 重定向到主页
        return redirect(reverse('home'))
    
    
    @login_required
    def set_password(request):
        if request.method == 'POST':
            old_pwd = request.POST.get('old_password')
            new_pwd = request.POST.get('new_password')
            confirm_password = request.POST.get('confirm_password')
            # 1.先判断旧密码是否正确
            is_right = request.user.check_password(old_pwd)
            if is_right:
                # 判断新密码与确认密码是否一致
                if new_pwd == confirm_password:
                    # 修改密码
                    request.user.set_password(new_pwd)
                    request.user.save()
                    # 重定向界面
                    return redirect(reverse('login'))
                else:
                    return HttpResponse('两次密码不一致')
            else:
                return HttpResponse('原密码不正确')
    

    login

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>登录页面</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
        {% load static %}
        <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
        <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
    
    </head>
    <body>
    <div class="container">
        <div class="row">
            <div class="col-md-8 col-md-offset-2 ">
                <h2 class="text-center">登录界面</h2>
                <div class="form-group">
                    <label for="id_username">用户名</label>
                    <input type="text" name="username" id="id_username" class="form-control">
                </div>
                <div class="form-group">
                    <label for="id_password">密码</label>
                    <input type="password" name="password" id="id_password" class="form-control">
                </div>
    {#            验证码框#}
                <div class="form-group">
                    <label for="id_code">验证码</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">
                            <img src="/get_code/" alt="" width="360" height="35" id="id_img">
                        </div>
                    </div>
                </div>
                <input type="button" class="btn btn-primary" value="登录" id="id_submit">
    {#            // 错误信息的展示#}
                <span style="color: red;" id="id_error"></span>
            </div>
        </div>
    </div>
    
    <script>
        {#绑定验证码点击刷新事件#}
        $('#id_img').click(function () {
            var oldPath = $(this).attr('src');
            $(this).attr('src',oldPath+='?')
        });
    
        {#发送ajax请求与后端交互#}
        $('#id_submit').click(function () {
            $.ajax({
                url:'',
                type:'post',
                data:{
                    'username':$('#id_username').val(),
                    'password':$('#id_password').val(),
                    'code':$('#id_code').val(),
                    'csrfmiddlewaretoken':'{{ csrf_token }}'
                },
                {#进行处理后端数据#}
                success:function (data) {
                    if(data.code==1000){
                        // 验证成功则跳转主页
                        window.location.href = data.url
                    }else {  // 报错信息的展示
                        $('#id_error').text(data.msg)
                    }
                }
            })
        })
    
    </script>
    </body>
    </html>
    

    home.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>主页</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
        {% load static %}
        <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
        <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
    
    </head>
    <body>
    
    {#导航条样式#}
    <nav class="navbar navbar-inverse">
      <div class="container-fluid">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="/home/">BBS首页系统</a>
        </div>
    
        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
          <ul class="nav navbar-nav">
            <li class="active"><a href="#">文章 <span class="sr-only">(current)</span></a></li>
            <li><a href="#">随笔</a></li>
            <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">更多 <span class="caret"></span></a>
              <ul class="dropdown-menu">
                <li><a href="#">Action</a></li>
                <li><a href="#">Another action</a></li>
                <li><a href="#">Something else here</a></li>
                <li role="separator" class="divider"></li>
                <li><a href="#">Separated link</a></li>
                <li role="separator" class="divider"></li>
                <li><a href="#">One more separated link</a></li>
              </ul>
            </li>
          </ul>
          <form class="navbar-form navbar-left">
            <div class="form-group">
              <input type="text" class="form-control" placeholder="Search">
            </div>
            <button type="submit" class="btn btn-default">Submit</button>
          </form>
          <ul class="nav navbar-nav navbar-right">
    {#     判断用户是否登录  显示登录注册按钮#}
              {% if request.user.is_authenticated %}
    {#              根据后端,显示登录之后的按钮#}
                    <li><a href="#">{{ request.user.username }}</a></li>
                    <li class="dropdown">
                      <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">更多操作 <span class="caret"></span></a>
                      <ul class="dropdown-menu">
    {#               添加模态框的属性data-toggle="modal" data-target="#myModal"#}
                        <li><a data-toggle="modal" data-target="#myModal">修改密码</a></li>
                        <li><a href="#">修改头像</a></li>
                        <li><a href="#">后台管理</a></li>
                        <li role="separator" class="divider"></li>
                        <li><a href="{% url 'logout' %}">退出登录</a></li>
                      </ul>
                    </li>
                  {% else %}
    {#              没有登录则显示登录注册按钮#}
                    <li><a href="{% url 'login' %}">登录</a></li>
                    <li><a href="{% url 'register' %}">注册</a></li>
              {% endif %}
    
          </ul>
        </div><!-- /.navbar-collapse -->
      </div><!-- /.container-fluid -->
    </nav>
    
    {#整体页面布局#}
    <div class="container-fluid">
        <div class="row">
            <div class="col-md-2">
    {#            左边面板#}
                <div class="panel panel-primary">
                  <div class="panel-heading">
                    <h3 class="panel-title">点击就送</h3>
                  </div>
                  <div class="panel-body">
                    劳斯莱斯5元代金券
                  </div>
                </div>
                <div class="panel panel-danger">
                  <div class="panel-heading">
                    <h3 class="panel-title">限定优惠</h3>
                  </div>
                  <div class="panel-body">
                    割双眼皮买二送一
                  </div>
                </div>
                <div class="panel panel-warning">
                  <div class="panel-heading">
                    <h3 class="panel-title">最后换购</h3>
                  </div>
                  <div class="panel-body">
                    买电烤炉送蜂窝煤一斤!
                  </div>
                </div>
            </div>
    {# 中间面板 #}
            <div class="col-md-8"></div>
            <div class="col-md-2">
    {#            右边面板#}
                <div class="panel panel-primary">
                  <div class="panel-heading">
                    <h3 class="panel-title">点击就送</h3>
                  </div>
                  <div class="panel-body">
                    劳斯莱斯5元代金券
                  </div>
                </div>
                <div class="panel panel-danger">
                  <div class="panel-heading">
                    <h3 class="panel-title">限定优惠</h3>
                  </div>
                  <div class="panel-body">
                    割双眼皮买二送一
                  </div>
                </div>
                <div class="panel panel-warning">
                  <div class="panel-heading">
                    <h3 class="panel-title">最后换购</h3>
                  </div>
                  <div class="panel-body">
                    买电烤炉送蜂窝煤一斤!
                  </div>
                </div>
            </div>
        </div>
    </div>
    
    {#修改密码的弹出框#}
    <!-- Modal -->
    <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
      <div class="modal-dialog" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
            <h4 class="modal-title" id="myModalLabel">修改密码</h4>
          </div>
          <div class="modal-body">
    {#          设置密码的更改#}
              <form action="{% url 'set_pwd' %}" method="post">
                  {% csrf_token %}
                  <div class="form-group">
                      <label for="id_username">用户名</label>
                      <input type="text" id="id_username" name="username" disabled class="form-control" value="{{ request.user.username }}">
                  </div>
                  <div class="form-group">
                      <label for="id_password">初始密码</label>
                      <input type="password" id="id_password" name="old_password" class="form-control" >
                  </div>
                  <div class="form-group">
                      <label for="id_new_password">新密码</label>
                      <input type="password" id="id_new_password" name="new_password" class="form-control" >
                  </div>
                  <div class="form-group">
                      <label for="id_confirm_password">确认新密码</label>
                      <input type="password" id="id_confirm_password" name="confirm_password" class="form-control">
                  </div>
    
                 <div class="modal-footer">
                    <button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
                    <button class="btn btn-primary" id="id_s">提交</button>
                  </div>
              </form>
          </div>
        </div>
      </div>
    </div>
    
    </body>
    </html>
    

    逻辑流程

    登录功能

    1.定义登录界面
    
    2.添加验证码的功能
    
    	图片验证码的传值有三种方式,直接写地址,文件二进制数据,路径
    	验证码的实现
    		通过Image获取imgobj对象
    		生成好的img对象交给ImageDraw.Draw 生成画笔
    		定义字体样式,文字大小
    		产生随机的验证码,利用chr实现,(65,96)大写,(97,122)小写,数字直接就是0-9
    		随机5个数字,在每个循环里写入
    		利用画笔对象.text((x轴,y轴)坐标,文本,图片北京,字体样式)
    		存储写的字
    	保存到session中的code
    	然后保存图片io
    	最终返回给前端值  return HttpResponse(io_obj.getvalue())
    	
    3.给验证码绑定点击事件
    	每点击一次url添加一个?用于刷新
    	
    4.使用ajax与后端进行交互
    	将用户的输入获取到手
    	success回调函数拿到后端返回的数据
    	根据code的信信息对相关标签进行渲染
    	后端得到数据进行验证
    		先判断验证码是否正确
    		然后利用auth模块判断密码是否正确
    		根据得到对象判断存在
    			定义返回字典,返回给前端
    			return JsonResponse(back_dic)
    

    验证码相关推导

    def get_code(request):
        # 推导步骤一:直接发送后端存在的图片
            # img标签可以直接返回二进制数据进行显示
        # with open(r'static/img/02b02.jpg.jpg','rb') as f:
        #     data = f.read()
        # return HttpResponse(data)
    
    
    
    
        # 推导步骤二 利用pillow模块自动生成图片
        '''
        from PIL import Image,ImageDraw,ImageFont
        Image       生成图片
        ImageDraw   在图片上写字
        ImageFont   控制字体的样式'''
        # 生成图片对象
        # img_obj = Image.new('RGB',(360,35),'red')     直接放文件的颜色
        # img_obj = Image.new('RGB',(360,35),get_random())   # 放rgb模式(255,23,232)
        # # 利用文件操作先保存下来
        # with open('xxx.png','wb') as f:
        #     img_obj.save(f,'png')
        # # 然后利用文件操作将图片数据读取并发送
        # with open(r'xxx.png','rb') as f:
        #     data = f.read()
        # return HttpResponse(data)
    
    
    
    
    
        # 推导步骤三  临时存储数据并且能够随时取出的地方
        '''内存管理模块
        from io import BytesIO,StringIO
        BytesIO     保存数据(并且在获取的时候,是以二进制的方式给你)
        StringIO    保存数据(以字符串的形式给你)
        '''
        # img_obj = Image.new('RGB',(360,35),get_random())
        #     # # 先生成一个io对象
        #     # io_obj = BytesIO()    # 可以将对象当做是文件的句柄
        #     # # 存储数据
        #     # img_obj.save(io_obj,'png')
        #     # # getvalue获取二进制的数据
        #     # return HttpResponse(io_obj.getvalue())
    
    
    
    
    
    
        # 推导步骤四     在图片上写字
        
        img_obj = Image.new('RGB',(360,35),get_random())
        # 将生成好的图片对象交给imageDraw
        img_draw = ImageDraw.Draw(img_obj)  # 生成一个画笔对象
        # 字体样式,将ttf格式字体,及字体的大小 设置
        img_font = ImageFont.truetype('static/fonts/1.ttf',30)
        # 产生一个随机验证码  大小写英文加数字 五位,每一位都可以是大小写数据
        code= ''
        for i in range(5):
            # chr 根据数字对应字符编码的英文
            upper_str = chr(random.randint(65,90))
            lower_str = chr(random.randint(97,122))
            random_int = str(random.randint(0,9))
            # 随机选取一个字符
            tmp = random.choice([upper_str,random_int,lower_str])
            # 向图片中写入一个((x轴,y轴)坐标,文本,图片北京,字体样式)
            img_draw.text((i*60+60,0),tmp,get_random(),img_font)
            # 存储写的字
            code += tmp
        print(code)
        # 这个验证码后面的其他视图函可能用得上,找到地方保存,并且这个地方的全局视图函数都可以访问
        request.session['code'] = code
        # 图片保存
        io_obj = BytesIO()
        img_obj.save(io_obj,'png')
        return HttpResponse(io_obj.getvalue())
    
  • 相关阅读:
    [App Store Connect帮助]八、维护您的 App(5)生成产品报告
    [App Store Connect帮助]八、维护您的 App(4.4)重置 App 总评分(iOS、Apple TVOS、macOS)
    [App Store Connect帮助]八、维护您的 App(4.3)回复顾客评论(iOS、macOS 或 watchOS)
    [App Store Connect帮助]八、维护您的 App(4.2)查看评分与评论
    Agent XPs disable
    (2.4)DDL增强功能-数据汇总grouping、rollup、cube
    (2.3)DDL增强功能-流程化控制与动态sql
    (2.2)DDL增强功能-自定义函数/表值函数与存储过程
    (2.1)sql server数据类型、同义词、分区表
    (1.5)DML增强功能-try catch及事务控制
  • 原文地址:https://www.cnblogs.com/fwzzz/p/12016591.html
Copyright © 2011-2022 走看看