Django(一)URL views template

Django概念及原理

概念

框架,即framework,特指为解决一个开放性问题而设计的具备必定约束性的支撑结构,使用框架能够帮你快速开发特定的系统,简单地说,就是你用别人搭建好的舞台来作表演(不用本身搭建地基建设舞台,只须要专心表演好就行)css

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, yuan</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()
View Code

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

若是要动态生成HTML,就须要把上述步骤本身来实现。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,若是咱们本身来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。正确的作法是底层代码由专门的服务器软件实现,咱们用Python专一于生成HTML文档。由于咱们不但愿接触到TCP链接、HTTP原始请求和响应格式,因此,须要一个统一的接口,让咱们专心用Python编写Web业务。这个接口就是WSGI:Web Server Gateway Interface。前端

 

 

 

-----------------------------Do a web  framework ourselves---------------------------python

//基础版 from wsgiref.simple_server import make_server def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return [b'<h1>Hello, web!</h1>'] httpd = make_server('', 8080, application) print('Serving HTTP on port 8000...') # 开始监听HTTP请求:
httpd.serve_forever() //升级版 print(environ['PATH_INFO']) path=environ['PATH_INFO'] start_response('200 OK', [('Content-Type', 'text/html')]) f1=open("index1.html","rb") data1=f1.read() f2=open("index2.html","rb") data2=f2.read() if path=="/yuan": return [data1] elif path=="/alex": return [data2] else: return ["<h1>404</h1>".encode('utf8')] //再升级 from wsgiref.simple_server import make_server def f1(): f1=open("index1.html","rb") data1=f1.read() return [data1] def f2(): f2=open("index2.html","rb") data2=f2.read() return [data2] def application(environ, start_response): print(environ['PATH_INFO']) path=environ['PATH_INFO'] start_response('200 OK', [('Content-Type', 'text/html')]) if path=="/yuan": return f1() elif path=="/alex": return f2() else: return ["<h1>404</h1>".encode("utf8")] httpd = make_server('', 8502, application) print('Serving HTTP on port 8084...') # 开始监听HTTP请求:
httpd.serve_forever() //最终版 from wsgiref.simple_server import make_server def f1(req): print(req) print(req["QUERY_STRING"]) f1=open("index1.html","rb") data1=f1.read() return [data1] def f2(req): f2=open("index2.html","rb") data2=f2.read() return [data2] import time def f3(req):        #模版以及数据库
 f3=open("index3.html","rb") data3=f3.read() times=time.strftime("%Y-%m-%d %X", time.localtime()) data3=str(data3,"utf8").replace("!time!",str(times)) return [data3.encode("utf8")] def routers(): urlpatterns = ( ('/yuan',f1), ('/alex',f2), ("/cur_time",f3) ) return urlpatterns def application(environ, start_response): print(environ['PATH_INFO']) path=environ['PATH_INFO'] start_response('200 OK', [('Content-Type', 'text/html')]) urlpatterns = routers() func = None for item in urlpatterns: if item[0] == path: func = item[1] break
    if func: return func(environ) else: return ["<h1>404</h1>".encode("utf8")] httpd = make_server('', 8518, application) print('Serving HTTP on port 8084...') # 开始监听HTTP请求:
 httpd.serve_forever()

整个application()函数自己没有涉及到任何解析HTTP的部分,也就是说,底层代码不须要咱们本身编写,咱们只负责在更高层次上考虑如何响应请求就能够了。application()函数必须由WSGI服务器来调用。有不少符合WSGI规范的服务器,咱们能够挑选一个来用。Python内置了一个WSGI服务器,这个模块叫wsgiref jquery

  application()函数就是符合WSGI标准的一个HTTP处理函数,它接收两个参数:nginx

    //environ:一个包含全部HTTP请求信息的dict对象;git

    //start_response:一个发送HTTP响应的函数。程序员

  在application()函数中,调用:web

    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。

MVC和MTV模式

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

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

 

 

 

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

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

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

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

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

 

 

 

django的流程和命令行工具

django流程

django #安装: pip3 install django
 添加环境变量 #1 建立project
       django-admin startproject mysite ---mysite ---settings.py ---url.py ---wsgi.py ---- manage.py(启动文件) #2 建立APP 
 python mannage.py startapp app01 #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   

  注意:在开发过程当中,数据库同步误操做以后,不免会遇到后面不能同步成功的状况,解决这个问题的一个简单粗暴方法是把migrations目录下的脚本(除__init__.py以外)所有删掉,再把数据库删掉以后建立一个新的数据库,数据库同步操做再从新作一遍。   

<5>当咱们访问http://127.0.0.1:8080/admin/时,会出现:

 

 

 因此咱们须要为进入这个项目的后台建立超级管理员:python manage.py createsuperuser设置好用户名和密码后即可登陆啦!

<6>清空数据库:python manage.py  flush

<7>查询某个命令的详细信息: django-admin.py  help  startapp

       admin 是Django 自带的一个后台数据库管理系统。

<8>启动交互界面 :python manage.py  shell

     这个命令和直接运行 python 进入 shell 的区别是:你能够在这个 shell 里面调用当前项目的 models.py 中的 API,对于操做数据,还有一些小测试很是方便。

<9> 终端上输入python manage.py 能够看到详细的列表,在忘记子名称的时候特别有用

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>建立我的信息</h1>

<form action="/userInfor/" method="post">

    <p>姓名<input type="text" name="username"></p>
    <p>性别<input type="text" name="sex"></p>
    <p>邮箱<input type="text" name="email"></p>
    <p><input type="submit" value="submit"></p>

</form>

<hr>

<h1>信息展现</h1>

<table border="1">

    <tr>
        <td>姓名</td>
        <td>性别</td>
        <td>邮箱</td>
    </tr> {% for i in info_list %} <tr>
            <td>{{ i.username }}</td>
            <td>{{ i.sex }}</td>
            <td>{{ i.email }}</td>
        </tr> {% endfor %} </table>

</body>
</html>


-----------------------url.py--------------------------------------- url(r'^userInfor/', views.userInfor) -----------------------views.py-------------------------------------- info_list=[] def userInfor(req): if req.method=="POST": username=req.POST.get("username",None) sex=req.POST.get("sex",None) email=req.POST.get("email",None) info={"username":username,"sex":sex,"email":email} info_list.append(info) return render(req,"userInfor.html",{"info_list":info_list})
实例练习1-提交数据并展现
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>建立我的信息</h1>

<form action="/userInfor/" method="post">

    <p>姓名<input type="text" name="username"></p>
    <p>性别<input type="text" name="sex"></p>
    <p>邮箱<input type="text" name="email"></p>
    <p><input type="submit" value="submit"></p>

</form>

<hr>

<h1>信息展现</h1>

<table border="1">

    <tr>
        <td>姓名</td>
        <td>性别</td>
        <td>邮箱</td>
    </tr> {% for i in info_list %} <tr>
            <td>{{ i.username }}</td>
            <td>{{ i.sex }}</td>
            <td>{{ i.email }}</td>
        </tr> {% endfor %} </table>

</body>
</html>


----------------------------------------------models.py from django.db import models # Create your models here.


class UserInfor(models.Model): username=models.CharField(max_length=64) sex=models.CharField(max_length=64) email=models.CharField(max_length=64) ----------------------------------------------views.py from django.shortcuts import render from app01 import models # Create your views here.


def userInfor(req): if req.method=="POST": u=req.POST.get("username",None) s=req.POST.get("sex",None) e=req.POST.get("email",None) #---------表中插入数据方式一
            # info={"username":u,"sex":e,"email":e}
            # models.UserInfor.objects.create(**info)

       #---------表中插入数据方式二
 models.UserInfor.objects.create( username=u, sex=s, email=e ) info_list=models.UserInfor.objects.all() return render(req,"userInfor.html",{"info_list":info_list}) return render(req,"userInfor.html")
实例练习2-提交数据并展现(数据库)

Django基本配置

 

 

 

 

  

 

静态文件static

1、概述: #静态文件交由Web服务器处理,Django自己不处理静态文件。简单的处理逻辑以下(以nginx为例):

     # URI请求-----> 按照Web服务器里面的配置规则先处理,以nginx为例,主要求配置在nginx.
                             #conf里的location

                         |---------->若是是静态文件,则由nginx直接处理 |---------->若是不是则交由Django处理,Django根据urls.py里面的规则进行匹配 # 以上是部署到Web服务器后的处理方式,为了便于开发,Django提供了在开发环境的对静态文件的处理机制,方法是这样:

    #一、在INSTALLED_APPS里面加入'django.contrib.staticfiles',

    #二、在urls.py里面加入
       if settings.DEBUG: urlpatterns += patterns('', url(r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT }), url(r'^static/(?P<path>.*)$', 'django.views.static.serve',{'document_root':settings.STATIC_ROOT}), ) # 三、这样就能够在开发阶段直接使用静态文件了。
 2、MEDIA_ROOT和MEDIA_URL #而静态文件的处理又包括STATIC和MEDIA两类,这每每容易混淆,在Django里面是这样定义的:

        #MEDIA:指用户上传的文件,好比在Model里面的FileFIeld,ImageField上传的文件。若是你定义

        #MEDIA_ROOT=c:\temp\media,那么File=models.FileField(upload_to="abc/")#,上传的文件就会被保存到c:\temp\media\abc 
        #eg:
            class blog(models.Model): Title=models.charField(max_length=64) Photo=models.ImageField(upload_to="photo") # 上传的图片就上传到c:\temp\media\photo,而在模板中要显示该文件,则在这样写
        #在settings里面设置的MEDIA_ROOT必须是本地路径的绝对路径,通常是这样写:
                 BASE_DIR= os.path.abspath(os.path.dirname(__file__)) MEDIA_ROOT=os.path.join(BASE_DIR,'media/').replace('\\','/') #MEDIA_URL是指从浏览器访问时的地址前缀,举个例子:
            MEDIA_ROOT=c:\temp\media\photo MEDIA_URL="/data/"
        #在开发阶段,media的处理由django处理:

        # 访问http://localhost/data/abc/a.png就是访问c:\temp\media\photo\abc\a.png

        # 在模板里面这样写<img src="{{MEDIA_URL}}abc/a.png">

        # 在部署阶段最大的不一样在于你必须让web服务器来处理media文件,所以你必须在web服务器中配置,
        # 以便能让web服务器能访问media文件
        # 以nginx为例,能够在nginx.conf里面这样:
 location ~/media/{ root/temp/
                       break; } # 具体能够参考如何在nginx部署django的资料。
 3、STATIC_ROOT和STATIC_URL、 STATIC主要指的是如css,js,images这样文件,在settings里面能够配置STATIC_ROOT和STATIC_URL, 配置方式与MEDIA_ROOT是同样的,可是要注意 #STATIC文件通常保存在如下位置:

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

    #二、app的static文件夹,在每一个app所在文夹都可以创建一个static文件夹,而后当运行collectstatic时,
    # Django会遍历INSTALL_APPS里面全部app的static文件夹,将里面全部的文件复制到STATIC_ROOT。所以,
    # 若是你要创建可复用的app,那么你要将该app所须要的静态文件放在static文件夹中。

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

    #三、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=( ('hello',os.path.join(BASE_DIR,"app01","statics")) , ) #<script src="/static/hello/jquery-1.8.2.min.js"></script>

    #注意3:
        STATIC_URL = '/static/' {% load staticfiles %} # <script src={% static "jquery-1.8.2.min.js" %}></script>

Django URL(路由系统)

简述

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

urlpatterns = [ url(正则表达式, views视图函数,参数,别名), ] 参数说明: 一个正则表达式字符串 一个可调用对象,一般为一个视图函数或一个指定视图函数路径的字符串 可选的要传递给视图函数的默认参数(字典形式) 一个可选的name参数

例如

from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), #url(r'^articles/[0-9]{4}/$', views.year_archive),
 url(r'^articles/([0-9]{4})/$', views.year_archive),  #no_named group
 url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail), ]

注意

#1 There’s no need to add a leading slash, because every URL has that. For # example, it’s ^articles, not ^/articles.

#2 A request to /articles/2005/03/ would match the third entry in the list. # Django would call the function views.month_archive(request, '2005', '03').

#3 /articles/2005/3/ would not match any URL patterns

#4 /articles/2003/ would match the first pattern in the list, not the second one

#5 /articles/2003/03/03/ would match the final pattern. Django would call the # functionviews.article_detail(request, '2003', '03', '03').

分组Named groups

The above example used simple, non-named regular-expression groups (via parenthesis) to capture bits of the URL and pass them as positional arguments to a view. In more advanced usage, it’s possible to use named regular-expression groups to capture URL bits and pass them as keyword arguments to a view.

       In Python regular expressions, the syntax for named regular-expression groups is (?P<name>pattern), where name is the name of the group and pattern is some pattern to match.

Here’s the above example URLconf, rewritten to use named groups:

正则中的分组使用

import re ret=re.search('(?P<id>\d{3})/(?P<name>\w{3})','weeew34ttt123/ooo') print(ret.group()) print(ret.group('id')) print(ret.group('name')) ready

Django中的使用:命名后的year会做为形参匹配到的views中的函数

from django.conf.urls import url from . import views urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive), url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive), url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail), ]

This accomplishes exactly the same thing as the previous example, with one subtle difference: The captured values are passed to view functions as keyword arguments rather than positional arguments.

Passing extra options to view functions

 URLconfs have a hook that lets you pass extra arguments to your view functions, as a Python dictionary.

The django.conf.urls.url() function can take an optional third argument which should be a dictionary of extra keyword arguments to pass to the view function.

For example:

from django.conf.urls import url from . import views urlpatterns = [ url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}), ]

 In this example, for a request to /blog/2005/, Django will call views.year_archive(request, year='2005',foo='bar').

This technique is used in the syndication framework to pass metadata and options to views.

Dealing with conflicts

       It’s possible to have a URL pattern which captures named keyword arguments, and also passes arguments with the same names in its dictionary of extra arguments. When this happens, the arguments in the dictionary will be used instead of the arguments captured in the URL.

name param

urlpatterns = [ url(r'^index',views.index,name='bieming'), url(r'^admin/', admin.site.urls), # url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/([0-9]{4})/$', views.year_archive), # url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
    # url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
 ] ###################

def index(req): if req.method=='POST': username=req.POST.get('username') password=req.POST.get('password') if username=='alex' and password=='123': return HttpResponse("登录成功") return render(req,'index.html') #####################

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body> {# <form action="/index/" method="post">#}
     <form action="{% url 'bieming' %}" method="post"> 用户名:<input type="text" name="username"> 密码:<input type="password" name="password">
         <input type="submit" value="submit">
     </form>
</body>
</html>


#######################

Including other URLconfs

#At any point, your urlpatterns can “include” other URLconf modules. This #essentially “roots” a set of URLs below other ones.

#For example, here’s an excerpt of the URLconf for the Django website itself. #It includes a number of other URLconfs:


from django.conf.urls import include, url urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^blog/', include('blog.urls')), ]

图解

 

 

 

 

 

 

 

Django Views(视图函数)

 

 

http请求中产生两个核心对象:        http请求:HttpRequest对象        http响应:HttpResponse对象

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

 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

注意一个经常使用方法:request.POST.getlist('')

HttpResponse对象

对于HttpRequest对象来讲,是由django自动建立的,可是,HttpResponse对象就必须咱们本身建立。每一个view请求处理方法必须返回一个HttpResponse对象。

  HttpResponse类在django.http.HttpResponse

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

页面渲染:         render()(推荐)<br> render_to_response(), 页面跳转: redirect("路径") locals(): 能够直接将函数中全部的变量传给模板
-----------------------------------url.py url(r"login", views.login), url(r"yuan_back", views.yuan_back), -----------------------------------views.py def login(req): if req.method=="POST": if 1: # return redirect("/yuan_back/")
            name="yuanhao"

            return render(req,"my backend.html",locals()) return render(req,"login.html",locals()) def yuan_back(req): name="苑昊"

    return render(req,"my backend.html",locals()) -----------------------------------login.html <form action="/login/" method="post">
    <p>姓名<input type="text" name="username"></p>
    <p>性别<input type="text" name="sex"></p>
    <p>邮箱<input type="text" name="email"></p>
    <p><input type="submit" value="submit"></p>
</form>
-----------------------------------my backend.html <h1>用户{{ name }}你好</h1>

#总结: render和redirect的区别: # 1 if render的页面须要模板语言渲染,须要的将数据库的数据加载到html,那么全部的这一部分 # 除了写在yuan_back的视图函数中,必须还要写在login中,代码重复,没有解耦.

# 2 the most important: url没有跳转到/yuan_back/,而是还在/login/,因此当刷新后 # 又得从新登陆.

 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)来实现

语法

模板也就是添加了模板语言的html文件,在后端的时候将模板利用模板语言渲染成纯html文件,再发给客户端

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

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

语法格式:       {{var_name}}

1、Template和Context对象

>>> 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}))

Django 模板解析很是快捷。 大部分的解析工做都是在后台经过对简短正则表达式一次性调用来完成。 这和基于 XML 的模板引擎造成鲜明对比,那些引擎承担了 XML 解析器的开销,且每每比 Django 模板渲染引擎要慢上几个数量级。

推荐使用的方法:

from django.shortcuts import render,HttpResponse from django.template.loader import get_template #记得导入 # Create your views here.


import datetime from django.template import Template,Context # def current_time(req):
    #原始的视图函数
    # now=datetime.datetime.now()
    # html="<html><body>如今时刻:<h1>%s.</h1></body></html>" %now
    # return HttpResponse(html)



# def current_time(req):

      #django模板修改的视图函数 # now=datetime.datetime.now() # t=Template('<html><body>如今时刻是:<h1 style="color:red">{{current_date}}</h1></body></html>')
      #t=get_template('current_datetime.html') # c=Context({'current_date':now}) # html=t.render(c) # return HttpResponse(html)

#另外一种写法(推荐)

def current_time(req): now=datetime.datetime.now() return render(req, 'current_datetime.html', {'current_date':now})

2、深度变量的查找(万能的句点号)

在到目前为止的例子中,咱们经过 context 传递的简单参数值主要是字符串,然而,模板系统可以很是简洁地处理更加复杂的数据结构,例如list、dictionary和自定义的对象。

在 Django 模板中遍历复杂数据结构的关键是句点字符 (.)。

#最好是用几个例子来讲明一下。 # 首先,句点可用于访问列表索引,例如:

>>> from django.template import Template, Context >>> t = Template('Item 2 is {{ items.2 }}.') >>> c = Context({'items': ['apples', 'bananas', 'carrots']}) >>> t.render(c) 'Item 2 is carrots.'

#假设你要向模板传递一个 Python 字典。 要经过字典键访问该字典的值,可以使用一个句点:
>>> from django.template import Template, Context >>> person = {'name': 'Sally', 'age': '43'} >>> t = Template('{{ person.name }} is {{ person.age }} years old.') >>> c = Context({'person': person}) >>> t.render(c) 'Sally is 43 years old.'

#一样,也能够经过句点来访问对象的属性。 比方说, Python 的 datetime.date 对象有 #year 、 month 和 day 几个属性,你一样能够在模板中使用句点来访问这些属性:

>>> from django.template import Template, Context >>> import datetime >>> d = datetime.date(1993, 5, 2) >>> d.year >>> d.month >>> d.day >>> t = Template('The month is {{ date.month }} and the year is {{ date.year }}.') >>> c = Context({'date': d}) >>> t.render(c) 'The month is 5 and the year is 1993.'

# 这个例子使用了一个自定义的类,演示了经过实例变量加一点(dots)来访问它的属性,这个方法适 # 用于任意的对象。
>>> from django.template import Template, Context >>> class Person(object): ... def __init__(self, first_name, last_name): ... self.first_name, self.last_name = first_name, last_name >>> t = Template('Hello, {{ person.first_name }} {{ person.last_name }}.') >>> c = Context({'person': Person('John', 'Smith')}) >>> t.render(c) 'Hello, John Smith.'

# 点语法也能够用来引用对象的方法。 例如,每一个 Python 字符串都有 upper() 和 isdigit() # 方法,你在模板中可使用一样的句点语法来调用它们:
>>> from django.template import Template, Context >>> t = Template('{{ var }} -- {{ var.upper }} -- {{ var.isdigit }}') >>> t.render(Context({'var': 'hello'})) 'hello -- HELLO -- False'
>>> t.render(Context({'var': '123'})) '123 -- 123 -- True'

# 注意这里调用方法时并* 没有* 使用圆括号 并且也没法给该方法传递参数;你只能调用不需参数的 # 方法。

3、变量的过滤器(filter)的使用

语法格式:      {{obj|filter:param}}
# 1 add : 给变量加上相应的值
   #    # 2 addslashes : 给变量中的引号前加上斜线
   #    # 3 capfirst : 首字母大写
   #    # 4 cut : 从字符串中移除指定的字符
   #    # 5 date : 格式化日期字符串
   #    # 6 default : 若是值是False,就替换成设置的默认值,不然就是用原本的值
   #    # 7 default_if_none: 若是值是None,就替换成设置的默认值,不然就使用原本的值


#实例:

#value1="aBcDe"
{{ value1|upper }}<br>

#value2=5
{{ value2|add:3 }}<br>

#value3='he llo wo r ld'
{{ value3|cut:' ' }}<br>

#import datetime #value4=datetime.datetime.now()
{{ value4|date:'Y-m-d' }}<br>

#value5=[]
{{ value5|default:'空的' }}<br>

#value6='<a href="#">跳转</a>'
 {{ value6 }} {% autoescape off %} {{ value6 }} {% endautoescape %} {{ value6|safe }}<br> {{ value6|striptags }} #value7='1234'
{{ value7|filesizeformat }}<br> {{ value7|first }}<br> {{ value7|length }}<br> {{ value7|slice:":-1" }}<br>

#value8='http://www.baidu.com/?a=1&b=3'
{{ value8|urlencode }}<br> value9='hello I am yuan'

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

{% tags %}

{% 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 %}
View Code

{% 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>
View Code

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

{% with total=fhjsaldfhjsdfhlasdfhljsdal %} {{ total }} {% endwith %}

{% verbatim %}: 禁止render

{% verbatim %} {{ hello }} {% endverbatim %}

自定义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)
View Code
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 %}
View Code

e、在settings中的INSTALLED_APPS配置当前app,否则django没法找到自定义的simple_tag.

注意:

filter能够用在if等语句后,simple_tag不能够

{% if num|filter_multi:30 > 100 %} {{ num|filter_multi:30 }} {% endif %}

 

 

 

 

extend模板继承

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

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

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

让咱们经过修改 current_datetime.html 文件,为 current_datetime 建立一个更加完整的模板来体会一下这种作法:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
    <title>The current time</title>
</head>
<body>
    <h1>My helpful timestamp site</h1>
    <p>It is now {{ current_date }}.</p>
 
    <hr>
    <p>Thanks for visiting my site.</p>
</body>
</html>
View Code

这看起来很棒,但若是咱们要为 hours_ahead 视图建立另外一个模板呢?

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
    <title>Future time</title>
</head>
<body>
    <h1>My helpful timestamp site</h1>
    <p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p>
 
    <hr>
    <p>Thanks for visiting my site.</p>
</body>
</html>
View Code

很明显,咱们刚才重复了大量的 HTML 代码。 想象一下,若是有一个更典型的网站,它有导航条、样式表,可能还有一些 JavaScript 代码,事情必将以向每一个模板填充各类冗余的 HTML 而了结。

解决这个问题的服务器端 include 方案是找出两个模板中的共同部分,将其保存为不一样的模板片断,而后在每一个模板中进行 include。 也许你会把模板头部的一些代码保存为 header.html 文件:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>

你可能会把底部保存到文件 footer.html :

<hr>
    <p>Thanks for visiting my site.</p>
</body>
</html>

对基于 include 的策略,头部和底部的包含很简单。 麻烦的是中间部分。 在此范例中,每一个页面都有一个<h1>My helpful timestamp site</h1> 标题,可是这个标题不能放在 header.html 中,由于每一个页面的 <title> 是不一样的。 若是咱们将 <h1> 包含在头部,咱们就不得不包含 <title> ,但这样又不容许在每一个页面对它进行定制。 何去何从呢?

Django 的模板继承系统解决了这些问题。 你能够将其视为服务器端 include 的逆向思惟版本。 你能够对那些不一样 的代码段进行定义,而不是 共同 代码段。

第一步是定义 基础模板,该框架以后将由子模板所继承。 如下是咱们目前所讲述范例的基础模板:

{% extends "base.html" %} {% block title %}The current time{% endblock %} {% block content %} <p>It is now {{ current_date }}.</p> {% endblock %}

再为 hours_ahead 视图建立一个模板,看起来是这样的:

{% extends "base.html" %} {% block title %}Future time{% endblock %} {% block content %} <p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p> {% endblock %}

看起来很漂亮是否是? 每一个模板只包含对本身而言 独一无二 的代码。 无需多余的部分。 若是想进行站点级的设计修改,仅需修改 base.html ,全部其它模板会当即反映出所做修改。

在加载 current_datetime.html 模板时,模板引擎发现了 {% extends %} 标签, 注意到该模板是一个子模板。 模板引擎当即装载其父模板,即本例中的 base.html 。此时,模板引擎注意到 base.html 中的三个 {% block %} 标签,并用子模板的内容替换这些 block 。所以,引擎将会使用咱们在 block title %} 中定义的标题,对 {% block content %} 也是如此。 因此,网页标题一块将由{% block title %}替换,一样地,网页的内容一块将由 {% block content %}替换。

     注意因为子模板并无定义 footer 块,模板系统将使用在父模板中定义的值。 父模板 {% block %} 标签中的内容老是被看成一条退路。继承并不会影响到模板的上下文。 换句话说,任何处在继承树上的模板均可以访问到你传到模板中的每个模板变量。你能够根据须要使用任意多的继承次数。 使用继承的一种常见方式是下面的三层法:

<1> 建立 base.html 模板,在其中定义站点的主要外观感觉。 这些都是不常修改甚至从不修改的部分。 <2> 为网站的每一个区域建立 base_SECTION.html 模板(例如, base_photos.html 和 base_forum.html )。这些模板对base.html 进行拓展, 并包含区域特定的风格与设计。 <3> 为每种类型的页面建立独立的模板,例如论坛页面或者图片库。 这些模板拓展相应的区域模板。

这个方法可最大限度地重用代码,并使得向公共区域(如区域级的导航)添加内容成为一件轻松的工做。

如下是使用模板继承的一些诀窍:

<1>若是在模板中使用 {% extends %} ,必须保证其为模板中的第一个模板标记。 不然,模板继承将不起做用。 <2>通常来讲,基础模板中的 {% block %} 标签越多越好。 记住,子模板没必要定义父模板中全部的代码块,所以 你能够用合理的缺省值对一些代码块进行填充,而后只对子模板所需的代码块进行(重)定义。 俗话说,钩子越 多越好。 <3>若是发觉本身在多个模板之间拷贝代码,你应该考虑将该代码段放置到父模板的某个 {% block %} 中。 若是你须要访问父模板中的块的内容,使用 {{ block.super }}这个标签吧,这一个魔法变量将会表现出父模 板中的内容。 若是只想在上级代码块基础上添加内容,而不是所有重载,该变量就显得很是有用了。 <4>不容许在同一个模板中定义多个同名的 {% block %} 。 存在这样的限制是由于block 标签的工做方式是双向的。 也就是说,block 标签不只挖了一个要填的坑,也定义了在父模板中这个坑所填充的内容。若是模板中出现了两个 相同名称的 {% block %} 标签,父模板将无从得知要使用哪一个块的内容。

 

因此须要引入模板的概念,模板包括template对象和context对象

 

 

 

 

 

 

 

 

 

 

当一个页面中只有部份内容不同,大部份内容同样时,可使用继承标签,减小代码冗余

 

 

 

 

csrf机制

 

 

 

 

html中使用别名指代静态文件路径

渲染相关

 

 

 

 

 

相关文章
相关标签/搜索