python_day19_Django-

发布时间:2019-09-12 07:59:02编辑:auto阅读(1684)

    MVC\MTV介绍
    python_day19_Django-3 (框架_模板)

    MVC介绍

      全名是Model View Controller,是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller),具有耦合性低、重用性高、生命周期成本低等优点。

    用户输入URL到 [控制器],并响应用户操作--> [视图] 展示信息
                          --> 传递指令到 [模型],存数据到数据库或取数据到 业务数据 --> 最后 [视图] 展示信息
    控制器: 传递指令,接收用户输入的指令
    模型: 负责业务对象与数据库的对象
    视图: 页面展示给用户

    MTV介绍

      Django框架的不同之处在于它拆分的三部分为:Model(模型)、Template(模板)和View(视图),也就是MTV框架。

    Model(模型):负责业务对象与数据库的对象(ORM)
    Template(模版):负责如何把页面展示给用户
    View(视图):负责业务逻辑,并在适当的时候调用Model和Template

    来源于 Django框架简介
    python_day19_Django-3 (框架_模板)


    django模板语言

    1.1、模板语言:常用格式

    1.1.1、变量

        {{ name }}  

    1.1.2、if

    固定格式
        {% if ..... %} 
        {% endif %}
    if 用法
        {% if 100 > nums %}
            {{ nums }}
        {% endif %}
    
    if else 用法
        {% if 100 > nums %}
            {{ nums }}
        {% else %}
            {{ val }}
        {% endif %}
    
    if in 当名称在这个列表中
        {% if name in name_list %}
            {{ name }}
        {% else %}
            {{ val }}
        {% endif %}

    1.1.3、for

    固定格式
    {% for .... %}
    {% endfor %}
    
    for用法
    {% for i in num_list %}
        {{ forloop.counter }} 统计从列表的行 
        {{ forloop.last }}  最后一个值
    {% endfor %}

    1.2、模板语言:Filter

      在变量的基础上做一些额外的操作, 语法: {{ value|filter_name:参数 }}, Filter一定要注意的是 value|filter_name左右都没有空格

    default

    views函数     项目视图函数中增加
    def t_test(request):
         # 传递一个对象到html页面中
        f_str = "test value"
        return render(
            request,
            "t_test.html",
            {"fstr": f_str},
        )
    
    html页面
    # 如果fstr为空,那么在页面中显示的就是Null   nulls是一个对比名
    {{ fstr|default:"Null" }}
    {{ nulls|default:"the value Null" }}

    lenght

        {{ fstr|length }}   获取元组的长度
    
    配合if使用  当大于3时打印第一步,否则打印else
    {%  if fstr|length > 3 %}
        <p>gt 3</p>
    {% else %}
        <p>lt 3</p>
    {% endif %}
    
    获取列表的长度
    l_str = ["1a","2bbe","3ccc"]
    {{ lstr|length }}   统计的是列表的长度
    如果想统计单个值的长度,可以使用切片的方式取出{{ lstr.1|length }}

    formatsize

    视图函数
    filesize = 10240000
    {"fstr": f_str, "lstr": l_str, "fsize": filesize},
    
    html
    {{ fsize|filesizeformat }}
    单位  B/KB/MB......

    date

    t_time = datetime.now()
    字典中添加 {"fstr": f_str, "lstr": l_str, "fsize": filesize,"now" : t_time},
    
    html页面
    {{ now|date:"Y-m-d H:i:s" }}
    
    页面显示结果: 2018-07-09 16:37:57

    safe
    Django的模板中会对HTML标签和JS等语法标签进行自动转义,如果自动转义的话显示的就是HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义

    比如: 例一
    t_html = "<p>p标签</p>"
    字典中添加: "t_html" : t_html,
    
    html
    {{ t_html }}
    
    页面中显示的就是   <p>p标签</p>
    
    如果添加了safe
    {{ t_html|safe }}  不进行转义 那就直接就是一个p标签, 如果用户XSS×××那么必将造成一定的风险
    
    比如: 评论用户在评论中直接输入
    <script> (for (i;;) alert(ssss);;) </script>  输入死循环,那么程序将会直接卡死,此处就不应该进行转义

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

    g_str = "真正优秀的人,从来不怕成功迟到, 坚守一颗执着的心,终会实现心中的梦想"
    字典中添加 "g_str": g_str
    
    html页面
         {{ g_str|truncatechars:20 }}
    
    显示: 真正优秀的人,从来不怕成功迟到, ...    

    自义定filter

    在项目下创建一个python包  templatetags   固定名称
    创建一个名为myfirst.py文件
    from django import template
    
    # 必须首先创建一个全局register变量,它是用来注册你自定义标签和过滤器的
    register = template.Library()
    
    @register.filter(name="tg")
    def first_reg(arg):
        return "{} myfirst".format(arg)
        # 结果: test value myfirst
    
    @register.filter(name="tg2")
    # 一个参数放变量值,一个用来放选项值
    def two_reg(arg1,arg2):
        # arg1 为模板定义的对象 就等于是 fstr
        # arg2 为手动输入的值 {{ fstr|tg2:"xiong" }}
        return "{}--{}".format(arg1,arg2)
        # 结果:test value--xiong
    
    html页面中引用
    需要先导入:  {% load myfirst %}   这个是创建的Py文件的名称
    这个是只有一个对象的函数
    {{ fstr|tg }}
    
    这个是有两个arg的函数
    {{ fstr|tg2:"xiong" }}

    1.3、模板语言:Tags

    for

    html页面
    <ol>
        {% for uList in lstr %}
            <li>{{ uList }}</li>
        {% endfor %}
    </ol>
    <ul>
        {% for uList in lstr %}
            {% if forloop.first %}
                <p>第一个: {{ uList }}</p>
            {% endif %}
        {% endfor %}
    </ul>
    
    页面展示为: 第一个: 1a
    
    <ul>
        {% for uList in lstr %}
            {% if forloop.last %}
                <p>最后一个: {{ uList }}</p>
            {% endif %}
        {% endfor %}
    </ul>
    
    页面展示为: 最后一个: 3ccc

    静态方法: inclusion_tag

    1、url中添加访问路径
        path("test/", views.test)
    
    2、项目view中添加
    def test(request):
        return render(request, "pags.html")
    
    3、template/page.html 导入模块
        {% load xx %}
        {% tagss 10 %}
    
    4、项目下创建 templatetags
    from django import template
    
    register = template.Library()
    
    @register.inclusion_tag("ul.html")
    def tagss(arg):
        arg = 1 if arg < 1 else int(arg)
        data = ["这是第{}号".format(i) for i in range(1, arg)]
        return {"data" : data}
    
    5、创建一个html
    <ul>
        {% for foo in data %}
            <li>{{ foo }}</li>
        {% endfor %}
    </ul>
    
    6、最终页面效果
    这是第1号
    这是第2号
    ........

    路由系统

       说明:以下使用django2.x urlConf写法

    URL conf 2.0官方文档

    1、django 1.1与2.0 url conf 写法:
       1.1写法 url(r'xx/[0-9]{2}/$')      意为: http://urlpath/xx/2个数字 [10-99] 
       2.0写法 re_path("xx/[0-9]{2}/$")
    
    2、普通写法
        语法 urls文件 urlpatterns = [
                     path('urls/', 视图.函数),
            ]

    2.1、正则表达式

    官网案例
    from django.urls import path, re_path
    
    from . import views
    
    urlpatterns = [
        path('articles/2003/', views.special_case_2003),
        re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
        re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
        re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\w-]+)/$', views.article_detail),
    ]
    
    案例对比:
    from django.urls import re_path
    
    urlpatterns = [
        re_path(r'^blog/(page-(\d+)/)?$', blog_articles),                  # bad
        re_path(r'^comments/(?:page-(?P<page_number>\d+)/)?$', comments),  # good
    ]
    
    案例一
    项目下的 urls.py文件
    导入re_path
        from django.urls import path, re_path 
        urlpatterns = [
                re_path('test/([0-9]{2}/$)', views.retest)
        ]
    
    app下定义 views.py文件
    def retest(request,nums):
        print(nums)
        return render(request, "retest_page.html",{"nums":nums})
    
    定义templates目录 新建retest_page.html
    <p>{{ nums }}</p>
    
    效果

    python_day19_Django-3 (框架_模板)

     注:当需要导入多个app时有多个view视图就需要使用别名
    from app01 import views as app01_view
    from app02 import views as app02_view
    urlpatterns = [
        path('app01/',app01_view.app_test),
        path('app02/',app02_view.app_test),
        ]
    
    案例二
    导入re_path
        from django.urls import path, re_path 
        urlpatterns = [
                re_path(r'^test2/(?P<name>[a-zA-Z]{1,5})/(?P<age>[0-9]{1,3})/$', views.retest2),
        ]
    
    app下定义 views.py文件
    def retest2(request,name,age):
        print(name,age)
        return HttpResponse(name,age)
    
    定义templates目录 新建retest_page.html
    <p>名称: {{ name }}</p>
    <p>年龄: {{ age }}</p>
    
    效果

    python_day19_Django-3 (框架_模板)

    2.2、include其他的URLconfs

    案例一:单个app导入
    1、创建一个app
        python manage.py startapp appname
        创建完之后需要在项目下的settings的INSTALLED_APPS中添加'app02.apps.App02Config',
    
    2、app下创建urls.py文件
        from django.urls import path, re_path
        from . import views
    
        urlpatterns = [
                re_path('app01/$', views.app_test),
                ]
    
    3、创建app01对应函数以及视图
        def app_test(request):
                return HttpResponse('app01.app_test')
    
    4、项目中include该app
        re_path('^ptest/',include('app01.urls')),
    
    5、展示效果,  访问一定是项目urls定义的名称/app定义的path名称

    python_day19_Django-3 (框架_模板)

    案例二:多个app
    项目名:pre
    app名称: app01 与 app02
    初始与单个app的第一第二步一样,都需要配置 setting文件以及导入相应的path
    
    1、urls配置文件
    from django.urls import path, re_path
    from . import views
    
    urlpatterns = [    # app01 app02定义的path要不相同
        re_path('app01/$', views.app_test),
        ]
    
    2、views配置 文件
    from django.shortcuts import render, HttpResponse
    
    def app_test(request):    # 注意响应到页面的展示效果
        return HttpResponse('app02.app_test2')
    
    3、pre项目下配置
    from app01 import views as app01_view
    from app02 import views as app02_view
    urlpatterns = [
        path('app01/',include('app01.urls')),
        path('app02/',include('app02.urls')),
        ]
    
    效果:

    python_day19_Django-3 (框架_模板)

    2.3、反向解析url

    功能: 当path的路径名称变更时,别名不动,在html页面中定义的a标签页面就不会受到影响,否则当path路径变更时,就需要修改html中a标签的路径地址

    大致思路:
    1、先定义urls,路径以及函数名称,
    2、配置view视图函数,定义urls中配置的函数名称,以及要响应的文件
    3、配置对应的templates html页面模板

    1、定义项目urls,导入其它应用下的urls文件
    from django.urls import path, re_path, include
    urlpatterns = [
        path('app01/', include('app01.urls')),
    ]
    
    2、app应用下的urls文件
    from django.urls import path, re_path
    from . import views
    
    urlpatterns = [
        path('atest/', views.atest, name='asatest'),     # name 对应path路径的别名
        path('btest/', views.btest, name='asbtest'),
    ]
    
    3、app应用下的view视图函数、
    def atest(request):
        return render(request, 'atest.html')
    
    def btest(request):
        return render(request, 'btest.html')
    
    4、配置templates下的html页面
    templates/btest.html
    <h1>btest page</h1>       
    <a href="{% url 'asatest' %}">跳转到a页面</a>
    
    templates/atest.html
    <h1>atest page</h1>
    <a href="{% url 'asbtest'  %}">跳转到b页面</a>
    
    5、最终效果
         path名称 app01/atest 如果修改成别的 点击跳转时依旧正常

    python_day19_Django-3 (框架_模板)

    官网示例

    示例
    Consider again this URLconf entry:
    
    from django.urls import path
    
    from . import views
    
    urlpatterns = [
        #...
        path('articles/<int:year>/', views.year_archive, name='news-year-archive'),
        #...
    ]
    According to this design, the URL for the archive corresponding to year nnnn is /articles/<nnnn>/.
    
    You can obtain these in template code by using:
    
    <a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
    {# Or with the year in a template context variable: #}
    <ul>
    {% for yearvar in year_list %}
    <li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
    {% endfor %}
    </ul>
    Or in Python code:
    
    from django.http import HttpResponseRedirect
    from django.urls import reverse
    
    def redirect_to_year(request):
        # ...
        year = 2006
        # ...
        return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))

    2.4、反向解析URL命名空间

    项目中定义: namespace
    应用中需要定义: name
    html页面中引用: {% url 'namespace:name' %}

    项目名称:upload
    应用两个:app01,app02
    
    案例引用了:  
        从其它页面引用 :include ,
        命名空间:namespace,
        别名:name,
        html引用: {% url 'ss' %}
    
    1、项目urls定义
    from django.urls import path, re_path, include
    from app01 import views as app01_view
    from app02 import views as app02_view
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('app01/', include(('app01.urls', 'app01-pool'),namespace='app01-pool')),
        path('app02/', include(('app02.urls', "app02-pool"),namespace='app02-pool'))
    ]
    
    2、app中urls中定义,  app01 app02的urls一样
    from django.urls import path
    from . import views
    
    urlpatterns = [
        path('aaa/', views.atest, name='asatest'),
        path('bbb/', views.btest, name='asbtest'),
    ]
    
    3、app中view定义, app01 app02的view
    from django.urls import path
    from . import views
    
    urlpatterns = [
        path('aaa/', views.atest, name='asatest'),
        path('bbb/', views.btest, name='asbtest'),
    ]
    
    4、namespace引用 语法     url 'namespace:name'
    <h1>a2 test page</h1>
    <a href="{% url 'app01-pool:asbtest' %}">跳转到app01的atest页面</a>
    
    html大致引用    app01 a页面跳到b页面,b页面跳到app02的a页面,然后app02的a页面在跳到app02的b页面,最终在跳回app01的a页面
    
    atest
        <a href="{% url 'app01-pool:asbtest'  %}">跳转到app01-btest页面</a>
    btest
        <a href="{% url 'app02-pool:asatest' %}">跳转到app02-atest页面</a>
    a2test
        <a href="{% url 'app02-pool:asbtest' %}">跳转到app02的btest页面</a>
    b2test
        <a href="{% url 'app01-pool:asatest' %}">跳转到app01的atest页面</a>
    
    5、最终测试效果

    python_day19_Django-3 (框架_模板)

    异常错误:

    'Specifying a namespace in include() without providing an app_name is not supported. Set the app_name attribute in the included module, or pass a 2-tuple containing the list of patterns and app_name instead.'
    
    我的代码为:
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('app01/', include(('app01.urls', namespace='app01-pool')),
        path('app02/', include(('app02.urls',namespace='app02-pool')),
    ]
    
    解决大致思路:https://blog.csdn.net/zoulonglong/article/details/79612973
    
    最终解决办法:  def include(arg, namespace=None):
      arg就是('app02.urls', "app02-pool")已经被占用了,而namespace没有被定义所以报错
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('app01/', include(('app01.urls', 'app01-pool'),namespace='app01-pool')),
        path('app02/', include(('app02.urls', "app02-pool"),namespace='app02-pool'))
    ]
    官网案例:
    urls.py
    from django.urls import include, path
    
    urlpatterns = [
        path('author-polls/', include('polls.urls', namespace='author-polls')),
        path('publisher-polls/', include('polls.urls', namespace='publisher-polls')),
    ]
    polls/urls.py
    from django.urls import path
    
    from . import views
    
    app_name = 'polls'
    urlpatterns = [
        path('', views.IndexView.as_view(), name='index'),
        path('<int:pk>/', views.DetailView.as_view(), name='detail'),
        ...
    ]
    Using this setup, the following lookups are possible:
    
    If one of the instances is current - say, if we were rendering the detail page in the instance 'author-polls' - 'polls:index' will resolve to the index page of the 'author-polls' instance; i.e. both of the following will result in "/author-polls/".
    
    In the method of a class-based view:
    
    reverse('polls:index', current_app=self.request.resolver_match.namespace)
    and in the template:
    
    {% url 'polls:index' %}
    

    2.5、母版

    base页面
    <head>
        <meta charset="UTF-8">
        {% block title %}
        {% endblock %}
        <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
        <link rel="stylesheet" href="/static/fontAwesome/css/font-awesome.css">
    </head>
    <body>
    
    <div class="container">
        {% block context %}
        {% endblock %}
    </div>
    
    <script src="/static/jquery-3.3.1.js"></script>
    <script src="/static/bootstrap/js/bootstrap.min.js"></script>
    </body>
    
    继承页面
    {% extends 'base.html' %}
    {% block title %}blog titles{% endblock %}
    {% block context %}
    <div class="row text-center">
    <h1>我的博客</h1>
    </div>
    <div class="row">
        <div class="col-xs-12 col-md-8">
            <ul>
                {% for foo in blog_title %}
                    <li>{{ foo.title }}</li>
                {% endfor %}
            </ul>
        </div>
    </div>
    {% endblock %}
    在base.html 中已经定义了{% block title % }和{% block content% }块, 语句@和则是在本模板文件中对“父模板” base.html 中的同名称块标签进行重写。
    
    项目下的url.py
    from django.urls import path, include
    urlpatterns = [
        path('admin/', admin.site.urls),
         # urlpath路径名称  导入include , 反向URL解析
        path('blog/', include(('blog.urls',"blog-pool"), namespace='blog')),
    ]
    
    应用下的urls.py
    from django.urls import path,re_path
    from blog import views
    
    urlpatterns = [
        re_path('', views.blog_title),
    ]
    
    应用下的视图函数  view 类于函数的视图
    from django.shortcuts import render
    from .models import BlogArticles
    # Create your views here.
    
    def blog_title(request):
        blogs = BlogArticles.objects.all()
        return render(request, "blog/titles.html", {"blog_title": blogs})
    
    应用下的models.py
    from django.db import models
    from django.utils import timezone
    from django.contrib.auth.models import User
    # Create your models here.
    
    class BlogArticles(models.Model):
        title = models.CharField(max_length=300)
        author = models.ForeignKey(User, related_name="blog_posts",on_delete=models.CASCADE)
        body = models.TextField()
        publish = models.DateTimeField(default=timezone.now())
    
        def __str__(self):
            return self.title
    
    最终效果

    python_day19_Django-3 (框架_模板)

关键字