框架基础, 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),
原文地址:https://www.cnblogs.com/fdsimin/p/13268233.html