虫虫

Django老男孩笔记

2019-02-21  本文已影响4人  莫辜负自己的一世韶光

Django基础篇

注意:
web通信的时候必须遵循HTTP协议,而HTTP协议的请求和响应是有固定的格式的.比如,我们现在写一个简单的web应用,打印出浏览器的请求体,如果只是单纯的发送二进制,在浏览器那边访问的时候会出现如下的页面

import socket

# 1. 生成socket实例对象
sk = socket.socket()
# 2. 绑定IP地址和端口
sk.bind(('127.0.0.1', 8000))
# 3. 设置监听
sk.listen()

# 循环等待客户端的连接
while 1:
    conn, addr = sk.accept()
    # 接收客户端发来的消息
    data = conn.recv(4096)
    print(data)  # 打印一下浏览器发送的消息是什么
    '''
    b'GET / HTTP/1.1\r\n  //请求行
    Host: 127.0.0.1:8000\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\n
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36\r\n
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\n
    Accept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\n
    # 中间全部是请求头
    \r\n'   这里是空行
    
    //请求体没有,没有请求体.
    '''
    # 给客户端回消息
    conn.send(b'qnmd')

    # 关闭连接
    conn.close()
    sk.close()

HTTP之请求消息Request

第一部分:

<请求行> 用来说明请求类型,要访问的资源路径,以及使用的协议版本
GET / HTTP/1.1\r\n 请求方法(GET) 请求的URL(/这里省略了域名) HTTP/1.1(请求协议) 回车符换行符

第二部分:

<请求头> 紧接着第一行之后的部分,用来说明服务器要使用的附加信息
Host: 127.0.0.1:8000\r\nConnection: keep-alive\r\n
Upgrade-Insecure-Requests: 1\r\n
User-Agent: Mozilla/5.0 (Windows NT 10.0;)/r/n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8\r\n
Accept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\n

第三部分:

<空行> 请求头后面的空行是必须的
即使后面没有请求体,空行也是必须的 \r\n

第四部分:

<请求主体> 可以添加任意的其他数据
name=Professional%20Ajax&publisher=Wiley


HTTP之响应消息Response

一般情况下,服务器接收并处理客户端发送过来的请求后会返回一个HTTP的响应消息
HTTP响应也由四部分构成:状态行,响应头部,空行和响应正文

第一部分:

状态行 HTTP协议版本 状态码 状态描述 \r\n

第二部分:

响应头部 客户端可以使用的一些信息

第三部分

空行 响应头和响应体之间必须有一个空行

第四部分

响应体 比如HTML文件,或者是其他的一些信息.

上面的例子由于只是发了二进制文件,并没有按照规定的格式发送,所以浏览器会报网站有错误.如何解决呢?
解决的根本途径就是按照它们的格式发送对应的响应体

按照HTTP协议的响应格式,发送响应,并且规定写清楚响应体的具体的类型.(text/html)和使用的编码(charset=utf-8)

import socket

# 1. 生成socket实例对象
sk = socket.socket()
# 2. 绑定IP地址和端口
sk.bind(('127.0.0.1', 8000))
# 3. 设置监听
sk.listen()

# 循环等待客户端的连接
while 1:
    conn, addr = sk.accept()
    # 接收客户端发来的消息
    data = conn.recv(4096)
    print(data)  # 打印一下浏览器发送的消息是什么
    '''
    b'GET / HTTP/1.1\r\n  //请求行
    Host: 127.0.0.1:8000\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\n
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36\r\n
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\n
    Accept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\n
    # 中间全部是请求头
    \r\n'   这里是空行
    
    //请求体没有,没有请求体.
    '''
    # 给客户端回消息
    # 先按照固定的格式发送响应  状态行  响应头部  空行  响应体(响应正文)
    # 下面指定响应体的格式类型是html格式的.
    conn.send(b'HTTP/1.1 200 OK\r\ncontent-type:text/html; charset=utf-8\r\n\r\n')
    # 这里就是浏览器上想要显示的正文
    conn.send(b"<h1>I am fine and fuck you!<h1>")

    # 关闭连接+
    conn.close()
    sk.close()
import socket

# 1. 生成socket实例对象
sk = socket.socket()
# 2. 绑定IP地址和端口
sk.bind(('127.0.0.1', 8000))
# 3. 设置监听
sk.listen()

# 循环等待客户端的连接
while 1:
    conn, addr = sk.accept()
    # 接收客户端发来的消息
    data = conn.recv(4096)
    print(data)  # 打印一下浏览器发送的消息是什么
    '''
    b'GET / HTTP/1.1\r\n  //请求行
    Host: 127.0.0.1:8000\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\n
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36\r\n
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\n
    Accept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\n
    # 中间全部是请求头
    \r\n'   这里是空行
    
    //请求体没有,没有请求体.
    '''
    # 首先是获取请求的url是什么
    # 先给数据转换为字符串
    str_data = str(data, encoding='utf-8')
    # 然后进行分割,分成两部,先取到请求行,然后再将请求行按照空格进行分割,找到请求路径
    url = str_data.split('\r\n')[0].split(' ')[1]

    print(url)

    # 给客户端回消息
    # 先按照固定的格式发送响应  状态行  响应头部  空行  响应体(响应正文)
    # 下面指定响应体的格式类型是html格式的.
    conn.send(b'HTTP/1.1 200 OK\r\ncontent-type:text/html; charset=utf-8\r\n\r\n')
    # 这里就是浏览器上想要显示的正文
    if url == '/yimi/':
        response = '<h1>Hello yimi</h1>'
    elif url == '/xiaohei/':
        response = '<h1>Hello xiaohei</h1>'
    else:
        response = '<h1>404 not found!</h1>'
    conn.send(bytes(response, encoding='utf-8'))

    # 关闭连接+
    conn.close()
import socket

# 1. 生成socket实例对象
sk = socket.socket()
# 2. 绑定IP地址和端口
sk.bind(('127.0.0.1', 8000))
# 3. 设置监听
sk.listen()

def yimi(url):
    return 'hello {}'.format(url)

def xiaohei(url):
    return 'hello {}'.format(url)

def notFound(url):
    return '404 not found'


# 循环等待客户端的连接
while 1:
    conn, addr = sk.accept()
    # 接收客户端发来的消息
    data = conn.recv(4096)
    print(data)  # 打印一下浏览器发送的消息是什么
    '''
    b'GET / HTTP/1.1\r\n  //请求行
    Host: 127.0.0.1:8000\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\n
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36\r\n
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\n
    Accept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\n
    # 中间全部是请求头
    \r\n'   这里是空行
    
    //请求体没有,没有请求体.
    '''
    # 首先是获取请求的url是什么
    # 先给数据转换为字符串
    str_data = str(data, encoding='utf-8')
    # 然后进行分割,分成两部,先取到请求行,然后再将请求行按照空格进行分割,找到请求路径
    url = str_data.split('\r\n')[0].split(' ')[1]

    print(url)

    # 给客户端回消息
    # 先按照固定的格式发送响应  状态行  响应头部  空行  响应体(响应正文)
    # 下面指定响应体的格式类型是html格式的.
    conn.send(b'HTTP/1.1 200 OK\r\ncontent-type:text/html; charset=utf-8\r\n\r\n')
    # 这里就是浏览器上想要显示的正文
    if url == '/yimi/':
        response = yimi(url)
    elif url == '/xiaohei/':
        response = xiaohei(url)
    else:
        response = notFound(url)
    conn.send(bytes(response, encoding='utf-8'))
    # 关闭连接+
    conn.close()

这样还不是很好,要写很多的if else语句,可以用另外一种实现,将访问的路由url和对应的处理函数用一个元组对应起来,
然后将很多个这样的对应关系放到一个列表中.然后遍历列表,根据路由找到对应的处理函数即可

路由和函数对应关系版web应用

1>建立和客户端的通信(sockt编程)
2>客户端连接,服务端收到客户端的请求.
3>按照格式解析客户端的请求,获取到请求的路径
4>按照路径和函数的对应关系,获取对应的要调用的处理函数
5>处理函数进行对应的处理,然后返回要响应的内容,服务器再发送给客户端,客户端想要请求的内容

import socket

# 1. 生成socket实例对象
sk = socket.socket()
# 2. 绑定IP地址和端口
sk.bind(('127.0.0.1', 8000))
# 3. 设置监听
sk.listen()


def yimi(url):
    return 'hello {}'.format(url)


def xiaohei(url):
    return 'hello {}'.format(url)


def notFound(url):
    return '404 not found'


# 循环等待客户端的连接
while 1:
    conn, addr = sk.accept()
    # 接收客户端发来的消息
    data = conn.recv(4096)
    print(data)  # 打印一下浏览器发送的消息是什么
    '''
    b'GET / HTTP/1.1\r\n  //请求行
    Host: 127.0.0.1:8000\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\n
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36\r\n
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\n
    Accept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\n
    # 中间全部是请求头
    \r\n'   这里是空行
    
    //请求体没有,没有请求体.
    '''
    # 首先是获取请求的url是什么
    # 先给数据转换为字符串
    str_data = str(data, encoding='utf-8')
    # 然后进行分割,分成两部,先取到请求行,然后再将请求行按照空格进行分割,找到请求路径
    url = str_data.split('\r\n')[0].split(' ')[1]

    print(url)

    # 先将路由和处理函数的对应关系写到一个列表中
    url_funcs = [
        ('/yimi/', yimi),
        ('/xiaohei/', xiaohei),
    ]

    # 遍历路由和函数的列表,根据不同的路由,获取不同的出去函数
    for i in url_funcs:
        if url == i[0]:
            func = i[1]
            break
    else:
        func = notFound

    response = func(url)

    # 给客户端回消息
    # 先按照固定的格式发送响应  状态行  响应头部  空行  响应体(响应正文)
    # 下面指定响应体的格式类型是html格式的.
    conn.send(b'HTTP/1.1 200 OK\r\ncontent-type:text/html; charset=utf-8\r\n\r\n')
    # 这里就是浏览器上想要显示的正文

    conn.send(bytes(response, encoding='utf-8'))
    # 关闭连接+
    conn.close()

返回具体的html文件的web服务端示例
将返回的字符串换成具体的html文件

import socket

# 1. 生成socket实例对象
sk = socket.socket()
# 2. 绑定IP地址和端口
sk.bind(('127.0.0.1', 8000))
# 3. 设置监听
sk.listen()


def yimi(url):
    with open('yimi.html','rb') as f:
        ret = f.read()
    return ret


def xiaohei(url):
    with open('xiaohei.html','rb') as f:
        ret = f.read()
    return ret


def notFound(url):
    return b'404 not found'


# 循环等待客户端的连接
while 1:
    conn, addr = sk.accept()
    # 接收客户端发来的消息
    data = conn.recv(4096)
    print(data)  # 打印一下浏览器发送的消息是什么
    '''
    b'GET / HTTP/1.1\r\n  //请求行
    Host: 127.0.0.1:8000\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\n
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36\r\n
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\n
    Accept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\n
    # 中间全部是请求头
    \r\n'   这里是空行
    
    //请求体没有,没有请求体.
    '''
    # 首先是获取请求的url是什么
    # 先给数据转换为字符串
    str_data = str(data, encoding='utf-8')
    # 然后进行分割,分成两部,先取到请求行,然后再将请求行按照空格进行分割,找到请求路径
    url = str_data.split('\r\n')[0].split(' ')[1]

    print(url)

    # 先将路由和处理函数的对应关系写到一个列表中
    url_funcs = [
        ('/yimi/', yimi),
        ('/xiaohei/', xiaohei),
    ]

    # 遍历路由和函数的列表,根据不同的路由,获取不同的出去函数
    for i in url_funcs:
        if url == i[0]:
            func = i[1]
            break
    else:
        func = notFound

    response = func(url)

    # 给客户端回消息
    # 先按照固定的格式发送响应  状态行  响应头部  空行  响应体(响应正文)
    # 下面指定响应体的格式类型是html格式的.
    conn.send(b'HTTP/1.1 200 OK\r\ncontent-type:text/html; charset=utf-8\r\n\r\n')
    # 这里就是浏览器上想要显示的正文

    conn.send(response)
    # 关闭连接+
    conn.close()

上面我们返回的都是静态网页,至于动态网页是怎么实现的呢?

动态网页的实现,本质上是字符串的替换.事先在html文件中,将需要动态展示的地方,有一个字符串进行标记.
然后服务器端读取这个html文件,当需要动态展示的时候,用replace方法将原来占位标记的字符串替换为需要展示
的字符串,然后返回给客户端.

import socket

# 1. 生成socket实例对象
sk = socket.socket()
# 2. 绑定IP地址和端口
sk.bind(('127.0.0.1', 8000))
# 3. 设置监听
sk.listen()

import time


def yimi(url):
    with open('yimi.html', 'r', encoding='utf-8') as f:
        ret = f.read()
        ret = ret.replace('@@xx@@', time.ctime())
    return bytes(ret, encoding='utf-8')


def xiaohei(url):
    with open('xiaohei.html', 'rb') as f:
        ret = f.read()
    return ret


def notFound(url):
    return b'404 not found'


# 循环等待客户端的连接
while 1:
    conn, addr = sk.accept()
    # 接收客户端发来的消息
    data = conn.recv(4096)
    print(data)  # 打印一下浏览器发送的消息是什么
    '''
    b'GET / HTTP/1.1\r\n  //请求行
    Host: 127.0.0.1:8000\r\nConnection: keep-alive\r\nUpgrade-Insecure-Requests: 1\r\n
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36\r\n
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\n
    Accept-Encoding: gzip, deflate, br\r\nAccept-Language: zh-CN,zh;q=0.9\r\n
    # 中间全部是请求头
    \r\n'   这里是空行
    
    //请求体没有,没有请求体.
    '''
    # 首先是获取请求的url是什么
    # 先给数据转换为字符串
    str_data = str(data, encoding='utf-8')
    # 然后进行分割,分成两部,先取到请求行,然后再将请求行按照空格进行分割,找到请求路径
    url = str_data.split('\r\n')[0].split(' ')[1]

    print(url)

    # 先将路由和处理函数的对应关系写到一个列表中
    url_funcs = [
        ('/yimi/', yimi),
        ('/xiaohei/', xiaohei),
    ]

    # 遍历路由和函数的列表,根据不同的路由,获取不同的出去函数
    for i in url_funcs:
        if url == i[0]:
            func = i[1]
            break
    else:
        func = notFound

    response = func(url)

    # 给客户端回消息
    # 先按照固定的格式发送响应  状态行  响应头部  空行  响应体(响应正文)
    # 下面指定响应体的格式类型是html格式的.
    conn.send(b'HTTP/1.1 200 OK\r\ncontent-type:text/html; charset=utf-8\r\n\r\n')
    # 这里就是浏览器上想要显示的正文

    conn.send(response)
    # 关闭连接+
    conn.close()

socket服务端功能划分

常见的框架分类,以及包含哪些部分.

WSGI

简介
WSGI(Web Server Gateway Interface,web 服务器网关接口)是python语言中所定义的web服务器和web应用程序之间或框架之间的通信接口标准.类似一种协议和规定.

为什么需要WSGI
我们在web开发的过程中,我们经常会把常用的功能封装起来,例如Django,Flask框架.但是服务器端和应用程序端需要相互配合才能给用户提供服务,而不同的框架会有不同的实现方式,所以它需要一种标准,让服务器和客户端都遵循这种标准,那么两者就能很好的配合使用了.

WSGI就是一种接口标准,类似于协议.它是服务器和客户端的一种约定,规定了各自使用的接口和功能,以便它们能够很好的配合.

WSGI将Web组件分成了三类

1> Web服务器(WSGI server)
2> Web中间件(WSGI middleware)
3> Web应用程序(WSGI Applacation)

Web server接收HTTP的请求,封装所需要的一系列环境变量.按照WSGI接口标准调用注册的WSGI Application,然后将处理结果返回给客户端

web应用的本质过程

1> 用户输入网址,浏览器发送HTTP请求
2> 服务器收到浏览器的请求,按照格式解析对应的URL,也就是请求的资源位置
3> 服务器根据url,调用对应的处理函数,生成对应的HTML文档
4> 服务器端把HTML文档作为HTTP响应的body发送给浏览器
5> 浏览器收到服务器端的响应,从HTTP body取出HTML文档进行显示

Python标准库提供的独立的WSGI服务器叫wsgiref,Django开发环境用的就是这个模块来做服务器的

我们python的标准库wsgiref模块代替我们写的web框架的socket server部分.
主要分成以下几步

1> 定义不同的url对应的视图处理函数
2> 定义url和要执行的函数的对应关系
3> 定义一个run_server(environ,start_response)函数,在里面社会响应的头部信息,以及根据url获取对应的要执行的函数.
然后返回一个列表[response,]
4> 主函数调用make_server,设置服务器的地址和端口以及一开始要运行的函数接口. 再调用server_forever()启动服务器.

# encoding:utf-8
__author__ = 'Fioman'
__time__ = '2019/2/19 14:26'
import time
from wsgiref.simple_server import make_server


# 将url对应的处理程序封装成函数
def yimi(url):
    with open('yimi.html', 'r', encoding='utf-8') as f:
        s = f.read()
        s = s.replace('@@xx@@', time.ctime())
    return bytes(s, encoding='utf-8')


def xiaohei(url):
    with open('xiaohei.html', 'r', encoding='utf-8') as f:
        s = f.read()
    return bytes(s, encoding='utf-8')


# 定义个url和要执行的函数之间的对应关系
url_funcs = [
    ('/yimi/', yimi),
    ('/xiaohei/', xiaohei),
]


# 定义run_server函数
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_funcs:
        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', 8000, run_server)
    print('我在8000端口等你哦')
    httpd.serve_forever()

Django基础知识

初始创建一个Django项目的时候的目录介绍

settings.py 文件中内容介绍
1. 路径相关

2.Django基础必备三件套

def index(request):
    # 业务逻辑代码
    return HttpResponse("OK")
def index(request):
    # 业务逻辑代码
    return render(request, "index.html", {"name": "alex", "hobby": ["烫头", "泡吧"]})
def index(request):
    # 业务逻辑代码
    return redirect("/home/")

重定向是怎么回事

标准意义上的“重定向”指的是HTTP重定向,它是HTTP协议规定的一种机制。这种机制是这样工作的:当client向server发送一个请求,要求获取一个资源时,在server接收到这个请求后发现请求的这个资源实际存放在另一个位置,于是server在返回的response中写入那个请求资源的正确的URL,并设置reponse的状态码为301(表示这是一个要求浏览器重定向的response),当client接受到这个response后就会根据新的URL重新发起请求。重定向有一个典型的特症,即:当一个请求被重定向以后,最终浏览器上显示的URL往往不再是开始时请求的那个URL了。这就是重定向的由来.

MVC和MTV模式的介绍

MVC模式指的是Model(模型),View(视图),Controller(控制)
1)最上面一层,是直接面向最终用户的视图层.它提供给用户的操作界面,是程序的外壳
2)最底下一层,是核心的数据层(Model),也就是程序需要操作的数据或信息
3)中间的一层,就是控制层,它负责根据用户从视图层输入的指令,选取数据层中的数据,然后对其进行相关的操作,产生最终的结果

Django框架的设计借鉴了MVC框架的思想,也是分成三部分. 它和MVC的不同之处是它分成了MTV模式
Model(模型): 负责业务对象与数据库对象(ORM)
Template(模板): 负责如何把页面展示给用户
View(视图): 负责业务逻辑,并在适当的时候调用Model和Template

APP
一个django项目可以分成很多个app,用来隔离不同功能模块的代码

命令行创建
python manage.py startapp app01

pycharm创建
打开manage.py任务管理器,然后输入 startapp app01就可以创建

创建以后一定要注册

ORM

ORM概念

对象关系映射(object relationship mapping对象关系模型),通过对象和数据库之间建立一种映射关系,将程序中数据方便的存储到数据库中的一种技术.

ORM的由来
几乎所有的软件开发过程中都会涉及到对象和关系数据库.在用户层面和业务逻辑层面,我们是面向对象的.当对象的信息发生变化的时候,我们就需要将数据的信息保存到数据库中.而按照传统的做法是要写很多重复的SQL语句,这样开发效率就会很低.所以Django开发了ORM,用对象的操作来代替SQL语句的操作

ORM的优点
ORM解决的主要问题是对象和关系的映射.通常一个类对应一张数据表,类的每个实例对应表中的一条记录,而类的属性对相应表中的字段.
不用直接编写SQL语句,让程序员专注于业务逻辑,提高了开发效率.

ORM的缺点
ORM的缺点是一定程序上牺牲了程序的执行效率.并且需要记忆这个特殊的语法,如果ORM使用的多了,SQL语句的操作的能力就会有所退化.

ORM能做哪些事
1.操作数据表 创建表/删除表/修改表
操作models.py里面的类
2.操作数据行 数据的增删改查
不能做的事情是,不能创建数据库,需要手动创建数据库

使用Django的ORM的详细步骤

create database mysite;
import pymysql

# 告诉Django用pymysql代替默认的MySQLdb
pymysql.install_as_MySQLdb()
class UserInfo(models.Model):
    id = models.AutoField(primary_key=True)  # 创建一个自增的主键字段
    name = models.CharField(null=False, max_length=32)  # 创建一个varchar(32)类型的不能为空的字段

    # 当打印这个类的值得时候会调用这个方法
    def __str__(self):
        return "<{}-{}>".format(self.id, self.name)

ORM的相关操作
表的查询操作
1. 查询所有的数据,返回一个列表

2. 为一个表添加一条数据

3. 删除一条数据
我们删除数据的时候,要知道删除的是哪一条,需要在url中以参数的形式传递过去.

而这个id的值,在后台是可以通过如下的方式获取的

4. 修改数据
修改的时候一样要知道修改的是哪一条,,需要在url中以参数的形式传递过去.

 编辑出版社的视图函数
def edit_publisher(request):
    if request.method == 'POST':
        # 如果是post请求,用户已经编辑完成提交过来,我们要知道提交的是哪个出版社
        # 1.先获取是哪个出版社
        edit_id = request.POST.get('id', None)
        # 2.根据id获取要编辑的对象
        edit_obj = models.Publisher.objects.get(id=edit_id)
        # 3.修改对象的值,取到对应的属性,直接赋值即可,寄到保存.修改的时候要保存才能在数据库中生效
        # 而创建和删除的时候不用保存
        new_name = request.POST.get('publisher_name', None)
        edit_obj.name = new_name
        edit_obj.save()

        return redirect('/publisher_list/')

    # 当是get请求的时候,只是要显示编辑界面,这个时候我们可以将要编辑的出版社先显示在编辑界面上,通过url的参数,获取id
    edit_id = request.GET.get('id', None)
    # 根据id获取要编辑的出版社对象
    edit_obj = models.Publisher.objects.get(id=edit_id)

    return render(request, 'edit_publisher.html', {'publisher': edit_obj})

修改数据的思路
1> 首先是获取要修改的模型的orm对象
2> 然后通过属性赋值,修改字段的值
3> 修改之后一定要保存,才能在数据库中生效

ORM的多表关联
当是一对多的关系时,一般在多的表中建立外键,Django带的ORM会自动的在字段的后面加_id,所以我们在创建字段的时候
不需要在后面加上_id

下面是一个ORM中多表关联的一个示例

# 书 和出版社的关系是多对一的关系
class Book(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(null=False,unique=True,max_length=64) # 书名
    publisher = models.ForeignKey(to='Publisher') # 外键,表示的是出版社对象,而在数据库存储的是publisher_id

在前端页面book_obj.publisher获取的是出版社对象,而book_obj.publisher_id获取的才是出版社id,关键的外键id值

如果数据库中已经有了数据,这个时候我们要在models.py中添加新的字段,如果没有设定默认值.会出现如下情况

数据库表的多对多的关系,利用第三张表建立关联

ORM中创建表的时候,可以指定为多对多关系,Django的ORM会自动生成第三张关联的表

多对多的关系在使用的时候,可以从一个对象,获取和它关联的对象.因为是多对多,所以要用all来获取,他的对象列表

当用form表单提交的是单个数据的时候,我们在后端获取这个值一般用get('name属性'),但是如果是提交了多个值,并且在后端要一次性获取这些值得时候,就不能用get,而应该用getlist()

还有一点就是多对多的关系表中,怎么创建一条记录.创建一条记录的时候,如果把跟它关联的那张表中值,保存到数据库中

上一篇下一篇

猜你喜欢

热点阅读