zoukankan      html  css  js  c++  java
  • 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
    
    header2:v2
    

    使用  隔多个header

    HTTP POST请求格式:

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

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

    HTTP响应的格式:

    200 OK
    Header1:v1
    
    Header2:v2
    
    
    
    
    响应体...

    让我们的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
    
    ")  头部
        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 61s8
                    > 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)   这样是穿过去的数据是字典

  • 相关阅读:
    kvm
    docker及lvs负载
    zookeeper,及k8s基础概念
    zabbix-proxy及ELK
    gitlab及jenkins
    绘图 Matplotlib Numpy Pandas
    Elasticsearch
    Git命令小结
    win黑窗口命令
    Linux基础命令
  • 原文地址:https://www.cnblogs.com/wangkun122/p/8269945.html
Copyright © 2011-2022 走看看