Pyhton-Web框架之【Django】

一、什么是web框架

框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构,使用框架可以帮你快速开发特定的系统,简单地说,就是你用别人搭建好的舞台来做表演。

对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。

import socket

def handle_request(client):

    buf = client.recv(1024)
    client.send("HTTP/1.1 200 OK\r\n\r\n".encode("utf8"))
    client.send("<h1 style='color:red'>Hello, web</h1>".encode("utf8"))

def main():

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind(('localhost',8001))
    sock.listen(5)

    while True:
        connection, address = sock.accept()
        handle_request(connection)
        connection.close()

if __name__ == '__main__':

    main()

web应用本质
web应用本质

最简单的Web应用就是先把HTML用文件保存好,用一个现成的HTTP服务器软件,接收用户请求,从文件中读取HTML,返回。

如果要动态生成HTML,就需要把上述步骤自己来实现。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。

        正确的做法是底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档。因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口,让我们专心用Python编写Web业务。这个接口就是WSGI:Web Server Gateway Interface。即:web服务网关接口。  定义了Web服务器与Web应用(或Web框架)之间的标准接口

    Python中wsgiref就是WSGI接口的一个模块,功能相当于apache、nginx

    如何实现一个web框架:

from wsgiref.simple_server import make_server


#http请求处理函数
def application(environ, start_response):
    print(environ)      #请求信息
    start_response('200 OK', [('Content-Type', 'text/html')])   #设置响应头

    return [b'<h1>Hello, web!</h1>']    #返回响应体,字符串迭代对象


if __name__ == '__main__':
    httpd = make_server('127.0.0.1', 8000, application)

    print ("Serving HTTP on port 8000...")

    httpd.serve_forever()   #监听http请求

step1
step1
整个application()函数本身没有涉及到任何解析HTTP的部分,也就是说,底层代码不需要我们自己编写,
我们只负责在更高层次上考虑如何响应请求就可以了。

application()函数必须由WSGI服务器来调用。有很多符合WSGI规范的服务器,我们可以挑选一个来用。

Python内置了一个WSGI服务器,这个模块叫wsgiref    
    
    
application()函数就是符合WSGI标准的一个HTTP处理函数,它接收两个参数:

        //environ:一个包含所有HTTP请求信息的dict对象;
        
        //start_response:一个发送HTTP响应的函数。

在application()函数中,调用:

start_response('200 OK', [('Content-Type', 'text/html')])

就发送了HTTP响应的Header,注意Header只能发送一次,也就是只能调用一次start_response()函数。
start_response()函数接收两个参数,一个是HTTP响应码,一个是一组list表示的HTTP Header,每
个Header用一个包含两个str的tuple表示。

通常情况下,都应该把Content-Type头发送给浏览器。其他很多常用的HTTP Header也应该发送。

然后,函数的返回值b'<h1>Hello, web!</h1>'将作为HTTP响应的Body发送给浏览器。

有了WSGI,我们关心的就是如何从environ这个dict对象拿到HTTP请求信息,然后构造HTML,
通过start_response()发送Header,最后返回Body。
注意
from wsgiref.simple_server import make_server


#http处理函数
def application(environ, start_response):
    # print(environ)    #请求信息
    start_response('200 OK', [('Content-Type', 'text/html')])   #设置响应头

    with open("index1.html","rb") as f:
        data = f.read()
    return [data]       #返回响应体


if __name__ == '__main__':
    httpd = make_server('127.0.0.1', 8000, application)

    print ("Serving HTTP on port 8000...")

    httpd.serve_forever()       #监听http请求

step2
step2
from wsgiref.simple_server import make_server


#http处理函数
def application(environ, start_response):
    # print(environ)    #请求信息
    start_response('200 OK', [('Content-Type', 'text/html')])   #设置响应头

    if environ["PATH_INFO"] == "/heilong":
        return [b"<h1>Hello, heilong!</h1>"]       #返回响应体
    elif environ["PATH_INFO"] == "/xiaohei":
        return [b"<h1>Hello, xiaohei!</h1>"]
    else:
        return [b"404 Not Found"]


if __name__ == '__main__':
    httpd = make_server('127.0.0.1', 8000, application)

    print ("Serving HTTP on port 8000...")

    httpd.serve_forever()       #监听http请求

step3
step3
from wsgiref.simple_server import make_server


def heilong():
    with open("heilong.html","rb") as f:
        data = f.read()
    return data

def xiaohei():
    with open("xiaohei.html","rb") as f:
        data = f.read()
    return data

def route_ctrl():
    url_dic = {
        "/heilong":heilong,
        "/xiaohei":xiaohei,
    }
    return url_dic

#http处理函数
def application(environ, start_response):
    # print(environ)    #请求信息
    url_path=environ["PATH_INFO"]

    start_response('200 OK', [('Content-Type', 'text/html')])   #设置响应头

    url_patterns=route_ctrl()


    for item in url_patterns:
        if item == url_path:
            func = url_patterns.get(item)
            return [func()]
    else:
        return [b"404 Not Found"]



if __name__ == '__main__':
    httpd = make_server('127.0.0.1', 8000, application)

    print ("Serving HTTP on port 8000...")

    httpd.serve_forever()       #监听http请求

step4
step4
from wsgiref.simple_server import make_server
import time

def heilong(req):
    with open("heilong.html","rb") as f:
        data = f.read()
    return data

def xiaohei(req):
    with open("xiaohei.html","rb") as f:
        data = f.read()
    return data

def showtime(req):
    with open("showtime.html","rb") as f:
        data = f.read().decode("utf-8")
        data = data.replace("{{time}}",str(time.ctime()))
    return data.encode("utf-8")

def route_ctrl():
    url_dic = {
        "/heilong":heilong,
        "/xiaohei":xiaohei,
        "/showtime":showtime,
    }
    return url_dic

#http处理函数
def application(environ, start_response):
    # print(environ)    #请求信息
    url_path=environ["PATH_INFO"]

    start_response('200 OK', [('Content-Type', 'text/html')])   #设置响应头

    url_patterns=route_ctrl()

    for item in url_patterns:
        if item == url_path:
            func = url_patterns.get(item)
            return [func(environ)]
    else:
        return [b"404 Not Found"]


if __name__ == '__main__':
    httpd = make_server('127.0.0.1', 8000, application)

    print ("Serving HTTP on port 8000...")

    httpd.serve_forever()       #监听http请求

step5
step5

二、MVC和MTV模式

1.著名的MVC模式:所谓MVC就是把web应用分为模型(M),控制器(C),视图(V)三层;他们之间以一种插件似的,解耦合的方式连接在一起。

2.模型负责业务对象与数据库的对象(ORM),视图负责与用户的交互(页面),控制器(C)接受用户的输入调用模型和视图完成用户的请求。

Django的MTV模式本质上与MVC模式没有什么差别,也是各组件之间为了保持松耦合关系,只是定义上有些许不同,Django的MTV分别代表:

           Model(模型):负责业务对象与数据库的对象(ORM)

           Template(模版):负责如何把页面展示给用户

           View(视图):负责业务逻辑,并在适当的时候调用Model和Template

      此外,Django还有一个url分发器,它的作用是将一个个URL的页面请求分发给不同的view处理,view再调用相应的Model和Template

 

Django WEB框架

三、Django框架的流程与命令行工具

    Django实现流程:

django
    #安装: pip3 install django

          添加环境变量

    #1  创建project
       django-admin startproject mysite

       ---mysite

          ---settings.py
          ---url.py
          ---wsgi.py

       ---- manage.py(启动文件)  

    #2  创建APP       
       python manage.py startapp  app01

    pycharm实现创建项目和应用:File——》New Project——》Django
            Location:项目路径及名称
            Application name:应用名

    #3  settings配置
    
       TEMPLATES

       STATICFILES_DIRS=(
            os.path.join(BASE_DIR,"statics"),
        )

       STATIC_URL = '/static/' 
       #  我们只能用 STATIC_URL,但STATIC_URL会按着你的STATICFILES_DIRS去找#4  根据需求设计代码
           url.py
           view.py

    #5  使用模版
       render(req,"index.html")   

    #6  启动项目
       python manage.py runserver  127.0.0.1:8090

    #7  连接数据库,操作数据
       model.py

django的命令行工具

    django-admin.py 是Django的一个用于管理任务的命令行工具,manage.py是对django-admin.py的简单包装,每一个Django Project里都会有一个mannage.py。

    <1> 创建一个django工程 : django-admin.py startproject mysite

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

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

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

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

    这样我们的django就启动起来了!当我们访问:http://127.0.0.1:8080/时就可以看到:

 <4>生成同步数据库的脚本:python manage.py makemigrations  

      同步数据库:  python manage.py migrate  

 

四、Django的配置文件settings.py

  1、STATIC_ROOT和STATIC_URL

STATIC主要指的是如css,js,images这样文件,在settings里面可以配置STATIC_ROOT和STATIC_URL,
    配置方式与MEDIA_ROOT是一样的,但是要注意

    #STATIC文件一般保存在以下位置:

    #1、STATIC_ROOT:在settings里面设置,一般用来放一些公共的js,css,images等。

    #2、app的static文件夹,在每个app所在文夹均可以建立一个static文件夹,然后当运行collectstatic时,
    #    Django会遍历INSTALL_APPS里面所有app的static文件夹,将里面所有的文件复制到STATIC_ROOT。因此,
    #   如果你要建立可复用的app,那么你要将该app所需要的静态文件放在static文件夹中。

    # 也就是说一个项目引用了很多app,那么这个项目所需要的css,images等静态文件是分散在各个app的static文件的,比
    #  较典型的是admin应用。当你要发布时,需要将这些分散的static文件收集到一个地方就是STATIC_ROOT。

    #3、STATIC文件还可以配置STATICFILES_DIRS,指定额外的静态文件存储位置。
    #  STATIC_URL的含义与MEDIA_URL类似。

    # ----------------------------------------------------------------------------
    #注意1:
        #为了后端的更改不会影响前端的引入,避免造成前端大量修改

        STATIC_URL = '/static/'               #引用名
        STATICFILES_DIRS = (
            os.path.join(BASE_DIR,"statics")  #实际名 ,即实际文件夹的名字
        )

        #django对引用名和实际名进行映射,引用时,只能按照引用名来,不能按实际名去找
        #<script src="/statics/jquery-3.1.1.js"></script>
        #------error-----不能直接用,必须用STATIC_URL = '/static/':
        #<script src="/static/jquery-3.1.1.js"></script>

    #注意2(statics文件夹写在不同的app下,静态文件的调用):

        STATIC_URL = '/static/'

        STATICFILES_DIRS=(
            (os.path.join(BASE_DIR,"app01","statics")) ,
        )

        #html中引用方式一
        #<script src="/static/jquery-3.1.1.js"></script>

    #注意3:
        STATIC_URL = '/static/'
       #html中引用方式二
        {% load staticfiles %}
       # <script src={% static "jquery-3.1.1.js" %}></script>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    {% load staticfiles %}
</head>
<body>
<h1>当前时间:{{time}}</h1>

{#<script src="/static/jquery-3.1.1.js"></script>#}
<script src="{% static 'jquery-3.1.1.js' %}"></script>
<script>
    $("h1").css("color","red")
</script>
</body>
</html>
def showtime(request):

    # return HttpResponse("hello django")
    t = time.ctime()
    #{"time":t}将t变量值渲染为html文件中的{{time}},在后端渲染之后传给前端
    return render(request,"showtime.html",{"time":t})

五、Django的URL(路由系统) 

 URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL模式以及要为该URL模式调用的视图函数之间的映射表;你就是以这种方式告诉Django,对应这个URL调用这段代码。

urlpatterns = [
    url(正则表达式, views视图函数,参数,别名),
]

 参数说明:

  • 一个正则表达式字符串
  • 一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
  • 可选的要传递给视图函数的默认参数(字典形式)
  • 一个可选的name参数
from django.conf.urls import url,include
from django.contrib import admin
from showtime import views            #showtime是当前应用名

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r"^showtime/$",views.showtime),

    #分组,一个()为一个组,做一个参数传递给views.tupletest(y,m)
    url(r"^tupletest/(\d{4})/(\d{2})",views.tupletest),
    #分组后,?<变量名>指定,做为views.tupletest(request,year,month)的参数名,必需与指定的一致
    url(r"^tupletest/(?P<year>\d{4})/(?P<month>\d{2})$",views.tupletest),
    
    url(r"^register/",views.register),
    #name指定别名
    url(r"^register/",views.register,name="reg"),
]

一个简单的URL配置
一个简单的URL配置

上述URL配置中,name指定了别名后,相对应的视图函数所对应的html文件中:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    {% load staticfiles %}    //Template模板
</head>
<body>

<h1>注册信息</h1>
<form action="{% url 'reg' %}" method="post">     //按别名指定URL

    <p>用户名:<input type="text" name = "user"></p>
    <p>年龄:<input type="text" name = "age"></p>
    <p>爱好:<input type="checkbox" name = "hobby" value="游泳">游泳
             <input type="checkbox" name = "hobby" value="听音乐">听音乐
             <input type="checkbox" name = "hobby" value="跑步">跑步
    </p>
    <p><input type="submit"></p>
</form>

</body>
</html>
View Code

URL的分发:

from django.conf.urls import url,include
from django.contrib import admin
from showtime import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r"^showtime/$",views.showtime),        #分发后这里URL必需用$指定以什么结尾,否则分发后的URL都将访问views.showtime

    url(r"^showtime/",include("showtime.urls")),        #URL分发
]

URL分发
URL分发
from django.conf.urls import url,include
from showtime import views

urlpatterns = [
    # url(r"^tupletest/(\d{4})/(\d{2})",views.tupletest),
    url(r"tupletest/(?P<year>\d{4})/(?P<month>\d{2})$",views.tupletest),

    # url(r"^register/",views.register),
    url(r"register/",views.register,name="reg"),
]

#注意:访问时,url路径前必需showtime,即相应的应用目录

分发到相应的应用中,而不在全局urls中
分发到相应的应用中,而不在全局urls中

六、Django的views(视图函数)

 http请求中产生两个核心对象:

      http请求:HttpRequest对象

      http响应:HttpResponse对象

 所在位置:django.http

 之前我们用到的参数request就是HttpRequest    检测方法:isinstance(request,HttpRequest)

1、HttpRequest对象的属性和方法:

# path:       请求页面的全路径,不包括域名
#
# method:     请求中使用的HTTP方法的字符串表示。全大写表示。例如
#
#                    if  req.method=="GET":
#
#                              do_something()
#
#                    elseif req.method=="POST":
#
#                              do_something_else()
#
# GET:         包含所有HTTP GET参数的类字典对象
#
# POST:       包含所有HTTP POST参数的类字典对象
#
#              服务器收到空的POST请求的情况也是可能发生的,也就是说,表单form通过
#              HTTP POST方法提交请求,但是表单中可能没有数据,因此不能使用
#              if req.POST来判断是否使用了HTTP POST 方法;应该使用  if req.method=="POST"
#
#
#
# COOKIES:     包含所有cookies的标准Python字典对象;keys和values都是字符串。
#
# FILES:      包含所有上传文件的类字典对象;FILES中的每一个Key都是<input type="file" name="" />标签中                     name属性的值,FILES中的每一个value同时也是一个标准的python字典对象,包含下面三个Keys:
#
#             filename:      上传文件名,用字符串表示
#             content_type:   上传文件的Content Type
#             content:       上传文件的原始内容
#
#
# user:       是一个django.contrib.auth.models.User对象,代表当前登陆的用户。如果访问用户当前
#              没有登陆,user将被初始化为django.contrib.auth.models.AnonymousUser的实例。你
#              可以通过user的is_authenticated()方法来辨别用户是否登陆:
#              if req.user.is_authenticated();只有激活Django中的AuthenticationMiddleware
#              时该属性才可用
#
# session:    唯一可读写的属性,代表当前会话的字典对象;自己有激活Django中的session支持时该属性才可用。

#方法
get_full_path(),   比如:http://127.0.0.1:8000/index33/?name=123 ,req.get_full_path()得到的结果就是/index33/?name=123
req.path:/index33
View Code

2 HttpResponse对象:

对于HttpRequest对象来说,是由django自动创建的,但是,HttpResponse对象就必须我们自己创建。每个view请求处理方法必须返回一个HttpResponse对象。

 HttpResponse类在django.http.HttpResponse

 在HttpResponse对象上扩展的常用方法:

页面渲染:         render()(推荐)<br>
                       render_to_response(),    #与render()区别是不用写request参数

页面跳转:         redirect("路径")    #达到某条件时跳转到另一个页面,注:参数必须是“路径”,即URL,而非HTML模板
#与render("html模板")区别,redirect会改变url,而render不会改变url,重新刷新不会保留当前页面,

locals():    可以直接将函数中所有的变量传给模板  注:request的属性也都可以传递过去
View Code

七、Template基础

模板系统介绍

你可能已经注意到我们在例子视图中返回文本的方式有点特别。 也就是说,HTML被直接硬编码在 Python代码之中。

def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)

  尽管这种技术便于解释视图是如何工作的,但直接将HTML硬编码到你的视图里却并不是一个好主意。 让我们来看一下为什么:

  • 对页面设计进行的任何改变都必须对 Python 代码进行相应的修改。 站点设计的修改往往比底层 Python 代码的修改要频繁得多,因此如果可以在不进行 Python 代码修改的情况下变更设计,那将会方便得多。

  • Python 代码编写和 HTML 设计是两项不同的工作,大多数专业的网站开发环境都将他们分配给不同的人员(甚至不同部门)来完成。 设计者和HTML/CSS的编码人员不应该被要求去编辑Python的代码来完成他们的工作。

  • 程序员编写 Python代码和设计人员制作模板两项工作同时进行的效率是最高的,远胜于让一个人等待另一个人完成对某个既包含 Python又包含 HTML 的文件的编辑工作。

    基于这些原因,将页面的设计和Python的代码分离开会更干净简洁更容易维护。 我们可以使用 Django的 模板系统 (Template System)来实现这种模式,这就是本章要具体讨论的问题。

 1、模板的组成

    组成:HTML代码+逻辑控制代码

 2、逻辑控制代码的组成

    变量:(使用双大括号来引用变量):

    语法:

{{var_name}}

    Template对象和Context对象

    Template:模板中如{{}}、{%%}

    Context:上下文,如locals()、{"name":user}

#cmd 中如下测试:
>>> python manange.py shell      #(进入该django项目的环境)
>>> from django.template import Context, Template
>>> t = Template('My name is {{ name }}.')
>>> c = Context({'name': 'Stephane'})
>>> t.render(c)
'My name is Stephane.'

# 同一模板,多个上下文,一旦有了模板对象,你就可以通过它渲染多个context,无论何时我们都可以
# 像这样使用同一模板源渲染多个context,只进行 一次模板创建然后多次调用render()方法渲染会更为高效

# Low
for name in ('John', 'Julie', 'Pat'):
    t = Template('Hello, {{ name }}')
    print t.render(Context({'name': name}))

# Good
t = Template('Hello, {{ name }}')
for name in ('John', 'Julie', 'Pat'):
    print t.render(Context({'name': name}))

#推荐使用
return render(request,"index.html",locals())

  变量:深度查找(万能的句点符号)在到目前为止的例子中,我们通过 context 传递的简单参数值主要是字符串,然而,模板系统能够非常简洁地处理更加复杂的数据结构,例如list、dictionary和自定义的对象。

from django.shortcuts import render

# Create your views here.

class People():
    def __init__(self,name,sex):
        self.name = name
        self.sex = sex

    def learn(self):
        print("学习。。。")
        return "正在学习!"


def templatevar(request):

    li = ["heilong","xiaolong","xiaohei"]

    dic = {"name":"heilong","age":20,"gender":""}

    p1 = People("heilong","")

    return render(request,"Template_var_deep.html",locals())

views.py
view.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h2>{{ li.0 }}</h2>         <!--heilong-->
<h2>{{ li.1 }}</h2>         <!--xiaolong-->
<h2>{{ li.2 }}</h2>         <!--xiaohei-->
<hr>
<h2>{{ dic.name }}</h2>     <!--heilong-->
<h2>{{ dic.age }}</h2>      <!--20-->
<h2>{{ dic.gender }}</h2>   <!--男-->
<hr>
<h2>{{ p1.name }}</h2>     <!--heilong-->
<h2>{{ p1.sex }}</h2>   <!--男-->
<!-- 如果调用方法,则返回函数的返回值。注:函数不能有参数,没什么意义-->
<h2>{{ p1.learn }}</h2>   <!--正在学习!-->

</body>
</html>

Template_var_deep.html
Template_var_deep.html

变量的过滤器(filter)的使用{{obj|filter:param}}

# 1  add          :   给变量加上相应的值
   #
   # 2  addslashes   :    给变量中的引号前加上斜线
   #
   # 3  capfirst     :    首字母大写
   #
   # 4  cut          :   从字符串中移除指定的字符
   #
   # 5  date         :   格式化日期字符串
   #
   # 6  default      :   如果值是False,就替换成设置的默认值,否则就是用本来的值
   #
   # 7  default_if_none:  如果值是None,就替换成设置的默认值,否则就使用本来的值
View Code

标签(tag)的使用(使用大括号和百分比的组合来表示使用tag)

    {% if %} 的使用 

    {% if %}标签计算一个变量值,如果是“true”,即它存在、不为空并且不是false的boolean值,系统则会显示{% if %}和{% endif %}间的所有内容

{% if num >= 100 and 8 %}

    {% if num > 200 %}
        <p>num大于200</p>
    {% else %}
        <p>num大于100小于200</p>
    {% endif %}

{% elif num < 100%}
    <p>num小于100</p>

{% else %}
    <p>num等于100</p>

{% endif %}



{% if %} 标签接受and,or或者not来测试多个变量值或者否定一个给定的变量
{% if %} 标签不允许同一标签里同时出现and和or,否则逻辑容易产生歧义,例如下面的标签是不合法的:

{% if obj1 and obj2 or obj3 %}

 {% for %}的使用

   {% for %}标签允许你按顺序遍历一个序列中的各个元素,每次循环模板系统都会渲染{% for %}和{% endfor %}之间的所有内容

<ul>
{% for obj in list %}
    <li>{{ obj.name }}</li>
{% endfor %}
</ul>


#在标签里添加reversed来反序循环列表:

    {% for obj in list reversed %}
    ...
    {% endfor %}

#{% for %}标签可以嵌套:

    {% for country in countries %}
        <h1>{{ country.name }}</h1>
        <ul>
         {% for city in country.city_list %}
            <li>{{ city }}</li>
         {% endfor %}
        </ul>
    {% endfor %}


#系统不支持中断循环,系统也不支持continue语句,{% for %}标签内置了一个forloop模板变量,
#这个变量含有一些属性可以提供给你一些关于循环的信息

1,forloop.counter表示循环的次数,它从1开始计数,第一次循环设为1:

    {% for item in todo_list %}
        <p>{{ forloop.counter }}: {{ item }}</p>
    {% endfor %}
2,forloop.counter0 类似于forloop.counter,但它是从0开始计数,第一次循环设为0
3,forloop.revcounter
4,forloop.revcounter0
5,forloop.first当第一次循环时值为True,在特别情况下很有用:

    
    {% for object in objects %}   
         {% if forloop.first %}<li class="first">{% else %}<li>{% endif %}   
         {{ object }}   
        </li>  
    {% endfor %}  
    
# 富有魔力的forloop变量只能在循环中得到,当模板解析器到达{% endfor %}时forloop就消失了
# 如果你的模板context已经包含一个叫forloop的变量,Django会用{% for %}标签替代它
# Django会在for标签的块中覆盖你定义的forloop变量的值
# 在其他非循环的地方,你的forloop变量仍然可用


#{% empty %}

{{li }}
      {%  for i in li %}
          <li>{{ forloop.counter0 }}----{{ i }}</li>
      {% empty %}
          <li>this is empty!</li>
      {% endfor %}

#         [11, 22, 33, 44, 55]
#            0----11
#            1----22
#            2----33
#            3----44
#            4----55
View Code

{%csrf_token%}:csrf_token标签

    用于生成csrf_token的标签,用于防治跨站攻击验证。注意如果你在view的index里用的是render_to_response方法,不会生效

       其实,这里是会生成一个input标签,和其他表单标签一起提交给后台的。

{% url %}:  引用路由配置的地址

<form action="{% url "bieming"%}" >
          <input type="text">
          <input type="submit"value="提交">
          {%csrf_token%}
</form>

{% with %}:用更简单的变量名替代复杂的变量名

{% with total=fhjsaldfhjsdfhlasdfhljsdal %}
{{ total }}    #注:只能在with与endwith之间用
{% endwith %}

{% verbatim %}: 禁止render

{% verbatim %}

         {{ hello }}    #这里不会被Template渲染,只返回{{ hello }}内容

{% endverbatim %}

{% load %}: 加载标签库

    自定义filter和simple_tag

      a、在app中创建templatetags模块(必须的)

      b、创建任意 .py 文件,如:my_tags.py

 

from django import template
from django.utils.safestring import mark_safe

register = template.Library()   #register的名字是固定的,不可改变


@register.filter
def filter_multi(v1,v2):
    return  v1 * v2


@register.simple_tag
def simple_tag_multi(v1,v2):
    return  v1 * v2


@register.simple_tag
def my_input(id,arg):
    result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
    return mark_safe(result)

  c、在使用自定义simple_tag和filter的html文件中导入之前创建的 my_tags.py :{% load my_tags %}

  d、使用simple_tag和filter(如何调用)

-------------------------------.html
{% load xxx %}   #首行
    
 # num=12
{{ num|filter_multi:2 }} #24

{{ num|filter_multi:"[22,333,4444]" }}


{% simple_tag_multi 2 5 %}      参数不限,但不能放在if for语句中
{% simple_tag_multi num 5 %}

e、在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag.

   注:filter与simple_tag区别

        filter可以用在if等语句后,simple_tag不可以

        filter只能传一个参数,而simple_tag不限

        在simple_tag中也可以引用变量,只是不需要加{{}}

   extend模板继承

    为了解决网站中,公共页面的代码重复与冗余

    extend(继承)模板标签

      到目前为止,我们的模板范例都只是些零星的 HTML 片段,但在实际应用中,你将用 Django 模板系统来创建整个 HTML 页面。 这就带来一个常见的 Web 开发问题: 在整个网站中,如何减少共用页面区域(比如站点导航)所引起的重复和冗余代码?

      解决该问题的传统做法是使用 服务器端的 includes ,你可以在 HTML 页面中使用该指令将一个网页嵌入到另一个中。 事实上, Django 通过刚才讲述的 {% include %} 支持了这种方法。 但是用 Django 解决此类问题的首选方法是使用更加优雅的策略—— 模板继承 。

      本质上来说,模板继承就是先构造一个基础框架模板,而后在其子模板中对它所包含站点公用部分和定义块进行重载

      step1:定义基础模板

         父模板中添加模板标签

{% block 名称 %}
{% endblock %}

step2:修改子模板

{% extends "基础模板" %}        #必须写在首行


{% block 名称 %}        #名称必须与父模板中一致,多个的话不能重复

    要修改的内容

{% endblock %}

注意:

子模板中{% extends %}  必须写在第一行,否则模板继承不起作用

一般来说,{% block %}  越多越好,这样比较灵活

不允许在同一个模板中定义多个同名的{% block %}

 具体来看一个例子:

#urls.py

from django.conf.urls import url
from django.contrib import admin
from manager_system import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r"^index/",views.index),
    url(r"^student/",views.student),
#views.py

from django.shortcuts import render

# Create your views here.

def index(request):

    return render(request,"index.html")

def student(request):

    li = ["heilong","xiaolong","xiaohei"]

    return render(request,"student.html",locals())
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    {% block styles %}

    {% endblock %}

    <style>
        *{
            margin: 0;
            padding: 0;
        }
        .title{
            width: 100%;
            height: 40px;
            background-color: #7259ff;
            line-height: 40px;
            text-align: center;
            color: white;
            font-size: 20px;
        }
        .left{
            width: 20%;
            min-height: 600px;
            background-color: darkgray;
        }
        .manager{
            text-align: center;
            padding: 20px 0;
            font-size: 25px;
        }
        .content{
            width: 80%;
            min-height: 600px;
            text-align: center;
        }
        .left,.content{
            float: left;
        }
    </style>

</head>
<body>

<div class="outer">

    <div class="title">标题</div>
    <div class="left">
        <div class="student manager"><a href="/student">学生管理</a></div>
        <div class="teacher manager"><a href="">老师管理</a></div>
        <div class="course manager"><a href="">课程管理</a></div>
        <div class="classes manager"><a href="">班级管理</a></div>
    </div>
    <div class="content">

        {% block content %}
            <h1>欢迎登录管理系统</h1>
        {% endblock %}

        {% include "thanks.html" %}
    </div>

</div>

</body>
</html>
index.html
{% extends "index.html" %}

{%  block styles %}
    <style>
        .stu_mes{
            color: red;
        }
    </style>
{% endblock %}


{% block content %}
    {{ block.super }}
    {% for item in li %}
        <h1 class="stu_mes">{{ forloop.counter }} : {{ item }}</h1>
    {% endfor %}
{% endblock %}
student.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <h2>感谢使用</h2>

</body>
</html>
thanks.html

上述例子中还用到一个{% include "thanks.html" %}

即将一个现有的模板添加到另一个模板中

八、Models(数据库模型)

  1、数据库的配置

    django默认支持sqlite,mysql, oracle,postgresql数据库。

         <1> sqlite

              django默认使用sqlite的数据库,默认自带sqlite的数据库驱动 , 引擎名称:django.db.backends.sqlite3

         <2> mysql

              引擎名称:django.db.backends.mysql

    mysql驱动程序

      MySQLdb(mysql python)

      mysqlclient

      MySQL

      PyMySQL(纯python的mysql驱动程序)

    在django的项目中会默认使用sqlite数据库,在settings里有如下设置

创建表的启动命令:

python manage.py makemigrations
python manage.py migrate
/***admin创建用户****/
python manage.py createsuperuser

 

 

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

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',               #数据库引擎
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),       #数据库名
    }
}

如果我们想要更改数据库,需要修改如下

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


DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',         #数据库引擎
        'NAME': 'heilong',                                       #你的数据库名称
        'USER': 'root',                                            #你的数据库用户名
        'PASSWORD': '123456',                              #你的数据库密码
        'HOST': '192.168.189.130',                         #你的数据库主机,留空默认为localhost
        'PORT': '3306',                                           #你的数据库端口
    }
}
#注意
NAME即数据库的名字,在mysql连接前该数据库必须已经创建,而上面的sqlite数据库下的db.sqlite3则是项目自动创建

USER和PASSWORD分别是数据库的用户名和密码。

设置完后,再启动我们的Django项目前,我们需要激活我们的mysql。

然后,启动项目,会报错:no module named MySQLdb

这是因为django默认你导入的驱动是MySQLdb,可是MySQLdb对于py3有很大问题,所以我们需要的驱动是PyMySQL

所以,我们只需要找到项目名文件下的__init__,在里面写入:

import pymysql
pymysql.install_as_MySQLdb()

2、ORM对象关系映射

    用于实现面向对象编程语言里不同类型系统的数据之间的转换,换言之,就是用面向对象的方式去操作数据库的创建表以及增删改查等操作。

    ORM: 一个类对应一个表,类属性对应字段;一个实例对象对应一条记录

 

    表与表之间的关系(两张表):

      一对一:利用外键约束并且创建唯一约束(unique)

      一对多:利用外键约束实现

      多对多:另外创建一个表用来存放两个表之间的关系(还是利用外键约束),本质就是两个一对多关系

 

    优点: 1 ORM使得我们的通用数据库交互变得简单易行,而且完全不用考虑该死的SQL语句。快速开发。

        2 可以避免一些新手程序猿写sql语句带来的性能问题。

    缺点:1  性能有所牺牲,不过现在的各种ORM框架都在尝试各种方法,比如缓存,延迟加载登来减轻这个问题。效果很显著。

       2  对于个别复杂查询,ORM仍然力不从心,为了解决这个问题,ORM一般也支持写raw sql。

                    3  通过QuerySet的query属性查询对应操作的sql语句

author_obj=models.Author.objects.filter(id=2)
print(author_obj.query)

 Django操作数据库步骤:

 1、数据库配置:修改DATABASES={...}

 2、修改项目文件下的__init__.py

import pymysql
pymysql.install_as_MySQLdb()

    3、models.py中创建类(表) 

#

from django.db import models

# Create your models here.


class book(models.Model):
    name=models.CharField(max_length=20)
    price=models.IntegerField()
    pub_date=models.DateField()

4、根据类生成迁移文件,命令如下:

#Terminal终端中
python manager.py makemigrations

5、将迁移文件写入到数据库,转换为对应的表,命令如下:

#Terminal终端中
python manager.py migrate

分析代码:

         <1>  每个数据模型都是django.db.models.Model的子类,它的父类Model包含了所有必要的和数据库交互的方法。并提供了一个简介漂亮的定义数据库字段的语法。

         <2>  每个模型相当于单个数据库表(多对多关系例外,会多生成一张关系表),每个属性也是这个表中的字段。属性名就是字段名,它的类型(例如CharField)相当于数据库的字段类型(例如varchar)。大家可以留意下其它的类型都和数据库里的什么字段对应。

         <3>  模型之间的三种关系:一对一,一对多,多对多。

               一对一:实质就是在主外键(author_id就是foreign key)的关系基础上,给外键加了一个UNIQUE=True的属性;

               一对多:就是主外键关系;(foreign key)

               多对多:(ManyToManyField) 自动创建第三张表(当然我们也可以自己创建第三张表:两个foreign key)

    <4>  模型常用的字段类型参数

<1> CharField
        #字符串字段, 用于较短的字符串.
        #CharField 要求必须有一个参数 maxlength, 用于从数据库层和Django校验层限制该字段所允许的最大字符数.

<2> IntegerField
       #用于保存一个整数.

<3> FloatField
        # 一个浮点数. 必须 提供两个参数:
        #
        # 参数    描述
        # max_digits    总位数(不包括小数点和符号)
        # decimal_places    小数位数
                # 举例来说, 要保存最大值为 999 (小数点后保存2位),你要这样定义字段:
                #
                # models.FloatField(..., max_digits=5, decimal_places=2)
                # 要保存最大值一百万(小数点后保存10位)的话,你要这样定义:
                #
                # models.FloatField(..., max_digits=19, decimal_places=10)
                # admin 用一个文本框(<input type="text">)表示该字段保存的数据.

<4> AutoField
        # 一个 IntegerField, 添加记录时它会自动增长. 你通常不需要直接使用这个字段; 
        # 自定义一个主键:my_id=models.AutoField(primary_key=True)
        # 如果你不指定主键的话,系统会自动添加一个主键字段到你的 model.

<5> BooleanField
        # A true/false field. admin 用 checkbox 来表示此类字段.

<6> TextField
        # 一个容量很大的文本字段.
        # admin 用一个 <textarea> (文本区域)表示该字段数据.(一个多行编辑框).

<7> EmailField
        # 一个带有检查Email合法性的 CharField,不接受 maxlength 参数.

<8> DateField
        # 一个日期字段. 共有下列额外的可选参数:
        # Argument    描述
        # auto_now    当对象被保存时,自动将该字段的值设置为当前时间.通常用于表示 "last-modified" 时间戳.
        # auto_now_add    当对象首次被创建时,自动将该字段的值设置为当前时间.通常用于表示对象创建时间.
        #(仅仅在admin中有意义...)

<9> DateTimeField
        #  一个日期时间字段. 类似 DateField 支持同样的附加选项.

<10> ImageField
        # 类似 FileField, 不过要校验上传对象是否是一个合法图片.#它有两个可选参数:height_field和width_field,
        # 如果提供这两个参数,则图片将按提供的高度和宽度规格保存.     
<11> FileField
     # 一个文件上传字段.
     #要求一个必须有的参数: upload_to, 一个用于保存上载文件的本地文件系统路径. 这个路径必须包含 strftime #formatting, 
     #该格式将被上载文件的 date/time 
     #替换(so that uploaded files don't fill up the given directory).
     # admin 用一个<input type="file">部件表示该字段保存的数据(一个文件上传部件) .

     #注意:在一个 model 中使用 FileField 或 ImageField 需要以下步骤:
            #(1)在你的 settings 文件中, 定义一个完整路径给 MEDIA_ROOT 以便让 Django在此处保存上传文件. 
            # (出于性能考虑,这些文件并不保存到数据库.) 定义MEDIA_URL 作为该目录的公共 URL. 要确保该目录对 
            #  WEB服务器用户帐号是可写的.
            #(2) 在你的 model 中添加 FileField 或 ImageField, 并确保定义了 upload_to 选项,以告诉 Django
            # 使用 MEDIA_ROOT 的哪个子目录保存上传文件.你的数据库中要保存的只是文件的路径(相对于 MEDIA_ROOT). 
            # 出于习惯你一定很想使用 Django 提供的 get_<#fieldname>_url 函数.举例来说,如果你的 ImageField 
            # 叫作 mug_shot, 你就可以在模板中以 {{ object.#get_mug_shot_url }} 这样的方式得到图像的绝对路径.

<12> URLField
      # 用于保存 URL. 若 verify_exists 参数为 True (默认), 给定的 URL 会预先检查是否存在( 即URL是否被有效装入且
      # 没有返回404响应).
      # admin 用一个 <input type="text"> 文本框表示该字段保存的数据(一个单行编辑框)

<13> NullBooleanField
       # 类似 BooleanField, 不过允许 NULL 作为其中一个选项. 推荐使用这个字段而不要用 BooleanField 加 null=True 选项
       # admin 用一个选择框 <select> (三个可选择的值: "Unknown", "Yes" 和 "No" ) 来表示这种字段数据.

<14> SlugField
       # "Slug" 是一个报纸术语. slug 是某个东西的小小标记(短签), 只包含字母,数字,下划线和连字符.#它们通常用于URLs
       # 若你使用 Django 开发版本,你可以指定 maxlength. 若 maxlength 未指定, Django 会使用默认长度: 50.  #在
       # 以前的 Django 版本,没有任何办法改变50 这个长度.
       # 这暗示了 db_index=True.
       # 它接受一个额外的参数: prepopulate_from, which is a list of fields from which to auto-#populate 
       # the slug, via JavaScript,in the object's admin form: models.SlugField
       # (prepopulate_from=("pre_name", "name"))prepopulate_from 不接受 DateTimeFields.

<15> XMLField
        #一个校验值是否为合法XML的 TextField,必须提供参数: schema_path, 它是一个用来校验文本的 RelaxNG schema #的文件系统路径.

<16> FilePathField
        # 可选项目为某个特定目录下的文件名. 支持三个特殊的参数, 其中第一个是必须提供的.
        # 参数    描述
        # path    必需参数. 一个目录的绝对文件系统路径. FilePathField 据此得到可选项目. 
        # Example: "/home/images".
        # match    可选参数. 一个正则表达式, 作为一个字符串, FilePathField 将使用它过滤文件名.  
        # 注意这个正则表达式只会应用到 base filename 而不是
        # 路径全名. Example: "foo.*\.txt^", 将匹配文件 foo23.txt 却不匹配 bar.txt 或 foo23.gif.
        # recursive可选参数.要么 True 要么 False. 默认值是 False. 是否包括 path 下面的全部子目录.
        # 这三个参数可以同时使用.
        # match 仅应用于 base filename, 而不是路径全名. 那么,这个例子:
        # FilePathField(path="/home/images", match="foo.*", recursive=True)
        # ...会匹配 /home/images/foo.gif 而不匹配 /home/images/foo/bar.gif

<17> IPAddressField
        # 一个字符串形式的 IP 地址, (i.e. "24.124.1.30").
<18># CommaSeparatedIntegerField
        # 用于存放逗号分隔的整数值. 类似 CharField, 必须要有maxlength参数.
字段类型

             <5>  Field重要参数

<1> null : 数据库中字段是否可以为空

    <2> blank: django的 Admin 中添加数据时是否可允许空值

    <3> default:设定缺省值

    <4> editable:如果为假,admin模式下将不能改写。缺省为真

    <5> primary_key:设置主键,如果没有设置django创建表时会自动加上:
        id = meta.AutoField('ID', primary_key=True)
        primary_key=True implies blank=False, null=False and unique=True. Only one
        primary key is allowed on an object.

    <6> unique:数据唯一

    <7> verbose_name  Admin中字段的显示名称

    <8> validator_list:有效性检查。非有效产生 django.core.validators.ValidationError 错误


    <9> db_column,db_index 如果为真将为此字段创建索引

    <10>choices:一个用来选择值的2维元组。第一个值是实际存储的值,第二个用来方便进行选择。
                如SEX_CHOICES= (( ‘F’,'Female’),(‘M’,'Male’),)
                gender = models.CharField(max_length=2,choices = SEX_CHOICES)
约束

3、表的操作(增删改查)

 表记录的添加:

def add(request):
    #方式一:
    b = book(name = "python",price=99,pub_date="1919-12-1")
    b.save()
    b = book(name="linux", price=88, pub_date="2000-12-1")
    b.save()
    b = book(name="django", price=22, pub_date="2222-1-1")
    b.save()

    # 方式二:
    book.objects.create(name="php", price=44, pub_date="1111-1-1")
    return HttpResponse("添加成功")

 

 

表记录的修改:

def modify(request):

    # 方式一:推荐使用
    book.objects.filter(name="php").update(price=444)

    # 方式二:
    b = book.objects.get(name="python")
    #book.objects.get(name="python")是一个model对象,只能取出一条记录,多条则报错
    b.price = 1212
    b.save()

    # 方式三:
    b = book.objects.filter(name="python")[0]
    #book.objects.filter(name="python")是一个QuerySet类型,是一个集合
    b.price = 1213
    b.save()

    return HttpResponse("修改成功")

表记录的删除:

def delete(request):

    book.objects.filter(name="php").delete()

    return HttpResponse("删除成功")

 九admin

 可参考的学习地址:

https://www.cnblogs.com/wumingxiaoyao/p/6928297.html

https://docs.djangoproject.com/en/1.11/ref/contrib/admin/actions/

django amdin是django提供的一个后台管理页面,改管理页面提供完善的html和css,使得你在通过Model创建完数据库表之后,就可以对数据进行增删改查,而使用django admin 则需要以下步骤:

 

  • 创建后台管理员
  • 配置url
  • 注册和配置django admin后台管理页面

 

注:不建议新手经常使用admin,会形成依赖,核心的是model模块的操作!

 

1、创建后台管理员

python manage.py createsuperuser

2、配置后台管理url(默认已配)

url(r'^admin/', include(admin.site.urls))

3、注册和配置django admin 后台管理页面

a、在admin中执行如下配置
from django.contrib import admin
  
from app01 import  models
  
admin.site.register(models.UserType)
admin.site.register(models.UserInfo)
admin.site.register(models.UserGroup)
admin.site.register(models.Asset)
View Code
b、设置数据表名称
class UserType(models.Model):
    name = models.CharField(max_length=50)
  
    class Meta:
        verbose_name = '用户类型'
        verbose_name_plural = '用户类型'
View Code
c、打开表之后,设定默认显示,需要在model中作如下配置
class UserType(models.Model):
    name = models.CharField(max_length=50)
  
    def __unicode__(self):  # python3 is __str__(self)
        return self.name
View Code
d、为数据表添加搜索功能
from django.contrib import admin
  
from app01 import  models
  
class UserInfoAdmin(admin.ModelAdmin):
    list_display = ('username', 'password', 'email')
    search_fields = ('username', 'email')
  
admin.site.register(models.UserType)
admin.site.register(models.UserInfo,UserInfoAdmin)
admin.site.register(models.UserGroup)
admin.site.register(models.Asset)
View Code
e、添加快速过滤
from django.contrib import admin
  
from app01 import  models
  
class UserInfoAdmin(admin.ModelAdmin):
    list_display = ('username', 'password', 'email')
    search_fields = ('username', 'email')
    list_filter = ('username', 'email')
      
  
  
admin.site.register(models.UserType)
admin.site.register(models.UserInfo,UserInfoAdmin)
admin.site.register(models.UserGroup)
admin.site.register(models.Asset)
View Code

 十,分页

page
View.py

十一,缓存

由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。

Django中提供了6种缓存方式:

  • 开发调试
  • 内存
  • 文件
  • 数据库
  • Memcache缓存(python-memcached模块)
  • Memcache缓存(pylibmc模块)

1、配置

a、开发调试

 # 此为开始调试用,实际内部不做任何操作
    # 配置:
        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.dummy.DummyCache',     # 引擎
                'TIMEOUT': 300,                                               # 缓存超时时间(默认300,None表示永不过期,0表示立即过期)
                'OPTIONS':{
                    'MAX_ENTRIES': 300,                                       # 最大缓存个数(默认300)
                    'CULL_FREQUENCY': 3,                                      # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
                },
                'KEY_PREFIX': '',                                             # 缓存key的前缀(默认空)
                'VERSION': 1,                                                 # 缓存key的版本(默认1)
                'KEY_FUNCTION' 函数名                                          # 生成key的函数(默认函数会生成为:【前缀:版本:key】)
            }
        }


    # 自定义key
    def default_key_func(key, key_prefix, version):
        """
        Default function to generate keys.

        Constructs the key used by all other methods. By default it prepends
        the `key_prefix'. KEY_FUNCTION can be used to specify an alternate
        function with custom key making behavior.
        """
        return '%s:%s:%s' % (key_prefix, version, key)

    def get_key_func(key_func):
        """
        Function to decide which key function to use.

        Defaults to ``default_key_func``.
        """
        if key_func is not None:
            if callable(key_func):
                return key_func
            else:
                return import_string(key_func)
        return default_key_func
View Code

b、内存

 # 此缓存将内容保存至内存的变量中
    # 配置:
        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
                'LOCATION': 'unique-snowflake',
            }
        }

    # 注:其他配置同开发调试版本
View Code

c、文件

  # 此缓存将内容保存至文件
    # 配置:

        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
                'LOCATION': '/var/tmp/django_cache',
            }
        }
    # 注:其他配置同开发调试版本
View Code

d、数据库

# 此缓存将内容保存至数据库

    # 配置:
        CACHES = {
            'default': {
                'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
                'LOCATION': 'my_cache_table', # 数据库表
            }
        }

    # 注:执行创建表命令 python manage.py createcachetable
View Code

e、Memcache缓存(python-memcached模块)

# 此缓存使用python-memcached模块连接memcache

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': '127.0.0.1:11211',
        }
    }

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': 'unix:/tmp/memcached.sock',
        }
    }   

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': [
                '172.19.26.240:11211',
                '172.19.26.242:11211',
            ]
        }
    }
View Code

f、Memcache缓存(pylibmc模块)

 # 此缓存使用pylibmc模块连接memcache
    
    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
            'LOCATION': '127.0.0.1:11211',
        }
    }

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
            'LOCATION': '/tmp/memcached.sock',
        }
    }   

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
            'LOCATION': [
                '172.19.26.240:11211',
                '172.19.26.242:11211',
            ]
        }
    }
View Code

g. Redis缓存(依赖:pip3 install django-redis)

CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS": {"max_connections": 100}
            # "PASSWORD": "密码",
        }
    }
}
View Code
from django_redis import get_redis_connection
conn = get_redis_connection("default")
视图中链接并操作

2、应用

a. 全站使用

   使用中间件,经过一系列的认证等操作,如果内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户,当返回给用户之前,判断缓存中是否已经存在,如果不存在则UpdateCacheMiddleware会将缓存保存至缓存,从而实现全站缓存

    MIDDLEWARE = [
        'django.middleware.cache.UpdateCacheMiddleware',
        # 其他中间件...
        'django.middleware.cache.FetchFromCacheMiddleware',
    ]

    CACHE_MIDDLEWARE_ALIAS = ""
    CACHE_MIDDLEWARE_SECONDS = ""
    CACHE_MIDDLEWARE_KEY_PREFIX = ""
View Code

b. 单独视图缓存

 方式一:
        from django.views.decorators.cache import cache_page

        @cache_page(60 * 15)
        def my_view(request):
            ...

    方式二:
        from django.views.decorators.cache import cache_page

        urlpatterns = [
            url(r'^foo/([0-9]{1,2})/$', cache_page(60 * 15)(my_view)),
        ]
View Code

c、局部视图使用

    a. 引入TemplateTag

        {% load cache %}

    b. 使用缓存

        {% cache 5000 缓存key %}
            缓存内容
        {% endcache %}
View Code

序列化

关于Django中的序列化主要应用在将数据库中检索的数据返回给客户端用户,特别的Ajax请求一般返回的为Json格式。

1、serializers

from django.core import serializers
ret = models.BookType.objects.all()
data = serializers.serialize("json", ret)

2、json.dumps

import json
 
#ret = models.BookType.objects.all().values('caption')
ret = models.BookType.objects.all().values_list('caption')
 
ret=list(ret)
result = json.dumps(ret)

由于json.dumps时无法处理datetime日期,所以可以通过自定义处理器来做扩展,如:

import json 
from datetime import date 
from datetime import datetime 
   
class JsonCustomEncoder(json.JSONEncoder): 
    
    def default(self, field): 
     
        if isinstance(field, datetime): 
            return o.strftime('%Y-%m-%d %H:%M:%S') 
        elif isinstance(field, date): 
            return o.strftime('%Y-%m-%d') 
        else: 
            return json.JSONEncoder.default(self, field) 
   
   
# ds = json.dumps(d, cls=JsonCustomEncoder) 
View Code

十二,信号

Django中提供了“信号调度”,用于在框架执行操作时解耦。通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者。

1、Django内置信号

Model signals
    pre_init                    # django的modal执行其构造方法前,自动触发
    post_init                   # django的modal执行其构造方法后,自动触发
    pre_save                    # django的modal对象保存前,自动触发
    post_save                   # django的modal对象保存后,自动触发
    pre_delete                  # django的modal对象删除前,自动触发
    post_delete                 # django的modal对象删除后,自动触发
    m2m_changed                 # django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
    class_prepared              # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发
Management signals
    pre_migrate                 # 执行migrate命令前,自动触发
    post_migrate                # 执行migrate命令后,自动触发
Request/response signals
    request_started             # 请求到来前,自动触发
    request_finished            # 请求结束后,自动触发
    got_request_exception       # 请求异常后,自动触发
Test signals
    setting_changed             # 使用test测试修改配置文件时,自动触发
    template_rendered           # 使用test测试渲染模板时,自动触发
Database Wrappers
    connection_created          # 创建数据库连接时,自动触发

对于Django内置的信号,仅需注册指定信号,当程序执行相应操作时,自动触发注册函数:

    from django.core.signals import request_finished
    from django.core.signals import request_started
    from django.core.signals import got_request_exception

    from django.db.models.signals import class_prepared
    from django.db.models.signals import pre_init, post_init
    from django.db.models.signals import pre_save, post_save
    from django.db.models.signals import pre_delete, post_delete
    from django.db.models.signals import m2m_changed
    from django.db.models.signals import pre_migrate, post_migrate

    from django.test.signals import setting_changed
    from django.test.signals import template_rendered

    from django.db.backends.signals import connection_created


    def callback(sender, **kwargs):
        print("xxoo_callback")
        print(sender,kwargs)

    xxoo.connect(callback)
    # xxoo指上述导入的内容
View Code
from django.core.signals import request_finished
from django.dispatch import receiver

@receiver(request_finished)
def my_callback(sender, **kwargs):
    print("Request finished!")
View Code

2、自定义信号

a. 定义信号

import django.dispatch
pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

b. 注册信号

def callback(sender, **kwargs):
    print("callback")
    print(sender,kwargs)
 
pizza_done.connect(callback)

c. 触发信号

from 路径 import pizza_done
 
pizza_done.send(sender='seven',toppings=123, size=456)

 

posted @ 2018-07-21 11:58  小L小  阅读(348)  评论(0编辑  收藏  举报