zoukankan      html  css  js  c++  java
  • python全栈学习------Django的视图层,Django的模板层

    #django相关命令
    1. 创建项目
    django-admin startproject 项目名称
    
    2.创建应用
    python manage.py startapp
    
    3.启动项目
    python manage.py runserver ip port
    

     步骤1,2都是下载过程,下载一些需要的代码。不写IP和端口,默认是8000 端口

    #请求流程
    1    URL :http://127.0.0.1:8000/index
    2    path("index",views.index)
    3    index视图函数响应HttpResponse(响应体字符串)
    

      request是由path来进行传参的。

    django,由4部分组成。路由控制+MTV

     路由控制:在全局文件夹下的urls.py
    1 简单配置
     re_path("^articles/(d{4})/(d{2})/$",views.article_month) # article_month(reqeust,2000,12)
    2 有名分组
      re_path("^articles/(?P<year>d{4})/(?P<month>d{2})/$",views.article_month) # 

    3 分发(解耦)     
     path('blog/', include('blog.urls')) 
    4 反向解析 path('index_new/', views.index,name="index"), re_path("^articles/(d{4})/(d{2})$", views.article_year,name="detail_article"), 情况1:在模板里: <form action="{% url '别名' 参数1 参数2 %}"></form> <a href=""> 情况2:在视图函数(python脚本) from django.urls import reverse _url=reverse('别名',args=(参数1,参数2))

    注意第4点。如果对应的是一个动态的url,比如"^articles/(d{4})/(d{2})$"

    那么视图函数和模板都需要传参。参数的个数,取决于正则表达式分组的个数。

    比如上面的正则有2个分组,那么必须传个参数才行。否则form提交之后,访问的url就是不正确的url。

    有名分组和有名分组的区别
    1. 传参不同。无名是位置参数,有名是关键字参数。
    2. 视图函数的形参。无名分组,名字可以随便。有名分组,名字必须和分组名一致

    反向解析,就是为了解决URL经常修改的情况。在公司里面,这个URL会被经常修改,比如业务下线了,或者业务重组了。所以说,在模版的里面的路径,不能写死。最好用反向解析。

    在视图函数里面,也要用反向解析。
    在模板里面,会涉及URL。比如form表单,那么action的属性不能写死。

    请求发送方式有以下几种:

    1.地址栏

    2.form表单

    3.a标签发请求

    4.ajax请求

    对于静态资源,比如img的src,link的src.只要涉及路径的,都要发送请求。静态资源的URL一般不会变动。

    注意:在模版里面出现的大括号内容,由render来渲染的,由后端完成替换,而不是前端来完成的。

    一、Django的视图层

    视图函数

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

    from django.shortcuts import render,HttpResponseRedirect,redirect
    import datetime
    
    def current_datetime(request):
        now = datetime.datetime.now()
        html = "<html><body>It is now %s.</body></html>“ % now
    
        return HttpResponse(html)
    

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

    • 首先,我们从 django.shortcuts模块导入了HttpResponse类,以及Python的datetime库。
    •   接着,我们定义了current_datetime函数。它就是视图函数。每个视图函数都使用HttpRequest对象作为第一个参数,并且通常称之为request
    • 注意,视图函数的名称并不重要;不需要用一个统一的命名方式来命名,以便让Django识别它。我们将其命名为current_datetime,是因为这个名称能够精确地反映出它的功能。

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

      

    视图层,熟练掌握两个对象即可:请求对象(request)和响应对象(HttpResponse)

    HttpRequest对象

    request属性

     django 将请求报文中的请求行,首部信息,内容主体封装成HttpRequest类中的属性。 除了特殊说明的之外,其他均为只读的。

    1.HttpRequest.GET
    
      一个类似于字典的对象,包含 HTTP GET 的所有参数。详情请参考 QueryDict 对象。
    
    2.HttpRequest.POST
    
      一个类似于字典的对象,如果请求中包含表单数据,则将这些数据封装成 QueryDict 对象。
    POST 请求可以带有空的 POST 字典 —— 如果通过 HTTP POST 方法发送一个表单,但是表单中没有任何的数据,QueryDict 对象依然会被创建。
       因此,不应该使用 if request.POST  来检查使用的是否是POST 方法;应该使用 if request.method == "POST"
      另外:如果使用 POST 上传文件的话,文件信息将包含在 FILES 属性中。
       
       注意:键值对的值是多个的时候,比如checkbox类型的input标签,select标签,需要用:
            request.POST.getlist("hobby")
    
    3.HttpRequest.body
    
      一个字符串,代表请求报文的主体。在处理非 HTTP 形式的报文时非常有用,例如:二进制图片、XML,Json等。
      但是,如果要处理表单数据的时候,推荐还是使用 HttpRequest.POST 。
    
    4.HttpRequest.path
    
      一个字符串,表示请求的路径组件(不含域名)。
      例如:"/music/bands/the_beatles/"
    
    5.HttpRequest.method
    
      一个字符串,表示请求使用的HTTP 方法。必须使用大写。
      例如:"GET"、"POST"
    
    6.HttpRequest.encoding
    
      一个字符串,表示提交的数据的编码方式(如果为 None 则表示使用 DEFAULT_CHARSET 的设置,默认为 'utf-8')。
       这个属性是可写的,你可以修改它来修改访问表单数据使用的编码。
       接下来对属性的任何访问(例如从 GET 或 POST 中读取数据)将使用新的 encoding 值。
       如果你知道表单数据的编码不是 DEFAULT_CHARSET ,则使用它。
    
    7.HttpRequest.META
    
       一个标准的Python 字典,包含所有的HTTP 首部。具体的头部信息取决于客户端和服务器,下面是一些示例:
    
        CONTENT_LENGTH —— 请求的正文的长度(是一个字符串)。
        CONTENT_TYPE —— 请求的正文的MIME 类型。
        HTTP_ACCEPT —— 响应可接收的Content-Type。
        HTTP_ACCEPT_ENCODING —— 响应可接收的编码。
        HTTP_ACCEPT_LANGUAGE —— 响应可接收的语言。
        HTTP_HOST —— 客服端发送的HTTP Host 头部。
        HTTP_REFERER —— Referring 页面。
        HTTP_USER_AGENT —— 客户端的user-agent 字符串。
        QUERY_STRING —— 单个字符串形式的查询字符串(未解析过的形式)。
        REMOTE_ADDR —— 客户端的IP 地址。
        REMOTE_HOST —— 客户端的主机名。
        REMOTE_USER —— 服务器认证后的用户。
        REQUEST_METHOD —— 一个字符串,例如"GET" 或"POST"。
        SERVER_NAME —— 服务器的主机名。
        SERVER_PORT —— 服务器的端口(是一个字符串)。
       从上面可以看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 之外,请求中的任何 HTTP 首部转换为 META 的键时,
        都会将所有字母大写并将连接符替换为下划线最后加上 HTTP_  前缀。
        所以,一个叫做 X-Bender 的头部将转换成 META 中的 HTTP_X_BENDER 键。
    
    8.HttpRequest.FILES
    
      一个类似于字典的对象,包含所有的上传文件信息。
       FILES 中的每个键为<input type="file" name="" /> 中的name,值则为对应的数据。
      注意,FILES 只有在请求的方法为POST 且提交的<form> 带有enctype="multipart/form-data" 的情况下才会
       包含数据。否则,FILES 将为一个空的类似于字典的对象。
    
    9.HttpRequest.COOKIES
    
      一个标准的Python 字典,包含所有的cookie。键和值都为字符串。
    
    10.HttpRequest.session
    
       一个既可读又可写的类似于字典的对象,表示当前的会话。只有当Django 启用会话的支持时才可用。
        完整的细节参见会话的文档。
    
    11.HttpRequest.user(用户认证组件下使用)
    
      一个 AUTH_USER_MODEL 类型的对象,表示当前登录的用户。
    
      如果用户当前没有登录,user 将设置为 django.contrib.auth.models.AnonymousUser 的一个实例。你可以通过 is_authenticated() 区分它们。
    
        例如:
    
        if request.user.is_authenticated():
            # Do something for logged-in users.
        else:
            # Do something for anonymous users.
    
    
           user 只有当Django 启用 AuthenticationMiddleware 中间件时才可用。
    
         -------------------------------------------------------------------------------------
    
        匿名用户
        class models.AnonymousUser
    
        django.contrib.auth.models.AnonymousUser 类实现了django.contrib.auth.models.User 接口,但具有下面几个不同点:
    
        id 永远为None。
        username 永远为空字符串。
        get_username() 永远返回空字符串。
        is_staff 和 is_superuser 永远为False。
        is_active 永远为 False。
        groups 和 user_permissions 永远为空。
        is_anonymous() 返回True 而不是False。
        is_authenticated() 返回False 而不是True。
        set_password()、check_password()、save() 和delete() 引发 NotImplementedError。
        New in Django 1.8:
        新增 AnonymousUser.get_username() 以更好地模拟 django.contrib.auth.models.User。
    

      

    request常用方法

    1.HttpRequest.get_full_path()
    
      返回 path,如果可以将加上查询字符串。
    
      例如:"/music/bands/the_beatles/?print=true"
    
    
    2.HttpRequest.is_ajax()
    
      如果请求是通过XMLHttpRequest 发起的,则返回True,方法是检查 HTTP_X_REQUESTED_WITH 相应的首部是否是字符串'XMLHttpRequest'。
    
      大部分现代的 JavaScript 库都会发送这个头部。如果你编写自己的 XMLHttpRequest 调用(在浏览器端),你必须手工设置这个值来让 is_ajax() 可以工作。
    
      如果一个响应需要根据请求是否是通过AJAX 发起的,并且你正在使用某种形式的缓存例如Django 的 cache middleware,
       你应该使用 vary_on_headers('HTTP_X_REQUESTED_WITH') 装饰你的视图以让响应能够正确地缓存。
    

    HttpResponse对象

    响应对象主要有三种形式:

    • HttpResponse()
    • render()
    • redirect()

    HttpResponse()括号内直接跟一个具体的字符串作为响应体,比较直接很简单,所以这里主要介绍后面两种形式。

    render()

    render(request, template_name[, context])
     
    结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse 对象。

    参数:

    • request: 用于生成响应的请求对象。
    • template_name:要使用的模板的完整名称,可选的参数
    • context:添加到模板上下文的一个字典。默认是一个空字典。如果字典中的某个值是可调用的,视图将在渲染模板之前调用它。

    render方法就是将一个模板页面中的模板语法进行渲染,最终渲染成一个html页面作为响应体。

    redirect()

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

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

    也可以是一个完整的URL:

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

    key:两次请求

    1)301和302的区别。
    
      301和302状态码都表示重定向,就是说浏览器在拿到服务器返回的这个状态码后会自动跳转到一个新的URL地址,这个地址可以从响应的Location首部中获取
      (用户看到的效果就是他输入的地址A瞬间变成了另一个地址B)——这是它们的共同点。
    
      他们的不同在于。301表示旧地址A的资源已经被永久地移除了(这个资源不可访问了),搜索引擎在抓取新内容的同时也将旧的网址交换为重定向之后的网址;
    
      302表示旧地址A的资源还在(仍然可以访问),这个重定向只是临时地从旧地址A跳转到地址B,搜索引擎会抓取新的内容而保存旧的网址。 SEO302好于301
    
     
    
    2)重定向原因:
    (1)网站调整(如改变网页目录结构);
    (2)网页被移到一个新地址;
    (3)网页扩展名改变(如应用需要把.php改成.Html或.shtml)。
            这种情况下,如果不做重定向,则用户收藏夹或搜索引擎数据库中旧地址只能让访问客户得到一个404页面错误信息,访问流量白白丧失;再者某些注册了多个域名的
        网站,也需要通过重定向让访问这些域名的用户自动跳转到主站点等。
    
    关于301与302
    

    用redirect可以解释APPEND_SLASH的用法!  

    二、Django的模板层

    你可能已经注意到我们在例子视图中返回文本的方式有点特别。 也就是说,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)来实现这种模式,这就是本章要具体讨论的问题。

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

    写法:

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

      

    1 模板语法之变量

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

    {{var_name}}

    views.py:

    def index(request):
        import datetime
        s="hello"
        l=[111,222,333]    # 列表
        dic={"name":"yuan","age":18}  # 字典
        date = datetime.date(1993, 5, 2)   # 日期对象
     
        class Person(object):
            def __init__(self,name):
                self.name=name
     
        person_yuan=Person("yuan")  # 自定义类对象
        person_egon=Person("egon")
        person_alex=Person("alex")
     
        person_list=[person_yuan,person_egon,person_alex]
     
     
        return render(request,"index.html",{"l":l,"dic":dic,"date":date,"person_list":person_list})
    

    templates:   

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

    2 模板之过滤器

    语法:

    {{obj|filter__name:param}}

    default

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

    {{ value|default:"nothing" }}

    length

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

    {{ 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" }}

    truncatechars

    如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。

    参数:要截断的字符数

    例如:

    {{ value|truncatechars:9 }}

    safe

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

    value="<a href="">点击</a>"

    html文件

    {{ value|safe}}

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

    完整Django 1.8.2 文档,请参考以下链接

    https://yiyibooks.cn/xx/django_182/ref/templates/builtins.html

    3 模板之标签 

    标签看起来像是这样的: {% 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
    

    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

    这个标签用于跨站请求伪造保护

    强行案例展示

     ifnotequal  用法

    后端字典
     {'books':[{'作者': None, '价格': None, '书名': None}, 
     {'作者': '司马迁', '价格': '958', '书名': '史记'}, 
     {'作者': '司马光', '价格': '2000', '书名': '资治通鉴'}, 
     {'作者': '孙膑', '价格': '689', '书名': '孙子兵法'}]
            }

    字典前端取值

    <table border="1" cellspacing="0" bordercolor="#000000" style="border-collapse:collapse;">
                    <tr>
                        <td>书名</td>
                        <td>作者</td>
                        <td>价格</td>
                    </tr>
                    {% for i in books %}
                        {% ifnotequal i.书名 None %}
                     <tr>
                        <td>{{i.书名}}</td>
                        <td>{{i.作者}}</td>
                        <td>{{i.价格}}</td>
                     </tr>
                        {% endifnotequal %}
    
                    {% endfor %}
    </table>

      

      

      



  • 相关阅读:
    Linux-Oracle 安装配置步骤
    lombok 安装
    request (请求对象)
    response (响应对象)
    ServletContext (上下文对象)
    JavaWeb数据库配置
    HttpServlet
    博客园代码字体大小
    博客园背景美化
    用PHP实现反向代理服务器
  • 原文地址:https://www.cnblogs.com/haowen980/p/9225305.html
Copyright © 2011-2022 走看看