• 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
    
    ".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{
                 100%;
                height: 40px;
                background-color: #7259ff;
                line-height: 40px;
                text-align: center;
                color: white;
                font-size: 20px;
            }
            .left{
                 20%;
                min-height: 600px;
                background-color: darkgray;
            }
            .manager{
                text-align: center;
                padding: 20px 0;
                font-size: 25px;
            }
            .content{
                 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)
  • 相关阅读:
    XSS
    XSS练习小游戏
    CTF中常见的编码
    BugkuCTF
    A、B、C、D和E类IP地址
    JDK和JRE的区别及配置
    SQL注入漏洞测试(HTTP头注入)
    MS17-010远程溢出漏洞(CVE-2017-0143)拿权限
    SQL注入——布尔型盲注注入攻击——手工注入篇——SQL手工注入漏洞测试(MySQL数据库)
    mysql增删改查
  • 原文地址:https://www.cnblogs.com/lanyinhao/p/9346171.html
Copyright © 2020-2023  润新知