Django框架(1)

Django框架

Django是一个功能强大的web框架

前言:框架模式简介

1、MVC和MTV框架

MVC:Web服务器开发领域里著名的MVC模式,所谓MVC就是把Web应用分为模型(M),控制器©和视图(V)三层,结构说明如下:

M: models 数据库相关操作
V: views 视图,也就是业务逻辑相关操作
C: controller  控制器,也就是通过路径找到对应视图函数

MTV:Django的MTV模式本质上和MVC是一样的,也是为了各组件间保持松耦合关系,只是定义上有些许不同。

M: models 数据库相关操作
T: templates html文件相关操作(模板渲染等)
V: views 视图,也就是业务逻辑相关操作

加上一个url控制器,也就是通过路径找到对应视图函数
2、WSGI

WSGI(Web Server Gateway Interface)就是一种规范,它定义了web应用程序与web服务器程序之间的接口格式,实现web应用程序与web服务器程序间的解耦。

开发的项目分为两个部分的程序
1 服务器程序  socket相关功能的模块,wsgiref、uwsgi等等,负责接收网络请求并解析网络请求相关数据,分装加工成一些可用的数据格式,格式大家都是统一的,方便应用程序的开发

2 应用程序  就是使用接收到的网络请求相关数据,进行逻辑代码的开发,比如数据库相关操作,数据结构的调整、文件操作等等。。。

一、基本使用

1、下载的三种方式:
  • 直接在pycharm中的setting中进行下载
  • 在cmd中通过命令下载:pip install django==版本
  • 在pycharm的Terminal控制台中进行下载(下载时要注意路径问题)
2、创建项目

(1)通过cmd或pycharm控制台的命令创建项目

​ 先切换到要创建项目的目录下,然后执行创建项目命令:

django-admin startproject mysite  # mysite是项目名称

​ 创建项目后会生成如下的目录,当前目录下会生成mysite的工程,里面有个主目录和我们创建的项目目录同名,在项目目录下有个manage.py文件,在主目录下有settings.py\urls.py\wsgi.py,每个文件的功能介绍如下:

manage.py ----- Django项目里面的工具,通过它可以调用django shell和数据库,启动关闭项目与项目交互等,不管你将框架分了几个文件,必然有一个启动文件,其实他们本身就是一个文件。
settings.py ---- 包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作的变量。
urls.py ----- 负责把URL模式映射到应用程序。
wsgi.py ---- runserver命令就使用wsgiref模块做简单的web server,后面会看到renserver命令,所有与socket相关的内容都在这个文件里面了,目前不需要关注它。

​ 一个django项目中可以有多个应用,每个应用完成项目的部分功能,这些功能相对于其他功能来说是相对独立的,但又同时存在于同一个项目中,每个应用的逻辑数据库等也都是相对独立的,每个应用都有属于自己的模块单位;开发的时候,都是通过应用来写逻辑

(2)通过pycharm创建django项目

  • 点击File --》New Project 选择第二项 Django

  • 在Location中选择选项目创建的地址和项目名

  • Project Interpreter:

    Project Interpreter中的Newenvironment using是创建项目执行的虚拟环境

    Project Interpreter中的Existing interpreter是使用本地的环境,也可以使用已创建好的虚拟环境

  • More Settings

    Template language:模板引擎;默认是Django的Template模板引擎

    如若下载jinja2模板引擎可进行切换,或者其他模板引擎

    注:django中的模板引擎未单独封装成模块;jinja2是模仿的的django的Template

    Templates folder:存放html文件的文件夹名

    Application name:是创建的应用的应用名

  • create创建完成后执行即可,通过控制台显示的链接即可访问

3、运行项目

启动项目命令:

python manage.py runserver 127.0.0.1:8080
ip和port可以不用写,不写时默认是 127.0.0.1:8000

运行成功后,会看到一个项目链接,在浏览器中输入此链接即可访问到创建的项目

4、创建应用Application

(1)创建项目时直接通过Application name创建应用

(2)pycharm中手动创建应用

  • cmd或pycharm控制器Terminal中创建应用
要在项目目录下执行命令进行创建应用
python manage.py startapp 应用名
经常用到的三个文件
models.py  数据库相关内容
views.py  视图,业务逻辑代码相关内容
tests.py 用来写一些测试代码,用来测试我们自己写的视图的,目前用不到
  • 手动创建文件夹
    • 创建应用文件夹(鼠标右键使用python package创建)
    • 在settings.py中找到INSTALLED_APPS在其下面添加应用的配置信息
    • 应用名.apps.应用名Config(后面的应用名的首字母大写)
  • 注意
    • 手动创建应用的时候要把应用指定给当前项目
    • 在settings文件的INSTALLED_APPS的下面
      • 方式一:应用名.apps.应用名Config(后面的应用名的首字母大写)
      • 方式二:应用名 ( 这是简写方式)
    • 如若不指定应用,Django中的某些方法将无法使用
5、django项目的导入

请看博客:https://www.cnblogs.com/wylshkjj/p/11983596.html

6、windows中安装不同版本的python解释器

在python3.7及以上版本中,使用django框架的时候,django的版本要在2.0或以上,否则会出现问题;python3.6使用django的1.0版本。

当想即使用python3.7和python3.6针对django的不同版本进行创建项目时,python解释器的安装要注意,

解释器安装请参考博客:https://www.cnblogs.com/wylshkjj/p/13122349.html

二、url路由系统

​ 在django中,url中的路径写法是正则,正则里面有无名分组正则,有有名分组正则,那么对应django中的功能,我们称之为无名分组路由和有名分组路由

​ 在django的1.0版本中路由配置文件urls.py中使用的是url(),里面可以直接使用正则匹配路径的方式

​ 而在django的2.0版本中路由配置文件urls.py中使用的是path(),里面不能直接使用正则匹配路径,如需使用正则路径进行匹配就要使用re_path(),使用前要先导入

1、无命名分组路由

看写法,urls.py文件中内容如下

urlpatterns = [
		...
    url(r'^books/(\d+)/(\d+)/', views.book),
    #正则里面()分组正则,会将分组中的正则匹配到的内容作为返回值返回
]

简单分析,伪代码
'''
当用户请求的路径是它: /books/2019/8/

url(r'^books/(\d+)/(\d+)/', views.book), 里面做的事情如下

re.match(^books/(\d+)/,/books/2019/)
2019 和 8 作为位置参数交给了要执行的book视图函数
视图函数book的写法
def book(request,xx,oo):
    xx = 2019
    oo = 8
    pass
'''

视图views.py文件中函数的写法

#位置传参,url中正则^books/(\d+)/(\d+)/,那么第一个()分组匹配到的数据,作为book函数的第二个参数,第二个()分组匹配到的数据,作为book的第三个参数
def book(request, year, month):
    print('year', year, 'month', month) #year 2020

    # return HttpResponse('%s所有书籍' % year)
    return HttpResponse('%s年%s月所有书籍' % (year, month))

使用url路由系统时需要注意几个点

1. urlpatterns中的元素按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续。
2. 若要从URL中捕获一个值,只需要在它周围放置一对圆括号(正则分组匹配)。
3. 不需要添加一个前导的反斜杠(也就是写在正则最前面的那个/),因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
4. 每个正则表达式前面的'r' 是可选的但是建议加上。
5. ^articles$  以什么结尾,以什么开头,严格限制路径
2、有名分组路由

其实就玩得正则的有名分组,看示例

Urls.py文件中的写法

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    # /books/2020/6/
    url(r'^books/(?P\d+)/(?P\d+)/', views.book),
    # {'year':2020,'month':6},url类将有名分组正则匹配出来的数据,交给了book视图函数作为关键字参数来使用]

View.py文件中函数的写法如下

# ^books/(?P\d+)/(?P\d+)/
#获取到url中的有名分组正则匹配到的数据,那么函数形参名称必须和有名分组正则的那个名称相同才可以,也就是按照上面的url来看的话,函数的形参必须是year和month这两个名称,并且关键字传参不需要考虑函数形参的位置
def book(request, month, year):
    # print('year', year, 'month', month) #year 2020
    print(request.path) #/books/2020/6/
    # return HttpResponse('%s所有书籍' % year)
    return HttpResponse('%s年%s月所有书籍' % (year, month))
3、路径中的尾部斜杠问题

当用户通过浏览器访问django框架完整的项目中的某个路径时,如果用户在输入网址路径的最后,没有加上/斜杠,比如http://127.0.0.1:8000/test,那么django会发将用户输入的网址路径加上一个后置的/,也就会将路径变成这样http://127.0.0.1:8000/test/,然后给浏览器发送一个重定向的响应操作,状态码为301,那么浏览器拿到这个重定向操作之后,就会自动发起一个这样的路径请求http://127.0.0.1:8000/test/,所以当我们打开浏览器控制台的network功能查看请求过程时,会看到两个请求,一个没有后置的斜杠的,一个是有后置斜杠的。第二个请求才会走到我们的urs.py文件中的路径配合和分发对应视图的地方。

我们可以通过一个配置项,告诉django,不要自动加路径后面的斜杠了,但是需要注意的就是你自己写的url中的正则,也别加后面的斜杠,不然正则匹配不到。

配置项直接写在settings配置文件中,任意位置

APPEND_SLASH = False  #False表示告诉Django,不加路径后面的斜杠,默认值是True
5、视图函数中指定默认值

views.py文件:

# 在路由没有匹配任何参数的时候,num使用自己的默认值
# 当路由中有分组匹配数据的动作,比如url(r'^test/(\d+)/', views.test),用户输入网址:http://127.0.0.1:8000/test/22/,那么22就被匹配到了,会作为参数传给我们的test函数,那么num的值就变成了22
def test(request, num=10):
    print('number>>>',num)
    return HttpResponse('test')

urls.py文件

# url(r'^test/', views.test),
	url(r'^test/(\d+)/', views.test),
6、url反向解析

​ 由于将来项目中的不同功能对应的url路径可能会发生变化,所以我们在每个url路径上加上一个别名,将来通过别名反向解析来使用这个别名对应的路径,那么不管路径将来发生什么变化,只要别名不变,那么逻辑中使用这个路径的地方,都可以通过别名获取到

(1)url别名用法

urlpatterns = [
    ...
    url(r'^add_book/', views.add_book, name='add_book'),  #name属性对应的值,就是这个路径的别名

]

(2)views视图中使用url反向解析的方式

# 首先在视图中引入反向解析的方法
from django.urls import reverse  #url别名反向解析,通过name别名对应的数据,解析出我们的url路径

1 针对没有参数的别名 url(r'^add_book/', views.add_book, name='add_book'),
	反向解析:reverse('book_list')
2 针对含有无名分组的url:url(r'^book_list/v2/(\d+)/(\d+)/', views.book_list, name='book_list'),
	反向解析:reverse('book_list',args=(11,22))
3 针对含有有名分组的url:url(r'^book_list/v2/(?P\d+)/(?P\d+)/', views.book_list, name='book_list'),
	反向解析:reverse('book_list',kwargs={'year':2022,'month':11})

(3)html文件中使用url别名反向解析

  • 无参数:{% url ‘add_book’ %}
  • 有参数:{% url ‘add_book’ 2020 12 %}
针对无参数的路径:url(r'^add_book/', views.add_book, name='add_book'),
	反向解析:添加书籍
这对有参数的路径:url(r'^add_book/(\d+)/(\d+)/', views.add_book, name='add_book'),
							 url(r'^add_book/(?P\d+)/(?P\d+)/', views.add_book, name='add_book'),
	反向解析: 添加书籍

三、视图

1、request的对象

常用的属性和方法

print(request)  # wsgirequest对象
print(request.path)  # 请求路径 #/index/
print(request.method)  # 请求方法
print(request.POST)  # post请求提交的数据 
print(request.GET)  # 获取url中的查询参数   #不是针对get请求的
print(request.body)  #获取http请求消息格式的请求数据部分的内容  b''
print(request.META)  #请求头信息
print(request.get_full_path())  # 获取完整路径(包含查询参数的) /index/?a=1&b=3

print(request.FILES)  # 上传的文件对象数据
print(request.FILES.get('file'))  # 上传的文件名

#
print(request.POST.get('username'))  # 前端中传输的username的值
print(request.POST.get('sex'))  # 前端中单选传输的sex值
# 多选提交来的数据通过getlist来获取
print(request.POST.getlist('hobby'))  # ['2', '3']
2、response的响应

(1)常用方法

from django.shortcuts import render, HttpResponse, redirect

return HttpResponse('你好') #回复字符串
return render(request,'home.html') #回复html页面

#重定向方法,参数是个路径
return redirect('/home/')  #封装了302状态码,以及浏览器要重定向的路径

(2)添加响应头键值对

ret = render(request,'home.html') 
ret['a'] = 'b' #添加响应头键值对
return ret

(3)添加响应状态码

ret = render(request,'home.html', status=202) #render修改状态码还可以这样改
#ret['a'] = 'b' #添加响应头键值对
ret.status_code = 201 #添加响应状态码
return ret #回复html页面
3、CBV和FBV

两种视图逻辑的写法方法

FBV:全称function based view,就是基于函数来写视图逻辑

CBV:全称class based view,就是基于类来写视图

基于类的视图CBV写法,如下,views.py文件

from django.views import View

#登录需求
class LoginView(View):
    # get请求  获取login页面
    def get(self,request):
        return render(request,'login.html')
        
    # post请求,获取post请求提交的数据,并校验等等
    def post(self,request):
        print(request.POST)
        
        #
        return render(request,'login.html')

url路径的写法:urls.py文件

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/', views.index),
    url(r'^home/', views.home),

    # 类视图的url写法
    url(r'^login/', views.LoginView.as_view()),

]
4、cbv源码重点(反射)
from django.views import View
View里面的dispatch方法中的反射逻辑,实现了不同的请求方法,找到我们视图类中的对应方法执行
5、FBV和CBV加装饰器

FBV和普通函数加装饰器方式一样

示例:

#装饰器函数
def outer(f):
    def inner(request, *args ,**kwargs):
        print('前面')
        ret = f(request, *args ,**kwargs)
        print('后面')
        return ret
    return inner

#使用装饰器
@outer
def books(request):
    print('FBV执行了')
    return HttpResponse('book.html--ok')

CBV加装饰器

#装饰器函数
def outer(f):
    def inner(request, *args ,**kwargs):
        print('前面')
        ret = f(request, *args ,**kwargs)
        print('后面')
        return ret
    return inner


#使用装饰器
#1 引入django提供的装饰器方法method_decorator来配合装饰器函数的使用
from django.utils.decorators import method_decorator

@method_decorator(outer,name='get') #CBV加装饰器方式3
class BookView(View):
    #给类方法统一加装饰器,借助dispatch方法(父类的dispatch方法,就是通过反射来完成不同的请求方法找到并执行我们自己定义的视图类的对应方法)
    # 重写dispatch方法,dispatch方法是在其他请求方法对应的类方法执行之前执行的
    # @method_decorator(outer) #加装饰器方式2
    def dispatch(self, request, *args, **kwargs):
        # print('xxxxxx')
        ret = super().dispatch(request, *args, **kwargs)
        # print('oooooo')
        return ret

    #CBV加装饰器的方式1,给单独的方法加装饰器
    # @method_decorator(outer)
    def get(self, request, xx):
        print('CBV的get方法')
        return render(request, 'book.html')

    # @method_decorator(outer)
    def post(self,request, xx):
        print('CBV的post方法')
        return HttpResponse('ok')
  

四、Template模板

1、Template的基本使用

(1)通过{{ 变量 }}:获取单个变量值

(2)通过{% 逻辑 %}:获取逻辑渲染结果

2、变量的使用

Number数据类型,容器数据类型和对象都可以直接进行渲染

(1)返回前端页面的数据格式

  • 在return返回的时候可以直接写入参数,区别在于html中渲染的时候直接通过元素直接获取(使用原参数没有作用),容器数据类型才有效,number类型无效

    return render(request, “index.html”, info)

  • 在return返回的时候也可以使用字典的方式,使用字典时,就是直接通过字典的键来进行相应的操作

    return render(request, “index.html”, {‘info’: info})

(2)句点号的使用:

​ 在字典数据类型中需要使用句点号和索引搭配才能获取到相应的值

​ 同理对象的方法和属性的调用也是通过句点号,而且要注意调用方法不能加()

# views.py
from django.shortcuts import render
import datetime
# Create your views here.
class obj():
    pass
def index(request):
    pdd = '1234'
    info = {
        'name': '旋风奥利奥',
        'age': '18',
        'hobby': "girl",
        'dict': {'drink': '饮品', 'milk': '牛奶'},
        'list': ['面包', '包子'],
        'object': obj(),
        'size': 123456,
        'time': datetime.datetime.now()
    }
    return render(request, "index.html", info)
    # return render(request, "index.html", {'info': info})

# html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h3>{{ name }}</h3>
<p>{{ dict }}</p>
<p>{{ list }}</p>
<p>{{ pdd }}</p>
<hr>
{% for foo in list %}
<p>{{ foo }}</p>
{% endfor %}
<hr>
{% for k,v in dict.items %}
<p>{{ k }} : {{ v }}</p>
{% endfor %}
<hr>
{{ object.obk }}
</body>
</html>

# url.py
from app01 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/', views.index)
]
3、Template过滤器
  • 通过过滤器对数据进行过滤处理显示
  • 使用方式:{{ 变量|过滤器:参数 }}
  • 过滤器支持链式操作,通过多个管道符和过滤器相配合实现层级过滤
  • 过滤器可以接收参数
  • 注意事项:管道符左右两遍不能留空格,否则不能识别;还有参数和:间也不能留空格;
3.1、内置过滤器

(1)default:默认值

​ 当变量获取的到值的时候显示获取的值,获取不到值或者获取的是一个布尔类型的False时就使用默认的default值:{{ value|default:“没有值”}}

(2)length:长度

​ 返回的是字符串或列表的长度:{{ value|length }}

(3)filesizeformat:文件大小的显示处理

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

(4)slice:切片:{{ value|slice:“2:-1” }}

(5)date:时间显示处理

​ 对获取的时间进行过滤处理:{{ value|date:“Y-m-d H:i:s”}}

(6)safe:声明此变量值(或代码段)不转义

{'a_tag':'百度',}
渲染

{{ a_tag|safe }} #生成标签效果

(7)truncatechars:指定字符串长度,超出部分以 … 显示
{{ value|truncatechars:9}}:指定九个字符长度,也包括 … 这三个字符

(8)truncatewords:以单词的形式指定字符串长度,超出部分以 … 显示

​ {{ value|truncatewords:3}}:指三个单词长度,不包括 … 部分

(9)cut:过滤字符串

​ {{ value|cut:’ ’ }}:过滤掉value变量中和参数中的空格相同的字符

(10)join:字符串拼接

​ {{ hobby|join:’+’ }}:把列表数据通过加号拼接成一个字符串

3.2、自定义过滤器
  • 在应用文件夹中创建一个名为templatetags的文件夹(文件夹的名字必须是templatetags)
  • 在templatetags文件夹中创建任意 .py 文件,如:mytag.py
  • 在mytag.py文件中写上如下内容
from django import template
register = template.Library()  # 制作注册器,名字必须叫register
#过滤最多两个参数
@register.filter  # 注册过滤器,需要两个参数的
def add(v1, v2):  # v1表示管道符前面的,v2表示冒号后面的参数
    print(v1,v2)  # 100 50
    return v1 + v2

@register.filter  # 注册过滤器,需要一个参数的
def xxx(v1):   # v1表示管道符前面的
    print(v1) 
    return 'xxx'
  • 在html文件中导入
{% load mytag %}  

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>

head>
<body>
<h1>base页面h1>
    
<div>
    {{ num|add:50}}  
div>
<div>
    {{ num|xxx }}
div>
  

body>
html>
4、Template标签

​ 使用方式:{% 标签 %} {%end标签%}

4.1、内置标签

(1)for 循环标签

​ {% for xx in hobby %}{% endfor %}

forloop的使用

​ 注:循环序号可以通过{{forloop}}显示,必须在循环内部用

  • forloop.counter 当前循环的索引值(从1开始),forloop是循环器,通过点来使用功能

  • forloop.counter0 当前循环的索引值(从0开始)

  • forloop.revcounter 当前循环的倒序索引值(从1开始)

  • forloop.revcounter0 当前循环的倒序索引值(从0开始)

  • forloop.first 当前循环是不是第一次循环(布尔值)

  • forloop.last 当前循环是不是最后一次循环(布尔值)

  • forloop.parentloop 本层循环的外层循环的对象,再通过上面的几个属性来显示外层循环的计数等

for循环的反向循环:

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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{% for i in dict %}
    <p>{{ i }}</p>
{% endfor %}
<hr>
{% for i in dict.values %}
    <p>{{ i }}</p>
{% endfor %}
<hr>
{% for k,v in dict.items %}
    <p>{{ k }} : {{ v }}</p>
{% endfor %}
<hr>
{% for foo in list %}
    <p>{{ forloop }} : {{ foo }}</p>
{% endfor %}
<hr>
{% for foo in list %}
    <p>{{ forloop.counter }} : {{ foo }}</p>
{% endfor %}
<hr>
{% for foo in list %}
    <p>{{ forloop.counter0 }} : {{ foo }}</p>
{% endfor %}
<hr>
{% for foo in list %}
    <p>{{ forloop.revcounter }} : {{ foo }}</p>
{% endfor %}
<hr>
{% for foo in list %}
    <p>{{ forloop.revcounter0 }} : {{ foo }}</p>
{% endfor %}
<hr>
{% for foo in list %}
    <p>{{ forloop.first }} : {{ foo }}</p>
{% endfor %}
<hr>
{% for foo in list %}
    <p>{{ forloop.last }} : {{ foo }}</p>
{% endfor %}
<hr>
{% for foo in list %}
    {% for foo in list %}
        <p>{{ forloop.parentloop.counter }} : {{ forloop.revcounter0 }} : {{ foo }}</p>
    {% endfor %}
{% endfor %}
<hr>

# 反向循环列表
{% for foo in list reversed %}
    <p>{{ foo }}</p>
{% endfor %}

</body>
</html>

(2)if 判断标签

​ {% if 判断条件 %}{% endif %}

  • if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断,注意条件两边都有空格。
  • 但是不支持连续判断操作:{% if a > b > c %}{% endif %}
  • {% if %}会对一个变量求值,如果它的值是“True”(存在、不为空、且不是boolean类型的false值),对应的内容块会输出。
{% if num > 100 or num < 0 %}
	

无效

{% elif num > 80 and num < 100 %}

优秀

{% else %}

凑活吧

{% endif %}

(3)with 起别名标签

​ 使用一个简单地名字缓存一个复杂的变量,多用于给一个复杂的变量起别名,当你需要使用一个“昂贵的”方法(比如访问数据库)很多次的时候是非常有用的;注意:等号左右不要加空格。

方式一:
{% with total=business.employees.count %}
    {{ total }} 
{% endwith %}

方式二:
{% with business.employees.count as total %}
    {{ total }}
{% endwith %}

(4)for empty联合使用的情况

​ 当循环的hobby没有数据或为空的时候,就显示empty下面的内容

    {% for xx in hobby %}
  • {{ xx }}
  • {% empty %}

    抱歉,没有查询到相关数据

    {% endfor %}

(5)Django的模板语言中属性的优先级大于方法

​ 处理的字典数据中不要出现以方法名为键的键值对,因为默认会获取该键值对数据,而不是走方法去处理数据,导致得不到想要的数据结果。

def xx(request):
    d = {"a": 1, "b": 2, "c": 3, "items": "100"}
    return render(request, "xx.html", {"data": d})

​ 如上,我们在使用render方法渲染一个页面的时候,传的字典d有一个key是items并且还有默认的 d.items() 方法,此时在模板语言中:{{ data.items }}

​ 默认会取d的items key的值。

4.2、自定义标签
  • 在应用文件夹中创建一个名为templatetags的文件夹(文件夹的名字必须是templatetags)
  • 在templatetags文件夹中创建任意 .py 文件,如:mytag.py
  • 在mytag.py文件中写上如下内容
from django import template
register = template.Library()  # 制作注册器,名字必须叫register
@register.simple_tag
def atag(v1,v2):  # 没有参数个数限制
    print(v1,v2)
    return v1 + v2
  • 在html文件中导入
 {% load mytag %}

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>

head>
<body>
<h1>base页面h1>
{% load mytag %}

<div>
    {% atag a b %}  
div>

body>

html>
5、Templete模板继承

将一些页面公共的部分,可以抽离出来单独做成一个html页面,使用这些公用部分的其他html文件,只需要继承一下它就可以了,具体使用流程如下:

(1) 创建公用模板,比如内容如下


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <style>
        body{
            padding: 0;
            margin: 0;
        }
        {% block css %}
        .nav{
            height: 60px;
            background-color: green;
        }
        {% endblock %}
        .nav a{
            color:white;
            text-decoration: none;
        }
        .left-menu{
            width: 30%;
            background-color: rgba(0,0,0,0.5);
            float:left;
        }
        .menu .menu-title{
            text-align: center;
        }
        .main{
            float: right;
            width: 65%;
            height: 300px;
            border: 1px solid red;
        }
    style>
head>
<body>

<div class="nav">
    <a href="/xx1/">首页a>
    <a href="/person/">个人中心a>
    <a href="/detail/">详情页a>
div>
<div class="left-menu">
    <div class="menu">
        <div class="menu-title">菜单1div>
        <div class="menu-body">
            <div class="item">局部按摩div>
            <div class="item">全身按摩div>
            <div class="item">足底按摩div>
            <div class="item">头部按摩div>
        div>
        <div class="menu-title">菜单2div>
        <div class="menu-body">
            <div class="item">盲人按摩div>
            <div class="item">推背div>
            <div class="item">刮痧div>
            <div class="item">精油、火罐div>
        div>
    div>
div>
<div class="main">
    {% block content %}
    公共页面
    {% endblock %}
div>

body>
{% block js %}
    
{% endblock %}

html>

(2)将来如果说继承公用模板的html文件中需要修改公用模板中的一些内容,那么需要在公用模板中预留一些钩子,钩子的写法如下

{% block content %}  #block 后面的块名称随便起
公共页面
{% endblock %}
#也可以这样写 {% endblock content %}  #endblock指定名称

(3)继承公用模板需要在html文件中写如下内容:

{% extends 'xx.html' %}  

{% block css %}
.nav{
    height: 60px;
    background-color: pink;
}
{% endblock %}

{% block content %}
    <h1>首页h1>
{% endblock %}


(4) 在使用公用模板的其他html文件中,如果需要更改公用模板里面的内容,只需要在html文件中写上相同的钩子,钩子里面写上自定义的内容,写法如下

{% block css %}
.nav{
    height: 60px;
    background-color: pink;
}
{% endblock %}

{% block content %}
    

首页

{% endblock %}

(5)注意事项:

  • 如果你在模版中使用 {% extends %} 标签,它必须是模版中的第一个标签。其他的任何情况下,模版继承都将无法工作,模板渲染的时候django都不知道你在干啥。

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

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

  • {{ block super }}的使用,在子模板中也展示出父模板原来钩子中的内容

    {% block content %}
        

    首页

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

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

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

  • 不能在一个模版中定义多个相同名字的 block 标签。

    #两个block都叫content,这种写法是不对的
    {% block content %}
    
        

    首页

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

    首页

    {{ block.super }} {% endblock %}
6、要注意Template模板渲染实在浏览器解释之前执行的,模板渲染后才轮到浏览器器来执行解释

​ 与safe处理效果相同的mark_safe方法,mark_safr方法需要导入模块

  • mark_safr的使用方法
    • 导入模块:from django.utils.safestring import mark_safe
    • mark_safe(html代码)
  • safe的使用方法:
    • 通过管道符safe:变量|safe

mark_safe与|safe的优缺点:

  • mark_safe可直接返回大量的html标签,可用于自定义标签中,通过后端python代码返回实现
  • |safe每次只能解决一个变量的问题,在自定义标签中不能使用,通过前端模板渲染实现
7、拓展:XSS攻击(上面过滤|safe的拓展)

xss攻击:,全称跨站脚本攻击

​ Django的模板中在进行模板渲染的时候会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全,django担心这是用户添加的数据,比如如果有人给你评论的时候写了一段js代码,这个评论一提交,js代码就执行啦,这样你是不是可以搞一些坏事儿了,写个弹窗的死循环,浏览器就不能用了,浏览器会一直弹出弹窗,这叫做xss攻击,所以浏览器中进行了一些转义处理。但是有的时候我们需要这些HTML元素不被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义。

8、django的UTC格林威治时间的处理

​ 在settings.py文件中,具体情况集体分析,主要修改settings配置文件的参数。

9、Template模板注意事项

在引入的javastript文件中使用模板渲染是不会生效的

​ Django对于html的Template渲染时是以字符串的形式先读取所有的html文件中的内容,然后执行模板渲染,此实javascript的导入部位代码还是字符串,文件还没有被引入,当模板渲染结束后返回给浏览器的时候,浏览器解析时异步执行javascript文件,而此时无法再进行模板渲染了,因为模板渲染是由后台执行的。浏览器并不会,也没有此功能。

​ 若想在javascript中使用模板渲染,那就不能使用文件引入的方式,只能在html文件中写javascript,并在里面使用模板渲染规则

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True
10、组件与动态组件的应用

(1)组件

组件就是一个html文件,其中封装了一些特定功能,比如就是一个导航栏,或者就是一个左侧菜单,相当我们将一些特定功能封装成了一个组件,将来任何其他html文件中如果使用这部分功能,可以直接引入使用。

在django模板渲染系统中使用组件的步骤

第一步:创建组件的html文件,名字随便取,比如叫做zujian.html,比如内容如下,做一个顶部导航栏组件


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>zujiantitle>
    <style>
        .nav{
            background-color: blue;
            height: 100px;
        }
        .nav a{
            color:white;

        }
    style>
head>
<body>

<div class="nav">
    <a href="">百度a>
    <a href="">京东a>
    <a href="">个人中心a>
div>


body>

html>

第二步:使用组件,需要借助下面这个标签语法

{% include '组件文件名称.html' %}

示例:比如我们需要某个html文件中使用,比如show.html文件中使用,show.html文件内容如下:


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>




head>
<body>

<h1>这是show页面h1> 
  
body>

html>

(2)动态组件的应用

注意:在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的标签

  1. 在app中创建templatetags文件夹(文件夹名只能是templatetags)

  2. 在templatetags文件夹中创建任意 .py 文件,如:mytag.py

  3. 在mytag.py文件中写上如下内容

from django import template
register = template.Library() #制作注册器,名字必须叫register
@register.inclusion_tag('zujian2.html')
def xiaolin(v1):
    #v1 = [11,22,33]
    return {'data': v1}
  1. 使用inclusion_tag,比如在show2.html文件中使用:



    
    Title


{% load mytag %}
{% xiaolin d %}

这是show2页面

  1. 需要后台给show2.html传递数据,比如views.py文件写法如下
def show2(request):
    d = ['国产', '欧美', '日韩']
    return render(request,'show2.html',{'d': d})

你可能感兴趣的:(Python基础)