Django基础
Django铺垫
基本Web框架
manager.py
import sys
from wsgi import run
# 从wsgi 文件中 引入run
from models import create_model
# python manage.py xx xx2
# 执行py文件时,后面携带的参数,可以通过py文件中的sys模块的sys.argv这个属性拿到,是个列表,列表第一项是文件名称,第二项之后,都是携带的参数
# 返回list first 文件名 second 运行参数
commands = sys.argv # xx xx2
# ['manage.py', 'xx', 'oo']
# 运行项目的指令: python manage.py runserver
# 数据库同步指令: python manage.py migrate
# 判断执行模块
a1 = commands[1]
if a1 == 'runserver':
run()
elif a1 == 'migrate':
create_model()
wsgi.py
import socket
import time
from threading import Thread
from urls import urlpatterns
def run():
server = socket.socket()
IP_PORT = ('127.0.0.1', 8001)
server.bind(IP_PORT)
server.listen() # 开启监听
while True:
# conn 链接对象
conn, addr = server.accept()
from_client_msg = conn.recv(1024)
from_browser_msg = from_client_msg.decode()
print(from_browser_msg) # 存储的是客户端请求的信息
path = from_browser_msg.split(' ')[1] # 剥离请求的path
# 127.0.0.1:8001 /index
print(path)
conn.send(b'HTTP/1.1 200 ok\r\n\r\n') # 回应st
# 遍历路由寻找返回数据
for item in urlpatterns:
if item[0] == path:
# t = Thread(target=item[1],args=(conn,))
# t.start()
data = item[1](conn)
break
# 达到某种情况再关闭服务器
# server.close()
urls.py
import views
urlpatterns = [
# ('/', views.html),
# ('/xx.css', views.css),
# ('/1.jpg', views.jpg),
# ('/xx.js', views.js),
# ('/person', views.person),
('/index', views.index),
]
views.py
import time
# 逻辑模块
# 数据库
# def html(conn):
# # 连接数据库,拿数据,将数据添加到html文件中,到页面展示
# now = str(time.time())
# with open('templates/beatfulpage.html', 'r', encoding='utf-8') as f:
# data = f.read()
# data = data.replace('%xxoo%', now).encode('utf-8')
#
# conn.send(data)
#
# 需要链接对象 index 路由的处理
def index(conn):
with open('templates/index.html', 'rb') as f:
data = f.read()
# return data
conn.send(data)
conn.close()
models.py
# 建立表模块
import pymysql
def create_model():
conn = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
password='',
database='nbweb',
charset='utf8'
)
cursor = conn.cursor()
sql = 'create table userinfo(id int primary key auto_increment, name char(10) not null, age int unsigned);'
cursor.execute(sql)
conn.commit()
conn.close()
wsgiref简单模块
wsgi.py
import time
from threading import Thread
from wsgiref.simple_server import make_server
from urls import urlpatterns
def run():
# wsgiref本身就是个web框架,提供了一些固定的功能(请求和响应信息的封装,不需要我们自己写原生的socket了也不需要咱们自己来完成请求信息的提取了,提取起来很方便)
# 函数名字随便起
def application(environ, start_response):
'''
:param environ: 是全部加工好的请求信息,加工成了一个字典,通过字典取值的方式就能拿到很多你想要拿到的信息
:param start_response: 帮你封装响应信息的(响应行和响应头),注意下面的参数
:return:
'''
start_response('200 OK', []) # 返回相应
print(environ['PATH_INFO']) # 输入地址127.0.0.1:8000,这个打印的是'/',输入的是127.0.0.1:8000/index,打印结果是'/index'
path = environ['PATH_INFO']
for item in urlpatterns:
if item[0] == path:
data = item[1]() # 返回网页数据 执行处理函数
break
else:
data = b'page no found!'
return [data]
httpd = make_server('127.0.0.1', 8080, application)
httpd.serve_forever()
####
# 逻辑处理上的更改
def index():
with open('templates/index.html', 'rb') as f:
data = f.read()
return data
# conn.send(data)
# conn.close()
Html协议
名称:超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)
例如:在浏览器地址栏键入URL,按下回车之后会经历以下流程:
1. 浏览器向 DNS 服务器请求解析该 URL 中的域名所对应的 IP 地址;
2. 解析出 IP 地址后,根据该 IP 地址和默认端口 80,和服务器建立TCP连接;
3. 浏览器发出读取文件(URL 中域名后面部分对应的文件)的HTTP 请求,该请求报文作为 TCP 三次握手的第三个报文的数据发送给服务器;
4. 服务器对浏览器请求作出响应,并把对应的 html 文本发送给浏览器;
5. 释放 TCP连接;
6. 浏览器将该 html 文本并显示内容;
request报文
请求消息格式:

请求数据说明: GET请求方法的请求数据在请求函个的URL部分,POST请求携带的数据在请求数据部分.
请求头键值对:
GET /1.jpg HTTP/1.1
Host: 127.0.0.1:8001
Connection: keep-alive
sec-ch-ua: "Chromium";v="86", "\"Not\\A;Brand";v="99", "Google Chrome";v="86"
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36
Accept: image/avif,image/webp,image/apng,image/*,*/*;q=0.8
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: no-cors
Sec-Fetch-Dest: image
Referer: http://127.0.0.1:8001/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
USER-AGENT:chorme.... 客户代理程序信息
HOST: 请求的服务端地址
Accept: 客户端可以接受的数据类型
response报文
响应信息格式

请求方式
Get请求
1 浏览器输入网址回车,就是get请求方法
2 a标签,href=='http://www.baidu.com' get请求方法
Post请求
1 form表单标签中用户输入的内容,点击提交按钮,一般都是用post请求
form标签,action='路由' method='post',默认是get
Get 和 Post区别
GET提交的数据会放在URL之后,也就是请求行里面,以?分割URL和传输数据,参数之间以&相连,如EditBook?name=test1&id=123456.(POST方法是把提交的数据放在HTTP包的请求数据部分.
GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制.
POST的数据不再url上面显示,所以看着安全一些.
ST码
2xx成功——请求已成功被服务器接收、理解、并接受
3xx重定向——需要后续操作才能完成这一请求
4xx请求错误——请求含有词法错误或者无法被执行
5xx服务器错误——服务器在处理某个正确请求时发生错误
重定向的大致过程

Netowork抓包
network中看到的内容解释
General部分
Request URL: http://127.0.0.1:8080/ 请求地址
Request Method: GET 请求方法
Status Code: 200 OK 响应状态码和描述
Remote Address: 127.0.0.1:8080 客户端的地址(ip+port)
request headers 请求头部键值对信息
response headers 响应头部键值对信息


jinja2
from jinja2 import Template
with open('beatfulpage.html', 'r', encoding='utf-8') as f:
data = f.read()
template = Template(data)
ret = template.render({"name": "于谦", "hobby_list": ["烫头", "泡吧"]}) # 渲染html
data = ret.encode()
return data
<h1>{{name}}</h1>
<ul>
{% for i in hobby_list %}
<li>{{i}}</li>
{% endfor %}
</ul>
Django安装
项目创建
django-admin startproject luffy(项目名称)
应用创建
python manage.py startapp piao(应用app名称)
在项目的settings.py文件中
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'piao.apps.PiaoConfig', # 两种写法都可以
'piao', # 加上应用名称
]
Django的知识
URL访问
1 url(r'^index/', views.index), 路径的前置导航斜杠(对应根路径那个),不需要写,django自动加上
2 http://127.0.0.1:8000/index 当我们访问django的url路径时,如果请求路径最后没有写/,那么django会发一个重定向的响应,告诉浏览器,加上/再来访问我
http://127.0.0.1:8000/index
重定向 http://127.0.0.1:8000/index/
# settigns.py配置文件中修改:
# APPEND_SLASH = True # 默认为True, 当值为True时,django需要请求路径后面加上斜杠,如果请求没有加,那么响应301重定向,让浏览器街上斜杠重新请求
# 值为False,就关闭了django的这个功能
# APPEND_SLASH = False
url(r'^index/$', views.index),
url(r'^index/xx/xx/', views.index2)
# 注意: 路径写正则时,要注意最好精确匹配,尾部加上$,或者写正则时,尽量不要路径差不多
url(r'^$', views.home), #匹配根路径的写法
url分组
无名分组
url(r'^books/(\d+)/(\d+)/', views.books) # 无名分组,位置参数,注意参数位置固定
视图函数写法:
def books(request, y, m):
print(y, m) # 2019 匹配出来的都是字符串
return HttpResponse('%s-%s所有书籍都在这儿,你随意看' % (y, m))
无名分组
url(r'^books/(?P<year>\d+)/(?P<month>\d+)/', views.books2),
# def books2(request, year): 函数参数必须和有名分组的名称相同
# def books2(request, year): 而且不在乎参数位置
def books2(request, month, year):
print(year, month)
return HttpResponse('%s--%s所有书籍都在这儿,你随意看' %(year,month ))
三个响应方法
render
响应页面 默认响应状态码为200
HttpResponse
响应字符串 默认响应状态码为200
redirect
重定向 默认响应状态码是302
响应头和状态码
def index(request):
re = HttpResponse('xxx')
# re = render('xxx')
# ret = redirect('/home/')
re['name'] = 'gaodaao' # 添加响应头键值对 #HttpResponse setattr
re.status_code = 404 # 修改状态码
return re
CBV和FBV
FBV(function base views) 就是在视图里使用函数处理请求。
CBV(class base views) 就是在视图里使用类处理请求。
urls.py
urlpatterns = [
...
url(r'^book/', views.BookView.as_view()),
]
views.py
from django.views import View
class BookView(View):
def get(self,request):
return HttpResponse('ok')
urls.py
url(r'^articles/(\d+)/', views.ArticalView.as_view())
class ArticalView(View):
# 和FBV模式相同,有名分组是关键字传参,无名分组是位置传参
def get(self,request, year):
print(year)
return HttpResponse('articals')
dispatch方法与装饰器
重写dispatch
def dispatch(self, request, *args, **kwargs):
print('111111')
# super 2.x class , self
ret = super(ArticalView, self).dispatch(request, *args, **kwargs)
print('222222')
return ret
@method_decorator(func)
def dispatch(self, request, *args, **kwargs):
print('111111')
ret = super(ArticalView, self).dispatch(request, *args, **kwargs)
print('222222')
return ret
CBV
def func(f):
def inner(*args,**kwargs):
print('aaaaa')
ret = f(*args,**kwargs)
print('bbbbb')
return ret #带返回值重写
return inner
@method_decorator(func)
def get(self,request, year):
print(year)
return render(request, 'articals.html')
# 方式 3
# @method_decorator(func,name='get')
class ArticalView(View):
def get(self,request, year):
print(year)
return render(request, 'articals.html')
模板渲染
# html中
'''{{变量}}'''
def index(request):
name = '赵万里'
age = 18
hobby = ['打游戏', '快乐风男', '嫖']
d1 = {'a':'b', 'c': 'd'}
class A:
def __init__(self):
self.username = '万里'
def my_hobby(self):
return '张宇'
a = A()
dd = {
'name': name,
"age": age,
"hobby": hobby,
"d1": d1,
"a": a,
}
dd = locals()
# 'asdfasdfasdf{{hobby.0}}' -- hobby[0]
# 模板渲染完成之后, 才返回给浏览器, 浏览器再进行页面渲染, 生成效果
return render(request, 'index.html', dd)
过滤器
在原有数据的基础上进行一些额外的加工处理来使用
length
<h3>{{ ss|length }}</h3>
# return 长度
Default
如果一个变量是false或者为空,使用给定的默认值。 否则,使用变量的值。
<h3>{{ ss|defalut:"moren"}}</h3>
filesizeformat
将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)。
<h3>{{ file_size|filesizeformat }}</h3>
Slice
切片
ss = 'wanli ai zhangyu'
<h3>{{ ss|slice:'0:5' }}</h3>
return wanli
Date
格式化,如果 value=datetime.datetime.now()
{{ value|date:"Y-m-d H:i:s"}}
Safe
为了防止xss攻击 后端以字符串存储 safe使用读取标签来展示
a_tag = '<a href="http://www.baidu.com">百度<a/>'
<h2>{{ a_tag|safe }}</h2>
truncatechars
截断字符
<h2>{{ aa|truncatechars:'8' }}</h2> <!-- 截断字符,注意8包含了三个点 -->
truncatewords
截断单词
<h2>{{ aa|truncatewords:'2' }}</h2> <!-- 以空格做个截断符号,截断单词,2不包含那三个点
cut
移除value中所有的与给出的变量相同的字符串
<h2>{{ aa|cut:' ' }}</h2>
join
字符串拼接
hobby = ['打游戏', '快乐风男', '嫖', 'look']
<h2>{{ hobby|join:'+' }}</h2>
模板渲染
标签 {% 标签 %}
for循环标签
<ul>
<!-- 可迭代对象都可以用循环 -->
<!-- 循环列表 -->
{% for foo in hobby %}
<li>{{ foo }}</li>
{% empty %}
ß<!-- 当循环的数据为空或者没有这个变量时显示empty下面的内容 -->
<h1>啥也没有</h1>
{% endfor %}
</ul>
<ul>
<!-- 循环字典 -->
{% for foo in d1 %} <!-- 只能获取键 -->
<li>{{ foo }}</li>
{% endfor %}
{% for key,value in d1.items %}
<!-- 获取键值对,items.keys,values都能用 -->
<li>{{ key }} -- {{ value }}</li>
{% endfor %}
</ul>
forloop
<ul>
{% for foo in hobby %}
forloop 循环标签对象,通过counter属性可以来记录循环次数
<li>{{ forloop.counter }}---{{ foo }}</li> 从1开始计数
<li>{{ forloop.counter0 }}---{{ foo }}</li> 从0开始计数
<li>{{ forloop.revcounter }}---{{ foo }}</li> 倒序,从1开始计数
<li>{{ forloop.revcounter0 }}---{{ foo }}</li> 倒序,从0开始计数
<li>{{ forloop.first }}---{{ foo }}</li> 如果是第一次循环,就得到True
<li>{{ forloop.last }}---{{ foo }} </li> 如果是最后一次循环,就得到True,其他为False
{% endfor %}
</ul>
{% for key,value in hobby2.items %}
forloop.parentloop 统计外层循环对象的循环次数
{% for v in value %}
<li>{{ forloop.parentloop.counter }} -- {{ forloop.counter }} -- {{ v }}</li>
{% endfor %}
{% endfor %}
reversed 倒序循环
<ul>
{% for foo in hobby reversed %}
<li>{{ foo }} </li>
{% endfor %}
</ul>
if标签
if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断,注意条件两边都有空格。
{% if age > 18 %}
<h1>太老了</h1>
{% elif age == 18 %}
<h1>还行</h1>
{% else %}
<h1>挺嫩</h1>
{% endif %}
{% if age > 18 or number > 100 %} <!-- 符号两边必须有空格 -->
<h1>太老了</h1>
{% elif age == 18 %}
<h1>还行</h1>
{% else %}
<h1>挺嫩</h1>
{% endif %}
{% if hobby|length > 3 %} <!-- 可以配合过滤器来使用 -->
<h1>爱好还挺多</h1>
{% else %}
<h1>爱好不够多</h1>
{% endif %}
[!IMPORTANT]
Django的模板语言中属性的优先级大于方法
with标签
写法1
{% with hobby2.xx.0 as kk %}
<h1>{{ kk }}</h1>
{% endwith %}
写法2
{% with kk=hobby2.xx.0 %}
<h1>{{ kk }}</h1>
{% endwith %}
csrf_token标签
<form action="" method="post">
{% csrf_token %}
<!-- 加上这个标签之后,post请求就能通过django的csrf认证机制,就不需要注释settings的配置了 -->
<input type="text" name="uname">
<input type="submit">
</form>
模板继承
先创建模板
# base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.c1{
background-color: pink;
height: 40px;
}
.left-menu{
background-color: tan;
width: 200px;
min-height: 600px;
}
.item{
background-color: yellow;
height: 40px;
border-bottom: 1px solid red;
}
.left{
float: left;
}
.right{
float: left;
}
</style>
{% block css %}
{% endblock %}
</head>
<body>
<div class="nav">
<div class="c1">
<a href="">32官网</a>
<span>性感荷官, 在线发牌</span>
</div>
</div>
<div class="main">
<div class="left">
<div class="left-menu">
<div class="menu1 item">
<a href="/t1/">菜单1</a> <!-- 写相对路径时,前面的斜杠必须写 -->
</div>
<div class="menu2 item">
<a href="/t2/">菜单2</a>
</div>
<div class="menu3 item">
<a href="/t3/">菜单3</a>
</div>
</div>
</div>
<div class="right">
<div class="content">
{% block content %}
<h1>基础模板</h1>
{% endblock %}
</div>
</div>
</div>
</body>
{% block js %}
{% endblock %}
</html>
钩子
{% block content %}
<h1>基础模板</h1>
{% endblock %}
# 可以指定endblock的名称,起到一个提示作用
{% block content %}
...
{% endblock content %}
子页面
[!IMPORTANT]
{{ block.super }}显示模板的内容
{% extends 'base.html' %}
{% block css %}
<style>
.c1{
background-color: green;
height: 40px;
}
</style>
{% endblock %}
{% block content %}
<h1>性感美女,在线指导</h1>
{{ block.super }} <!-- 显示模板的内容 -->
{% endblock %}
组件
一个完整功能的模块,其他页面如果想使用,就直接以组件的形式引入
比如创建一个zujian.htmlm,内容如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.c1{
background-color: pink;
height: 40px;
}
</style>
</head>
<body>
<div class="nav">
<div class="c1">
<a href="">32官网</a>
<span>性感荷官, 在线发牌</span>
</div>
</div>
</body>
</html>
引入组件
在页面什么位置引入,组件效果就生成到什么位置
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>这是home页面</h1>
{% include 'zujian.html' %}
</body>
</html>
静态文件
1 在settings.py文件中加上如下配置
STATIC_URL = '/static/' #别名,映射到STATICFILES_DIRS配置的静态文件存放路径,
#那么引入静态文件时,我们使用别名路径来写,如果使用别名路径, 那么修改静态文件夹名称之后,也不会影响静态文件的返回
# STATIC_URL = '/abc/' 别名可以修改的
# 静态文件夹配置的位置
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'statics'),
]
2 在项目根目录下创建一个文件夹,名称随意,比如叫做statics
3 在html文件中引入
两种方式
方式1
直接写别名路径开头
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/static/css/xx.css"> 方式1
</head>
<body>
<div class="c1">xxx</div>
</body>
</html>
方式2
先load一下static
% static 'css/xx.css' %
{% load static %} 先load一下static
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="{% static 'css/xx.css' %}" > 方式2
</head>
<body>
<div class="c1">xxx</div>
</body>
</html>
自定义过滤器
1 在应用文件夹中创建一个叫做templatetags的文件夹(注意,名称必须是它)
2 在templatetags文件夹中创建一个py文件,名称随意,比如叫做mytag.py
3 在mytag.py文件中写如下内容
from django import template
register = template.Library() #注册器,变量名称必须叫register
@register.filter #过滤器
def xx(v1): #第一参数是使用过滤器时,管道符前面的数据 <h1>{{ name|xx }}</h1>
return v1 + 'xx'
@register.filter #过滤器,至多有两个参数
def xx2(v1, v2): #第一参数是使用过滤器时,管道符前面的数据 ,第二个参数是冒号后面的值,<h1>{{ name|xx:'oo' }}</h1>
return v1 + 'xx2' + v2
4 在html文件中使用
{% load mytag %} 先load一下我们的mytagpy文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>{{ name|xx }}</h1> #以过滤器的形式使用,这个是一个参数的
<h1>{{ name|xx2:'oo' }}</h1> # 以过滤器的形式使用,这个是两个参数的
</body>
</html>
自定义标签
1 在应用文件夹中创建一个叫做templatetags的文件夹(注意,名称必须是它)
2 在templatetags文件夹中创建一个py文件,名称随意,比如叫做mytag.py
3 在mytag.py文件中写如下内容
from django import template
register = template.Library() #注册器,变量名称必须叫register
@register.simple_tag
def tag1(v1, v2 ,v3): #参数个数没有限制
return v1 + v2 + v3
4 在html文件中使用
{% load mytag %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>{% tag1 11 22 number %}</h1> <!-- 先写标签名称,然后写参数,参数以空格分隔 ,最终得到的tag1的return值 -->
</body>
</html>
自定义标签inclusion_tag实现动态组件
1 在应用文件夹中创建一个叫做templatetags的文件夹(注意,名称必须是它)
2 在templatetags文件夹中创建一个py文件,名称随意,比如叫做mytag.py
3 在mytag.py文件中写如下内容
from django import template
register = template.Library() #注册器,变量名称必须叫register
# 通过inclusion_tag来做为装饰器,并且需要传入一个参数,这个参数就是一个html文件(你想做成动态组件的html文件)
# 渲染的页面
@register.inclusion_tag('zujian2.html')
def dongtai(v1): #参数没有个数限制
data = v1 #[11,22,33]
return {'xx': data }
# zujian2.html会收到定义的inclusion_tag函数的返回值,然后进行zujian2.html这个动态组件的模板渲染
zujian2.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.left-menu {
background-color: tan;
width: 200px;
min-height: 600px;
}
.item {
background-color: yellow;
height: 40px;
border-bottom: 1px solid red;
}
.left {
float: left;
}
</style>
</head>
<body>
<!--data键就是从inclusion_tag中传递过来的参数,可以在模板中直接调用-->
<div class="left">
<div class="left-menu">
{% for item in xx %} <!-- [11,22,33] ,注意 data这是inclusion_tag函数的返回值那个字典中的键 -->
<div class="menu1 item">
<a href="/t1/">{{ item }}</a> <!-- 写相对路径时,前面的斜杠必须写 -->
</div>
{% endfor %}
</div>
</div>
</body>
</html>
4 使用inclusion_tag
basic.html
{% load mytag %} 先load
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<!-- menu_list参数后台试图传递 -->
{% dongtai menu_list %} #最终将渲染好的动态组件(zujian2.html),通过include引入组件的方式,加载到这里
</body>
</html>
5 在后台视图中渲染basic.html页面是可以传入动态数据
def basic(request):
menu_list = [22,33]
return render(request, 'basic.html',{'menu_list': menu_list})

浙公网安备 33010602011771号