• 框架基础, django下载与基本使用


    模拟服务器给客户端发送数据

    import socket
    import time
    
    sk = socket.socket()
    sk.bind(("127.0.0.1",8001))
    sk.listen()
    
    
    def gen():
        timer = str(time.time())
        with open('text.html','r',encoding='utf-8') as fp:
            data = fp.read()
            data_str = data.replace('%abcd%',timer)
            data = data_str.encode()
        return data
    def photo():
        with open('text.png','rb') as fp:
            data = fp.read()
        return data
    def jingdong():
        with open('jd.ico','rb') as fp:
            data = fp.read()
        return data
    def css():
        with open('text.css','rb') as fp:
            data = fp.read()
        return data
    def js():
        with open('text.js','rb') as fp:
            data = fp.read()
        return data
    lst = [('/',gen),('/text.png',photo),('/jd.ico',jingdong),('/text.css',css),('/text.js',js)]
    while 1:
        print("服务器已启动")
        conn, addr = sk.accept()
        msg = conn.recv(1024)
        # print(msg)
        msg_str = msg.decode()
        # print(msg_str)
        conn.send(b'HTTP/1.1 200 ok
    
    ')
        path = msg_str.split(" ")[1]
        print('请求url>>> ', path)
        for i in lst:
            if path == i[0]:
                data = i[1]()
                conn.send(data)
                break
        else:
            conn.send(b'404 notfound ')
        conn.close()

    Jinja2模板渲染简单使用

    pip install jinja2

    使用示例

    html文件中标记特殊符号,比如文件名称为index.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>

    视图中的写法

    from wsgiref.simple_server import make_server
    from jinja2 import Template
    
    
    def index():
        with open("index2.html", "r",encoding='utf-8') as f:
            data = f.read()
        template = Template(data)  # 生成模板文件
        ret = template.render({"name": "bob", "hobby_list": ["running", "walking"]})  # 把数据填充到模板里面
        return [bytes(ret, encoding="utf8"), ]

     

    MVC和MTV框架

    MVC   Web服务器开发领域里著名的MVC模式,所谓MVC就是把Web应用分为模型(M),控制器(C)和视图(V)三层,结构说明如下:

    M: models 数据库相关操作
    V: views 视图,也就是业务逻辑相关操作
    C: controller  控制器,也就是通过路径找到对应视图函数
    

    MTV   Django的MTV模式本质上和MVC是一样的,也是为了各组件间保持松耦合关系,只是定义上有些许不同。

    M: models 数据库相关操作
    T: templates html文件相关操作(模板渲染等)
    V: views 视图,也就是业务逻辑相关操作
    
    加上一个url控制器,也就是通过路径找到对应视图函数
    

    WSGI

    WSGI(Web Server Gateway Interface)就是一种规范,它定义了web应用程序与web服务器程序之间的接口格式,实现web应用程序与web服务器程序间的解耦。

    开发的项目分为两个部分的程序
    1 服务器程序  socket相关功能的模块,wsgiref、uwsgi等等,负责接收网络请求并解析网络请求相关数据,分装加工成一些可用的数据格式,格式大家都是统一的,方便应用程序的开发
    
    2 应用程序  就是使用接收到的网络请求相关数据,进行逻辑代码的开发,比如数据库相关操作,数据结构的调整、文件操作等等。。。

    django

    Django是MTV模式架构的框架。历史版本介绍,参考:https://www.djangoproject.com/download/

    下载安装

    pip3 install django==1.11.9

    创建项目

    可以通过指令来创建,将来还可以通过IDE来进行创建,先看指令的写法

    django-admin startproject mysite #mysite是自己的项目名称

    执行上面的指令之后会生成如下的目录,当前目录下会生成mysite的工程,里面有个主目录和我们创建的项目目录同名,在项目目录下有个manage.py文件,在主目录下有settings.pyurls.pywsgi.py,每个文件的功能介绍如下:

    manage.py ----- Django项目里面的工具,通过它可以调用django shell和数据库,启动关闭项目与项目交互等,不管你将框架分了几个文件,必然有一个启动文件,其实他们本身就是一个文件。
    settings.py ---- 包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作的变量。
    urls.py ----- 负责把URL模式映射到应用程序。
    wsgi.py ---- runserver命令就使用wsgiref模块做简单的web server,后面会看到renserver命令,所有与socket相关的内容都在这个文件里面了

    在一个项目中可以有多个应用,每个应用完成项目的部分功能,比如微信项目,其中有很多的应用,比如朋友圈功能、聊天、支付等等。在django框架看来,每个应用都有自己的逻辑部分,数据库部分等等,所以我们进行业务逻辑开发的时候,需要创建应用来写逻辑。

    运行项目

    python manage.py runserver 127.0.0.1:8080
    ip和port可以不用写,不写的话,默认是 127.0.0.1:8000

    创建应用

    创建应用的指令如下:需要借助到我们创建的项目中的manage.py文件

    python manage.py startapp blog  #blog是应用名称

    目录介绍

    models.py  数据库相关内容
    views.py  视图,业务逻辑代码相关内容
    tests.py 用来写一些测试代码,用来测试我们自己写的视图的,目前用不到

    pycharm来创建django框架结构项目

      

    通过django来完整一个简单的web项目

    第一步 创建视图函数

    在应用文件夹下面的views.py文件中写视图函数,比如:

    def home(request):
        #request--environ  请求相关数据,request叫做HTTPRequest对象,请求相关数据都是request的属性
    
        return render(request, 'home.html')
        #render方法用来打开html文件,对文件进行模板渲染,第一个参数是request,第二个参数是html文件路径,(这里我只写了文件名称,因为django会自动去templates文件夹下面去找html文件),渲染完整之后,返回响应页面数据,最终交给wsgi中的socket将页面数据返回给客户端

    第二步:创建html文件

    如果视图响应的是一个html文件,那么我们需要在项目目录下面的templates文件夹中创建一个htm文件,比如叫做home.html

    为什么django能够自动找到templates文件夹下面的home.html文件呢?也就是我们使用render方法时,只写了一个home.html文件名称,就能够自动帮我们找到这个home.html文件,是因为在django的默认配置中有一个关于templates模板相关功能的配置项,里面指定了html文件的存放目录,找到主目录下面的settings.py,打开这个文件,找到TEMPLATES这个配置,内容如下

    #BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 项目根路径
    
    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates')] #DIRS指的就是html文件存放路径的配置,注意,有些版本的django或者通过指令来创建项目时,这个DIRS的配置是空的,需要我们自己指定html文件的存放路径,所以如果你发现这个DIRS为空,我们需要自定来配置路径,可以按照现在这种方式来写
            ,
            'APP_DIRS': True,
            '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',
                ],
            },
        },
    ]

    第三步 创建url路径和函数的映射关系

    在项目主目录的urls.py文件中的urlpatterns中写上如下内容

    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    urlpatterns = [
        # url(r'^admin/', admin.site.urls), #这是django提供的一个内置应用,暂时忽略它
        # ('/home',views.home), 我们之前的写法
    
        url(r'^home/', views.home),
    
    ]

    url中的正则路径如何找到对应的函数的,看简单分析:

    #伪代码
    import re
    path = request.path  当前请求路径
    for item in urlpatterns:
        ret = re.match(item.regex,path)  #item.regex -- ^home/
        if ret:
            item.func(request)   #item.func--views.home函数
            break
        else:
            pass

     

    简单介绍几个request对象的属性

    在views.py文件的视图函数中打印以下几个属性,看看效果:

    def home(request):
        print(request) #<WSGIRequest: GET '/home/'>  wsgi封装的一个对象,WSGIRequest类的对象
    
        print(request.path) #/home/ 请求路径
        print(request.method) #GET 请求方法
        print(request.POST)  #获取post请求提交过来的数据
            # <QueryDict: {'username': ['root'], 'password': ['123']}>
        uname = request.POST.get('username') #取出username数据
        
        return render(request, 'xx/home.html')

    完成一个登录功能

    views.py内容如下

    ####一个视图函数搞定登录功能#####
    def login(request):
    
        if request.method == 'GET':
    
            return render(request,'login.html')
    
        else:
            print(request.POST)
            # <QueryDict: {'username': ['root'], 'password': ['123']}>
            uname = request.POST.get('username')
            pwd = request.POST.get('password')
            if uname == 'root' and pwd == '123':
    
                return render(request,'xx/home.html')
            else:
                return HttpResponse('用户名或者密码错误!!请重新登录')

    urls.py文件内容如下

    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    urlpatterns = [
    
        url(r'^home/', views.home),
        url(r'^login/', views.login),
        # url(r'^login2/', views.login2),
    
    ]

    Login.html内容如下

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    
    </head>
    <body>
    <!-- /login2/ 相对路径,注意前置导航斜杠必须写,那么发送请求时,会自动在相对路径前面拼接上我们当前的ip和端口 http://127.0.0.1:8000/login2/-->
    {#<form action="/login2/" method="post">#}
    <form action="/login/" method="post">
        用户名: <input type="text" name="username">
        密码: <input type="password" name="password">
        <button>提交</button>
    </form>
    
    </body>
    
    </html>

    url路由系统

    在django中,url中的路径写法是正则,正则里面有无名分组正则,有有名分组正则,那么对应django中的功能,我们称之为无名分组路由和有名分组路由

    无名分组路由

    看写法,urls.py文件中内容如下

    urlpatterns = [
            ...
        url(r'^books/(d+)/(d+)/', views.book),
        #正则里面()分组正则,会将分组中的正则匹配到的内容作为返回值返回
    ]
    
    简单分析,伪代码
    '''
    当用户请求的路径是它: /books/2019/8/
    
    url(r'^books/(d+)/(d+)/', views.book), 里面做的事情如下
    
    re.match(^books/(d+)/,/books/2019/)
    2019 和 8 作为位置参数交给了要执行的book视图函数
    视图函数book的写法
    def book(request,xx,oo):
        xx = 2019
        oo = 8
        pass
    '''

    视图views.py文件中函数的写法

    #位置传参,url中正则^books/(d+)/(d+)/,那么第一个()分组匹配到的数据,作为book函数的第二个参数,第二个()分组匹配到的数据,作为book的第三个参数
    def book(request, year, month):
        print('year', year, 'month', month) #year 2020
    
        # return HttpResponse('%s所有书籍' % year)
        return HttpResponse('%s年%s月所有书籍' % (year, month))

    使用url路由系统时需要注意几个点

    1. urlpatterns中的元素按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续。
    2. 若要从URL中捕获一个值,只需要在它周围放置一对圆括号(正则分组匹配)。
    3. 不需要添加一个前导的反斜杠(也就是写在正则最前面的那个/),因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
    4. 每个正则表达式前面的'r' 是可选的但是建议加上。
    5. ^articles$  以什么结尾,以什么开头,严格限制路径

     

    有名分组路由

    Urls.py文件中的写法

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        # /books/2020/6/
        url(r'^books/(?P<year>d+)/(?P<month>d+)/', views.book),
        # {'year':2020,'month':6},url类将有名分组正则匹配出来的数据,交给了book视图函数作为关键字参数来使用
    
    ]

    View.py文件中函数的写法如下

    # ^books/(?P<year>d+)/(?P<month>d+)/
    #获取到url中的有名分组正则匹配到的数据,那么函数形参名称必须和有名分组正则的那个名称相同才可以,也就是按照上面的url来看的话,函数的形参必须是year和month这两个名称,并且关键字传参不需要考虑函数形参的位置
    def book(request, month, year):
        # print('year', year, 'month', month) #year 2020
        print(request.path) #/books/2020/6/
        # return HttpResponse('%s所有书籍' % year)
        return HttpResponse('%s年%s月所有书籍' % (year, month))

    补充说明

    当用户通过浏览器访问django框架完整的项目中的某个路径时,如果用户在输入网址路径的最后,没有加上/斜杠,比如http://127.0.0.1:8000/test,那么django会发将用户输入的网址路径加上一个后置的/,也就会将路径变成这样http://127.0.0.1:8000/test/,然后给浏览器发送一个重定向的响应操作,状态码为301,那么浏览器拿到这个重定向操作之后,就会自动发起一个这样的路径请求http://127.0.0.1:8000/test/,所以当我们打开浏览器控制台的network功能查看请求过程时,会看到两个请求,一个没有后置的斜杠的,一个是有后置斜杠的。第二个请求才会走到我们的urs.py文件中的路径配合和分发对应视图的地方。

    我们可以通过一个配置项,告诉django,不要自动加路径后面的斜杠了,但是需要注意的就是你自己写的url中的正则,也别加后面的斜杠,不然正则匹配不到。

    配置项直接写在settings配置文件中,任意位置

    APPEND_SLASH = False  #False表示告诉Django,不加路径后面的斜杠,默认值是True

     

    视图函数中指定默认值

    views.py文件:

    # 在路由没有匹配任何参数的时候,num使用自己的默认值
    # 当路由中有分组匹配数据的动作,比如url(r'^test/(d+)/', views.test),用户输入网址:http://127.0.0.1:8000/test/22/,那么22就被匹配到了,会作为参数传给我们的test函数,那么num的值就变成了22
    def test(request, num=10):
        print('number>>>',num)
        return HttpResponse('test')

    urls.py文件

    # url(r'^test/', views.test),
        url(r'^test/(d+)/', views.test),
  • 相关阅读:
    requests
    Unit5 Going places
    Unit1 A time to remember
    SQL:找到一个关于all some any的用法,可在SSMS里看效果
    SQL join小结
    mac 配置tomcat
    oc与java c++语法区别
    swift调用oc项目
    java网络编程之socket
    windows远程控制mac
  • 原文地址:https://www.cnblogs.com/fdsimin/p/13268233.html
Copyright © 2020-2023  润新知