Django基础三之路由、视图、模板

1. Django 请求和返回周期

Django默认使用wsgiref模块但是该模块并发量特别小(大约1000),不适用于线上环境,所以在Django项目上线之后会使用uwsgi

1.1 路由层之路由匹配

主要是在ursl.py文件里书写。

1.11版本:
urlpatterns = [
url('^admin/', admin.site.urls),
] 3.2版本:
urlpatterns = [
path('admin/', admin.site.urls),
path('test/', views.test),
path('testadd/', views.testadd),
]
1版本中使用url方法:
url()方法:
1,第一个参数为一个正则
2,只要能匹配上就会执行后面的视图函数 3版本中使用path
path()方法
第一个参数是一个字符串
如果使用正则,则要使用 re_path() 而不是 path() 。
urlpatterns = [
re_path(r'^admin/', admin.site.urls),
] test/和testadd/ 在匹配的时候如果不写后面的斜杠(/),发现也能匹配上,是因为Django在做的时候如果test匹配不上,它会让浏览器后面自动加上斜杠(/)再试一次。
这个是用settings里面的APPEND_SLASH参数控制,默认为True,如果只想匹配一次则设置为False.
APPEND_SLASH=False

Django3.x在匹配时有了路径转换器:

  • str - 匹配除了 '/' 之外的非空字符串。如果表达式内不包含转换器,则会默认匹配字符串。

  • int - 匹配 0 或任何正整数。返回一个 int

       path('articles/<int:year>/', views.year_archive),
    <int:year>是个整型参数
  • slug - 匹配任意由 ASCII 字母或数字以及连字符和下划线组成的短标签。比如,building-your-1st-django-site

  • uuid - 匹配一个格式化的 UUID 。为了防止多个 URL 映射到同一个页面,必须包含破折号并且字符都为小写。比如,075194d3-6885-417e-a8a8-6c931e272f00。返回一个 UUID 实例。

  • path - 匹配非空字段,包括路径分隔符 '/' 。它允许你匹配完整的 URL 路径而不是像 str 那样匹配 URL 的一部分。

1.2 有名分组

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

在Django3中路由匹配使用正则:
ursl.py文件:
from django.contrib import admin
from django.urls import path,re_path #要手动导入re_path from orm import views
urlpatterns = [ path('admin/', admin.site.urls),
path('test/', views.test),
path('testadd/', views.testadd),
re_path(r'test/(?P<year>[0-9]{4})/', views.testadd), ] 在views.py:
def testadd(request,year):
print(year)
return HttpResponse("from test") // 分组名必须要传给后面的视图函数,否则会报错。
如上面的例子,分组名为year,如果不传给后端的views.testadd函数,报错信息:
testadd() got an unexpected keyword argument 'year' 有名分组
将括号内正则表达式匹配到的内容当做关键字参数传递给后面的视图函数

1.3 无名分组

有命名组语法,例如 (?P<year>[0-9]{4}) ,你也可以使用更短的未命名组,例如 ([0-9]{4})

在Django3中路由匹配使用正则:
ursl.py文件:
from django.contrib import admin
from django.urls import path,re_path #要手动导入re_path from orm import views urlpatterns = [
path('admin/', admin.site.urls),
path('test/', views.test),
path('testadd/', views.testadd),
re_path(r'test/([0-9]{4})/$', views.test),
] 启动访问:
http://127.0.0.1:8000/test/1234/
报错:
test() takes 1 positional argument but 2 were given
解决方法:
在views.py:
def test(request,what):
print(what)
return HttpResponse("from test") 再执行访问成功。
控制台打印的结果:
1234 无名分组:
将括号内正则表达式匹配到的内容当做位置参数传递给后面的视图函数。

总结:

  1. 有名分组和无名分组不能混合使用。
  2. 单个种类可以重复使用

2. 反射解析

当路由频繁变化的时候,HTML界面上的连接地址如何做到动态解析。

"""
1. 给路由与视图函数对应关系添加一个别名(名字自己定义,名字之间不要冲突)
path('show/', views.show, name='showtime'), 2. 根据这个别名动态解析出一个结果,该结果可以直接访问到对应的路由
前端使用别名:
<a href="{% url 'showtime' %}"><h1>Hello Django</h1></a>
这样不管path里面的show怎么变,只要name='showtime'不变,那么访问就没问题 后端使用别名:
ursl.py:
urlpatterns = [
path('show/', views.show, name='showtime'),
] views.py
from django.shortcuts import render, HttpResponse,redirect,reverse
def delete(request):
......
print(reverse('showtime')) # 打印url
return redirect('showtime') # 也可以直接在重定向里写别名 """

无名和有名分组指向解析

ursl.py
"""
from django.urls import path,re_path
urlpatterns = [
re_path(r'test/([0-9]{4})/$', views.test, name='index_test'),
]
"""
views.py
"""
def delete(request):
......
print(reverse('index_test',args=(1,))) # 打印url args=(1,) args后面跟一个元组,里面这写的是1,推荐写主键的值
r'test/([0-9]{4})/([0-9]{4})/$ 如果有两个分组,则args后面必须写两个值,(1,2)第二个值可以随便写
""" 前端也一样:
<a href="{% url 'index_test' 123 %}"><h1>Hello Django</h1></a>
这里123也是随便写的,只要写个数字就行 有名:
后端
reverse('index_test',kwargs={'id':123})
前端
<a href="{% url 'index_test' id=123 %}"><h1>Hello Django</h1></a>

总结

无名和有名都可以使用一种(无名)反向解析的形式

3. 路由分发

其实Django中的每一个应用都可以有自己的urls.pystatic文件夹、templates文件夹,这样使用Django做分组开发非常的简便。每个人只需要写息的应用即可,最后汇总到一个空的Django项目中然后使用路由分发将多个应用关联。

示例:

创建一个项目,并创建两个应用(app01,app02).
在每个应用里面都创建一个urls.py文件。
app01 urls.py:
""" from django.urls import path
from app01 import views
urlpatterns = [
path('index', views.index),
]
"""
app01 views.py: """
from django.shortcuts import render,HttpResponse # Create your views here. def index(request):
return HttpResponse("from app01 index") """ app02 urls.py:
"""
from django.urls import path
from app02 import views
urlpatterns = [
path('index', views.index),
]
"""
app02 views.py:
"""
from django.shortcuts import render,HttpResponse # Create your views here. def index(request):
return HttpResponse("from app02 index") """ 项目中总的urls.py:
"""
from django.contrib import admin
from django.urls import path,include
# 导入应用的urls
from app01 import urls as app01_urls
from app02 import urls as app02_urls urlpatterns = [
path('admin/', admin.site.urls),
path('app01/', include(app01_urls)),
path('app02/', include(app02_urls)), ]
"""
注意:
需要在总的urls.py里导入include
from django.urls import path,include
在总的路由里面不能加$符号,否则没办法分发 还有一种在总的urls.py里不需要导入应用urlsr 的方法: 项目中总的urls.py:
"""
from django.contrib import admin
from django.urls import path,include urlpatterns = [
path('admin/', admin.site.urls),
path('app01/', include('app01.urls')),
path('app02/', include('app02.urls')), ]
"""

4 名称空间

当多个应用在反射解析的时候如果出现了别名冲突的情况,那么将会无法自动识别

示例:

app01 urls.py:
"""
from django.urls import path
from app01 import views
urlpatterns = [
path('index', views.index,name='index_name'),
path('login', views.login)
]
"""
app01 views.py:
"""
from django.shortcuts import render,HttpResponse,reverse # Create your views here. def index(request):
return HttpResponse("from app01 index") def login(request):
print(reverse('index_name'))
return HttpResponse("from app01 login")
"""
app02 urls.py:
""" from django.urls import path
from app02 import views
urlpatterns = [
path('index', views.index,name='index_name'),
path('login', views.login),
]
"""
app02 views.py:
"""
from django.shortcuts import render,HttpResponse,reverse # Create your views here. def index(request):
return HttpResponse("from app02 index") def login(request):
print(reverse('index_name'))
return HttpResponse("from app02 login")
""" 项目中总的urls.py:
""" from django.contrib import admin
from django.urls import path,include urlpatterns = [
path('admin/', admin.site.urls),
path('app01/', include('app01.urls')),
path('app02/', include('app02.urls')), ]
"""
虽然访问页面:
http://127.0.0.1:8000/app01/login
http://127.0.0.1:8000/app02/login
的时候能正常拿到对应的页面,但是在后端发现拿到的是同一个:
/app02/index
/app02/index

要解决这个问题就用到了名称空间

解决方法一:使用名称空间

在总路上加上namespace这个参数:
项目中总的urls.py:
""" from django.contrib import admin
from django.urls import path,include urlpatterns = [
path('admin/', admin.site.urls),
path('app01/', include('app01.urls',namespace='app01')),
path('app02/', include('app02.urls',namespace='app02')), ]
""" app01 urls.py:
"""
from django.urls import path
from app01 import views
app_name='app01'
urlpatterns = [
path('index', views.index,name='index_name'),
path('login', views.login)
]
"""
app01 views.py:
"""
from django.shortcuts import render,HttpResponse,reverse # Create your views here. def index(request):
return HttpResponse("from app01 index") def login(request):
print(reverse('app01:index_name'))
return HttpResponse("from app01 login")
"""
app02 urls.py:
""" from django.urls import path
from app02 import views
app_name='app02'
urlpatterns = [
path('index', views.index,name='index_name'),
path('login', views.login),
]
"""
app02 views.py:
"""
from django.shortcuts import render,HttpResponse,reverse # Create your views here. def index(request):
return HttpResponse("from app02 index") def login(request):
print(reverse('app02:index_name'))
return HttpResponse("from app02 login")
""" 访问页面:
http://127.0.0.1:8000/app01/login
http://127.0.0.1:8000/app02/login
拿到的就是
/app01/index
/app02/index 注意在Django3.2版本中使用名称空间的时候,一定要给每个应用设置应用名,否则会报错:
'''pecifying 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.'''
解决方法:
app01 urls.py:
'''
app_name='app01'
''' app02 urls.py:
'''app_name='app02''''
这两个必须要设置。

前端使用名称空间:

<a href="{% url 'app01:index_name' %}">app01_index</a>
<a href="{% url 'app02:index_name' %}">app02_index</a>

注意:

虽然我们现在可以将模板文件直接放在 app01/templates 文件夹中(而不是再建立一个 app01 子文件夹),但是这样做不太好。Django 将会选择第一个匹配的模板文件,如果你有一个模板文件正好和另一个应用中的某个模板文件重名,Django 没有办法 区分 它们。我们需要帮助 Django 选择正确的模板,最好的方法就是把他们放入各自的 命名空间 中,也就是把这些模板放入一个和 自身 应用重名的子文件夹里。(app01/templates/app01/login.html)

同理:多个应用下的静态文件也是这样。

所以在前端使用名称空间的时候,HTML文件的路径为:

app01/templates/app01/login.html
app02/templates/app02/login.html 后端app01 views.py:
from django.shortcuts import render,HttpResponse,reverse
def login(request):
print(reverse('app01:index_name'))
return render(request, "app01/login.html") 后端app02 views.py:
from django.shortcuts import render,HttpResponse,reverse
def login(request):
print(reverse('app02:index_name'))
return render(request, "app02/login.html")

解决方法二:别名别冲突

写别名的时候要加上自己应用名做前缀。

5. JsonResponse

给前端返回一个json格式的数据

方法一:自己序列化

views.py:
from django.shortcuts import render,HttpResponse,reverse
import json def index(request):
d = {'user':'Hans', 'password':123}
d_json = json.dumps(d)
return HttpResponse(d_json) # json默认不能直接识别的字符直接返回对应的unicode编码,如上面的汉字要正确返回则需要设置ensure_ascii=False
d = {'user':'Hans你好', 'password':123}
d_json = json.dumps(d,ensure_ascii=False)

方法二: 使用JsonResponse

views.py:

from django.shortcuts import render,HttpResponse,reverse
from django.http import JsonResponse def index(request):
d = {'user':'Hans', 'password':123}
return JsonResponse(d) # JsonResponse 对不能识别的字符也是直接返回unicode编码,如果对汉字也能正常展示,加上json_dumps_params={'ensure_ascii':False}参数:
d = {'user':'Hans你好', 'password':123}
return JsonResponse(d,json_dumps_params={'ensure_ascii':False}) # 如果序列化一个非字典类型的,则需要让safe=False 如:
li = ['A','B','C']
return JsonResponse(d, safe=Fasle)

6. 上传文件

前端页面:

    <form action="" method="post" enctype="multipart/form-data" class="form-control">
<p><input type="file" name="files"></p>
<p><input type="submit" value="提交" ></p> </form> # 路由层:
path('upfile', views.upfile),
# 视图层
views.py:
from django.shortcuts import render,HttpResponse,reverse def upfile(request):
if request.method == 'POST':
file_obj = request.FILES.get('files')
print(file_obj.name)
with open(r'./app01/templates/%s' % file_obj.name, 'wb') as f:
for chunk in file_obj.chunks():
f.write(chunk)
return render(request,"app01/upfile.html")

7. FBV和CBV

FBV:基于函数的视图

CBV:基于类的视图

上面写的都为FBV,基于函数的视图,现在写一个基于类的视图。

# views.py
from django.shortcuts import render,HttpResponse,reverse
from django.views import View class MyView(View):
def get(self,request):
return HttpResponse("GET方法")
def pos(self,request):
return HttpResponse("POST方法") # urls.py
from django.urls import path
from . import views urlpatterns = [
path('myview', views.MyView.as_view()),
] #CBV和FBV路由匹配其实是一样的。

8. 模板语法传值

8.1 传基本数据类型

# 方法一:精确传值

# urls.py
"""
from django.contrib import admin
from django.urls import path from templateByValue import views urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index),
]
"""
# 前端HTML:
"""
<body>
<ul>{{ i }}</ul>
<ul>{{ f }}</ul>
<ul>{{ str }}</ul>
<ul>{{ Li }}</ul>
<ul>{{ set01 }}</ul>
<ul>{{ t }}</ul>
<ul>{{ bool_value }}</ul>
<ul>{{ d }}</ul>
</body>
""" views.py:
"""
from django.shortcuts import render # Create your views here. def index(request):
i = 123
f = 12.3
str = "Hello Django"
Li = [1, 2, 3]
d = {'username':"Hans", "age":19}
t = (1, 2, 3, 4)
set01 = {1, 2, 3, 4}
bool_value = True return render(request,'index.html',{"i":i,"f":f,"str":str,"Li":Li,"d":d,'t':t, "set01":set01,'bool_value':bool_value}) """ # 方法二:使用locals函数
# 在views.py 中给前端页面传值每个都要写,在值特别多的时候不方便,可以使用locals函数
"""
return render(request,"index.html",locals())
"""
locals() 获取全部局部变量:
{'request': <WSGIRequest: GET '/index/'>, 'i': 123, 'f': 12.3, 'str': 'Hello Django', 'Li': [1, 2, 3], 'd': {'username': 'Hans', 'age': 19}, 't': (1, 2, 3, 4), 'set01': {1, 2, 3, 4}, 'bool_value': True},然后全部传给前端页面。 两者的优缺点:
方法一,可以精确传值,不会造成资源浪费,但传的值多的时候书写不方便
方法二, 书写方便,但是会造成资源浪费。

8.2 传函数名

# 前端:
"""
<body>
<p>{{ foo }}</p>
</body>
"""
# views.py:
"""
from django.shortcuts import render # Create your views here. # 定义函数
def index(request):
def foo():
print("hello")
return "Hello Django"
return render(request,"index.html",{"foo":foo}) # 给前端传递,前面拿到的是函数的返回值。
"""
使用模板语法传函数的时候,不支持带参数

8.3 传类名

# 前端:
"""
<body>
<p>{{ MyClass }}</p>
<p>{{ obj }}</p>
<p>{{ obj.get_self }}</p>
<p>{{ obj.get_cls }}</p>
<p>{{ obj.get_static }}</p>
</body>
"""
#views.py
"""
from django.shortcuts import render # Create your views here. def index(request):
class MyClass(object):
def get_self(self):
return "绑定给对象的方法"
@classmethod
def get_cls(cls):
return "绑定给类的方法"
@staticmethod
def get_static():
return "普通的函数"
obj = MyClass()
print(locals())
return render(request,"index.html",{"MyClass":MyClass,"obj":obj})
"""
或直接写:
return render(request,"index.html",locals())

总结

传递函数名和类名都会自动加括号调用(模板语法不支持额外的传参数)

9. 模板语法获取值

Django中模板语法取值只用.

# views.py
"""
from django.shortcuts import render # Create your views here. def index(request):
Li = [1, 2, 3]
d = {'username':"Hans", "age":19} return render(request,'index.html',locals()) """
# 前端:
"""
<ul>{{ Li.1}</ul> 拿列表第二个值
<ul>{{ set01.age}}</ul> 拿年龄
"""

10. 模板语法过滤器

过滤器的符号是管道符:|,将管道符左侧的数据当做第一个参数。

# views.py:
"""
from django.shortcuts import render # Create your views here. def index(request):
i = 123
str = "Hello Django"
Li = [1, 2, 3]
d = {'username':"Hans", "age":19}
bool_value = True
bool_var = False
import datetime
ctime = datetime.datetime.now()
file_size = 409600
h = "<h1>Hello</h1>"
from django.utils.safestring import mark_safe
h1 =mark_safe("<h1>Django</h1>") #后端也可以直接写HTML语法返回给前端了
return render(request,"index.html",locals()) """ # 前端:
"""
<body>
<p>过滤器:将管道符左侧的数据当做第一个参数</p>
<p>统计长度:{{ str|length }}</p>
<p>加法:{{ i|add:10000 }}</p>
<p>字符串拼接:{{ str|add:"HAHA" }}</p>
<p>日期格式:{{ ctime|date:"Y-m-d" }}</p>
<p>默认值:{{ bool_value|default:"哈哈" }}</p>
<p>默认值:{{ bool_var|default:"哈哈" }}</p>
<p>文件大小:{{ file_size|filesizeformat }}</p>
<p>截取文本(截6个字符,包括3个点):{{ str|truncatechars:6 }}</p>
<p>截取文本(截1个单词,不包括3个点):{{ str|truncatewords:1 }}</p>
<p>h源信息:{{ h }}</p>
<p>前端把后端传过来的数据(h),格式成HTML格式: {{ h|safe }}</p>
<p>后端传过来的数据(h1)直接为HTML格式显示: {{ h1 }}</p>
</body> """

11. 模板语法标签(流程控制)

# if
{% if var %}
<p>good</p>
{% endif %} # if else
{% if bool_var %}
<p>var</p>
{% else %}
<p>valu</p>
{% endif %} # if ... elif ... else {% if bool_var %}
<p>var</p>
{% elif bool_value %}
<p>value</p>
{% else %}
<p>都没有</p>
{% endif %} # for {% for foo in Li %}
<p>foo</p>
{% endfor %} # for内可以嵌套if
{% for foo in Li %}
<p>foo</p>
{% empty %} # 如果是空的时候,打印empty里的
<p>空值</p>
{% endfor %} {{}} 变量相关的用
{%%} 逻辑相关的用 # with
{% with d.3.username as name %} # 给d.3.username起别名
{{ name }}
{% endwith %} 这个别名只能在with里面用。

12. 自定义过滤器、标签、inclusion_tag

类似于python里面的自定义函数

1. 在应用下创建一个名字必须叫"templatetags"文件夹
2, 在上述文件夹内创建一个任意名称的py文件
3, 在该py文件内固定写入:
from django import template
register = template.Library()

12.1 自定义过滤器:

示例:

1,在应用下创建templatetags文件夹
2,在templatetags夹里创建myFilter.py
文件内容:
"""
from django import template register = template.Library() @register.filter(name="My") # 过滤器名
def index(a,b):
return a+b
"""
3, views.py
from django.shortcuts import render
def index(request):
i = 123
return render(request,"index.html",locals()) 4,前端页面:
<div>
{% load myFilter %}
<p>{{ i |My:100}}</p>
</div> 5. 浏览器显示结果:
223

过滤器只能接受两个参数。

12.2 自定义标签

1, 依然是在myFilter.py文件里:
"""
from django import template register = template.Library() @register.simple_tag(name='myTag') # 标签名
def foo(a,b,c,d):
return "{%s:%s %s:%s}" % (a,b,c,d)
"""
2, 前端页面:
"""
<div>
{% load myFilter %}
{% myTag 1 "hans" 2 "Hello" %} # 标签传值使用空格分隔
</div>
"""

标签可以接受多个参数

12.3 自定义inclusion_tag

前面自定义的过滤器和标签,都是自定义的过滤器函数和标签函数直接返回给前端,自定义inclusion_tag有些不同。

在myFilter.py文件里:
from django import template register = template.Library() @register.inclusion_tag('login.html', name="myInclusion") # inclusion_tag名字
def foo2(n):
l =[]
for i in range(1, n+1):
l.append("第%s页" % i)
return locals() # login.html
<ul>
{% for foo in l %}
<li>{{ foo }}</li>
{% endfor %}
</ul> # 前端页面:
<div>
{% load myFilter %}
{% myInclusion 4 %}
</div> 结果: 第1页
第2页
第3页
第4页

总结:

前端要使用自定义过滤器,标签和inclusion_tag都先要load.

在某个区域需要反复使用并且数据不固定,适合使用inclusion_tag.

13. 模板的导入

类似于python导模块

例如有一个页面会经常用到,不可能每次用到就写一份,可以使用模板导入的方法。

页面导入模板关键字:{%include%}

经常用到的页面form.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<form>
<div class="form-group">
<label for="exampleInputEmail1">Email address</label>
<input type="email" class="form-control" id="exampleInputEmail1" placeholder="Email">
</div>
<div class="form-group">
<label for="exampleInputPassword1">Password</label>
<input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</div> </div> </div>
</body>
</html>

模板导入:

需要用到模板的页面:
index.html
<body>
<div>
{% include 'form.html' %}
</div> </body>

14. 模板的继承

示例:

主页home.html(模板)

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Brand</a>
</div> <!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">One more separated link</a></li>
</ul>
</li>
</ul>
<form class="navbar-form navbar-left">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
</ul>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<!--左侧-->
<div class="list-group col-md-2">
<a href="#" class="list-group-item active">
Cras justo odio
</a>
<a href="/compute/" class="list-group-item">电脑</a>
<a href="/phone/" class="list-group-item">手机</a>
<a href="/beauty/" class="list-group-item">beauty</a>
<a href="#" class="list-group-item">Vestibulum at eros</a>
</div>
<!--右侧-->
{% block content %}
<div class="jumbotron col-md-10">
<h1>Hello, world!</h1>
<p>...</p>
<p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>
</div>
{% endblock %}
</div>
</div>
</body>
</html> <!--
{% block content %}
这个区域做了标记,这个区域是可以修改的。
content 这个名字可以随意起
{% endblock %}
-->

电脑(compute.html)页面继承home.html

{% extends 'home.html' %}
{% block content %}
<div class="row">
<div class="col-xs-6 col-md-3">
<a href="https://www.apple.com.cn/shop/buy-mac/macbook-pro/MK1A3CH/A" class="thumbnail">
<img src="https://store.storeimages.cdn-apple.com/8756/as-images.apple.com/is/mbp16-spacegray-gallery1-202110_GEO_CN?wid=4000&hei=3072&fmt=jpeg&qlt=80&.v=1633656602000"> </a>
</div>
</div>
{% endblock %} <!--
{% extends 'home.html' %} 继承home.html
{% block content %}
这个区域写homecompute自己的内容
{% endblock %}
-->

手机(phone.html)页面继承home.html

{% extends 'home.html' %}
{% block content %}
<div class="row">
<div class="col-xs-6 col-md-3">
<a href="#" class="thumbnail">
<img src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fexp-picture.cdn.bcebos.com%2F27725684cde34b2ca90aafca0d0e7c75e4f4437e.jpg%3Fx-bce-process%3Dimage%2Fresize%2Cm_lfit%2Cw_500%2Climit_1&refer=http%3A%2F%2Fexp-picture.cdn.bcebos.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1648558900&t=4b7021e3f90edeb7bf92842b1df965cb
">
</a>
</div>
</div>
{% endblock %}

子模板不但能修改被标记的位置,还可以使用模板内容:

{% extends 'home.html'%}
{% block content %}
<div class="row">
<div class="col-xs-6 col-md-3">
<a href="#" class="thumbnail">
<img src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F4k%2Fs%2F02%2F2110021F21V024-0-lp.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1648559897&t=c5b2a29fac9a42cb0f7019ea13b40d21">
</a>
</div>
</div>
{{ block.super }}
{% endblock %} <!--
{{ block.super }} 为模板内被标记的区域
-->

模板在标记区域的时候一般有三个区域

  1. CSS区域
  2. HTML区域
  3. JS区域

目的是为了让继承的子模板具有独立的CSS和JS,增加扩展性

<head>
{% balock css %}
css 样式
{% endblock %}
</head> <body>
{% balock html %}
html内容
{% endblock %} {% balock js %}
js 内容
{% endblock %}
</body>
子板也可以使用模板标记的区域的内容:
{{ block.super }}

Django基础三之路由、视图、模板的更多相关文章

  1. day 53-1 Django基础三之视图函数

    Django基础三之视图函数   本节目录 一 Django的视图函数view 二 CBV和FBV 三 使用Mixin 四 给视图加装饰器 五 Request对象 六 Response对象 一 Dja ...

  2. day 67 Django基础三之视图函数

    Django基础三之视图函数   本节目录 一 Django的视图函数view 二 CBV和FBV 三 使用Mixin 四 给视图加装饰器 五 Request对象 六 Response对象 一 Dja ...

  3. django基础2: 路由配置系统,URLconf的正则字符串参数,命名空间模式,View(视图),Request对象,Response对象,JsonResponse对象,Template模板系统

    Django基础二 request request这个参数1. 封装了所有跟请求相关的数据,是一个对象 2. 目前我们学过1. request.method GET,POST ...2. reques ...

  4. Django基础三之视图函数

    一 Django的视图函数view 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错 ...

  5. 03.Django基础三之视图函数

    一 Django的视图函数view 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错 ...

  6. django第三天(路由基础和路由分配)

    路由基础 url(正则路径,视图函数地址,默认关键字参数,路由别名) 路由由上而下匹配, ""可以匹配任意路由 "^$"来匹配"/" url ...

  7. <Django> MVT三大块之Template(模板)

    1.模板简介 创建项目,基本配置 第一步:配置数据库 第二步:创建APP,配置APP 第三步:配置模板路径 第四步:配置分发urls.py(APP里面的) 根目录下,增加命名空间namespace,作 ...

  8. Django基础三(form和template)

    上一篇博文学习了Django的View和urls,接下来是对django form 和 template的学习. 1 django form django form为我们提供了便捷的方式来创建一些HT ...

  9. python django基础三 模版渲染

    request对象 当一个页面被请求时,Django就会创建一个包含本次请求原信息的HttpRequest对象.Django会将这个对象自动传递给响应的视图函数,一般视图函数约定俗成地使用 reque ...

随机推荐

  1. Android总结【不定期更新】

    全屏显示: this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParam ...

  2. lua语言:string

    转载请注明来源:https://www.cnblogs.com/hookjc/ 字符串库函数string.len(s)          返回字符串s的长度:string.rep(s, n)      ...

  3. UIImageView的序列帧动画

    #pragma mark - 开始动画 - (IBAction)startAnimation { // 1.1 加载所有的图片 NSMutableArray<UIImage *> *ima ...

  4. 2021江西省赛赛后总结(Crypto)

    美国大选 程序: from Crypto.Util.number import * from secret import p,q def gcd(a, b): while b: a, b = b, a ...

  5. Hadoop文件操作常用命令

    1.创建目录 #hdfs dfs -mkidr /test 2.查询目录结构 #hdfs dfs -ls / 子命令 -R递归查看//查看具体的某个目录:例如#hdfs dfs -ls /test 3 ...

  6. Note -「线性规划」学习笔记

    \(\mathcal{Definition}\)   线性规划(Linear Programming, LP)形式上是对如下问题的描述: \[\operatorname{maximize}~~~~z= ...

  7. 今天你花里胡哨了吗 --- 定制属于自己的linux ssh迎宾信息

    请开始你的表演 linux-oz6w:~ # cat << 'eof' > /etc/profile.d/ssh-login-info.sh #!/bin/sh # 输出一个图像 e ...

  8. 深入MySQL(一):MySQL的组织架构

    今天开始将自己所学过的MySQL的知识都尝试融会贯通,并且用写博客的方式记录分享下来. 今天讲的主题是MySQL的组织架构,对于学习一个中间件或者开源项目而言,我觉得最重要的便是先知晓其组织架构,以一 ...

  9. 继承及super关键字

    继承 继承的本质是对某一批类的抽象,从而实现对世界更好的建模 extend的意思是"扩展",子类是父类的扩展. Java中类只有单继承,没有多继承:儿子只能有一个亲生爸爸,一个爸爸 ...

  10. 网络测试技术——802.1X TLS认证(上篇)

    一.TLS认证简介 1.TLS认证 (1)认证过程 · 最安全认证技术 · 实施最复杂 (2)TLS双向证书认证 · 服务器对客户端进行认证 · 客户端对服务器进行认证 2.TLS认证过程 3.交换机 ...