Django开发:django基础 & url控制器

Posted neozheng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django开发:django基础 & url控制器相关的知识,希望对你有一定的参考价值。

HTTP请求协议

HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于万维网(WWW:World Wide Web )服务器与本地浏览器之间传输超文本的传送协议。http协议是基于TCP/IP协议之上的应用层协议

请求协议:

  

请求方式: get与post请求
  1. GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditBook?name=test1&id=123456. POST方法是把提交的数据放在HTTP包的请求体中.
  2. GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制.
  3. GET与POST请求在服务端获取请求数据方式不同

响应协议:

  

响应状态码

  状态码的值 是当客户端向服务器端发送请求时, 返回的请求 结果。借助状态码,用户可以知道服务器端是正常 理了请求,还是出 现了 。

 

wsgiref模块

WSGI:Web Server Gateway Interface。wsgiref模块是python基于wsgi协议开发的服务模块。

from wsgiref.simple_server import make_server

def application(environ,start_response):
    # wsgi做的两件事情:
    # 1. 按照HTTP请求协议解析数据:environ参数是个字典;
    # 2. 按照HTTP响应协议封装数据:start_response

    # 当前请求路径
    path = environ.get(\'PATH_INFO\')
    start_response(\'200 OK\',[(\'Content-Type\',\'text/html\')])  # 第一个参数是响应头(字符串);第二个是响应首行(列表)

    print(path)
    # 动态匹配
    if path == "/login":
        with open("login.html","rb") as f:
            data = f.read()
            return [data]  # return的格式是列表
    elif path == "/index":
        with open("index.html","r") as f:
            data = f.read()
            return [data.encode("utf-8")]  # return的格式是列表
    # start_response中的元素和return的内容共同组成了响应体

    ret = "<h2>hello world!</h2>".encode(\'utf-8\')
    return [ret]

# 封装好的socket
httped = make_server("127.0.0.1",9001,application)

# 等待用户连接;相当于 accept()方法;开始监听HTTP请求
httped.serve_forever()  # 一旦有用户连接,便会执行 application函数

DIY一个Web框架

from wsgiref.simple_server import make_server

def login(environ):  # environ 需要传入函数中,因为好多时候需要读取请求方式
    with open("login.html","rb") as f:
        data = f.read()
    return data
def fav(environ):
    with open("favicon.ico", "rb") as f:
        data = f.read()
    return data

def application(environ, start_response):
    start_response(\'200 OK\', [(\'Content-Type\', \'text/html\')])

    path = environ.get("PATH_INFO")

    # 方案一
    # # favicon.ico是网页的图标(浏览器默认会多发一次请求获取favicon.ico)
    # if path == "/favicon.ico":
    #     with open("favicon.ico","rb") as f:
    #         data = f.read()
    #     return [data]
    #
    # elif path == "/login":
    #     with open("login.html","rb") as f:
    #         data = f.read()
    #     return [data]

    # ret = "<h2>hello web!</h2>".encode(\'utf-8\')
    # return [ret]

    # 方案二:路由分发
    url_pattern = [
        ("/favicon.ico",fav),
        ("/login",login)
    ] # 列表中放元组,元组中放路径和视图函数

    func = None
    for item in url_pattern:
        if path == item[0]:
            func = item[1]
            break

    if func:
        return [func(environ)]
    else:
        return [b\'404!\']

httpd = make_server(\'\', 8080, application)

print(\'Serving HTTP on port 8080...\')
# 开始监听HTTP请求:
httpd.serve_forever()

上述代码可以从耦合性上优化如下

main.py

from wsgiref.simple_server import make_server

def application(environ, start_response):
    start_response(\'200 OK\', [(\'Content-Type\', \'text/html\')])

    path = environ.get("PATH_INFO")

    from urls import url_pattern
    func = None
    for item in url_pattern:
        if path == item[0]:
            func = item[1]
            break

    if func:
        return [func(environ)]
    else:
        return [b\'404!\']

httpd = make_server(\'\', 8080, application)

print(\'Serving HTTP on port 8080...\')
# 开始监听HTTP请求:
httpd.serve_forever()

urls.py

from views import *

# 专门处理路径
url_pattern = [
        ("/favicon.ico",fav),
        ("/login",login)
    ]

views.py

# 专门处理视图分发功能
def login(environ):  # environ 需要传入函数中,因为好多时候需要读取请求方式
    with open("templates/login.html","rb") as f:
        data = f.read()
    return data
def fav(environ):
    with open("templates/favicon.ico", "rb") as f:
        data = f.read()
    return data

一个简单Web框架组成:

main.py : 启动文件,封装了socket

1. urls.py : 路径与视图函数映射关系 ------ url控制器

2. views.py : 视图函数,固定有一个形式参数:environ ----- 视图函数

3. templates 文件夹:html文件 ----- 模板

4. models.py: 在项目启动前,在数据库中创建表结构  ---- 与数据库相关

 

Django

知识预览

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

  • M 代表模型(Model): 负责业务对象和数据库的关系映射(ORM);
  • T 代表模板 (Template):负责如何把页面展示给用户(html);
  • V 代表视图(View):   负责业务逻辑,并在适当时候调用Model和Template。

除了以上三层之外,还需要一个URL分发器,它的作用是将一个个URL的页面请求分发给不同的View处理,View再调用相应的Model和Template,MTV的响应模式如下所示:

一般是用户通过浏览器向我们的服务器发起一个请求(request),这个请求回去访问视图函数,(如果不涉及到数据调用,那么这个时候视图函数返回一个模板也就是一个网页给用户),视图函数调用模型,模型去数据库查找数据,然后逐级返回,视图函数把返回的数据填充到模板中空格中,最后返回网页给用户。

Django的基本命令

1. 创建一个django project: django-admin.py startproject mysites

 当前目录下会生成mysite的工程,目录结构如下:

  • manage.py ----- Django项目里面的工具,通过它可以调用django shell和数据库等;
  • settings.py ---- 包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作的变量;
  • urls.py ----- 负责把URL模式映射到应用程序。

2. 在mysite目录下创建应用: python manage.py startapp blog

3. 启动django项目:python manage.py runserver 8080

 

Django简单示例:静态文件配置

目录结构如下:

urls.py

"""demo URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/2.0/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path(\'\', views.home, name=\'home\')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path(\'\', Home.as_view(), name=\'home\')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path(\'blog/\', include(\'blog.urls\'))
"""
from django.contrib import admin
from django.urls import path

from app01 import views

urlpatterns = [
    path(\'admin/\', admin.site.urls),
    path(\'timer/\', views.timer),
]

views.py

from django.shortcuts import render

# Create your views here.

def timer(request):
    import time
    ctime = time.time()

    return render(request,"timer.html",{"ctime":ctime})
    # render方法用于发送响应页面;第三个参数字典会嵌入到第二个参数的页面中

settings.py

"""
Django settings for demo project.

Generated by \'django-admin startproject\' using Django 2.0.1.

For more information on this file, see
https://docs.djangoproject.com/en/2.0/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.0/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = \'(+nwjycw@5azl7tpxu^)6uf_z@e#(zg6fzwce@%1qxqu-1_(mb\'

# SECURITY WARNING: don\'t run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    \'django.contrib.admin\',
    \'django.contrib.auth\',
    \'django.contrib.contenttypes\',
    \'django.contrib.sessions\',
    \'django.contrib.messages\',
    \'django.contrib.staticfiles\',
    \'app01.apps.App01Config\',
]

MIDDLEWARE = [
    \'django.middleware.security.SecurityMiddleware\',
    \'django.contrib.sessions.middleware.SessionMiddleware\',
    \'django.middleware.common.CommonMiddleware\',
    \'django.middleware.csrf.CsrfViewMiddleware\',
    \'django.contrib.auth.middleware.AuthenticationMiddleware\',
    \'django.contrib.messages.middleware.MessageMiddleware\',
    \'django.middleware.clickjacking.XFrameOptionsMiddleware\',
]

ROOT_URLCONF = \'demo.urls\'

TEMPLATES = [
    {
        \'BACKEND\': \'django.template.backends.django.DjangoTemplates\',
        \'DIRS\': [os.path.join(BASE_DIR, \'templates\')]
        ,
        \'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\',
            ],
        },
    },
]

WSGI_APPLICATION = \'demo.wsgi.application\'


# Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases

DATABASES = {
    \'default\': {
        \'ENGINE\': \'django.db.backends.sqlite3\',
        \'NAME\': os.path.join(BASE_DIR, \'db.sqlite3\'),
    }
}


# Password validation
# https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        \'NAME\': \'django.contrib.auth.password_validation.UserAttributeSimilarityValidator\',
    },
    {
        \'NAME\': \'django.contrib.auth.password_validation.MinimumLengthValidator\',
    },
    {
        \'NAME\': \'django.contrib.auth.password_validation.CommonPasswordValidator\',
    },
    {
        \'NAME\': \'django.contrib.auth.password_validation.NumericPasswordValidator\',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/2.0/topics/i18n/

LANGUAGE_CODE = \'en-us\'

TIME_ZONE = \'UTC\'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, javascript, Images) # 静态文件包括:css,js和图片
# https://docs.djangoproject.com/en/2.0/howto/static-files/

STATIC_URL = \'/static/\'

# 上面的static路径是Django提供给我们的用于代指下面拼出的绝对路径;即使urls.py中没有静态文件夹(static),client浏览器也能通过static来获取static文件夹中的文件;(静态文件夹都放在static中)
# STATICFILES_DIRS 一个字都不能错
STATICFILES_DIRS = [
    os.path.join(BASE_DIR,"static"),
]
# 上面两个要配合使用

timer.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/app01/timer.css">

</head>
<body>
<h4>当前时间:{{ ctime }}</h4>
{#嵌入页面的内容需要用两个大括号包裹,参数对应的是字典中的key#}
</body>
{#通过/static/来引入静态文件夹中的静态文件#}
<script src="/static/jquery-3.3.1.js"></script>
<script src="/static/app01/timer.js"></script>
</html>

timer.css

h4{
    color:red;
        }

timer.js

$(function () {
    $("h4").click(function () {
        $(this).css("color","green")
    })
})

 

路由控制

Django1.0:re_path(url)

1. 无名分组、有名分组&分发

目录结构:

路由分发.urls.py

"""路由控制 URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/2.0/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path(\'\', views.home, name=\'home\')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path(\'\', Home.as_view(), name=\'home\')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path(\'blog/\', include(\'blog.urls\'))
"""
from django.contrib import admin
from django.urls import path,re_path,include

from app01 import views

urlpatterns = [
    path(\'admin/\', admin.site.urls),

    # 分发:全局分发器;用于把路径分发到不同的应用(application)里面
    re_path(r"^app01/",include("app01.urls"))
    # include()是分发函数;如果用户访问的是 app01, include里面的 app01.urls这个py文件就能分发下去;此时用户输入的url中需要有 /app01/ ,e.g. http://127.0.0.1:8000/app01/articles/2003/10/123/
    # 如果想把路径中的 /app01/ 去掉,如下:
    # re_path(r"^",include("app01.urls"))
]

app01/urls.py

from django.contrib import admin
from django.urls import path,re_path

from app01 import views

urlpatterns = [
    path(\'admin/\', admin.site.urls),

    # 路由配置:路径 ----> 视图函数
    re_path(r\'^articles/2003/$\', views.special_case_2003),
    # ^articles/2003/$ :正则匹配;匹配以articles/2003/开头、以articles/2003/结尾的路径;唯一匹配

    re_path(r\'^articles/([0-9]{4})/$\', views.year_archive),
    # ([0-9]{4}) 是一个分组匹配(加了括号);匹配到路径后,request会传入 year_archive 函数的第一个参数,分组匹配结果会以位置参数传入到year_archive函数的第二个参数, e.g. year_archive(request,1999);so year_archive函数需要有两个参数
    # 从上到下执行,所以如果匹配到了2003,会走第一个路径,下面的不再执行
    # 匹配分组之后,视图函数一定要传入相应的位置参数

    re_path(r\'^articles/([0-9]{4})/([0-9]{2})/$\', views.month_archive),
    # 同理, month_archive需要有三个参数

    re_path(r\'^articles/(?P<y>[0-9]{4})/(?P<m>[0-9]{2})/(?P<c>[0-9]+)/$\', views.article_detail),
    # (?P<名字>):这是有名分组(就是给每个组取了个名字,用的比较多),有名分组利用的是关键字传参;
    # 有名分组取的名字一定要和后面函数的形参相同;有名分组传参不依赖于位置顺序
]

views.py

from django.shortcuts import render,HttpResponse

# Create your views here.

def special_case_2003(request):  # request指请求对象

    return HttpResponse("special_case_2003")
    # HttpResponse 指响应对象;参数是字符串,响应体的内容

def year_archive(request,year):
    return HttpResponse("year_archive_%s"%year)

def month_archive(request,year,month):
    return HttpResponse("month_archive_%s_%s"%(year,month))

def article_detail(request,c,m,y):  # 形参位置顺序无所谓 # y,m,c都是字符串;通过re_path(url)传过来的参数都是字符串格式
    return HttpResponse(y+"-"+m+"-"+c)

2. 反向解析:

反向解析一:在模板中

urls.py

"""路由控制之反向解析 URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/2.0/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path(\'\', views.home, name=\'home\')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path(\'\', Home.as_view(), name=\'home\')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path(\'blog/\', include(\'blog.urls\'))
"""
from django.contrib import admin
from django.urls import path

from app01 import views

urlpatterns = [
    path(\'admin/\', admin.site.urls),
    path("login/",views.login,name="log")  # name=log 是这个url的别名(反向解析); path()的第一个参数是接口,用户需要知道
]

app01/views.py

from django.shortcuts import render,HttpResponse

# Create your views here.

def login(request):
    # request 是请求对象;所有的请求信息都在request里面
    print(request.method)
    # request.method 表示获取 请求方式(GET/POST)

    if request.method ==

以上是关于Django开发:django基础 & url控制器的主要内容,如果未能解决你的问题,请参考以下文章

Python全栈开发之Django基础

django基础知识之GET属性:

Django - - 基础 - - Django的路由系统

如何在 django 模板中设置页面范围的索引

Django开发笔记四

Python开发Django:基础