• Django 路由、模板和模型系统


    一、路由系统

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

    1、1 路由格式

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

    示例

    下面是一个简单的 URLconf:

    from django.conf.urls import url
    
    from . 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})/([0-9]{2})/$', views.month_archive),
        url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
    ]
    NOTE:
        1 一旦匹配成功则不再继续
        2 若要从URL 中捕获一个值,只需要在它周围放置一对圆括号。
        3 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
        4 每个正则表达式前面的'r' 是可选的但是建议加上。
    
    一些请求的例子:
    /articles/2005/3/ 不匹配任何URL 模式,因为列表中的第三个模式要求月份应该是两个数字。
    /articles/2003/ 将匹配列表中的第一个模式不是第二个,因为模式按顺序匹配,第一个会首先测试是否匹配。
     /articles/2005/03/ 请求将匹配列表中的第三个模式。Django 将调用函数
                           views.month_archive(request, '2005', '03')。
    #设置项是否开启URL访问地址后面不为/跳转至带有/的路径
    APPEND_SLASH=True
    SLASH
    urls.py
    1.普通路由
    url(r'^index/', views.index),
    2.正则路由
    url(r'^page/d+', views.page),
    匹配开头结束
    正则表达式:
    以**开头,利用^,例如:url(r'^index/', views.index),
    以**结尾,利用$,例如:url(r'index/$', views.index),
    通过域名进行访问,显示默认首页,例如:url(r'^$', views.index),

    1、2 有名分组(named group)

    上面的示例使用简单的、没有命名的正则表达式组(通过圆括号)来捕获URL 中的值并以位置 参数传递给视图。在更高级的用法中,可以使用命名的正则表达式组来捕获URL 中的值并以关键字 参数传递给视图。

    在Python 正则表达式中,命名正则表达式组的语法是(?P<name>pattern),其中name 是组的名称,pattern 是要匹配的模式。

    下面是以上URLconf 使用命名组的重写:

    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),
    ]

    这个实现与前面的示例完全相同,只有一个细微的差别:捕获的值作为关键字参数而不是位置参数传递给视图函数。例如:

    /articles/2005/03/    
    请求将调用views.month_archive(request, year='2005', month='03')函数
    /articles/2003/03/03/ 
    请求将调用函数views.article_detail(request, year='2003', month='03', day='03')。

    在实际应用中,这意味你的URLconf 会更加明晰且不容易产生参数顺序问题的错误 —— 你可以在你的视图函数定义中重新安排参数的顺序。当然,这些好处是以简洁为代价;有些开发人员认为命名组语法丑陋而繁琐。

    1、3  URLconf 在什么上查找

    URLconf 在请求的URL 上查找,将它当做一个普通的Python 字符串。不包括GET和POST参数以及域名。

    例如,http://www.example.com/myapp/ 请求中,URLconf 将查找myapp/。

    在http://www.example.com/myapp/?page=3 请求中,URLconf 仍将查找myapp/。

    URLconf 不检查请求的方法。换句话讲,所有的请求方法 —— 同一个URL的POST、GET、HEAD等等 —— 都将路由到相同的函数。

    1、4 捕获的参数永远是字符串

    每个捕获的参数都作为一个普通的Python 字符串传递给视图,无论正则表达式使用的是什么匹配方式。例如,下面这行URLconf 中:

    url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),

    views.year_archive() 的year 参数将是一个字符串

    1、5 指定视图参数的默认值

    有一个方便的小技巧是指定视图参数的默认值。 下面是一个URLconf 和视图的示例:

    # URLconf
    from django.conf.urls import url
    
    from . import views
    
    urlpatterns = [
        url(r'^blog/$', views.page),
        url(r'^blog/page(?P<num>[0-9]+)/$', views.page),
    ]
    
    # View (in blog/views.py)
    def page(request, num="1"):
    
        ...

    在上面的例子中,两个URL模式指向同一个视图views.page —— 但是第一个模式不会从URL 中捕获任何值。如果第一个模式匹配,page() 函数将使用num参数的默认值"1"。如果第二个模式匹配,page() 将使用正则表达式捕获的num 值。

    1、6 路由分发 include

    如果一个项目中应用太多,导致方法太多耦合性太强,所以我们可以用include进行解耦,在每一个应用中分别建立一个urls

    #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')),
    ]

    应用中的urls:

    from django.conf.urls import url
    
    import views
    
    urlpatterns = [
        url(r'^articles/2003/05$', views.year_month2),  # year(requset,1990,12)
        url(r'^articles/(?P<year>d{4})/(?P<month>d{2})$', views.year_month),  # year(requset,year=1990,month=12)   按位置传参数
    ]

    2 传递额外的选项给视图函数(了解)

    URLconfs 具有一个钩子,让你传递一个Python 字典作为额外的参数传递给视图函数。

    django.conf.urls.url() 函数可以接收一个可选的第三个参数,它是一个字典,表示想要传递给视图函数的额外关键字参数。

    例如:

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

     在这个例子中,对于/blog/2005/请求,Django 将调用views.year_archive(request, year='2005', foo='bar')

    这个技术在Syndication 框架中使用,来传递元数据和选项给视图。

    3 URL 的反向解析

    使用Django 项目时,一个常见的需求是获得URL 的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。

    人们强烈希望不要硬编码这些URL(费力、不可扩展且容易产生错误)或者设计一种与URLconf 毫不相关的专门的URL 生成机制,因为这样容易导致一定程度上产生过期的URL。

    换句话讲,需要的是一个DRY 机制。除了其它有点,它还允许设计的URL 可以自动更新而不用遍历项目的源代码来搜索并替换过期的URL。

    获取一个URL 最开始想到的信息是处理它视图的标识(例如名字),查找正确的URL 的其它必要的信息有视图参数的类型(位置参数、关键字参数)和值。

    Django 提供一个办法是让URL 映射是URL 设计唯一的地方。你填充你的URLconf,然后可以双向使用它:

    根据用户/浏览器发起的URL 请求,它调用正确的Django 视图,并从URL 中提取它的参数需要的值。

    根据Django 视图的标识和将要传递给它的参数的值,获取与之关联的URL。

    第一种方式是我们在前面的章节中一直讨论的用法。第二种方式叫做反向解析URL、反向URL 匹配、反向URL 查询或者简单的URL 反查。

    在需要URL 的地方,对于不同层级,Django 提供不同的工具用于URL 反查:

    在模板中:使用url 模板标签。

    在Python 代码中:使用django.core.urlresolvers.reverse() 函数。

    在更高层的与处理Django 模型实例相关的代码中:使用get_absolute_url() 方法。

    例子:

    考虑下面的URLconf:

    from django.conf.urls import url
    
    from . import views
    
    urlpatterns = [
        #...
        url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
        #...
    ]

    根据这里的设计,某一年nnnn对应的归档的URL是/articles/nnnn/

    你可以在模板的代码中使用下面的方法获得它们:

    <a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
    
    <ul>
    {% for yearvar in year_list %}
    <li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
    {% endfor %}
    </ul>

    在Python 代码中,这样使用:

    from django.core.urlresolvers import reverse
    from django.http import HttpResponseRedirect
    
    def redirect_to_year(request):
        # ...
        year = 2006
        # ...
        return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))

    如果出于某种原因决定按年归档文章发布的URL应该调整一下,那么你将只需要修改URLconf 中的内容。

    在某些场景中,一个视图是通用的,所以在URL 和视图之间存在多对一的关系。对于这些情况,当反查URL 时,只有视图的名字还不够。

    4 命名URL 模式

    为了完成上面例子中的URL 反查,你将需要使用命名的URL 模式。URL 的名称使用的字符串可以包含任何你喜欢的字符。不只限制在合法的Python 名称。

    当命名你的URL 模式时,请确保使用的名称不会与其它应用中名称冲突。如果你的URL 模式叫做comment,而另外一个应用中也有一个同样的名称,当你在模板中使用这个名称的时候不能保证将插入哪个URL。

    在URL 名称中加上一个前缀,比如应用的名称,将减少冲突的可能。我们建议使用myapp-comment 而不是comment。

    5 CBV

    url(r'^login.html$', views.Login.as_view()),
     
    ============================
    from django.views import View
    class Login(View):
         
        def dispatch(self, request, *args, **kwargs):
            print('before')
            obj = super(Login,self).dispatch(request, *args, **kwargs)
            print('after')
            return obj
     
        def get(self,request):
            
            return render(request,'login.html')
     
        def post(self,request):
            print(request.POST.get('user'))
            return HttpResponse('Login.post')
    View Code

    视图层之视图函数(views)

    1、简单视图:

     一个视图函数,简称视图,是一个简单的Python 函数,它接受Web请求并且返回Web响应。响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. . . 是任何东西都可以。无论视图本身包含什么逻辑,都要返回响应。代码写在哪里也无所谓,只要它在你的Python目录下面。除此之外没有更多的要求了——可以说“没有什么神奇的地方”。为了将代码放在某处,约定是将视图放置在项目或应用程序目录中的名为views.py的文件中。

    下面是一个返回当前日期和时间作为HTML文档的视图:

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

    让我们逐行阅读上面的代码:

    首先,我们从 django.http模块导入了HttpResponse类,以及Python的datetime库。

    接着,我们定义了current_datetime函数。它就是视图函数。每个视图函数都使用HttpRequest对象作为第一个参数,并且通常称之为request。

    注意,视图函数的名称并不重要;不需要用一个统一的命名方式来命名,以便让Django识别它。我们将其命名为current_datetime,是因为这个名称能够精确地反映出它的功能。

    这个视图会返回一个HttpResponse对象,其中包含生成的响应。每个视图函数都负责返回一个HttpResponse对象。

     HttpRequest对象 (重点)

    当请求一个页面时,Django 创建一个 HttpRequest对象包含原数据的请求。然后 Django 加载适当的视图,通过 HttpRequest作为视图函数的第一个参数。每个视图负责返回一个HttpResponse目标。

    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支持时该属性才可用。
    
    META:       一个标准的Python字典包含所有可用的HTTP头。可用标题取决于客户端和服务器,但这里是一些例子:
    
                CONTENT_LENGTH       – 请求体的长度(一个字符串)。
                CONTENT_TYPE         – 请求体的类型。
                HTTP_ACCEPT          - 为响应–可以接受的内容类型。
                HTTP_ACCEPT_ENCODING – 接受编码的响应
                HTTP_ACCEPT_LANGUAGE – 接受语言的反应
                HTTP_HOST            – 客户端发送的HTTP主机头。
                HTTP_REFERER         – 参考页面
                HTTP_USER_AGENT      – 客户端的用户代理字符串。
                QUERY_STRING         – 查询字符串,作为一个单一的(分析的)字符串。
                REMOTE_ADDR          – 客户端的IP地址
                REMOTE_HOST          – 客户端的主机名
                REMOTE_USER          – 用户通过Web服务器的身份验证。
                REQUEST_METHOD       – 字符串,如"GET""POST"
                SERVER_NAME          – 服务器的主机名
                SERVER_PORT          – 服务器的端口(一个字符串)。
    HttpRequest对象属性

    方法:

    get_full_path()

    注意:键值对的值是多个的时候,比如checkbox类型的input标签,select标签,需要用:

    request.POST.getlist("hobby")

    Response

    Httpresponse()        返回字符串
    
    render(request,template_name,context)
    结合一个给定的摸版和一个给定的上下文字典,并返回一个渲染后的HttpResponse对象
    参数说明:
        1.request:用于生产响应的请求对象
        2.template_name:要使用的模板的完整名称,可选参数
        3.context:添加到模板上下文的一个字典,默认是一个空字典。例如字典中的某个值是可调用的,视图将在渲染模板之前调用
        4.content_type:生成的文档要使用的MIME类型。默认为DEFAULT_CONTENT_TYPE设置的值
        5.status:响应的状态码。默认为200
    
    redirect(跳转,重定向)
        redirct("/路径/")
        模拟用户点击submit请求:
        请求url:http://127.0.0.1:8000/login/
            1.请求url:/login/ POST
            2.url(r'^login/',app01_views.login,name="login")
            3.login(request):验证, if 成功,redirect("/index/")
        重定向请求
            请求路径:http://127.0.0.1:8000/index/
            1.请求url:/index/ GET
            2.url(r'^index/',app01_views.index,name="index")
            3.index(request):取出数据库数据,渲染到index.html页面
        用户看到的是:渲染的index.html页面
        
        redirect与render的区别:
            redirct发出两次请求
            render发出一次请求 
    View Code

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

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

    页面渲染:render(推荐),render_to_response,

    页面跳转:redirect

    locals:   可以直接将对应视图函数中所有的变量传给模板    

    render 函数

    render(request, template_name[, context])

    结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse 对象。

    参数:

         request: 用于生成响应的请求对象。

         template_name:要使用的模板的完整名称,可选的参数

         context:添加到模板上下文的一个字典。默认是一个空字典。如果字典中的某个值是可调用的,视图将在渲染模板之前调用它。

         content_type:生成的文档要使用的MIME类型。默认为DEFAULT_CONTENT_TYPE 设置的值。

      status:响应的状态码。默认为200

    def index(request):
        name="yuan"
        return render(request,"index.html",{"n":name})

    redirect 函数(重定向)

    参数可以是:

    一个模型:将调用模型的get_absolute_url() 函数

    一个视图,可以带有参数:将使用urlresolvers.reverse 来反向解析名称

    一个绝对的或相对的URL,将原封不动的作为重定向的位置。

    默认返回一个临时的重定向;传递permanent=True 可以返回一个永久的重定向。

    你可以用多种方式使用redirect() 函数。

    传递一个对象

    将调用get_absolute_url() 方法来获取重定向的URL:

    from django.shortcuts import redirect
     
    def my_view(request):
        ...
        object = MyModel.objects.get(...)
        return redirect(object)

    传递一个视图的名称

    可以带有位置参数和关键字参数;将使用reverse() 方法反向解析URL: 

    def my_view(request):
        ...
        return redirect('some-view-name', foo='bar')

    传递要重定向的一个硬编码的URL

    def my_view(request):
        ...
        return redirect('/some/url/')

    也可以是一个完整的URL:

    def my_view(request):
        ...
        return redirect('http://example.com/')

    默认情况下,redirect() 返回一个临时重定向。以上所有的形式都接收一个permanent 参数;如果设置为True,将返回一个永久的重定向:

    def my_view(request):
        ...
        object = MyModel.objects.get(...)
        return redirect(object, permanent=True)  

    跳转(重定向)应用

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

    注意:render和redirect的区别:

    1、 if 页面需要模板语言渲染,需要的将数据库的数据加载到html,那么render方法则不会显示这一部分。

    2、 the most important: url没有跳转到/yuan_back/,而是还在/login/,所以当刷新后又得重新登录。

    模板层(template)

    我们创建一个新项目的时候路径下都会自带一个templates,这个文件夹就是用来放我们的html代码的。通俗的讲模版就是html代码+模版语法

    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)来实现这种模式,这就是本章要具体讨论的问题。

    python的模板:HTML代码+模板语法

    模版包括在使用时会被值替换掉的 变量,和控制模版逻辑的 标签。

    def current_time(req):
        def current_time(req):
        # ================================原始的视图函数
        # import datetime
        # now=datetime.datetime.now()
        # html="<html><body>现在时刻:<h1>%s.</h1></body></html>" %now
    
    
        # ================================django模板修改的视图函数
        # from django.template import Template,Context
        # now=datetime.datetime.now()
        # t=Template('<html><body>现在时刻是:<h1>{{current_date}}</h1></body></html>')
        # #t=get_template('current_datetime.html')
        # c=Context({'current_date':str(now)})
        # html=t.render(c)
        #
        # return HttpResponse(html)
    
    
        #另一种写法(推荐)
        import datetime
        now=datetime.datetime.now()
        return render(req, 'current_datetime.html', {'current_date':str(now)[:19]})

    time.html:

    <body>
    <h1>current time: {{ time }}</h1>
    </body>

    模板语法之变量

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

    语法:  

    {{var_name}}

    1views

    def index(request):
        name="hello template"
        i=200
        l=[111,[333,444,555],333]
        d={"name":"yuan","age":23}
        class Person(object):
            def __init__(self,name,age):
                self.name=name
                self.age=age
            def dream(self):
                return "I am dreaming"
        person_bjd=Person("bjd",20)
    
        #return render(request,"index.html",{"name":name,"i":i,"l":l,"d":d,"person_egon":person_bjd})
        return render(request,"index.html",locals()) #locals()可以代替传参,但是必须在html里的模版变量和view里的变量名一致,耗资源,不推荐。

    2、template

    <h4>{{s}}</h4>
    <h4>列表:{{ l.0 }}</h4>
    <h4>列表:{{ l.2 }}</h4>
    <h4>字典:{{ dic.name }}</h4>
    <h4>日期:{{ date.year }}</h4>
    <h4>类对象列表:{{ person_list.0.name }}</h4>

    注意:句点符也可以用来引用对象的方法(无参数方法)。

    <h4>字典:{{ dic.name.upper }}</h4>

    模板之过滤器

    语法:

    {{obj|filter_name:param}}

    default 设置默认

    如果一个变量是false或者为空,使用给定的默认值。例如:

    {{ value|default:"查询为空" }}

    lenght 长度

    返回值的长度。它对字符串和列表都起作用。例如:

    {{ value|length }}

    如果 value 是 ['a', 'b', 'c', 'd'],那么输出是 4。

    filesizeformat  文件大小

    将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)例如:

    {{ value|filesizeformat }}

    如果 value 是 123456789,输出将会是 117.7 MB。  

    date  时间

    如果 value=datetime.datetime.now()

    {{ value|date:"Y-m-d" }} 

    slice 切分

    如果 value="hello world"

    {{ value|slice:"2:-1" }}

    顾头不顾尾

    truncatecharstruncatewords

    按照指定的字符或单词数量截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。

    参数:要截断的字符数或单词数

    {{ value|truncatechars:20 }}    <!--按字符截断-->
    {{ value|truncatewords:5 }}     <!--按单词截断-->

    safe 安全机制

    Django的模板中会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全。但是有的时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义。比如:

    value="<a href="">点击</a>"
    {{ value|safe}}

    这里简单介绍一些常用的模板的过滤器,更多详见

    模板之标签 

    标签看起来像是这样的: {% tag %}。标签比变量更加复杂:一些在输出中创建文本,一些通过循环或逻辑来控制流程,一些加载其后的变量将使用到的额外信息到模版中。

    一些标签需要开始和结束标签 (例如{% tag %} ...标签 内容 ... {% endtag %})

    for标签

    遍历每一个元素:

    {% for person in person_list %}
        <p>{{ person.name }}</p>
    {% endfor %}    <!--必须有的结束符-->

    可以利用{% for obj in list reversed %}反向完成循环。

    遍历一个字典:

    {% for key,val in dic.items %}
        <p>{{ key }}:{{ val }}</p>
    {% endfor %}

    注:循环序号可以通过{{forloop}}显示  

    forloop.counter         The current iteration of the loop (1-indexed)
    forloop.counter0    The current iteration of the loop (0-indexed)
    forloop.revcounter  The number of iterations from the end of the loop (1-indexed)
    forloop.revcounter0 The number of iterations from the end of the loop (0-indexed)
    forloop.first           True if this is the first time through the loop
    forloop.last            True if this is the last time through the loop
    View Code

    for ... empty 

    for 标签带有一个可选的{% empty %} 从句,以便在给出的组是空的或者没有被找到时,可以有所操作。

    {% for person in person_list %}
        <p>{{ person.name }}</p>
    
    {% empty %}
        <p>sorry,no person here</p>
    {% endfor %}

    if 标签分支

    {% if %}会对一个变量求值,如果它的值是“True”(存在、不为空、且不是boolean类型的false值),对应的内容块会输出。

    {% if num > 100 or num < 0 %}
        <p>无效</p>
    {% elif num > 80 and num < 100 %}
        <p>优秀</p>
    {% else %}
        <p>凑活吧</p>
    {% endif %}

    with 缓存

    使用一个简单地名字缓存一个复杂的变量,当你需要使用一个“昂贵的”方法(比如访问数据库)很多次的时候是非常有用的

    例如:

    {% with total=business.employees.count %}
        {{ total }} employee{{ total|pluralize }}
    {% endwith %}

    csrf_token 

    csrf_token就是用来解决post请求的。(用于跨站请求伪造保护)

    form action="/login/" method="post">
        {% csrf_token %}
        <p><input type="text" name="user"></p>
        <input type="submit">
    </form>

    它是隐藏的,value值相当于带着一个服务器给它的身份证,没有身份证的post请求会被拒绝,value值是打开登录页面是get请求的时候返回的。

    自定义标签和过滤器

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

    2、在app中创建templatetags模块(模块名只能是templatetags)

    3、创建任意 .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
    <br>
    @register.simple_tag
    def simple_tag_multi(v1,v2):
        return  v1 * v2
    <br>
    @register.simple_tag
    def my_input(id,arg):
        result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
    return mark_safe(result)
    View Code

    前三行也是固定的不可改变

    如果是自定义过滤器加@register.filter装饰器

    如果是自定义标签加@register.simple_tag装饰器

    4、在使用自定义simple_tag和filter的html文件中导入之前创建的 my_tags.py

    {% load my_tags %} 

    5、使用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 %}
    
    注意:filter可以用在if等语句后,simple_tag不可以
    
    {% if num|filter_multi:30 > 100 %}
        {{ num|filter_multi:30 }}
    {% endif %}

    模板继承 (extend)

    Django模版引擎中最强大也是最复杂的部分就是模版继承了。模版继承可以让您创建一个基本的“骨架”模版,它包含您站点中的全部元素,并且可以定义能够被子模版覆盖的 blocks 。

    通过从下面这个例子开始,可以容易的理解模版继承:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <link rel="stylesheet" href="style.css" />
        <title>{% block title %}My amazing site{%/span> endblock %}</title>
    </head>
    
    <body>
        <div id="sidebar">
            {% block sidebar %}
            <ul>
                <li><a href="/">Home</a></li>
                <li><a href="/blog/">Blog</a></li>
            </ul>
            {% endblock %}
        </div>
    
        <div id="content">
            {% block content %}{% endblock %}   #{% endblock %}结束标志
        </div>
    </body>
    </html>

    这个模版,我们把它叫作 base.html, 它定义了一个可以用于两列排版页面的简单HTML骨架。“子模版”的工作是用它们的内容填充空的blocks。

    在这个例子中, block 标签定义了三个可以被子模版内容填充的block。 block 告诉模版引擎: 子模版可能会覆盖掉模版中的这些位置。

    子模版可能看起来是这样的:

    {% extends "base.html" %}
     
    {% block title %}My amazing blog{% endblock %}
     
    {% block content %}
    {% for entry in blog_entries %}
        <h2>{{ entry.title }}</h2>
        <p>{{ entry.body }}</p>
    {% endfor %}
    {% endblock %}
    View Code

    extends 标签是这里的关键。它告诉模版引擎,这个模版“继承”了另一个模版。当模版系统处理这个模版时,首先,它将定位父模版——在此例中,就是“base.html”。

    那时,模版引擎将注意到 base.html 中的三个 block 标签,并用子模版中的内容来替换这些block。根据 blog_entries 的值,输出可能看起来是这样的:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <link rel="stylesheet" href="style.css" />
        <title>My amazing blog</title>
    </head>
     
    <body>
        <div id="sidebar">
            <ul>
                <li><a href="/">Home</a></li>
                <li><a href="/blog/">Blog</a></li>
            </ul>
        </div>
     
        <div id="content">
            <h2>Entry one</h2>
            <p>This is my first entry.</p>
     
            <h2>Entry two</h2>
            <p>This is my second entry.</p>
        </div>
    </body>
    </html>
    View Code

    请注意,子模版并没有定义 sidebar block,所以系统使用了父模版中的值。父模版的 {% block %} 标签中的内容总是被用作备选内容(fallback)。

    这种方式使代码得到最大程度的复用,并且使得添加内容到共享的内容区域更加简单,例如,部分范围内的导航。

    这里是使用继承的一些提示:

    如果你在模版中使用 {% extends %} 标签,它必须是模版中的第一个标签。其他的任何情况下,模版继承都将无法工作。

    在base模版中设置越多的 {% block %} 标签越好。请记住,子模版不必定义全部父模版中的blocks,所以,你可以在大多数blocks中填充合理的默认内容,然后,只定义你需要的那一个。多一点钩子总比少一点好。

    如果你发现你自己在大量的模版中复制内容,那可能意味着你应该把内容移动到父模版中的一个 {% block %} 中。

    为了更好的可读性,你也可以给你的 {% endblock %} 标签一个 名字 。例如:

    {% block content %}
    ...
    {% endblock content %}

    在大型模版中,这个方法帮你清楚的看到哪一个  {% block %} 标签被关闭了。

    最后,请注意您并不能在一个模版中定义多个相同名字的 block 标签。这个限制的存在是因为block标签的作用是“双向”的。这个意思是,block标签不仅提供了一个坑去填,它还在 _父模版_中定义了填坑的内容。如果在一个模版中有两个名字一样的 block 标签,模版的父模版将不知道使用哪个block的内容。

  • 相关阅读:
    Windows Azure Web Site (19) Azure Web App链接到VSTS
    Windows Azure Virtual Machine (35) Azure VM通过Linked DB,执行SQL Job
    Azure PowerShell (16) 并行开关机Azure ARM VM
    Windows Azure Virtual Network (12) 虚拟网络之间点对点连接VNet Peering
    Azure ARM (21) Azure订阅的两种管理模式
    Windows Azure Platform Introduction (14) 申请海外的Windows Azure账户
    Azure ARM (20) 将非托管磁盘虚拟机(Unmanage Disk),迁移成托管磁盘虚拟机(Manage Disk)
    Azure ARM (19) 将传统的ASM VM迁移到ARM VM (2)
    Azure ARM (18) 将传统的ASM VM迁移到ARM VM (1)
    Azure Automation (6) 执行Azure SQL Job
  • 原文地址:https://www.cnblogs.com/qiangyuge/p/7841504.html
Copyright © 2020-2023  润新知