zoukankan      html  css  js  c++  java
  • Django

    目录

    • HTTP协议介绍
    • Web框架本质
    • 服务器程序和应用程序

    1,HTTP协议介绍

    • HTTP协议对收发消息的格式要求
    • 每个HTTP请求和响应都遵循相同的格式,一个HTTP包含Header和Body两部分,其中Body是可选的。 HTTP响应的Header中有一个 Content-Type表明响应的内容格式。如 text/html表示HTML网页。

    1.1 HTTP协议简介

    • 超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网的数据通信的基础。
    • HTTP的发展是由蒂姆·伯纳斯-李于1989年在欧洲核子研究组织(CERN)所发起。HTTP的标准制定由万维网协会(World Wide Web Consortium,W3C)和互联网工程任务组(Internet Engineering Task Force,IETF)进行协调,最终发布了一系列的RFC,其中最著名的是1999年6月公布的 RFC 2616,定义了HTTP协议中现今广泛使用的一个版本——HTTP 1.1。
    • 2014年12月,互联网工程任务组(IETF)的Hypertext Transfer Protocol Bis(httpbis)工作小组将HTTP/2标准提议递交至IESG进行讨论,于2015年2月17日被批准。 HTTP/2标准于2015年5月以RFC 7540正式发表,取代HTTP 1.1成为HTTP的实现标准。

    1.2 HTTP协议概述

    • HTTP是一个客户端终端(用户)和服务器端(网站)请求和应答的标准(TCP)。通过使用网页浏览器、网络爬虫或者其它的工具,客户端发起一个HTTP请求到服务器上指定端口(默认端口为80)。我们称这个客户端为用户代理程序(user agent)。应答的服务器上存储着一些资源,比如HTML文件和图像。我们称这个应答服务器为源服务器(origin server)。在用户代理和源服务器中间可能存在多个“中间层”,比如代理服务器、网关或者隧道(tunnel)。
    • 尽管TCP/IP协议是互联网上最流行的应用,HTTP协议中,并没有规定必须使用它或它支持的层。事实上,HTTP可以在任何互联网协议上,或其他网络上实现。HTTP假定其下层协议提供可靠的传输。因此,任何能够提供这种保证的协议都可以被其使用。因此也就是其在TCP/IP协议族使用TCP作为其传输层。
    • 通常,由HTTP客户端发起一个请求,创建一个到服务器指定端口(默认是80端口)的TCP连接。HTTP服务器则在那个端口监听客户端的请求。一旦收到请求,服务器会向客户端返回一个状态,比如"HTTP/1.1 200 OK",以及返回的内容,如请求的文件、错误消息、或者其它信息。

    1.3 HTTP工作原理

    • HTTP协议定义Web客户端如何从Web服务器请求Web页面,以及服务器如何把Web页面传送给客户端。HTTP协议采用了请求/响应模型。客户端向服务器发送一个请求报文,请求报文包含请求的方法、URL、协议版本、请求头部和请求数据。服务器以一个状态行作为响应,响应的内容包括协议的版本、成功或者错误代码、服务器信息、响应头部和响应数据。
    • 以下是 HTTP 请求/响应的步骤:
      • 1 客户端连接到Web服务器
        • 一个HTTP客户端,通常是浏览器,与Web服务器的HTTP端口(默认为80)建立一个TCP套接字连接。例如,http://www.luffycity.com
      • 2 发送HTTP请求
        • 通过TCP套接字,客户端向Web服务器发送一个文本的请求报文,一个请求报文由请求行、请求头部、空行和请求数据4部分组成。
      • 3 服务器接受请求并返回HTTP响应
        • Web服务器解析请求,定位请求资源。服务器将资源复本写到TCP套接字,由客户端读取。一个响应由状态行、响应头部、空行和响应数据4部分组成。
      • 4 释放连接TCP连接
        • 若connection 模式为close,则服务器主动关闭TCP连接,客户端被动关闭连接,释放TCP连接;若connection 模式为keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求;
      • 5 客户端浏览器解析HTML内容
        • 客户端浏览器首先解析状态行,查看表明请求是否成功的状态代码。然后解析每一个响应头,响应头告知以下为若干字节的HTML文档和文档的字符集。客户端浏览器读取响应数据HTML,根据HTML的语法对其进行格式化,并在浏览器窗口中显示。
    • 例如:在浏览器地址栏键入URL,按下回车之后会经历以下流程:
      • 浏览器向 DNS 服务器请求解析该 URL 中的域名所对应的 IP 地址;
      • 解析出 IP 地址后,根据该 IP 地址和默认端口 80,和服务器建立TCP连接;
      • 浏览器发出读取文件(URL 中域名后面部分对应的文件)的HTTP 请求,该请求报文作为 TCP 三次握手的第三个报文的数据发送给服务器;
      • 服务器对浏览器请求作出响应,并把对应的 html 文本发送给浏览器;
      • 释放 TCP连接;
      • 浏览器将该 html 文本并显示内容;

    1.4 HTTP请求方法

    • HTTP/1.1协议中共定义了八种方法(也叫“动作”)来以不同方式操作指定的资源:
      • GET
        • 向指定的资源发出“显示”请求。使用GET方法应该只用在读取数据,而不应当被用于产生“副作用”的操作中,例如在Web Application中。其中一个原因是GET可能会被网络蜘蛛等随意访问。
      • HEAD
        • 与GET方法一样,都是向服务器发出指定资源的请求。只不过服务器将不传回资源的本文部分。它的好处在于,使用这个方法可以在不必传输全部内容的情况下,就可以获取其中“关于该资源的信息”(元信息或称元数据)。
      • POST
        • 向指定资源提交数据,请求服务器进行处理(例如提交表单或者上传文件)。数据被包含在请求本文中。这个请求可能会创建新的资源或修改现有资源,或二者皆有。
      • PUT
        • 向指定资源位置上传其最新内容。
      • DELETE
        • 请求服务器删除Request-URI所标识的资源。
      • TRACE
        • 回显服务器收到的请求,主要用于测试或诊断。
      • OPTIONS
        • 这个方法可使服务器传回该资源所支持的所有HTTP请求方法。用'*'来代替资源名称,向Web服务器发送OPTIONS请求,可以测试服务器功能是否正常运作。
      • CONNECT
        • HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。通常用于SSL加密服务器的链接(经由非加密的HTTP代理服务器)。
    • 注意事项:
      • 方法名称是区分大小写的。当某个请求所针对的资源不支持对应的请求方法的时候,服务器应当返回状态码405(Method Not Allowed),当服务器不认识或者不支持对应的请求方法的时候,应当返回状态码501(Not Implemented)。
      • HTTP服务器至少应该实现GET和HEAD方法,其他方法都是可选的。当然,所有的方法支持的实现都应当匹配下述的方法各自的语义定义。此外,除了上述方法,特定的HTTP服务器还能够扩展自定义的方法。例如PATCH(由 RFC 5789 指定的方法)用于将局部修改应用到资源。

    1.5 HTTP状态码

    • 所有HTTP响应的第一行都是状态行,依次是当前HTTP版本号,3位数字组成的状态代码,以及描述状态的短语,彼此由空格分隔。
    • 状态代码的第一个数字代表当前响应的类型:
      • 1xx消息——请求已被服务器接收,继续处理
      • 2xx成功——请求已成功被服务器接收、理解、并接受
      • 3xx重定向——需要后续操作才能完成这一请求
      • 4xx请求错误——请求含有词法错误或者无法被执行
      • 5xx服务器错误——服务器在处理某个正确请求时发生错误
    • 虽然 RFC 2616 中已经推荐了描述状态的短语,例如"200 OK","404 Not Found",但是WEB开发者仍然能够自行决定采用何种短语,用以显示本地化的状态描述或者自定义信息。

    1.6 URL

    • 超文本传输协议(HTTP)的统一资源定位符将从因特网获取信息的五个基本元素包括在一个简单的地址中:
      • 传送协议。
      • 层级URL标记符号(为[//],固定不变)
      • 访问资源需要的凭证信息(可省略)
      • 服务器。(通常为域名,有时为IP地址)
      • 端口号。(以数字方式表示,若为HTTP的默认值“:80”可省略)
      • 路径。(以“/”字符区别路径中的每一个目录名称)
      • 查询。(GET模式的窗体参数,以“?”字符为起点,每个参数以“&”隔开,再以“=”分开参数名称与数据,通常以UTF8的URL编码,避开字符冲突的问题)
      • 片段。以“#”字符为起点
    • 以http://www.luffycity.com:80/news/index.html?id=250&page=1 为例, 其中:
      • http,是协议;
      • www.luffycity.com,是服务器;
      • 80,是服务器上的网络端口号;
      • /news/index.html,是路径;
      • ?id=250&page=1,是查询。
    • 大多数网页浏览器不要求用户输入网页中“http://”的部分,因为绝大多数网页内容是超文本传输协议文件。同样,“80”是超文本传输协议文件的常用端口号,因此一般也不必写明。一般来说用户只要键入统一资源定位符的一部分(www.luffycity.com:80/news/index.html?id=250&page=1)就可以了。
    • 由于超文本传输协议允许服务器将浏览器重定向到另一个网页地址,因此许多服务器允许用户省略网页地址中的部分,比如 www。从技术上来说这样省略后的网页地址实际上是一个不同的网页地址,浏览器本身无法决定这个新地址是否通,服务器必须完成重定向的任务。

    1.7 HTTP请求格式

    1.8 HTTP响应格式

    2,Web框架本质

    • Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端。 这样就可以实现Web框架了。

    2.1 半成品自定义web框架

    import socket
    
    sk = socket.socket()
    sk.bind(("127.0.0.1", 80))
    sk.listen()
    
    
    while True:
        conn, addr = sk.accept()
        data = conn.recv(8096)
        conn.send(b"OK")
        conn.close()
    
    • HTTP协议主要规定了客户端和服务器之间的通信格式
    import socket
    
    sk = socket.socket()
    sk.bind(("127.0.0.1", 80))
    sk.listen()
    
    
    while True:
        conn, addr = sk.accept()
        data = conn.recv(8096)
        print(data)  # 将浏览器发来的消息打印出来
        conn.send(b"OK")
        conn.close()
    
    # 执行结果
    b'GET / HTTP/1.1
    Host: 127.0.0.1:8080
    Connection: keep-alive
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
    DNT: 1
    Accept-Encoding: gzip, deflate, br
    Accept-Language: zh-CN,zh;q=0.9
    Cookie: csrftoken=RKBXh1d3M97iz03Rpbojx1bR6mhHudhyX5PszUxxG3bOEwh1lxFpGOgWN93ZH3zv
    
    '
    
    • 响应相关信息可以在浏览器调试窗口的network标签页中看到。

    • 点击view source之后显示如下图:

    2.2 处女版自定义web框架

    • 要想让自定义w的web server端正经起来,必须要让Web server在给客户端回复消息的时候按照HTTP协议的规则加上响应状态行,这样就实现了一个正经的Web框架了。
    import socket
    
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(('127.0.0.1', 8000))
    sock.listen()
    
    while True:
        conn, addr = sock.accept()
        data = conn.recv(8096)
        # 给回复的消息加上响应状态行
        conn.send(b"HTTP/1.1 200 OK
    
    ")
        conn.send(b"OK")
        conn.close()
    

    2.3 根据不同的路径返回不同的内容

    """
    根据URL中不同的路径返回不同的内容
    """
    
    import socket
    sk = socket.socket()
    sk.bind(("127.0.0.1", 8080))  # 绑定IP和端口
    sk.listen()  # 监听
    
    
    while 1:
        # 等待连接
        conn, add = sk.accept()
        data = conn.recv(8096)  # 接收客户端发来的消息
        # 从data中取到路径
        data = str(data, encoding="utf8")  # 把收到的字节类型的数据转换成字符串
        # 按
    分割
        data1 = data.split("
    ")[0]
        url = data1.split()[1]  # url是我们从浏览器发过来的消息中分离出的访问路径
        conn.send(b'HTTP/1.1 200 OK
    
    ')  # 因为要遵循HTTP协议,所以回复的消息也要加状态行
        # 根据不同的路径返回不同内容
        if url == "/index/":
            response = b"index"
        elif url == "/home/":
            response = b"home"
        else:
            response = b"404 not found!"
    
        conn.send(response)
        conn.close()
    

    2.4 根据不同的路径返回不同的内容--函数版

    """
    根据URL中不同的路径返回不同的内容--函数版
    """
    
    import socket
    sk = socket.socket()
    sk.bind(("127.0.0.1", 8080))  # 绑定IP和端口
    sk.listen()  # 监听
    
    
    # 将返回不同的内容部分封装成函数
    def index(url):
        s = "这是{}页面!".format(url)
        return bytes(s, encoding="utf8")
    
    
    def home(url):
        s = "这是{}页面!".format(url)
        return bytes(s, encoding="utf8")
    
    
    while 1:
        # 等待连接
        conn, add = sk.accept()
        data = conn.recv(8096)  # 接收客户端发来的消息
        # 从data中取到路径
        data = str(data, encoding="utf8")  # 把收到的字节类型的数据转换成字符串
        # 按
    分割
        data1 = data.split("
    ")[0]
        url = data1.split()[1]  # url是我们从浏览器发过来的消息中分离出的访问路径
        conn.send(b'HTTP/1.1 200 OK
    
    ')  # 因为要遵循HTTP协议,所以回复的消息也要加状态行
        # 根据不同的路径返回不同内容,response是具体的响应体
        if url == "/index/":
            response = index(url)
        elif url == "/home/":
            response = home(url)
        else:
            response = b"404 not found!"
    
        conn.send(response)
        conn.close()
    

    2.5 根据不同的路径返回不同的内容--函数进阶版

    """
    根据URL中不同的路径返回不同的内容--函数进阶版
    """
    
    import socket
    sk = socket.socket()
    sk.bind(("127.0.0.1", 8080))  # 绑定IP和端口
    sk.listen()  # 监听
    
    
    # 将返回不同的内容部分封装成函数
    def index(url):
        s = "这是{}页面!".format(url)
        return bytes(s, encoding="utf8")
    
    
    def home(url):
        s = "这是{}页面!".format(url)
        return bytes(s, encoding="utf8")
    
    
    # 定义一个url和实际要执行的函数的对应关系
    list1 = [
        ("/index/", index),
        ("/home/", home),
    ]
    
    while 1:
        # 等待连接
        conn, add = sk.accept()
        data = conn.recv(8096)  # 接收客户端发来的消息
        # 从data中取到路径
        data = str(data, encoding="utf8")  # 把收到的字节类型的数据转换成字符串
        # 按
    分割
        data1 = data.split("
    ")[0]
        url = data1.split()[1]  # url是我们从浏览器发过来的消息中分离出的访问路径
        conn.send(b'HTTP/1.1 200 OK
    
    ')  # 因为要遵循HTTP协议,所以回复的消息也要加状态行
        # 根据不同的路径返回不同内容
        func = None  # 定义一个保存将要执行的函数名的变量
        for i in list1:
            if i[0] == url:
                func = i[1]
                break
        if func:
            response = func(url)
        else:
            response = b"404 not found!"
    
        # 返回具体的响应消息
        conn.send(response)
        conn.close()
    

    2.6 返回具体的HTML文件

    """
    根据URL中不同的路径返回不同的内容--函数进阶版
    返回独立的HTML页面
    """
    
    import socket
    sk = socket.socket()
    sk.bind(("127.0.0.1", 8080))  # 绑定IP和端口
    sk.listen()  # 监听
    
    
    # 将返回不同的内容部分封装成函数
    def index(url):
        # 读取index.html页面的内容
        with open("index.html", "r", encoding="utf8") as f:
            s = f.read()
        # 返回字节数据
        return bytes(s, encoding="utf8")
    
    
    def home(url):
        with open("home.html", "r", encoding="utf8") as f:
            s = f.read()
        return bytes(s, encoding="utf8")
    
    
    # 定义一个url和实际要执行的函数的对应关系
    list1 = [
        ("/index/", index),
        ("/home/", home),
    ]
    
    while 1:
        # 等待连接
        conn, add = sk.accept()
        data = conn.recv(8096)  # 接收客户端发来的消息
        # 从data中取到路径
        data = str(data, encoding="utf8")  # 把收到的字节类型的数据转换成字符串
        # 按
    分割
        data1 = data.split("
    ")[0]
        url = data1.split()[1]  # url是我们从浏览器发过来的消息中分离出的访问路径
        conn.send(b'HTTP/1.1 200 OK
    
    ')  # 因为要遵循HTTP协议,所以回复的消息也要加状态行
        # 根据不同的路径返回不同内容
        func = None  # 定义一个保存将要执行的函数名的变量
        for i in list1:
            if i[0] == url:
                func = i[1]
                break
        if func:
            response = func(url)
        else:
            response = b"404 not found!"
    
        # 返回具体的响应消息
        conn.send(response)
        conn.close()
    

    2.7 让网页动态起来

    """
    根据URL中不同的路径返回不同的内容--函数进阶版
    返回HTML页面
    让网页动态起来
    """
    
    import socket
    import time
    
    sk = socket.socket()
    sk.bind(("127.0.0.1", 8080))  # 绑定IP和端口
    sk.listen()  # 监听
    
    
    # 将返回不同的内容部分封装成函数
    def index(url):
        with open("index.html", "r", encoding="utf8") as f:
            s = f.read()
            now = str(time.time())
            s = s.replace("@@oo@@", now)  # 在网页中定义好特殊符号,用动态的数据去替换提前定义好的特殊符号
        return bytes(s, encoding="utf8")
    
    
    def home(url):
        with open("home.html", "r", encoding="utf8") as f:
            s = f.read()
        return bytes(s, encoding="utf8")
    
    
    # 定义一个url和实际要执行的函数的对应关系
    list1 = [
        ("/index/", index),
        ("/home/", home),
    ]
    
    while 1:
        # 等待连接
        conn, add = sk.accept()
        data = conn.recv(8096)  # 接收客户端发来的消息
        # 从data中取到路径
        data = str(data, encoding="utf8")  # 把收到的字节类型的数据转换成字符串
        # 按
    分割
        data1 = data.split("
    ")[0]
        url = data1.split()[1]  # url是我们从浏览器发过来的消息中分离出的访问路径
        conn.send(b'HTTP/1.1 200 OK
    
    ')  # 因为要遵循HTTP协议,所以回复的消息也要加状态行
        # 根据不同的路径返回不同内容
        func = None  # 定义一个保存将要执行的函数名的变量
        for i in list1:
            if i[0] == url:
                func = i[1]
                break
        if func:
            response = func(url)
        else:
            response = b"404 not found!"
    
        # 返回具体的响应消息
        conn.send(response)
        conn.close()
    

    3,服务器程序和应用程序

    • 对于真实开发中的python web程序来说,一般会分为两部分:服务器程序和应用程序。
    • 服务器程序负责对socket服务器进行封装,并在请求到来时,对请求的各种数据进行整理。
    • 应用程序则负责具体的逻辑处理。为了方便应用程序的开发,就出现了众多的Web框架,例如:Django、Flask、web.py 等。不同的框架有不同的开发方式,但是无论如何,开发出的应用程序都要和服务器程序配合,才能为用户提供服务。
    • 这样,服务器程序就需要为不同的框架提供不同的支持。这样混乱的局面无论对于服务器还是框架,都是不好的。对服务器来说,需要支持各种不同框架,对框架来说,只有支持它的服务器才能被开发出的应用使用。
    • 这时候,标准化就变得尤为重要。我们可以设立一个标准,只要服务器程序支持这个标准,框架也支持这个标准,那么他们就可以配合使用。一旦标准确定,双方各自实现。这样,服务器可以支持更多支持标准的框架,框架也可以使用更多支持标准的服务器。
    • WSGI(Web Server Gateway Interface)就是一种规范,它定义了使用Python编写的web应用程序与web服务器程序之间的接口格式,实现web应用程序与web服务器程序间的解耦。
    • 常用的WSGI服务器有uwsgi、Gunicorn。而Python标准库提供的独立WSGI服务器叫wsgiref,Django开发环境用的就是这个模块来做服务器。

    3.1 wsgiref

    • 利用wsgiref模块来替换自己写的web框架的socket server部分:
    """
    根据URL中不同的路径返回不同的内容--函数进阶版
    返回HTML页面
    让网页动态起来
    wsgiref模块版
    """
    
    import time
    from wsgiref.simple_server import make_server
    
    
    # 将返回不同的内容部分封装成函数
    def index(url):
        with open("index.html", "r", encoding="utf8") as f:
            s = f.read()
            now = str(time.time())
            s = s.replace("@@oo@@", now)
        return bytes(s, encoding="utf8")
    
    
    def home(url):
        with open("home.html", "r", encoding="utf8") as f:
            s = f.read()
        return bytes(s, encoding="utf8")
    
    
    # 定义一个url和实际要执行的函数的对应关系
    list1 = [
        ("/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 list1:
            if i[0] == url:
                func = i[1]
                break
        if func:
            response = func(url)
        else:
            response = b"404 not found!"
        return [response, ]
    
    
    if __name__ == '__main__':
        httpd = make_server('127.0.0.1', 8090, run_server)
        print("我在8090等你哦...")
        httpd.serve_forever()
    

    3.2 jinja2

    • 上面的代码实现了一个简单的动态,我完全可以从数据库中查询数据,然后去替换我html中的对应内容,然后再发送给浏览器完成渲染。 这个过程就相当于HTML模板渲染数据。 本质上就是HTML内容中利用一些特殊的符号来替换要展示的数据。 我这里用的特殊符号是我定义的,其实模板渲染有个现成的工具: jinja2
    • 下载jinja2:
    pip install jinja2
    
    • index2.html文件
    <!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>
        <h1>姓名:{{name}}</h1>
        <h1>爱好:</h1>
        <ul>
            {% for hobby in hobby_list %}
            <li>{{hobby}}</li>
            {% endfor %}
        </ul>
    </body>
    </html>
    
    • 使用jinja2渲染index2.html文件:
    from wsgiref.simple_server import make_server
    from jinja2 import Template
    
    
    def index():
        with open("index2.html", "r") as f:
            data = f.read()
        template = Template(data)  # 生成模板文件
        ret = template.render({"name": "Alex", "hobby_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('', 8000, run_server)
        print("Serving HTTP on port 8000...")
        httpd.serve_forever()
    
    • 使用pymysql连接数据库:
    conn = pymysql.connect(host="127.0.0.1", port=3306, user="root", passwd="xxx", db="xxx", charset="utf8")
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    cursor.execute("select name, age, department_id from userinfo")
    user_list = cursor.fetchall()
    cursor.close()
    conn.close()
    
    • 创建一个测试的user表:
    CREATE TABLE user(
      id int auto_increment PRIMARY KEY,
      name CHAR(10) NOT NULL,
      hobby CHAR(20) NOT NULL
    )engine=innodb DEFAULT charset=UTF8;
    
    • 模板的原理就是字符串替换,我们只要在HTML页面中遵循jinja2的语法规则写上,其内部就会按照指定的语法进行相应的替换,从而达到动态的返回内容。

    • 转自https://www.cnblogs.com/liwenzhou/p/8258992.html

  • 相关阅读:
    《Programming in Lua 3》读书笔记(十)
    《Programming in Lua 3》读书笔记(九)
    《Programming in Lua 3》读书笔记(八)
    [原]NYOJ-括号匹配-2(java)
    [原]NYOJ-字符串替换-113
    [原]NYOJ-小光棍数-458
    [原]NYOJ-公约数和公倍数 -40
    [原]NYOJ-开灯问题-77
    [原]NYOJ-数的位数-69
    [原]NYOJ-大数阶乘-28
  • 原文地址:https://www.cnblogs.com/xiaoqshuo/p/10020100.html
Copyright © 2011-2022 走看看