zoukankan      html  css  js  c++  java
  • Django

    1,http

    小提示:"{:0>3}".formate(9) 右对齐若小于3位 --->00n 0位占位符,> 表示右对齐

    响应格式

     

    请求格式

     

    import socket
    import os
    # =========================================================
    def ret(path):
       dir = "../html/"
       file = os.path.join(dir,path.strip(r"[/]"))
       if os.path.exists(file):
           with open(file,"rb") as f:
               return f.read()
       else:
           with open(os.path.join(dir,"error.html"),"rb") as f:
               return f.read()
    # =========================================================
    sk = socket.socket()
    sk.bind(("127.0.0.1",8080))
    sk.listen()
    while True:
       conn,_ = sk.accept()
       data = conn.recv(8096)
       data_str = str(data,encoding="utf8")
       list = data_str.split(" ")
       # for i in list:
       #     print(i) # 获取每行,还可以通过 空格分隔 获取访问路径,根据路径返回不同那内容
       # # 通过请求路径,建立字典,对应但会数据,可直接返回
       firstLine = str(list[0]).split(' ')
       temp = firstLine[1].split("?")
       path = temp[0]
       #print(path)
       conn.send(b'http1.1 200 ')
       conn.send(ret(path))
       conn.close()
    sk.close()
    """
    # http 请求
    GET /sadasd/?name=dzf HTTP/1.1
    Host: 127.0.0.1:8080
    Connection: keep-alive
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36
    Sec-Fetch-Mode: navigate
    Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3
    Sec-Fetch-Site: none
    Accept-Encoding: gzip, deflate, br
    Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7 '
    """
    # =========================================================
    """
    Python中 Web框架的分类:
    1. web框架的本质:
      socket服务端 与 浏览器的通信
    2. socket服务端功能划分:
      a. 负责与浏览器收发消息(socket通信) --> wsgiref/uWsgi/gunicorn... 自己写的长时间连接会报错
      b. 根据用户访问不同的路径执行不同的函数
      c. 从HTML读取出内容,并且完成字符串的替换(动态网站的本质) --> jinja2(模板语言)
    1. 按上面三个功能划分:
      1. 框架自带a,b,c                 --> Tornado
      2. 框架自带b和c(和jinja2类似),使用第三方的a(wsgiref)   --> Django
      3. 框架自带b,使用第三方的a和c(jinja2)   --> Flask
    2. 按另一个维度来划分:
      1. Django   --> 大而全(你做一个网站能用到的它都有)
      2. 其他     --> Flask 轻量级
    """
    # 安装jinja2
    from wsgiref.simple_server import make_server #   a 功能
    from jinja2 import Template # c功能


    def index():
       with open("09 jinja2版web框架.html", "r", encoding="utf-8") as f:
           data = f.read()
       template = Template(data)  # 生成模板文件
       # 从数据库中取数据
       import pymysql
       conn = pymysql.connect(
           host="127.0.0.1",
           port=3306,
           user="root",
           password="123456",
           database="day59",
           charset="utf8",
      )
       cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
       cursor.execute("select * from userinfo;")
       user_list = cursor.fetchall()
       # 实现字符串的替换
       ret = template.render({"user_list": user_list})  # 把数据填充到模板里面
       return [bytes(ret, encoding="utf8"), ]
    def home():
       with open("home.html", "rb") as f:
           data = f.read()
       return [data, ]
    # 定义一个url和函数的对应关系
    URL_LIST = [
      ("/index/", index),
      ("/home/", home),
    ]
    def run_server(environ, start_response):
       start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])  # 设置HTTP响应的状态码和头信息
       url = environ['PATH_INFO']  # 取到用户输入的url
       func = None  # 将要执行的函数
       for i in URL_LIST:
           if i[0] == url:
               func = i[1]  # 去之前定义好的url列表里找url应该执行的函数
               break
       if func:  # 如果能找到要执行的函数
           return func()  # 返回函数的执行结果
       else:
           return [bytes("404没有该页面", encoding="utf8"), ]

    if __name__ == '__main__':
       httpd = make_server('127.0.0.1', 8000, run_server)
       print("Serving HTTP on port 8000...")
       httpd.serve_forever()
    """
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="x-ua-compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <title>Title</title>
    </head>
    <body>


    <table border="1">
      <thead>
      <tr>
          <th>ID</th>
          <th>用户名</th>
          <th>密码</th>
      </tr>
      </thead>
      <tbody>
      {% for user in user_list %}
      <tr>
          <td>{{user.id}}</td>
          <td>{{user.name}}</td>
          <td>{{user.pwd}}</td>
      </tr>
      {% endfor %}
      </tbody>
    </table>
    </body>
    </html>
    """

    2 django基础

    # ==============================================================================
    # 安装 pip install Django==2.2.4
    # setting 中添加库 https://pypi.tuna.tsinghua.edu.cn/simple/ 防止time out
    # cmd 新建项目 进入目标目录 django-admin startprojext project_name
    # 或pycharm 新建Django 使用存在的解释器,第二个
    # # 项目配置
    """
    1,urls.py
    urlpatterns:保存了路径与函数的对应关系
      在该文件中定义新的项,并写函数,支持正则
      也可以建立专门的函数文件,只需在urls 中导入即可
      import django.shortcuts import HttpResponse
      def admin(request): # request为所有请求的参数
          return HttpResponse("xxx)
      patterns,函数内容都可以动态修改,
    项目启动
    普通启动后,只能127.0.0.1 访问
    若要使用ip访问,allowed_host = ['*'] runserver 0.0.0.0:80
    1,cmd中python manage.py runserver [port]
    2,选择项目 ,点击旁边三角 edit config 也可改端口
    template下建立html文件
    所有与html文件有关的设置都放在 setting的templates下
    如何那绝对路径:在/下建立文件 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    指定html文件目录:'DIRS': [os.path.join(BASE_DIR, 'templates')]
      用到的时候 直接写文件名即可,"./写template",或"./xx/xx.html"
      不能直接写文件名
    返回方式:
      字符:直接写或文件--->字符 打开文件 字节返回
      文件使用模块: render(request,"文件路径")
      return render(request,"Hello.html") # 此处可直接写文件名
    此处注意,若在template下有多级文件夹,文件夹下有文件,此时访问 只写(xxx/xx.html) 不用加"/",以文件夹开头即可

    对于static下的文件

    2,配置静态文件,js,css等
    setting 最后添加
      STATICFILES_DIRS=[
          os.path.join(BASE_DIR,"static") # static 为自己制定的文件夹,名字随意,可配置多个
      ]
    STATIC_URL="/static/" 就代表的是 "D:/xxx/yy/static/" 别名 若有多个都当做在static下
    html引用时使用绝对路径就不用从头开始写
      例:href="/static/bootstrap/css/bootstrap.min.css"
    3,若出现403   中间价问题
      注释settings中47行 'django.middleware.csrf.CsrfViewMiddleware',
    4,连接数据库,后边详细
    """
    # 登录时,一个函数处理即可,若为get 表示请求html,若为post,处理数据,返回页面
    # if request.method=="POST" "GET"
    # 默认的页面请求是get,a标签也是get

    """
    def
      if post:
          处理
      return html
       
    render(request,"xx.html",{"msg":"xxx"})   html中使用{{msg}}可获取

    redirect 模块 跳转
    return redirect("http://www.baidu.com") # 让浏览器请求新的页面,不是服务器返回的
    return redirect("/login/") # 本网站 用"/"包裹

    """
    # ===============================================
    # app:方便在项目中管理实现不同的业务功能
    """
      project -->项目 (学校)  
      app --> 学院(软件学院,量子力学)
      1,创建app
          在cmd ,某个project 根目录 python(3) manage.py startapp app_name
          执行后会在根目录下创建文件夹 app_name
          文件夹 migrations
          文件 __init__.py
              admin.py:管理控制台
              apps.py:app相关的配置
              models.py:ORM的类 entity
              tests.py:测试文件
              views.py:函数文件
      2,或在创建项目的时候直接添加一个
    settings
      INSTALLED_APPS 配置,添加上"app_01"
      或"app_01.apps.App_01Config" 类 推荐
    """
    # =============================================
    # ORM 简单,开发效率高, 执行效率低
    # 不能创建数据库
    # 步骤
    """
    1,创建数据库
    2,setting 配置数据库
    DATABASES = {
      'default': {
          #数据库类型
          'ENGINE': 'django.db.backends.mysql',
          'HOST':'127.0.0.1',
          'PORT':3306,
          'NAME':'test',
          'USER':'root',
          'PASSWORD':'xxxx'
      }
    }
    3,告诉Django用什么连接数据库??MYsqlDB(不支持python3), pymysql
      mysqldb是默认的,需要更改为pymysql
      项目下,__init__.py 不是app的init
          import pymysql
          pymysql.install_as_MySQLdb()
    4,创建类 modules.py 必须在个文件,必须继承(models.Model)
    class UserInfo(models.Model):
      id = models.AutoField(primary_key=True) # 创建一个自增的主键字段
      name = models.CharField(null=False, max_length=32,unique=True)   # 创建一个varchar(20)类型的不能为空的字段
    5,创建表
      创建后 不能修改,若要修改只能通过 modules修改,不然函数调用会报错
      1. python3 manage.py makemigrations # 记录moduls 的变化,会记录在app/migrations下
      2. python3 manage.py migrate # 转变为sql执行
      可能pymsql驱动的mysqlclient客户端版本过低,修改G:ProgramPythonPython3.7.4Libsite-packagesdjangodbackendsmysqlase.py
      注释掉如下,但还有错误 str 编码错误,还要修改operations.py
      # if version < (1, 3, 13):
      #   raise ImproperlyConfigured('mysqlclient 1.3.13 or newer is required; you have %s.' % Database.__version__)   # 需要更换pymsql
      或
      下载mysqlclient,手动下载安装 https://www.lfd.uci.edu/~gohlke/pythonlibs/#mysqlclient
      mysqlclient‑1.4.4‑cp37‑cp37m‑win32.whl 37为对应版本,还有显卡版本 注意app一定要在setting注册 否则会失败 # init 中不用写了
    6, 会创建很多表,默认实体表名为 app_name_class_name 还有其他权限表,会话表等
    """
    # ========================================================
    """
      request.GET[POST] 大字典
      在函数中获取数据库中数据
      from app_01 import modules
      ### 查询所有的数据
          ret = modules.Userinfo(类名).objects.all().order_by('id') 列表返回 userinfo对象,并根据id排序
           
          ret[0].id 或name 即可得到对应数据
          使用render传入html即可
      ### 创建
          modules.Userinfo(类名).objects.create(name="xxx")
      ### 删除
          request.Get.get("id",None)
          ret = modules.Userinfo(类名).objects.get(id="xxx") 请求不到会报错,可以使用 filter(id="xxx")
          ret.delete()
      ### 修改
          request.Get.get("id",None)
          ret = modules.Userinfo(类名).objects.get(id="xxx") 请求不到会报错,可以使用 filter(id="xxx")
          ret.name = new_name
          ret.save() # 提交到数据库
           
    """

    3 django web实例

    # 1,get 携带数据最大40k url长度不同浏览器不同2k-8k
    # 2,... makemigrate app_name 只有一个时可省
    # 3,外键
    """
    class A(modules):pass
    class B(modules):
      public = modules.Foreignkey(to=A) # A必须在前面存在
      public = modules.Foreignkey(to="A") # 没要求,只要最后有A即可
      最后 public列在库中名为 public_A主键名,好像是这个如果不是的话就是
      public_id,(好像这个可能比较大)
    注:存入的时候public存的是A的id,使用create(public_id=xxx)
    或使用 create(public=查到id的对象)
    但获取get() B对象时 获取到所有属性,public 这个属性对应的是一个对象,若要获取某个属性,需再次加点
    """
    # 4,数据库中已存在数据,此时修改modules,例如添加列,
    # 会指定让你输入默认值,或直接在modules中 default="xxx"
    # 5,多对多关系,需要第三张表 (id,table_id,table2_id)
    """
    # 例如作者,书
      class book(modules):pass 只写 属性即可
      class auther(modules):
          .....
          book=modules.ManyToMany(to="book")
           
          auther 类执行后会生成2个表
              第一张:app_name_auther,注意没有book属性
              第二张:app_name_ManyToMany所在类名_赋值名(book)
                  属性:id ,auther_id,book(book类名)_id
    例:查询某个作者
    1,先ret = get(id=x)得到作者
    2,ret.book(是上边的manytomany的book).all() 帮助查询关联的对象
    控制台打印all 有括号 列表返回所有书对象
    for 显示的时候 for b in ret.book.all 没有括号
    """
    # 6,request.POST.get("xxx") 若xxx中多个参数 返回值列表中对后一个
    #   使用getlist("xxx") 获取列表
    # 7,添加作者并关联存在的书本
    #   author =....creat(name=...等属性赋值) 注意没有book
    #   author.book(manytomany那个book).set(getlist中得到的books列表)
    #   注意不用save()
    # 8,删除作者 普通的删除,只不过是关联删除,先删书,再删作者
    # 9,更改作者,与普通更改相同,获取目标对象obj,修改普通属性,
    #   再obj.book.set(获取到的list) obj.save()

     

    4,MVC

    # 在python中称为MTV
    # module(modules),
    # view(Templates)
    # controller(urls,views),
    # 母板
    """
    1,新建公共html
      ....
      {# 这里是页面不同部分 #}
      {% block page_main(名字随意) %}
      {% endblock %}
      ....
    2,建立子html
      {% extends "base.html路径"%}
      {% block page-css %}{% endblock%}
      {% block page-main %}<h1>直接写即可,不用body等标签</h1>{% endblock%}
      {% block page-js %}{% endblock%}
    用处:1,替换固定的模板内容
      2,替换某个html专用css ,其实在子html中可直接加入cssdeng
          但会造成css位置混乱,此方法可使css等都位于head标签
    注意:
      1,模板不能嵌套,
      2,extends行一定在第一行, 路径必须加引号
      3,可有多个block,一般3个
      4,views中返回的是子html,不是base.html
    """
    # 导入组件:就是替换
    """
      将导航条放入单一功能模块
      {% include "xxx.html" %}
    """
    # 引入静态文件
    """
      若static别名更改,引入的css等路径都要更改
      解决方案: 路径拼接
          {%load static%}
          <link href="{% static 'bootstrap/xxx'%}" rel="stylesheet>
          或者
          {%load static%} 也要导入
          <link href="{%get_static_prefix%}bootstrap/xxx" rel="stylesheet>
    多次使用的图片
    {% load static%}
    {%static 'xxx.jpg' as yy%}
    <img src="{{yy}}"/> 即可
    """
    # simpletag
    """
    复杂的filter
    路径是实在app下templatags下
    from...
    register... 注意register不能更改
    @register.simple_tag(name="xx") 可不指定名字默认是函数名
    def my_sum(arg1,arg2,arg3):
      return arg1+arg2+arg3

    html使用
    {%load xxx文件%}
    {% xx arg1 arg2 arg3 %}
    """
    # inclusion_tag 返回html代码
    """
      与simple类似
    @register.inclusion_tag("xxx.html") 注意此处没有name ,调用使用函数名,向下12行
    def my_inclusion(arg1):
      data = 处理参数args,变为其他数据,列表,字典等
      return {"result":data}
    xxx.html
    <ui>
    {% for i in result %} # 加入为迭代对象
      <li>{{i}}</li>
    {%endfor%}
    </ui>
    调用{{my_inclusion arg}}
    """

    # ======================================
    # view(接受响应的部分)
    # CBV(基于类的视图) FBA(基于函数的视图:前面的都是)
    """
    form django.views import View
    class add_list(View):
      # urls调用时使用类名add_list ,会根据请求方式转到对应方法
      def get(self,request):pass
      def post(self,request):pass
    urls 中
      path("xx",add_list.as_view()) 调用
    """
    # request
    """
    request.method
    request.GET
    request.POST
    request.path_info "/xxx/yy/" 形式,不带ip,端口,参数
    request.body
      若为get     ---->b''
      若为post   ----->b'提交的参数名=值(若为中文会变成%E6879AS7D54%等编码数据)'
    """
    # =============================================
    # 上传文件
    """
      form 注意使用post 还有enctype="multipart/form-data"
      def upload(request):
          request.FILES 字典,{"file1":obj,"file2",obj}
          filname =request.FILES['表单中name'].name
          with open0.....
              for i in request.FILES['表单中name'].chunks()
                  f.write(i)
    """
    # ===============================================
    # response
    """"
    1,HttpResponse
    2,render
    3,redirect

    4,返回json
    import json
    return HttpResponse(json.dumps(xxx)) 返回json字符串

    from django.http import JsonHttpResponse # 封装的json ,不能串list
    return JsonHttpResponse(xxxx)直接返回
      若要传list JsonHttpResponse(xxxx,safe=False) 即可
    """

    5,django 路由系统

    # 路由系统
    """
    urlpatterns=[
      url,path(2.0以后)(正则,函数名,参数,别名)
    ]
      r"^book/[0-9]{2,4}/$"
      r"^book/([0-9]{2,4})/([a-zA-Z]{2})/$"
    分组匹配时,会把分组的内容当做参数传入:位置参数
      例: book/11/ac   对应函数应该为(request,arg1,arg2) 接受
      <(?P<name1>w*)> 匹配"<里边是字符>" (?P=name1) 复制匹配规则
    多路径匹配, 最后注意加 / $
      对于路径上的"/" 最后会默认添加"/" 若要取消
      settings APPEND_SLASH=False

    分组命名匹配
      r"^book/(?P<year>[0-9]{2,4})/(?P<month>[a-zA-Z]{2})/$"
      def fun(request,year,month) 要明确变量
      def fun(request,**kwargs) 也可 接收到kwargs为{"year":xx,"month":yy}
      注意不能混用,若month不写,后边分组匹配不到
    多个路径对应一个函数:通常适用于 无参时访问第一页,有参访问对应页面
      def fun(res,id="1"):指定默认值即可

    app中建立app01_urls.py 名字无规定
      import django.urls import url
      urlpatterns=[] 必须有这个属性
    在主urls中导入
      from ... import app01_urls
      urlpattrens=[
          ...
          url(r"^app01/",include(urls)) # 所有以app01开头的 分流
      ]
      查找时 /app01/xx/yy 注意为r"^app01",后边没有"/" 会报错
    注:url(xxx,yy,{"age":18}) 对应的yy函数 使用def yy(req,age)
      可以传参,但不常用
    """
    # 页面之间跳转的时候 不能写死跳转路径:反向解析 ->通过别名方式
    # 命名url与url解析:urlpattern中的url会发生变化,html中写死了
    #   url(xx,yy,name="zzz") 此时html中 写 href="{url 'zzz'}" 相当于xxx 即可跳转到yy函数
    # 若在函数中跳转,也不能写死
    #   from django.urls import reverse
    #   analysis_url=reverse("zzz")
    #   return redirect(analysis_url)
    # 注意对于传参数的url 需要传参数
    #   reverse("zzz",kwargs={"xx":1,"yy":2}) 当分组有别名时字典传入,若不是 args=(..) 元祖传入即可
    #   {% url 'zzz' arg1 arg2 ...%}
    # 在不同的app中了能会出现相同的别名
    #   可以再父urls中 url(xx,include(app01_urls.py,namespace="app01"))
    #       html {% url 'app01:zzz'%} 找到app01 里面的别名zzz
    # ==========================================
    # orm 配合 路由系统
    """
      1,不同的表的删除,可以使用一个方法:
      url(r"^delete/([a-zA-Z]+)/(d)/$",delete) 传递表名,id
      对于比较长的正则,可以建文件夹,编译 r = re.complie(xxx),再引入即可
      2,def fun(res,arg1,arg2):
          hasttr(py文件,"xxx") getattr(py文件,"xxx")得到目标
          if hasattr(modules,arg1.capitalized()) 首字母打大写
              cls = get....
              cls.Object.get(id=arg2).delete try本句
    """
    # ==========================================
    # orm常用字段 charfiled 对应varchar,没有固定长度的字段,可自定义
    """
    class FixedCharField(models.Field):
      自定义的char类型的字段类
      def __init__(self, max_length, *args, **kwargs):
          self.max_length = max_length
          super(FixedCharField, self).__init__(max_length=max_length, *args, **kwargs)

      def db_type(self, connection):

          限定生成数据库表的字段类型为char,长度为max_length指定的值
          return 'char(%s)' % self.max_length
    class Person(models.Model):
      name = models.CharField(max_length=32)
      new_name = FixedCharField(max_length=64, default="张三") # char(64)
      age = models.IntegerField(default=18)
      birthday = models.DateField(auto_now_add=True)

      def __str__(self):
          return self.name

      class Meta:
          db_table = "person" 指明 生成的数据库名


    """
    #   1,AutoField int自增列,必须primary_key=True,若没有自增列,会自动创建id自增列
    #   2,IntegerField 整数范围 21亿那个
    #   3,CharField 必须max_length, 指定长度
    #   4,DateTimeField 相当于datetime模块
    #       yyyy-mm-dd hh:MM[:ss[.uuuuu]][TZ]
    #   5,DateField
    #         auto_now_add=True 创建记录时会添加当前是时间,不用写default
    #         auto_now=True 每次更新记录时会更新该字段
    # 不常用字段
    #   BigAutoField,大整数
    #   SmallIntegerField 小整数 -32768-32767
    #   PositiveSmallIntegerField 正小整的 0-32767
    #   PositiveIntegerField 0-21亿
    #   BigIntegerField -922..... --- 922....
    #   BooleanFiled
    #   NullBooleanField 可为空的bool
    #   TextField 大文本
    #   EmailField 还是charfiled django做了校验
    #   IPAddressField 有验证
    #   GenericIPAddressField 支持ipv4,ipv6
    #   URLFiled charfiled 验证
    #   SlugFiled 字符串类型,字母数字下划线连字符等
    #   CommaSeparatedIntegerFiled 格式为逗号分割的数字
    #   UUIDField UUID验证
    #   TimeFiled
    #   DurationFiled 长整数,时间间隔orm中获取到的类型为datetime.timedel类型
    #   FloatField 浮点型
    #   DecimalField 10进制小数
    #       max_dights,小数总长度,decimal_places,小数位长度
    #   BinaryField 二进制数据
    # =========================================
    # 字段参数
    #   null 没写=True 表示不能为空
    #   unique
    #   db_index=true 表示为此字段设置索引
    #   default
    #   to 设置关联的表
    #   to_field="xxx" 设置关联的列 默认是id
    #   related_name 反向操作时使用的字段名,用于代替反向查询时的"表名_set"
    #   related_query_name 反向查询操作时,使用的链接前缀,用于替换表明
    #   on_delete 当删除关联表中的数据时,当前表与其的关联行为
    #       modules.Cascade 关联删除 默认的
    #       modules.DO_NOTHING 引发Integrity错误
    #       modules.PROJECT 引发protected错误
    #       modules.SET_NLL 关联的字段置位NULL(前提字段可空)
    #       modules.SET_DEFAULT 关联的字段为默认值(前提字段有默认值)
    #       modules.SET(func) 可自定义函数
    #   db_constraint=Flase 用上了外键,但是没有级联操作,
    #   软外键:方法1,代码实现 方法2,db_constraint=Flase
    # ======================================
    # class Mate:
    # db_table 重写表名
    # index_together 联合索引   2列做索引
    # unique_together 联合唯一索引 2列可以有一个重复,不能都重复
    # ordering 指定an什么字段排序,设置了该属性,结果才可以reverse()

    5_orm_1

    # ORM小练习 如何在一个Python脚本或文件中 加载Django项目的配置和变量信息
    # 常用的查询方法
    import os
    if __name__ == '__main__':
       # 加载Django项目的配置信息
       os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ormday69.settings")
       # 导入Django,并启动Django项目
       import django
       django.setup()

       # from app_01 import models

       # # 查询所有的人
       # ret = models.Person.objects.all()

       # # get查询
       # ret = models.Person.objects.get(name="小黑") 只查询到 第一个

       # # filter
       # ret = models.Person.objects.filter(id=100) # 不存在返回一个空的QuerySet,不会报错
       # # 就算查询的结果只有一个,返回的也是QuerySet,我们要用索引的方式取出第一个元素
       # ret = models.Person.objects.filter(id=1)[0]

       # print("exclude".center(80, "*")) # 占80个字符居中,*号填充
       # # exclude
       # ret = models.Person.objects.exclude(id=1) 反向查询 id!=1

       # print("values".center(80, "*"))
       # # values 返回一个QuerySet对象,里面都是字典。 不写字段名,默认查询所有字段
       # ret = models.Person.objects.values("name", "birthday")

       # print("values_list".center(80, "*"))
       # # values_list 返回一个QuerySet对象,里面都是元祖。 不写字段名,直接写字段值,默认查询所有字段
       # ret = models.Person.objects.values_list()

       # print("order_by".center(80, "*"))
       # # order_by 按照指定的字段排序
       # ret = models.Person.objects.all().order_by("birthday")

       # print("reverse".center(80, "*"))
       # # reverse 将一个有序的QuerySet 反转顺序
       # # 对有序的QuerySet才能调用reverse
       # ret = models.Person.objects.all().reverse()

       # print("count".center(80, "*"))
       # # count 返回QuerySet中对象的数量
       # ret = models.Person.objects.all().count()

       # print("first".center(80, "*"))
       # # first 返回QuerySet中第一个对象
       # ret = models.Person.objects.all().first()

       # print("last".center(80, "*"))
       # # last 返回QuerySet中最后一个对象
       # ret = models.Person.objects.all().last()

       # print("exists".center(80, "*"))
       # # exists 判断表里有没有数据
       # ret = models.Book.objects.exists()
       # print(ret)
    # ===================================================

       # 单表查询之神奇的双下划线
       # # 查询id值大于1小于4的结果
       # ret = models.Person.objects.filter(id__gt=1, id__lt=4)
    # ===================================================
       # # in
       # # 查询 id 在 [1, 3, 5, 7]中的结果
       # ret = models.Person.objects.filter(id__in=[1, 3, 5, 7])
       # ret = models.Person.objects.exclude(id__in=[1, 3, 5, 7]) 等于not in
    # ===================================================
       # 模糊查询
       # # contains 字段包含指定值的
       # # icontains 忽略大小写包含指定值
       # ret = models.Person.objects.filter(name__contains="小")
       # isstartwith,startwith,endwith,isendwith
    # ===================================================
       # # range
       # # 判断id值在 哪个区间的 SQL语句中的between and 1<= <=3
       # ret = models.Person.objects.filter(id__range=[1,3])
    # ===================================================
       # # 日期和时间字段还可以有以下写法,按照日期中的某一项查询
       # ret = models.Person.objects.filter(birthday__year=2000)
       # ret = models.Person.objects.filter(birthday__year=2000, birthday__month=5)
    # ===================================================
       # 注意 obj得到的是对象,不能直接.value或value_list

       # 外键的查询操作

       # 正向查询,通过有外键字段的表查没得是正向
       # 基于对象 跨表查询
       # book_obj = models.Book.objects.all().first()
       # ret = book_obj.publisher # 和我这本书关联的出版社对象
       # ret = book_obj.publisher.name # 和我这本书关联的出版社对象

       # 查询id是1的书的出版社的名称
       # 利用双下划线 跨表查询
       # 双下划线就表示跨了一张表
       # ret = models.Book.objects.filter(id=1).values_list("publisher__name")或value
    # =================================================================

       # 反向查询
       # 1. 基于对象查询
       # publisher_obj = models.Publisher.objects.get(id=1) # 得到一个具体的对象
       # # ret = publisher_obj.book_set.all() # 反向得到书的信息,默认是表名_set
       # 建表时通过related_name="books"可更改
       # ret = publisher_obj.books.all()

       # # 2. 基于双下划线
       # ret = models.Publisher.objects.filter(id=1).values_list("(related_query_name)__title")
    # =================================================================
       # 多对多
       # 查询
       # author_obj = models.Author.objects.first()
       # print(author_obj.name)
       # 查询金老板写过的书
       # ret = author_obj.books.all() 前边学过 author_obj.books:关联管理器
    # ==========================
       # 1. create
       # 通过作者创建一本书,会自动保存
       # 做了两件事:
       # 1. 在book表里面创建一本新书,2. 在作者和书的关系表中添加关联记录
       # author_obj.books.create(title="金老板自传", publisher_id=2)
    # =============
       # 2. add
       # 在金老板关联的书里面,再加一本id是4的书
       # book_obj = models.Book.objects.get(id=4)
       # author_obj.books.add(book_obj) # 加已经存在的书
       # 添加多个
       # book_objs = models.Book.objects.filter(id__gt=5)
       # author_obj.books.add(*book_objs) # 要把列表打散再传进去
       # 直接添加id
       # author_obj.books.add(9)
    # =======================================
       # remove
       # 从金老板关联的书里面把 开飞船 删掉
       # book_obj = models.Book.objects.get(title="跟金老板学开飞船")
       # author_obj.books.remove(book_obj)
       # 从金老板关联的书里面把 id是8的记录 删掉
       # author_obj.books.remove(8)
    # =======================================
       # clear
       # 清空
       # 把景女神 关联的所有书都删掉
       # jing_obj = models.Author.objects.get(id=2)
       # jing_obj.books.clear()
    # =======================================

       # 额外补充的,外键的反向操作

       # 找到id是1的出版社
       # publisher_obj = models.Publisher.objects.get(id=2)
       # publisher_obj.books.clear() # 注意books的 外键是否可为空
    # =================================================================
       # 聚合
       from django.db.models import Avg, Sum, Max, Min, Count
       # ret = models.Book.objects.all().aggregate(price_avg=Avg("price"))
       # print(ret) 返回字典{"price":xxx} 按price列指定, 可修改(k=Avg("price"))

       # ret = models.Book.objects.all().aggregate(price_avg=Avg("price"), price_max=Max("price"), price_min=Min("price"))
       # 也是字典返回
       # print(ret.get("price_max"), type(ret.get("price_max")))
    # =================================================================
       # 分组查询

       # 查询每一本书的作者个数
       # ret = models.Book.objects.all().annotate(author_num=Count("author")) queryset 书对象
       # # print(ret)
       # for book in ret:
       #     print("书名:{},作者数量:{}".format(book.title, book.author_num)) # 书多了一个author_num属性

       # 查询作者数量大于1的书
       # ret = models.Book.objects.all().annotate(author_num=Count("author")).filter(author_num__gt=1)
       # print(ret)

       # 查询各个作者出的书的总价格
       # ret = models.Author.objects.all().annotate(price_sum=Sum("books__price")).values_list("name", "price_sum")
       # ret = models.Author.objects.all().annotate(price_sum=Sum("books__price"))
       # print(ret)
       # for i in ret:
       #     print(i, i.name, i.price_sum)
       # print(ret.values_list("id", "name", "price_sum")) 与for类似
    # =================================================================
       # F(两个字段作比较)和Q
           # ret = models.Book.objects.filter(price__gt=9.99)
           # print(ret)

       # 查询出 库存数 大于 卖出数的 所有书(两个字段做比较)
       from django.db.models import F
       # ret = models.Book.objects.filter(kucun__gt=F("maichu"))
    # =================================================================
       # 刷单 把每一本书的卖出数都乘以3
       # obj = models.Book.objects.first()
       # obj.maichu = 1000 * 3
       # obj.save() 只修改一个对象
       # 具体的对象没有update(),QuerySet对象才有update()方法。

       # models.Book.objects.update(maichu=F("maichu")*3) 全都修改了

       # 给每一本书的书名后面加上 第一版
       # from django.db.models.functions import Concat
       # from django.db.models import Value
       # 修改字符串
       # models.Book.objects.update(title=Concat(F("title"), Value("第一版")))


       # Q查询
       from django.db.models import Q
       # 查询 卖出数大于1000,并且 价格小于100的所有书
       # ret = models.Book.objects.filter(maichu__gt=1000, price__lt=100) # 并且
       # print(ret)
       # 查询 卖出数大于1000,或者 价格小于100的所有书
       # ret = models.Book.objects.filter(Q(maichu__gt=1000) | Q(price__lt=100))
       # print(ret)
       # Q查询和字段查询同时存在时, 字段查询要放在Q查询的后面 后边的与前边是 与的关系
       # ret = models.Book.objects.filter(Q(maichu__gt=1000) | Q(price__lt=100), title__contains="金老板")
       # print(ret)


       # Django ORM 事务

       # try:
       #     from django.db import transaction
       #
       #     with transaction.atomic():   # 加入事务
       #         # 先创建一个出版社
       #         new_publisher = models.Publisher.objects.create(name="火星出版社")
       #         # 创建一本书
       #         models.Book.objects.create(
       #             title="橘子物语",
       #             price=11.11,
       #             kucun=10,
       #             maichu=10,
       #             publisher_id=1000 # 指定一个不存在的出版社id
       #         )
       # except Exception as e:
       #     print(str(e))

       # 没有指定原子操作
       # try:
       #
       #     # 先创建一个出版社
       #     new_publisher = models.Publisher.objects.create(name="火星出版社")
       #     # 创建一本书
       #     models.Book.objects.create(
       #         title="橘子物语",
       #         price=11.11,
       #         kucun=10,
       #         maichu=10,
       #         publisher_id=1000 # 指定一个不存在的出版社id
       #     )
       # except Exception as e:
       #     print(str(e))

       # 执行原生SQL
       # 更高灵活度的方式执行原生SQL语句
       # from django.db import connection
       # cursor = connection.cursor() # cursor = connections['default'].cursor()
       # cursor.execute("SELECT * from app01_book where id = %s", [1])
       # ret = cursor.fetchone()
       # print(ret)


       # 在QuerSet查询的基础上自己指定其他的SQL语句(了解即可)
       ret = models.Book.objects.extra(
           # 把出版社计数 赋值给newid
           select={'newid': 'select count(1) from app01_publisher where id>%s'},
           select_params=[1, ],

           where=["app01_book.id=%s"],

           params=[1, ],
           tables=['app01_publisher']
      )

       print(ret)
       for i in ret:
           print(i)

    6_orm_2

    # orm一对一:
    #   当一个表中属性过多的时候,将属性分开,分为常用的属性表,和不常用的
    #   例如第三方登录时,常请求的用户名,密码,而爱好,身份证号等不常用信息,可存放在另一张表中
    #   构成一对一关系
    """
    class A(model.Model):
      ...
      detail=models.OneToOneField(to="B") 逐数据库中 列名为detail_id
    class B(models.Model):
      ...若没有主键会自动创建id列
    通过A获取B a = models.A.objects.get(id=1) b = a.deatil b.xxx可获取属性
    """
    # orm多对多:
    #   1,自动创建第三张表
    #   2,自己创建
    """ 自己创建第三张表 查询比较慢,不能使用author.books了
    class Author_Book(model.Model):
      ...
      author = modelsForeignKey("Author") author_id
      book = modelsForeignKey("Book) book_id
    查询时,手动经
    过第三张表查询
    """
    #   3,自己创建表,但使用ManyToMany
    """
      第三张表的建立与2相同
      class Author():
          ...
          books = models.ManyToMany(to="Book",throuth="第三张表",throght_fields=(author,book))
          里边是元祖,顺序固定,应为是在author中 所以先写author(第三张表中的author)
          注意第三张表 class Meta:
                                  unique_tgether = ("author","book")
    """
    # 第三张表无其他字段,第一种
    # 有其他字段:第三种 如聊天记录,不仅要双方那个id,还有时间,内容.... 因此需要自己创建
    #   使用第三种方法时,是没有add方法,remove()方法等
    #   例:给作者1加一本书 obj.get(id=1).books.add(xxx) 第一种
    #   第三种:直接添加记录
    #   反查有book查author   ...filter(id=1).value("related__name__author的属性")

    # ===========================================
    # csfr 跨站请求伪造 服务器返回给用户一个html页面,里面有form表单   action="xxxx"
    #   此时即可得到xxxx请求地址, 即可自定义html,form添加其他input 请求服务器,即跨站请求伪造
    #   解决方案:服务器返回的html中有一项input name=key value="每个用户不同,或每次请求不同",以此识别用户
    # 默认是开启的, 即不能跨站请求,弱不需要注释即可
    """
      使用方法:在form中 {% csrf_token%} 在html中会变为 <input type="hidden" name="csrfmiddlewaretoken"
      value="随机字符串"/>
      若出现跨站请求即会禁止 一般就是403
      在render中 生成html时,会自动产生key,通过Post接受参数时,会自动校验,不通过即拒绝
    """

    7_分页_session_cookies

     

    # 分页
    class Page():

       def __init__(self, page_num, total_count, url_prefix, per_page=10, max_page=11):
           """
          :param page_num: 当前页码数
          :param total_count: 数据总数
          :param url_prefix: a标签href的前缀
          :param per_page: 每页显示多少条数据
          :param max_page: 页面上最多显示几个页码
          """
           self.url_prefix = url_prefix
           self.max_page = max_page
           # 每一页显示多少条数据
           # 总共需要多少页码来展示
           total_page, m = divmod(total_count, per_page)
           if m:
               total_page += 1
           self.total_page = total_page

           try:
               page_num = int(page_num)
               # 如果输入的页码数超过了最大的页码数,默认返回最后一页
               if page_num > total_page:
                   page_num = total_page
           except Exception as e:
               # 当输入的页码不是正经数字的时候 默认返回第一页的数据
               page_num = 1
           self.page_num = page_num

           # 定义两个变量保存数据从哪儿取到哪儿
           self.data_start = (page_num - 1) * 10
           self.data_end = page_num * 10

           # 页面上总共展示多少页码
           if total_page < self.max_page:
               self.max_page = total_page

           half_max_page = self.max_page // 2
           # 页面上展示的页码从哪儿开始
           page_start = page_num - half_max_page
           # 页面上展示的页码到哪儿结束
           page_end = page_num + half_max_page
           # 如果当前页减一半 比1还小
           if page_start <= 1:
               page_start = 1
               page_end = self.max_page
           # 如果 当前页 加 一半 比总页码数还大
           if page_end >= total_page:
               page_end = total_page
               page_start = total_page - self.max_page + 1
           self.page_start = page_start
           self.page_end = page_end

       @property
       def start(self):
           return self.data_start

       @property
       def end(self):
           return self.data_end


       def page_html(self):
           # 自己拼接分页的HTML代码
           html_str_list = []
           # 加上第一页
           html_str_list.append('<li><a href="{}?page=1">首页</a></li>'.format( self.url_prefix))

           # 判断一下 如果是第一页,就没有上一页
           if self.page_num <= 1:
               html_str_list.append('<li class="disabled"><a href="#"><span aria-hidden="true">&laquo;</span></a></li>'.format(self.page_num-1))
           else:
               # 加一个上一页的标签
               html_str_list.append('<li><a href="{}?page={}"><span aria-hidden="true">&laquo;</span></a></li>'.format( self.url_prefix, self.page_num-1))

           for i in range(self.page_start, self.page_end+1):
               # 如果是当前页就加一个active样式类
               if i == self.page_num:
                   tmp = '<li class="active"><a href="{0}?page={1}">{1}</a></li>'.format(self.url_prefix, i)
               else:
                   tmp = '<li><a href="{0}?page={1}">{1}</a></li>'.format( self.url_prefix, i)

               html_str_list.append(tmp)

           # 加一个下一页的按钮
           # 判断,如果是最后一页,就没有下一页
           if self.page_num >= self.total_page:
               html_str_list.append('<li class="disabled"><a href="#"><span aria-hidden="true">&raquo;</span></a></li>')
           else:
               html_str_list.append('<li><a href="{}?page={}"><span aria-hidden="true">&raquo;</span></a></li>'.format( self.url_prefix, self.page_num+1))
           # 加最后一页
           html_str_list.append('<li><a href="{}?page={}">尾页</a></li>'.format( self.url_prefix, self.total_page))

           page_html = "".join(html_str_list)
           return page_html
       # from utils.mypage import Page
       # page_obj = Page(page_num, total_count, per_page=10, url_prefix="/books/", max_page=9,)
       # ret = models.Book.objects.all()[page_obj.start:page_obj.end]
       # page_html = page_obj.page_html()
       # return render(request, "books.html", {"books": ret, "page_html": page_html})
    # ====================================================================
    # cookies 和session 因为http请求是无状态的,请求之间无关系
    # cookie 保存在浏览器上的键值对,访问时会自动添加
    #   例如:登录,输入密码登陆后,若成功,响应请求,让浏览器保存cookie本机,下次访问会默认带上cookie
    #   都是键值对name value
    """
    用法:得到响应对象 rep = render()或redirect或httpresponse
    1,rep.set_cookies("xxx","yyy") 默认关闭浏览器失效
    2,rep.set_signed_cookie("xxx","yyy",salt="zzz",max_age=10 单位是s) 设置加盐cookies
    1,request.COOKIES['xxx'] 获取到
    2,rep.get_signed_cookie("xxx",default="yy"取不到异常,加default,salt="zzz")

    清除cookies:rep.delete_cookie("xxxx")

    当多个页面需要校验cookies时
    使用装饰器
    def cookies(fun):
      @wraps(fun) 修复注释,文档名等
      def inner(request,*args,**kwargs):
          if not request.get_singed_cookies.get("xxx",default="yyy",salt=""):
              return render()
          else:
              跳转登录,   跳转后应该再次到请求的页面,不能固定,写死
              1,获取请求的url:Request.path_info
              redirect("..html/?next={}".format(url))   在对应方法中取出next值,动态跳转即可
          ret = fun(request,*args,**kwargs)
          return ret
      return inner
    request.get_full_path:全路径带参数
    request.path_info:不带参数
    HTML中 action={{request.get_full_path}} 跳转到url中的路径   action 为空的时候默认跳转到当前url
    action 要么不写要么 使用{{}}
    expire= 针对ie的超时参数
    path="/" 生效路径 默认是"/"
    domain= 生效域名
    source=False https传输
    httponly=False 只能使用http协议传输,无法被javascript获取,不是绝对的,抓包可以修改

    最大4kb
    """
    # =============================================
    # session 它依赖于cookie
    #   cookies 键值保存在客户端
    #   session中的键值保存在服务器,通过sessionid连接,保存在cookie中
    #   Django session 存
    #       1,生成字符串
    #       2,生成大字典对应1中字符串
    #       生成的数据是在数据库中的 django_session session_key session_date(加密过得) expire_date session默认两周
    #       3,返回给cookie 浏览器
    #   取
    #   1,从cookie中找到字符串
    #   2,找到的大字典
    #   3,大字典取值
    """"
    request.session['k1']
    request.session.get('k1',None)
    request.session.set('k1',"123") 存在则不设置
    del request.session['k1']
    request.session.delete() 删除所有session中的值,没神魔用,会使cookiezhaobudao对应值,等于无效
    request.session.flush() session,cookie都删除

    request.session.clear_expired() 数据库中的session记录不会自动删除,本语句就是删除过期的session
    request.session.exists("key") 判断key存在
    request.session.set_expiry(整数秒,datatime或timedelta,0表示关闭失效,None settings中设置) 失效的是cookie

    """
    # settings中配置全局session信息
    # 默认引擎
    SESSION_ENGINE="django.contrib.session.backends.db"
    # 缓存session
    SESSION_ENGINE = "django.contrib.session.backends.cache"
    SESSION_CACHE_ALLAS="default" # 使用的缓存别名默认内存缓存,也可memcache
    # 文件Session
    SESSION_ENGINE = "django.contrib.session.backends.file"
    SESSION_FILE_PATH=None # 若为None tempfile.gettempdir获取临时地址
    # 缓存加数据库
    SESSION_ENGINE="django.contrib.session.backends.cached_db"
    # 加密Cookie Session 加密的cookies 相当于没有使用session
    SESSION_ENGINE="django.contrib.session.backends.singed_cookies"

    # 其他设置
    SESSION_COOKIE="sessionid"
    SESSION_COOKIE_PATH="/"
    SESSION_COOKIE_DOMAIN=None
    SESSION_COOKIE_SECURE=False
    SESSION_COOKIE_HTTPONLY=True
    SESSION_COOKIE_AGE=1209600 # 2 WEEK
    SESSION_EXPIRE_AT_BROWSER_CLOSE=False # 浏览器关闭清除Session
    SESSION_SAVE_EVERY_REQUEST=False #每次请求后更改SESSION
    # ==========================================
    # cvb(类中get) 使用装饰器
    #   get,post (self,request) 装饰器中第一个参数是request,不匹配
    #   解决方案:form django.utils.decorators import method_decorator
    #   get或post方法上 @method_decorator(自定义的装饰器) 也可以加在类上 但要指明方法
    #   @method_decorator(自定义的装饰器,name="get")
    # 注意:其实在cvb中有dispatch方法
    """
      def dispatch(self,request,*args,**kwargs): 用来选择是get请求还是post请求
          return super(本类名,self).dispatch(request,*args,**kwargs)
          若在此上边加,表示get,post都加装饰器
    """
    # 补充 csfr token
    # 对于cvb中
    """
      from django.views.decorator.csrf import csrf_protect,csrf_exempt
      @method_decorator(csfr_protect) 即时sttting中注释了,不验证跨站请求,加了本装饰器,也会验证
      @method_decorator(csfr_exempt) 即时sttting中验证跨站请求,加了本装饰器,也不会验证,即取消跨站验证
      只能放在cvb的dispatch方法上
       
    """

    8_Django 中的html javascript

    # json (javascript object Notation)
    # 是javascript中的对象类型
    # javascript 数字,字符串,布尔,数组,对象,null
    # python 整形浮点,字符串,布尔,列表,字典,None 因此python不能json对象
    # 二者通过json字符串转化
    # json注意事项: 1,key必须双引号,
    #              2,不能16进制,
    #              3,不能undefined,
    #              4,value不能是函数,或日起对象
    # ====================================================
    # JQuery 发ajax请求
    """
    $.ajax(
        {
            url:"xxx",
            type:"get"
            data:{字典}
            success:function(data){
            }
        }
    )
    ajax 发送跨站请求时
        方法1:要把{{csrf_token}} 的值取到拼接到发送的数据中
        方法2:引入jquery.cookie.js
            type下多个headers:{"X-CSFRToken":$.cookie("csfrtoken")},
        方法3:存入js文件,发ajax前引入,发送步骤与普通相同,不用再额外添加
        function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie !== '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) === (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
    var csrftoken = getCookie('csrftoken');
    
    function csrfSafeMethod(method) {
      // these HTTP methods do not require CSRF protection
      return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }
    
    $.ajaxSetup({
      beforeSend: function (xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
          xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
      }
    });
    """
    # ==============================================
    # 对象的序列化 需要转为字典 然后变为json字符串,
    # from django.core import serializers
    #   s= serializers.serializer("json",数据库查询的对象列表)
    # ========================================
    # sweetalert 插件,漂亮的弹出框
    """
    1,swal("title","content","css") 
    css:success,warning,info,error
    2,
     swal({
              title: "你确定要删除吗?",
              text: "一旦删除就找不回来了",
              type: "warning",
              showCancelButton: true,
              confirmButtonClass: "btn-warning",
              confirmButtonText: "确认",
              cancelButtonText: "取消",
              closeOnConfirm: false,
              showLoaderOnConfirm: true //若删除耗时,显示加载状态
            },
            function(){
                // 向后端发送删除的请求
                $.ajax({
                    url: "/delete/",
                    type: "post",
                    datatype:"json", //返回值的格式,回调函数中,按照此类型解析,不写就是字符串类型
                    traditional:True,// 为true,阻止深度序列化,不懂什么意思,反正就可以传list了
                    data: {"id":delId,"list":[1,2,3]}, 接受的时候使用getlist接受,但不能是双层列表 
                    success:function (arg) {
                        swal(arg, "你可以跑路了!", "success");
                        $trEle.remove();
                    }
                });
                
            }
        );
    """
    # ==================================================
    # Django 的form组件
    # 第一步:定义class
    # from django import  forms
    # from django.forms import  widgets
    # class RegForm(forms.Form):
    #     name = forms.CharField(max_length=16,label="用户名") 校验规则
    #     pwd = forms.CharField(
    #     label="密码",
    #     widget = widgets.PasswordInput(attr={'class':'xx'},render_value=True), //表示为密码类型,切验证后密码还存在 html相关
    #     min_length=6,
    #     error_message={"required":"不能为空","invalid":"格式错误","min_length":"最短6位"}
    #     )
    
    # def fun(request):
    #     form_obj = RegForm()
    #     if reauest.method=="post":
    #         form_obj=RegForm(request.POST)
    #         if form_obj.is_valid :存入数据库
    #               name = form_obj.cleanned_data.get("name") 经过验证的数据
    #               先从字典中去掉无用字符串pop("xxx")这种不报错
    #               .create(**form_obj.cleanned_data) 但要注意名字与数据库中列相同
    #     return render(request,"xxx.html",{"html":form_obj})
    # 第二部,html中调用属性
    # <form  novalidate> 关闭浏览器校验
    # {{csrf_token}}
    # {{form_obj.as_p}} 每个都用p标签包裹
    # {{form_obj.errors.pwd}}
    # <p><input type="submit" /></p>
    # </form>
    # 或在form中自己写
    """<div>
    {{form_obj.name.label}}
    {{form_obj.name}}
    <span>{{form_obj.name.errors.0}}</span>
    </div>这种,只不过每个都要自己写
    
    服务器端校验,通常是request中获取值,再返回,比较麻烦
    django 校验后还可以保留信息
    其他组件
    单选按钮:forms.fields.ChoiceField(
            choices=((1,"男"),(2,"女")),
            label="性别",
            initial=3,默认是3选中
            widget = forms.widgets.RadioSelect
        )
    单选框,修改为widget = forms.widgets.Select 就是下拉菜单
    多选框forms.MutipleChoiceField
            initial=[1,3]
            widget = forms.widgets.SelectMultiple  下拉菜单全部显示的那种
    单选框,记住密码那种:forms.fields.ChoiceField
                widget = forms.widgets.CheckboxInput
                initial="checked"
    多选框,
    forms.fields.MultipleChoiceField(
            choices=((1,"男"),(2,"女")),
            label="爱好",
            initial=[1,3],默认是3选中
            widget = forms.widgets.CheckBoxSelectMultiple
        )
    """
    """
    自定义校验规则
    from django.core.validators import RegexValidator
    Charfield(
        加上字段validators=[ 正则列表
        RegexValidator(r"[0-9]+$","请输入数字"),
        RegexValidator(r"^1[3-9][0-9]{9}$","159开头"),
        ]
    )
    在类中定义方法
    def clean_name(self): 名字固定 clean_列名
        value = self.cleanned_data.get("校验的列名 如name")
        if "非法字符" in value:
            raise ValidationError("含有非法字符")
        return value
    def  clean(self): 重写父类clean方法,父类的方法默认什么都没干
        pwd = self.cleaned_date.get("pwd")
        ...
        if xx==yy
            self.add_error("字段",ValidatorError("不一致") )  应该在那里显示呢?
            raise ValidatorError("不一致")
        return self.cleaned_data
        
    reg_pwd  {{ form_obj.errors}}
    """
    # =====================多选框从数据库取值
    forms.CharField(
        choices=models.xxx.objects.all().value_list("id",....)
        #此时虽然可以获取,但是静态字段,若数据库增加,不重启服务器,新的数据不能获取
    )
    需要从写from的__init__方法
    def __init__(self,*args,**kwargs):
        super().__init__(*args,**kwargs)
        self.fields['那一列'].widget.choices=models......
    内置字段:等待添加....
    

    9_ 中间件

    https://www.cnblogs.com/liwenzhou/

     

    # importlib的使用
    import importlib
    o = importlib.import_module("模块字符串")
    # 这样即可导入模块 ,其实是通过反射
    
    # 要实现权限验证,如登陆后访问,原来是装饰器,但若函数过多...
    # 中间件:官方说是 用来处理Django的请求和响应的框架级级别的钩子,轻量级
    #   全局的,慎用,使用不当,影响性能 说白了就是在执行urls.py前后,执行某些方法
    # setting  MIDDLEWARE   定义后加入列表即可
    # 固定方法 其实中间件相当于过滤器
    from django.utils.deprecation import MiddlewareMixin
    class A(MiddlewareMixin):
        # 先request,次view 最后response
        def process_request(self,request):pass
        # 按照setting中的顺序,请求时 123 响应是 321 是反向
        # 返回None 继续执行url,若有return httpresponse 则直接返回
        def process_request(self,request,response):# 必须要两个参数,且必须返回值,要么自定义返回 ,或返回视图的response
            pass
        def process_view(self,request,view_func,view_args,view_kwargs):
            """
            :param request: 请求
            :param view_func: 要执行的函数名字
            :param view_args: 位置参数
            :param view_kwargs: 关键字参数
            :return:
            在找到urls.py前执行,按顺序执行,
            """
        def process_exception(self):pass
        # 只有在视图函数中出现异常的时候执行, 也是倒序
        # 返回None,继续执行其他中间件的exception
        # HttpResponse,跳过其他中间件的exception ,通常是视图页面错误,既不能正常返回,在此定义返回页面
        def process_template_response(self,request,response):pass
        #  倒序执行, 在视图函数执行完毕 但没有返回render()之前
        # 返回Noneh或HttpResponse
        # 因此返回的对象中必须存在render()方法,然后会执行render()方法,名字必须为render(),内容可自定义
    
    
    
        # request列表没执行完毕,某一个request返回了响应,则直接跳到该中间件的response
        # request列表执行完毕,会继续第一个中间件的view --->到最后一个view
        #   若view列表没执行完毕,某一个返回响应了,后边的view不执行,  跳到第一个response(返回时候的第一个res) (urls中的view不执行)
        #   若view列表执行完毕,执行urls view ,然后response列表
    #
    #     1,process_request
    #         urls.py
    #     2,process_view
    #         view
    #     3,有异常process_exception
    #     4,若视图函数返回对象有render()方法,执行
    #     5,process_response
    #
    # day74
    # 2018 - 05 - 21
    #
    # 课程安排
    # 周一:
    # 中间件
    # auth模块 + 分析BBS项目需求(小组讨论把表结构设计出来)
    #
    #
    # 1.
    # 今日内容
    # 中间件:http: // www.cnblogs.com / liwenzhou / p / 8761803.
    # html
    #
    # 1.
    # URL的白名单
    # url = ["/xx/", "/oo/", "/haha/"]
    # 2.
    # 登陆之后才能访问某些URL
    # 之前使用装饰器
    #
    # 中间件的定义:
    # wsgi之后
    # urls.py之前
    # 在全局
    # 操作Django请求和响应的模块!
    #
    # 中间件的使用:
    # 5
    # 个固定的方法
    # process_request(self, request)
    # 执行顺序:
    # 按照注册的顺序(在settings.py里面设置中
    # 从上到下的顺序)
    # 何时执行:
    # 请求从wsgi拿到之后
    # 返回值:
    # 返回None,继续执行后续的中间件的process_request方法
    # 返回response, 不执行后续的中间件的process_request方法
    #
    # process_response
    # 执行顺序:
    # 按照注册顺序的倒序(在settings.py里面设置中
    # 从下到上的顺序)
    # 何时执行:
    # 请求有响应的时候
    # 返回值:
    # 必须返回一个response对象
    #
    # process_view(self, request, view_func, view_args, view_kwargs):
    # 执行顺序:
    # 按照注册的顺序(在settings.py里面设置中
    # 从上到下的顺序)
    # 何时执行:
    # 在urls.py中找到对应关系之后
    # 在执行真正的视图函数之前
    # 返回值:
    # 返回None,继续执行后续的中间件的process_view方法
    # 返回response,
    #
    # process_exception(self, request, exception)
    # 执行顺序:
    # 按照注册顺序的倒序(在settings.py里面设置中
    # 从下到上的顺序)
    # 何时执行:
    # 视图函数中抛出异常的时候才执行
    # 返回值:
    # 返回None, 继续执行后续中间件的process_exception
    # 返回response,
    #
    #
    #
    # process_template_response(self, request, response)
    # 执行顺序:
    # 按照注册顺序的倒序(在settings.py里面设置中
    # 从下到上的顺序)
    # 何时执行:
    # 视图函数执行完,在执行视图函数返回的响应对象的render方法之前
    # 返回值:
    # 返回None, 继续执行后续中间件的process_exception
    # 返回response,
    #
    #
    # Django调用
    # 注册的中间件里面五个方法的顺序:
    # 1.
    # process_request
    # urls.py
    # 2.
    # process_view
    # view
    # 3.
    # 有异常就执行
    # process_exception
    # 4.
    # 如果视图函数返回的响应对象有render方法, 就执行process_template_response
    # 5.
    # process_response
    #
    # Django已经学过的知识点:
    # 1.
    # Urls.py
    # 路由系统:
    #
    # 正则
    # 分组匹配 --> 位置参数
    # 分组命名匹配 --> 关键字参数
    #
    # 分级路由
    # include
    #
    # 给路由起别名
    # name = "xx"
    #
    # 反向解析url
    # view
    # from django.urls import reverse
    #
    # reverse("xx", args=[1, 2, 3])
    # reverse("xx", kwargs={”k
    # ": "
    # v
    # "})
    #
    # 自取其辱
    #
    # 2.
    # 视图
    # views.py
    # request
    # request.method
    # request.GET --> URL里面的参数
    # request.POST --> post请求的数据
    #
    # request.path_info --> 路径
    # request.get_full_path() --> 路径加路径的参数
    #
    # response
    # 新手必备3件套
    # render(request, "xx.html", {“k”: "v", ...})
    # HttpResponse("响应")
    # redirect("/index/")
    # redirect("http://www.luffycity.com")
    #
    # from django.http import JsonResponse
    #
    # JsonResponse()
    #
    # FBV和CBV
    #
    # 函数装饰器和方法装饰器的区别
    #
    # 3.
    # 模板
    #
    # filter
    # 内置的filter方法
    # 自定义的filter方法
    #
    # tag
    # 内置的tag
    # 自定义的simpleTag
    # 自定义的inclusionTag
    #
    # 母版和继承
    #
    # { % extends ‘base.html’ %}
    #
    # { % block
    # page - main %}
    # { % block
    # small %}
    # { % endblock
    # small %}
    # { % endblock
    # page - main %}
    #
    #
    # 组件
    # { % include
    # nav %}
    #
    #
    # 静态文件相关的tag
    #
    # 在模板语言里面反向解析url
    #
    # { % url
    # 'url的别名'
    # xx %}
    #
    #
    # 4.
    # ORM
    #
    # 对应关系
    # 类 --> 数据表
    # 对象 --> 数据行
    # 属性 --> 字段
    #
    # Django连接MySQL数据库的步骤:
    # 1.
    # 手动创建库
    # 2.
    # 配置settings.py中数据库的连接信息
    # 3.
    # 修改settings.py同目录下的__init__.py文件,添加两句
    # import pymysql
    #
    # pymysql.install_as_MySQLdb()
    # 4.
    # 在app下面的models.py中定义类,类一定要继承mdoels.Model
    # 5.
    # 执行两句命令
    # 1.
    # python
    # manage.py
    # makemigrations
    # 2.
    # python
    # manage.py
    # migrate
    #
    # 操作数据表
    #
    # 操作数据行(增删改查)
    # 单表
    # 外键
    # 多对多
    # 一对一
    #
    # ORM高级:
    # 常用字段和方法
    # 必知必会13条
    # 神奇的双下划线
    # 跨表的正向查询反向查询
    #
    # F和Q
    #
    # 聚合和分组
    #
    # 事务
    #
    # 执行原生的SQL语句
    #
    # 5.
    # Cookie和Session, 分页
    #
    # 6.
    # AJAX
    #
    # $.ajax({
    #     url: “”,
    # type: "post",
    # data: {"k1": JSON.stringify([1, 2, 3])},
    # success: function(data)
    # {
    #
    # }
    # })
    # 7.
    # form表单
    #
    # 8.
    # 中间件
    

    10_auth模块

    # 当在html要获取当前用户信息的时候,通常是session存id
    # 视图中查询到,传入html,存在问题:需要的页面都要获取,再传入
    # 解决方案:自带的中间件,自带的倒数第三个 auth有关的
    """
    python manage.py createsuperuser 向auth_user 添加用户 
    from django.contrib import auth
      obj = auth.authenticate(username="xx",password="xx")
        将认证的用户放入request.user:
      auth.login(request,obj)根据cookie,将用户放入session, 检测当前用户,下次来的是会有请求中会放入user
      auth.lgout(request) 相当于request.session.flush()
    
    from django.contrib.auth.decorators import login_required
    
    需要登陆权限的视图 @login_requried() 装饰器 默认""
    默认LOGIN_URL="/accounts/login/" 不存在 添加 修改即可  而且实现的登陆跳转
    
    request.user.is_authenticated() 返回
    
    from django.contrib.auth.models import User
        注意username不能重复
        User.Objects.create(...)  不能使用这个创建,创建后是明文密码
        User.Objects.create_superuser()
        User.Objects.create_user(....) 密文密码
    
    
        obj.check_password("密码") 检测密码正确与否
        obj.set_password("xxx") 修改密码
        obj.save() 修改后要保存
    
    """
    # ====================================
    # 扩展自带的表
    # 1,models.OneToOneField(to=User)
    # 2,继承自带的类,auth_user 不会创建了
    """
        from django.contrib.auth.models import User,AbstractUser
        继承后添加额外属性
        若使用本方法 sttings指定 AUTH_USER_MODELS='appname.类名'
    """
    python manager.py createsuperuser
    
  • 相关阅读:
    第十六节:Linq用法大全(四)
    第十五节:EF Core大数据量处理(一)之EFCore.BulkExtensions
    第十四节:EF Core性能优化
    查看mysql执行的线程,并杀掉他
    docker安装与卸载
    新手根据菜鸟教程安装docker,从No package docker-io available开始遇到的坑...(转)
    MySQL启动出现The server quit without updating PID file错误解决办法
    Linux下彻底卸载mysql详解
    Linux 下的 Redis 安装 && 启动 && 关闭 && 卸载
    Linux安装mysql
  • 原文地址:https://www.cnblogs.com/Dean0731/p/11661187.html
Copyright © 2011-2022 走看看