Django基础 一

1、POST和GET是HTTP协议定义的与服务器交互的方法。GET一般用于获取/查询 资源信息,而POST一般用于更新 资源信息。还有另两种方法是PUT和DELETE

2、POST和GET都可以与服务器交互完成查、改、增、删的操作。  注意都是大写的  而且都是客户端对服务端的请求

<form> 标签的 action 属性

form表单是用于提交数据的,  action就是将数据提交到哪儿  

如       <form action="/index/" method="post">   这个是将数据提交到   当前主网页的   /index/  中去   方法是post

Web框架本质

我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端。 这样我们就可以自己实现Web框架了。

import socket

sk = socket.socket()
sk.bind(("127.0.0.1", 80))
sk.listen(5)


while True:
    conn, addr = sk.accept()
    data = conn.recv(8096)
    conn.send(b"OK")
    conn.close()

可以说Web服务本质上都是在这十几行代码基础上扩展出来的。这段代码就是它们的祖宗。

用户的浏览器一输入网址,会给服务端发送数据,那浏览器会发送什么数据?怎么发?这个谁来定? 你这个网站是这个规定,他那个网站按照他那个规定,这互联网还能玩么?

所以,必须有一个统一的规则,让大家发送消息、接收消息的时候有个格式依据,不能随便写。

这个规则就是HTTP协议,以后浏览器发送请求信息也好,服务器回复响应信息也罢,都要按照这个规则来。

HTTP协议主要规定了客户端和服务器之间的通信格式,那HTTP协议是怎么规定消息格式的呢?

让我们首先看下我们在服务端接收到的消息是什么。

 

然后再看下我们浏览器收到的响应信息是什么。

响应头在浏览器的network窗口可以看到,我们看到的HTML页面内容就是响应体。本质上还是字符串,因为浏览器认识HTML,所以才会渲染出页面。

HTTP协议介绍

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

HTTP GET请求的格式:

GET /path HTTP/1.1     注意这里有一个空格 
header1:v1\r\n
header2:v2\r\n

使用 \r\n隔多个header

HTTP POST请求格式:

POST /path HTTP/1.1
header1:v1\r\n
header2:v2\r\n
\r\n\r\n
请求体...

当遇到连续两个 \r\n\r\n,表示Header部分结束了,后面的数据是Body

HTTP响应的格式:

200 OK
Header1:v1\r\n
Header2:v2\r\n
\r\n\r\n
响应体...

让我们的Web框架在给客户端回复响应的时候按照HTTP协议的规则加上响应头,这样我们就实现了一个正经的Web框架了。

import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('127.0.0.1', 8000))
sock.listen(5)

while True:
    conn, addr = sock.accept()
    data = conn.recv(8096)
    conn.send(b"HTTP/1.1 200 OK\r\n\r\n")  头部
    conn.send(b"OK")  打印的信息
    conn.close()

上述通过socket来实现了其本质。

对于真实开发中的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开发环境用的就是这个模块来做服务器。

wsgiref模块示例

from wsgiref.simple_server import make_server

def index():
    return "这是index页面"

def home():
    return "这是home页面"

def login():
    with open("login.html", encoding="utf8") as f:
        data = f.read()
    return data

URL_FUNC = [
    ("/index/", index),
    ("/home/", home),
    ("/login/", login),
]

def run_server(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html;charset=utf8')])  # 设置HTTP响应的状态码和头信息
    url = environ['PATH_INFO']  # 取到用户输入的url
    print("--->url:", url)
    # 根据url的不同,返回不同的内容
    func_name = None
    for i in URL_FUNC:
        if url == i[0]:  # 如果能找到对应关系,就把函数名拿到
            func_name = i[1]
            break
    # 拿到可以执行的函数,执行函数拿到结果
    if func_name:
        body = func_name()
    else:
        body = "404找不到这个页面"

    return [bytes("<h1>{}</h1>".format(body), encoding="utf8"),]


if __name__ == '__main__':
    httpd = make_server('', 8000, run_server)
    print("Serving HTTP on port 8000...")
    httpd.serve_forever()

解决了不同URL返回不同内容的需求。 但是问题又来了,如果有很多很多页面怎么办?难道要挨个判断? 当然不用,我们有更聪明的办法。

from wsgiref.simple_server import make_server


def index():
    return [bytes("<h1>这是index页面</h1>", encoding="utf8"), ]    #这里注意返回值的格式一定要设置成bytes格式,因为信息传送是要bytes格式


def home():
    return [bytes("<h1>这是home页面</h1>", encoding="utf8"), ]


# 定义一个url和函数的对应关系
URL_LIST = [
    ("/index/", index),
    ("/home/", home),
]


def run_server(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html;charset=utf8'), ])  # 设置HTTP响应的状态码和头信息  返回的格式要是utf8  
                                              与返回的信息格式保持一致,才能翻译好
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"), ] #格式保持一值 utf8 if __name__ == '__main__': httpd = make_server('', 8000, run_server) print("Serving HTTP on port 8000...") httpd.serve_forever()

依据客户端的位置选则性返回相应的网站内容

这里返回的是一个HTML文件组成的字符串,浏览器解析渲染出来网页

from wsgiref.simple_server import make_server

def index():
    with open("index.html", encoding="utf8") as f:
        data = f.read()  将写好的HTML文件读取出来写在变量里,用于稍后的返回给客户端的浏览器

    # 连接数据库
    import pymysql
    # 连接
    conn = pymysql.connect(host="localhost", user="root", password="root1234", database="s8", charset="utf8")  # 没有-
    # 获取光标
    cursor = conn.cursor()
    # 写sql语句
    sql = "select name, pwd from userinfo where id =1;"
    cursor.execute(sql)
    ret = cursor.fetchone()
    print(ret)
    # 将数据库中的数据填充到HTML页面
    new1_data = data.replace("@@2@@", ret[0])
    new2_data = new1_data.replace("##3##", ret[1])

    return new2_data    吧信息填好,返回给浏览器的请求端,然后就能将从数据库中取出的内容都出来

def home():
    return "这是home页面"

def login():
    with open("login.html", encoding="utf8") as f:
        data = f.read()
    import time
    time_str = str(time.time())
    new_data = data.replace("@@2@@", time_str)
    return new_data

URL_FUNC = [
    ("/index/", index),
    ("/home/", home),
    ("/login/", login),
]

def run_server(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html;charset=utf8')])  # 设置HTTP响应的状态码和头信息
    url = environ['PATH_INFO']  # 取到用户输入的url
    print("--->url:", url)
    # 根据url的不同,返回不同的内容
    func_name = None
    for i in URL_FUNC:
        if url == i[0]:  # 如果能找到对应关系,就把函数名拿到
            func_name = i[1]
            break
    # 拿到可以执行的函数,执行函数拿到结果
    if func_name:
        body = func_name()
    else:
        body = "404找不到这个页面"

    return [bytes("<h1>{}</h1>".format(body), encoding="utf8"),]


if __name__ == '__main__':
    httpd = make_server('', 8000, run_server)
    print("Serving HTTP on port 8000...")
    httpd.serve_forever()

其实模板渲染有个现成的工具: jinja2

<!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标签   jinjia2主要是对这里进行渲染,让一些内容可以导入并进行替换中括号中的内容
        <li>{{hobby}}</li>
        {% endfor %}
    </ul>
</body>
</html>

 

使用jinja2渲染index2.html文件:   这里用到了render

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()

 

模板的原理就是字符串替换,我们只要在HTML页面中遵循jinja2的语法规则写上,其内部就会按照指定的语法进行相应的替换,从而达到动态的返回内容。

Django

Django官网下载页面

安装(安装最新LTS版):

pip3 install django==1.11.9   注意正常是pip install  但是有的时候给程序  即在cmd 中启动Python 时 用的名字是 Python3  所以给他装也加上那个序号

创建一个django项目:

新建Django项目:
            命令行方式:
                > 先进入到你新建的项目要存放的目录   cd /d D:\py\上课内容\day 61\s8
                > django-admin startproject s8
                > cd s8  进入刚建成的项目中去
                > python manage.py runserver
            PyCharm方式:
                File -> new project -> 选Django -> 起名字 -> 点右下角create
                

 

 

 

目录介绍:

复制代码
mysite/
├── manage.py  # 管理文件
└── mysite  # 项目目录
    ├── __init__.py
    ├── settings.py  # 配置
    ├── urls.py  # 路由 --> URL和函数的对应关系
    └── wsgi.py  # runserver命令就使用wsgiref模块做简单的web server
复制代码

运行Django项目:

python manage.py runserver 127.0.0.1:8000

settings.py中的配置

模板文件配置:  这个在settings.py文件中

templates这个文件夹中只放  html 文件

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, "template")],  # template文件夹位置  当前学的是
        'APP_DIRS': True,    DIRS指的是目录  在setting中的有对它进行设置, 
      os.path.join 拼接路径, BADE_DIR当前文件的符路径的父路径 然后拼接上templates ,就是他的路径
'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ]

静态文件配置:  

static  也是新建一个文件夹,这里通常存放 css js 文件

这个在settings.py文件中

STATIC_URL = '/static/'  # HTML中使用的静态文件夹前缀
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),  # 静态文件存放位置 static是文件夹的名字  base_dir是
]   

看不明白?有图有真相:

刚开始学习时可在配置文件中暂时禁用csrf中间件,方便表单提交测试。

以免影响自己在本地试验

 

Django基础必备三件套:

from django.shortcuts import HttpResponse, render, redirect

HttpResponse

内部传入一个字符串参数,返回给浏览器。 也可以是标签对象

例如:

def index(request):
    # 业务逻辑代码
    return HttpResponse("OK")

render

除request参数外还接受一个待渲染的模板文件(就是html文件)和一个保存具体数据的字典参数。

将数据填充进模板文件,最后把结果返回给浏览器。(类似于我们上面用到的jinja2)

例如:

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

redirect

接受一个URL参数,表示跳转到指定的URL。

例如:

def index(request):
    # 业务逻辑代码
    return redirect("/home/")

跟request相关的方法:
request.method
request.POST
request.POST.get("key") --> 获取对应的值

新建Django项目三件事:
1.注释csrf那一行
2. 配置静态文件
3. 检查templates配置项

课后练习:

实现登录验证功能

from django.shortcuts import HttpResponse,render,redirect
def index(request):  #表示所有跟请求相关的数据都放在request中
    # return HttpResponse(b'<h1>hello</h1>')
    error_msg=''
    print(request.method)#获得并打印当前请求的方法,在未点提交前方法是 GET 所以if 条件不成立,
    # 先执行最后一 渲染网页,当点击提交的时候 此时 request.method 的是POST所以执行判断登录信息
    if request.method=="POST":
        #获取用户输入的用户名和密码,因为用户输入的信息在后端是以字典的形式保存的,所以直接get 键 获得值
        name=request.POST.get('username')
        pwd=request.POST.get('password')
        print(name,pwd)
        #去数据库中去对比输入信息是否正确
        import pymysql
        conn=pymysql.connect(host='localhost',user='root',password='123456',database='db2',charset='utf8')
        cursor=conn.cursor()
        sql='select name,psw from s8 where name=%s'
        ret=cursor.execute(sql,name)
        if ret==0:
            error_msg='无此用户'
        if ret==1:
            name1,psw=cursor.fetchone()
            cursor.close()
            conn.close()
            print(name1,psw,name,pwd)
            if ret==1:
                if psw==pwd:
                    # redirect立即跳转到相应网站
                    return redirect('https://www.baidu.com/')
                # 否则给 error 赋值 密码错误,
                else:
                    error_msg = '密码错误'

    return render(request,'denglu.html',{"error":error_msg}) #给客户端返回这个网站


urlpatterns = [
    url(r'index/',index),#url中有 index/ 就执行 index
]
View Code

 for 循环 和 if语句的使用

for循环的写法

开头:                  {% for class in calss_list %}

中间可以使用相应的值  如       <th scope="row">{{ class.id }}</th>

结尾:                  {% endfor %}

for循环详见

http://www.cnblogs.com/wangkun122/p/8278045.html

if语句的写法  如下

if 判断:
{% if student.cid == class.id %}
<option selected value="{{ class.id }}">{{ class.cname }}</option>
{% else %}
<option value="{{ class.id }}">{{ class.cname }}</option>
{% endif %}

编辑页函数代码

def edit(request):
    if request.method=='GET':
        name=''
        ret=request.GET.get('id')
        print(ret)
        conn = pymysql.connect(host='localhost', user='root', password='123456',
                               database='db1', charset='utf8')
        cursor = conn.cursor(pymysql.cursors.DictCursor)
        sql = 'select id,cname from class where id=%s'
        cursor.execute(sql, ret)
        ret2 = cursor.fetchone()
        print(ret2)
        conn.commit()
        cursor.close()
        conn.close()
        name=ret2
        return render(request,'eidt.html',{"name":name})
    if request.method == 'POST':
        retid = request.POST.get('id')
        retname = request.POST.get('name')
        print(retid,retname)
        conn = pymysql.connect(host='localhost', user='root', password='123456',
                               database='db1', charset='utf8')
        cursor = conn.cursor(pymysql.cursors.DictCursor)
        sql = 'update class set cname=%s where id=%s'
        cursor.execute(sql,(retname,retid))
        # ret2 = cursor.fetchone()
        conn.commit()
        cursor.close()
        conn.close()
        return redirect('/classlist/')
View Code

编辑学生菜单操作   html端的写法   if  else   语句

          <select name="cid" id="">
                #先用for循环取出每一个值
                    {% for class in class_list %}
                        #然后再用if  else 语句判断是否符合条件
                        {% if class.id == student_list.cid %}
                        #符合条件的即编辑之前的id  和 班级名称,设为默认选中值
                            <option value="{{ class.id }}" selected>{{ class.cname }}</option>
                        {% else %}
                            <option value="{{ class.id }}">{{ class.cname }}</option>
                         #以 endif 结尾
                        {% endif %}
                        #结束for循环
                    {% endfor %}
                </select>

 

总结:  常与后端传过来的含有多个字典的列表配合使用

后端的 cursor = conn.cursor(pymysql.cursors.DictCursor)   这样是穿过去的数据是字典

 

posted on 2018-01-11 19:32  王大拿  阅读(203)  评论(0编辑  收藏  举报

导航