jQuery与django框架的视图层、模板层
jQuery
筛选器
1.下一个元素
$("#id").next() // 筛选出元素的下一个兄弟元素
$("#id").nextAll() // 筛选元素后面所有的兄弟
$("#id").nextUntil("#i2") // 筛选出元素后面所有兄弟元素直到选择器元素位置
2.上一个元素
$("#id").prev() // 筛选元素的上一个兄弟元素
$("#id").prevAll() // 筛选元素前面所有的兄弟
$("#id").prevUntil("#i2") // 筛选出元素前面所有兄弟元素直到选择器元素位置
3.父亲元素
$("#id").parent() // 筛选出元素的父元素
$("#id").parents() // 查找当前元素的所有父辈元素
$("#id")parentsUntil() // 查找当前元素的所有父辈元素,直到选择器元素为止
4.链式操作的底层原理
对象调用方法之后返回一个对象,从而实现链式操作的效果
操作标签
jQuery操作 js操作 jQuery操作功能
.css('样式名','样式值') style.样式名 = '样式值'
1.样式操作
addClass() classList.add() 添加指定的css类名
removeClass() classList.remove() 移除指定的css类名
hasClass() classList.contains() 判断样式存不存在
toggleClass() classList.toggle() 有css类名就移除,没有就添加
2.文本操作
text() innerText() 取得所有匹配元素的内容
html() innerHTML() 取得第一个匹配元素的html内容
val() value 取得第一个匹配元素的当前值
[0].files files 获取所有文件
3.属性操作
attr() 静态属性 setAttribute() 返回第一个匹配元素的属性值
prop() 动态属性(checked) 获取属性
4.文档处理
append() append() 添加到指定元素内部的后面
prepend() 添加到指定元素内部的前面
after() 添加到指定元素外部的后面
before() 添加到指定元素外部的前面
remove() 从DOM中删除所有匹配的元素
empty() 删除匹配的元素集合中所有的子节点
jQuery绑定事件方法
js绑定事件与jQuery绑定事件
1.js绑定事件
标签对象.on事件名 = function(){事件代码}
2.jQuery绑定事件
2.1方法1:
jQuery对象.事件名(function(){事件代码})
$btnEle.click(function(){alter(123)})
2.2方法2:
jQuery对象.on('事件名',function(){事件代码})
$btnEle.on('click',function(){alter(123)})
'使用jQuery方法1绑定事件无法触发时可以切换为方法2'
事件案例
1.常用事件
click(function(){...}) // 单击事件
hover(function(){...}) // 悬浮事件
blur(function(){...}) // 鼠标移除input框
focus(function(){...}) // 鼠标进入input框
change(function(){...}) // 文本域变化事件
keyup(function(){...}) // 松开键盘事件
2.clone()克隆事件示例
<body>
<button id="d1" class="c1">多重影分身之术</button>
<script>
let $btnEle = $('#d1');
$btnEle.click(function (){
$('body').append($(this).clone())
})
</script>
</body>
3.hover事件示例
<body>
<p>第一个</p>
<p>第二个</p>
<p>第三个</p>
<script>
// 影响所有p标签
$('p').hover(
function (){
alert('我进来了')
},
function (){
alert('我出来了')
}
)
</script>
</body>
4.实时监听input输入值变化示例
<body>
<input type="text" id="d1">
<script>
$('#d1').on('input', function (){
console.log(this.value)
})
</script>
</body>
事件相关补充知识
1.能够触发form表单提交数据动作的标签有两个
1.1<input type="submit" value="提交">
1.2<button>提交</button>
'给已经有事件的标签绑定事件,会先执行绑定的事件,再去执行默认的执行'
2.也可以让标签之前的事件不执行
2.1return false
2.2$(':submit').click(function (e){
alert('来了')
e.preventDefault()
})
3.事件冒泡
'涉及到标签嵌套并且有相同事件的时候,当你触发儿子标签的事件时,它会逐级向上汇报'
<body>
<div>div
<p>div>p
<span>div>p>span</span>
</p>
</div>
<script>
$('div').click(function (){
alert('div')
})
$('p').click(function (){
alert('p')
})
$('span').click(function (){
alert('span')
})
</script>
</body>
4.阻止事件冒泡
4.1return false
4.2$('p').click(function (e){
alert('p')
e.stopPropagation()
})
'''
创建标签的两种方法
1.js
document.createElement()
2.jQuery
$('<标签名>')
'''
5.事件委托
事情绑定默认情况下是不会对动态创建的标签生效的,如果想生效需要事情委托
$('div').on('click','button',function () {
alert('阿姨压一压')
})
jQuery动画效果
1.基本
show([s,[e],[fn]]) // 显示隐藏的匹配元素
hide([s,[e],[fn]]) //
toggle([s],[e],[fn]) //
Bootstrap
下载地址
https://v3.bootcss.com/getting-started/
web框架
手写web框架
1.web框架可以看成是一个功能强大的socker服务端
先根据socket套接字编写一个简易的服务端
import socket
server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)
while True:
sock, address = server.accept()
data = sock.recv(1024)
sock.send(b'HTTP/1.1 200 OK\r\n\r\n')
print(data.decode('utf8'))
2.根据不同请求对应响应
2.1socket代码
import socket
server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)
while True:
sock, address = server.accept()
data = sock.recv(1024)
sock.send(b'HTTP/1.1 200 OK\r\n\r\n')
target_url = data.decode('utf8').split(' ')[1]
if target_url == '/index':
sock.send(b'index view')
elif target_url == '/login':
sock.send(b'login view')
elif target_url == '/reg':
sock.send(b'reg view')
else:
sock.send(b'404 error')
3.代码缺陷
3.1socket代码重复编写、反复造轮子
3.2请求数据格式的处理复杂且重复
3.3不同网址后缀的匹配方式太简陋
基于wsgiref模块写框架
1.wsgiref内部封装了socket代码和对应请求数据的处理
from wsgiref.simple_server import make_server
def run(request, response):
"""
:param request: 请求数据
:param response: 响应数据
:return: 返回给客户端的数据
"""
print(request) # 自动将请求数据全部处理成字典k:v键值对形式
response('200 OK', []) # 固定代码
return [b'hello good bye']
if __name__ == '__main__':
server = make_server('127.0.0.1', 8080, run) # 任何访问127.0.0.1:8080的请求都会给第三个参数加括号调用
server.serve_forever() # 永久启动
'''
wsgiref模块解决了两个问题
1.socket代码重复编写、反复造轮子
2.请求数据格式的处理复杂且重复
'''
2.根据不同的网址后缀返回不同的内容(函数化)
'从大字典中查找出不同的网址后缀的键值对,不推荐使用多个if判断,对面条版代码可以封装成函数'
from wsgiref.simple_server import make_server
def index():
return 'index'
def login():
return 'login'
def register():
return 'register'
def error():
return '404 error'
urls = (('/index', index),
('/login', login),
('/register', register))
def run(request, response):
"""
:param request: 请求数据
:param response: 响应数据
:return: 返回给客户端的数据
"""
response('200 OK', []) # 固定代码
target_path = request.get('PATH_INFO')
func_name = None
for url_tuple in urls:
if url_tuple[0] == target_path:
func_name = url_tuple[1] # 存储匹配到的函数名
break # 匹配的函数名后立刻结束for循环
if func_name: # 判断func_name有没有匹配到函数名
res = func_name()
else:
res = error()
return [res.encode('utf8')]
if __name__ == '__main__':
server = make_server('127.0.0.1', 8080, run) # 任何访问127.0.0.1:8080的请求都会给第三个参数加括号调用
server.serve_forever() # 永久启动
动静态网页
1.动态网页
页面上的数据不是全部写死的,有些是动态获取的(后端传入)
2.静态网页
页面上数据直接写死的,想要改变只能修改源码
3.实际需求
后端回去当前时间,让前端页面展示
3.1字符串替换
def get_time():
import time
ctime = time.strftime('%Y-%m-%d %H:%M:%S')
with open(r'templates/myhtml01.html', 'r', encoding='utf8')as f:
data = f.read()
data = data.replace('time', ctime) # 将html文件内数据替换成时间,在返回给浏览器
return data
3.2将字典数据传递给html页面并且想要在页面上操作字典数据
'在html页面上使用类似于后端的语法来操作数据类型>>>jinja2'
jinja2模板
1.jinja2能够让我们在html文件内使用类似于后端的语法来操作各种数据类型
def get_dict():
from jinja2 import Template
user_dict = {'name': 'barry', 'pwd': 123, 'age': 18}
with open(r'templates/myhtml01.html', 'r', encoding='utf8')as f:
data = f.read()
temp = Template(data)
res = temp.render(data=user_dict)
return res
'''
{'name': 'barry', 'pwd': 123, 'age': 18}
barry
123
18
'''
2.html文件语法
<body>
<h2>{{ data }}</h2>
<h2>{{ data['name'] }}</h2>
<h2>{{ data.get('pwd') }}</h2>
<h2>{{ data.age }}</h2>
</body>
前端、后端、数据库联动模板语法
1.views.py代码
def get_mysql():
import pymysql
conn = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
password='321',
database='py02',
autocommit=True
)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
sql = 'select * from userinfo'
cursor.execute(sql)
user_data = cursor.fetchall()
with open(r'templates/myhtml01.html', 'r', encoding='utf8') as f:
data = f.read()
temp = Template(data)
res = temp.render(user_data=user_data)
return res
2.html文件语法
<body>
<div class="container">
<div class="row">
<h1 class="text-center">数据展示</h1>
<div class="col-md-6 col-md-offset-3">
<table class="table table-hover table-striped">
<thead>
<tr>
<th>id</th>
<th>姓名</th>
<th>年龄</th>
</tr>
</thead>
<tbody>
{% for user in user_data %}
<tr>
<td>{{user.id}}</td>
<td>{{user.name}}</td>
<td>{{user.age}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</body>
django
python主流web框架
1.django
自带的功能非常多,但是有事会略显笨重
缺陷:开发小项目时使用该框架有些笨重(大材小用)
2.flask
自身携带的功能非常少,但是第三方模块非常多
缺陷:受限于第三方模块的开发
3.tornado框架
异步非阻塞,该框架快到可以作为游戏服务器
缺点:上手难度是三者最高
4.fastapi框架、sanic框架、...
使用占比较小,但最近也慢慢开始类型
'框架内部的逻辑几乎一致,所以学会其中一种,其他的就比较简单了'
diango框架简介
1.版本
1.X:支持同步
2.X:支持同步
3.X:支持异步
2.启动注意事项
2.1计算机的名称不能是中文
2.2项目中所有的py文件名尽量不要用中文
2.3不同版本的python解释器配合不同版本的django,会有些报错
'仔细查找报错信息,里面会提示你是哪个py文件的代码出错,找到那行,把逗号删除即可'
widgets.py>>>152行
3.验证django是否下载成功
cmd终端输入:django-admin
diango基本操作命令
1.创建django项目
django-admin startproject 项目名
2.启动django项目
2.1先切换到项目目录下
cd 项目名
2.2执行启动目录
python38 manage.py runserver (ip:port)
3.访问django服务端
浏览器直接访问(http://127.0.0.1:8000/)
4.创建app应用
'''
django框架类似于一个空壳子,给你提供所需的资源
至于到底要写哪些功能,需要通过创建app来划分
django框架可以看成是一所大学,app相当于是大学里面的各个学院
'''
python38 manage.py startapp 应用名
5.pycharm操作
File>>>New Prozect...>>>Django
6.要将app注册
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01.apps.App01Config', # 完整写法
'app01' # 简写
]
'在启动django项目的时候,一定要确保一个端口只有一个项目'
命令行与pycharm操作的区别
1.命令行不会自动创建templates文件夹
2.命令行不会在配置文件编写关于settings.py文件夹的TEMPLATES配置
'DIRS': [os.path.join(BASE_DIR, 'templates')]
3.pycharm自动创建的第一个应用会自动注册到配置文件中
4.针对db.sqlite3文件不用在乎它有没有创建,只要运行了django就会自动出来
5.将settings.py文件夹的MIDDLEWARE配置的第四行注释
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
django目录结构
1.项目同名文件夹
__init__.py>>>很少用,主要做一些冷门配置
settings.py>>>项目配置文件
urls.py>>>对应关系(目前可以理解为:网址后缀与函数名的关系)
wsgi.py>>>django服务,一般不用
mangae.py>>>django入口文件(类似于启动文件)
templates文件夹>>>存储项目所需的html文件
2.应用名文件夹
migrations文件夹>>>orm相关(与数据库打交道的记录)
__init__.py>>>很少用,主要做一些冷门配置
admin.py>>>django自带的后台管理
apps.py>>>创建应用之后用于用于的注册
models.py>>>存储与数据库表相关的类
tests.py>>>自带的测试文件
views.py>>>存储业务相关的逻辑代码(函数、类)
db.splite3>>>自带的小型数据库
3.主要文件
urls.py>>>路由层>>>对应关系
views.py>>>视图层>>>编写核心业务逻辑代码
templates.py>>>模板层>>>存储html文件的
models.py>>>模型层>>>与数据库相关
diango小白必会三板斧
1.HttpResponse
主要用于直接返回字符串类型的数据
2.render
主要用于返回html页面,并支持模板语法
3.redirect
主要用于页面重定向(自动跳转地址)
4.views.py
from django.shortcuts import render, HttpResponse, redirect
# Create your views here.
def index(request):
return HttpResponse('你好啊 django2.2.22版本')
def func(request):
user_dict = {'name': 'barry', 'pwd': 123}
return render(request, 'func.html', {'data': user_dict})
def login(request):
return redirect('https://www.baidu.com/')
静态文件配置
1.编写一个登录功能
1.1创建django项目并创建一个app
1.2在urls.py添加一组对应关系
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', views.login),
]
1.3在app的views.py中编写登录核心逻辑
def login(request):
return render(request, 'login.html')
1.4利用三板斧与前端做交互
'提前在urls.py中开设了相应的资源连接,才可以在访问django框架资源的时候拿到数据,如果访问不到资源,那就是没有开设相应的接口'
2.静态文件
html页面上使用的不经常改变的资源
2.1不同文件资源
第三方框架文件、css文件、js文件、图片文件
'静态文件资源一般都会放在static文件夹内'
2.2当static目录下出现了很多不同类型的静态文件资源,还可以分类管理
others文件夹(第三方框架文件)
css文件夹(所有css文件)
js文件夹(所有js文件)
img文件夹(所有img文件)
3.对静态文件资源的访问也需要提前开设相应的接口
在文件同名文件夹下settings.py
STATIC_URL = '/static/' # 接口前缀(访问静态资源必须要以static开头)
# 静态文件资源配置
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')
]
4.动态解析
{% load static %}
<link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
请求方法
'URL:统一资源定位符(网址)'
1.GET请求
1.1朝别人索要数据,也可以携带数据
z在网址栏上显示:url?xxx=yyy&aaa=bbb&ccc=ddd
1.2上述携带数据的方式有两个限制
数据只能是一些无关紧要的非敏感数据
数据大小有限制2KB~4KB左右
'GET请求没有请求体(HTTP数据格式)'
2.POST请求
朝别人提交数据,也可以携带额外数据
数据都在请求中,并且数据大小没有限制
3.form表单默认的数据提交方式是get
3.1在html文件修改:<form action="" method="post">
method='post'
action>>>控制数据的提交地址
3.2action地址编写方式
方式1:不写,朝当前页面所在的地址提交
方式2:写后缀(/index/),自动补全ip和post
方式3:写全称(https://www.baidu.com/)
4.提交post请求前需要去配置文件中注释一行代码
在文件同名文件夹下settings.py文件里注释下列第四行
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
request对象方法
request.method>>>获取请求方式,结果是纯大写的字符串
print(request.method)
# POST
request.POST>>>获取POST请求发送来的普通数据(不包括文件)
print(request.POST)
# <QueryDict: {'username': ['kevin', 'barry'], 'password': ['123']}>
request.POST.get()>>>默认只获取列表中最后一个数据值
print(request.POST.get('username'))
# barry
request.POST.getlist()>>>获取键对应的整个列表,无论有几个数据值
print(request.POST.getlist('username'))
# ['kevin', 'barry']
request.GET>>>获取url后面后面携带的非敏感数据
print(request.GET)
# <QueryDict: {'aaa': ['111'], 'bbb': ['333']}>
request.GET.get()>>>默认只获取列表中最后的一个数据值
print(request.GET.get('aaa'))
# 333
request.GET.getlist()>>>获取键对应的整个列表,无论有几个数据值
print(request.GET.getlist('aaa'))
# ['111', '333']
pycharm连接MySQL
1.在pycharm提供的database按钮
左下角或侧边栏,若是没有则下载插件或下载重装
2.首次连接数据库需要下载对应的驱动(点一下Download)
3.驱动下载好后,在user:的输入框内输入用户名,在password输入框内输入密码,在Database:输入框内输入数据库名,在点击Test Connection,测试能否连接到数据库,在点击Apply、点OK即可
4.可以进行简单的增删改查
django连接MySQL
django默认的sqliste3,但是这款数据库一般只能用于本地测试,功能较少
1.在配置文件中修改配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 指定数据库软件名称
'NAME': 'db1', # 指定库名
'USER': 'root',
'PASSWORD': '321',
'HOST': '127.0.0.1',
'PORT': 3306,
'CHARSET': 'utf8'
}
}
2.指定连接MySQL的模块
django1.11版本需要在项目或者应用目录下的__init__.py中编写一行代码
import pymysql
pymysql.install_as_MySQLdb()
django2.2以上版本需要下载mysqlclient模块
django orm
1.ORM:对象关系映射
类>>>映射成>>>表
对象>>>映射成>>>记录
对象.属性>>>映射成>>>字段对应的值
'ORM让不会MySQL的python程序员使用python操作MySQL'
2.先去应用目录下的models.py编写模型类
# 类似于定义表名
class User(models.Model):
# 类似于定义主键(id int primary key auto_increment)
id = models.AutoField(primary_key=True)
# 类似于定义普通字段(name varchar(32))
name = models.CharField(max_length=32)
# 类似于定义普通字段(pwd int)
pwd = models.IntegerField()
3.数据库迁移/同步命令
2.1将models中有关数据库的操作记录下来(migrations文件夹)
python38 manage.py makemigrations、
2.2将操作真正影响到数据库中
python38 manage.py migrate
'当修改了models中与数据库相关的代码,都必须执行上述的命令'
ps:可以简写,在pycharm上方Tools中Run manage.py Task后可以只写makemigrations、migrate
4.表的主键在orm中可以不写,orm会自动帮你添加一个id的主键,如果需要的主键名称不是id,就需要自己创建
orm语法
1.查
models.User.objects.filter() 结果可以看成是一个列表套数据对象
'可以使用first()方法获取对象,如果没有值会返回None'
2.增
models.User.objects.create()
3.该
models.User.objects.filter(id=1).update(name='barry233')
4.删
models.User.objects.filter(id=4).delete()
5.实例
from app01 import models
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
user_obj = models.User.objects.filter(name=username, pwd=password).first()
if user_obj:
print(user_obj.id) # 1
print(user_obj.name) # barry
print(user_obj.pwd) # 123
return HttpResponse('登录成功')
return HttpResponse('用户名或密码错误')
return render(request, 'login.html')
orm外键关联
1.一对多
外键字段建在多的一方
2.多对多
外键字段可以直接写在其中一张表中,orm会自动帮你创建第三张表
3.一对一
外键字段建在查询频率较高的表中
class Book(models.Model): # 书
title = models.CharField(max_length=32)
# 书于出版社是一对多,书是多
publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
# 书于作者是多对多
authors = models.ManyToManyField(to='Authors')
class Publish(models.Model): # 出版社
pub_name = models.CharField(max_length=32)
class Authors(models.Model): # 作者
name = models.CharField(max_length=32)
# 作者与作者资料是一对一
detail = models.OneToOneField(to='Detail', on_delete=models.CASCADE)
class Detail(models.Model): # 资料
name = models.CharField(max_length=32)
django请求生命周期图
路由匹配
1.路由
path('网址后缀', 函数名)
一旦网址的后缀匹配上时,就会自动执行后面的函数并结束整个路由的匹配
2.路由结尾的斜杠
2.1如果输入网址的时候后缀不写斜杠,django会自动添加斜杠
'自动加上斜杠,再匹配一次'
2.2django配置文件中可以指定是否自动添加斜杠
APPEND_SLASH = False
3.path转换器
3.1当网址后缀不固定的时候,可以使用转换器来匹配
'int': IntConverter(),
'path': PathConverter(),
'slug': SlugConverter(),
'str': StrConverter(),
'uuid': UuidConverter(),
4.re_path正则匹配
re_path(正则表达式,函数名)
一旦网址后缀的正则能匹配内容就会自动执行后面的函数并结束整个路由的匹配
re_path('^test/', views.test)
5.正则匹配之无名分组
re_path('^test/(\d+)/', views.test)
正则表达式匹配到的内容会当做视图函数的位置参数传递给视图函数
6.正则匹配之有名分组
re_path('^rest/(?P<year>\d+)/(?P<others>.*?)/', views.test)
正则表达式匹配到的内容会当做视图函数的关键字参数传递给视图函数
7.django版本区别
在django1.11中,只支持正则匹配,并且方式是url()
在django2,3,4中,path()、re_path等价于url()
反向解析
1.在页面上直接写死很多路由,一旦路由发生变化会导致所有页面的相关链接失效,为了防止出现该问题,我们需要使用反向解析
'返回一个结果,该结果可以访问到对应的路径'
2.路由对应关系起别名
path('delete/', views.reg, name='reg_view')
3.使用反向解析语法
3.1html页面
{% url 'reg_view' %}
3.2后端
from django.shortcuts import reverse
reverse('reg_view')
'反向解析的操作其他三个方法都一样path()、re_path()、url()'
无名有名反向解析
路由
path('reg/<str:imfo>/', views.reg, name='reg_view')
当路由中有不确定的匹配因素是,反向解析时需要人为的给出一个具体的值
后端
reverse('reg_view', args=('barry',))
html页面
{% url 'reg_view' 'barry' %}
'反向解析的操作其他三个方法都一样path()、re_path()、url()'
路由分支
1.django中的每个应用都可以有独自的urls.py文件夹、static文件夹
这样基于django开发多个应用可以完全独立,便于小组开发
2.总路由
path('app01/', include('app01.urls')),
path('app02/', include('app02.urls')),
3.子路由
path('after/', views.after) # 这个是app01
path('after/', views.after) # 这个是app02
名称空间
'有路由分发场景下多个应用在涉及到反向解析别名冲突的时候无法正常解析'
方法1:
patah('app01/', include(('app01.urls', 'app01'), namespace='app01'))
patah('app02/', include(('app02.urls', 'app02'), namespace='app02'))
方法2:
别名不冲突即可eg:app01_reg_view、app02_reg_view
网页伪静态
伪静态页面其实是动态页面,只是看起来和静态页面一样,将动态网页伪装成静态网页,可以提升网页被搜索引擎收录的概率,表现上网址看的像一个具体的文件路径
def test(request):
from django.shortcuts import HttpResponse
return HttpResponse('伪静态')
urlpatterns = [
path('test.html', test),
]
网址:
http://127.0.0.1:8000/test.html
视图层
视图层的返回值
视图层函数必须返回一个HttpResponse对象
1.return HttpResponse()
'HttpResponse是一个类,类加括号就是产生这个类的对象'
class HttpResponse(HttpResponseBase):
pass
2.return render()
def render(request, template_name, context=None, content_type=None, status=None, using=None):
content = loader.render_to_string(template_name, context, request, using=using)
return HttpResponse(content, content_type, status)
'render加括号会返回HttpResponse加括号'
3.return redirect()
def redirect(to, *args, permanent=False, **kwargs):
redirect_class = HttpResponsePermanentRedirect if permanent else HttpResponseRedirect
return redirect_class(resolve_url(to, *args, **kwargs))
'redirect加括号内有一个三元函数,它的两个结果都会继承一个HttpResponseRedirectBase的父类'
class HttpResponseRedirectBase(HttpResponse):
allowed_schemes = ['http', 'https', 'ftp']
'而HttpResponseRedirectBase又会继承一个HttpResponse的父类'
视图函数返回json格式数据
1.json的方法
def test(request):
dict = {'name': 'barry', 'age': 18, 'true_name': '巴里'}
json_str = json.dumps(dict, ensure_ascii=False) # 不把中文编码
return HttpResponse(json_str)
2.django的方法
from django.http import JsonResponse
def test(request):
dict = {'name': 'barry', 'age': 18, 'true_name': '巴里'}
return JsonResponse(dict, json_dumps_params={'ensure_ascii': False})
"给JsonResponse底层的json_dumps_params传了{'ensure_ascii': False}字典,**在实参中会将字典打散成关键字参数>>>ensure_ascii=False"
class JsonResponse(HttpResponse):
def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
json_dumps_params=None, **kwargs):
if safe and not isinstance(data, dict):
raise TypeError(
'In order to allow non-dict objects to be serialized set the '
'safe parameter to False.'
)
if json_dumps_params is None:
json_dumps_params = {}
kwargs.setdefault('content_type', 'application/json')
data = json.dumps(data, cls=encoder, **json_dumps_params)
super().__init__(content=data, **kwargs)
form表单携带文件数据
form表单携带文件数据,需要具备几个条件
1.html文件的method属性值必须是post,enctype属性值必须是multipart/form-data
<form action="" method="post" enctype="multipart/form-data">
2.后端获取文件数据的操作
def func(request):
if request.method == 'POST':
print(request.POST)
# <QueryDict: {'username': ['barry']}>
print(request.FILES)
# <MultiValueDict: {'file': [<InMemoryUploadedFile: image-20220808163623745.png (image/png)>]}>
return render(request, 'func.html')
FBV与CBV
1.FBV:基于函数的视图
后端:def index(request):
return HttpResponse()
路由:path('index/', views.index)
2.CBV:基于类的视图
路由:path('func/', views.MyView.as_view())
后端:from django import views
class MyView(views.View):
def get(self, request):
return HttpResponse('get')
def post(self, request):
return HttpResponse('post')
'CBV会自动根据请求方式的不同匹配类中定义的方法并自动执行'
3.CBV源码分析
3.1path('func/', views.MyView.as_view())
@classonlymethod
def as_view(cls, **initkwargs):
def view(request, *args, **kwargs):
# cls是我们直接定义的类,self = MyView()
return self.dispatch(request, *args, **kwargs)
return view
'''
as_view内部会返回一个view,所以路由匹配本质上是:
path('func/', views.MyView.view)
'''
3.2path('func/', views.MyView.view)
所以我们访问func时会触发view执行
return self.dispatch(request, *args, **kwargs)
'view会返回一个dispatch'
3.3dispatch方法
def dispatch(self, request, *args, **kwargs):
# 获取请求方式转换为小写,在判断请求方式在不在http_method_names方法里
if request.method.lower() in self.http_method_names: # 假设是get
# get函数名 = getattr(对象, 'get')
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
'最后执行handler,handler是get函数名则会执行get函数'
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
模板层
模板语法传值
1.模板语法传值
1.1方式1:指名道姓传参,不浪费资源
def func(request):
name = 'barry'
return render(request, 'func.html', {'name':name})
1.2方式2:locals()
将整个局部名称空间中的名字全部传入简单快捷
def func(request):
s = 'aaa'
return render(request, 'func.html', locals())
html获取名字方法:<p>{{ s }}</p>
2.模板语法传值范围
2.1基本数据类型可以直接传递使用
s = 'aaa'
i = 11
f = 22.2
l = [1, 2, 3]
d = {'name': 'barry', 'pwd': 666}
t = (1, 2, 3)
se = {1, 2, 3}
b = True
'django的模板语法在操作容器类型的时候只能使用句点符'
2.2函数名的传递会自动加括号执行并将返回值展示到页面上,如果函数有参则不会执行也不会展示,模板语法不支持有参函数
def func1():
return 'func1'
<p>{{ func1 }}</p>
2.3类名的传递也会自动加括号产生对象并将返回值展示到页面上,对象的传递则直接使用
'模板语法会判断名字是否可以调用,如果可以调用则调用'
模板语法过滤器
1.后端
s = 'aaa'
i = 11
from datetime import datetime
res = datetime.today()
file = 45354
l = [1, 2, 3]
s1 = 'Batman is watching you'
tag = "<h1>'蝙蝠侠在看着你'<h1>"
return render(request, 'func.html', locals())
2.html文件
<p>统计长度:{{ s|length }}</p>
# 统计长度:3
<p>加法运算:{{ i|add:2 }}、加法运算:{{ s|add:'abc' }}</p>
# 加法运算:13、加法运算:aaaabc
<p>日期格式:{{ res|date:'Y-m-d H:i:s' }}</p>
# 日期格式:2022-09-02 21:47:45
<p>文件大小:{{ file|filesizeformat }}</p>
# 文件大小:44.3 KB
<p>数据切片:{{ l|slice:'0.1' }}</p>
# 数据切片:[1, 2, 3]
<p>字符截取(三个点算一个):{{ s1|truncatechars:3 }}</p>
# 字符截取(三个点算一个):Ba…
<p>单词截取(空格):{{ s1|truncatewords:3 }}</p>
# 单词截取(空格):Batman is watching …
<p>语法转义:{{ tag|safe }}</p> # 默认是不转的,必须加转义方法
# 语法转义:'蝙蝠侠在看着你'
3.有时候html页面上的数据不一定非要在html页面上编写了,也可以后端写好传入
'''
django模板语法中的符号就只有连个:
需要使用数据时: {{}}
需要使用方法时: {%%}
'''
模板语法标签
1.流程控制
{% if 条件1 %}
条件1成立的代码
{% elif 条件2 %}
条件2成立执行的代码
{% else %}
条件都不成立时执行的代码
{% endif %}
'条件一般是模板语法传过来的数据'
2.循环标签
{% for i in l %}
{% if forloop.first %} # 第一次循环时first为True
<p>第一次循环</p>
{% elif forloop.last %} # 最后一次循环last为True
<p>最后一次循环</p>
{% else %}
<p>{{ i }}</p>
{% endif %}
{% endfor %}
自定义相关功能
1.自定义标签函数、过滤器、inclusion_tag
'''
想要自定义,需要先做以下三件事
1.在应用下创建一个templatetags文件夹
2.在该文件夹内创建任意名称的py文件
3.在该py文件内编写自定义相关代码
from django.template import Library
register = Library()
'''
2.自定义过滤器
@register.filter(name='myfilter')
def my_add(a, b):
return a + b
3.自定义标签函数
@register.simple_tag(name='mt')
def func(a, b, c, d):
return a + b + c + d
4.自定义inclusion_tag
@register.inclusion_tag(filename='it.html')
def index(n):
html = []
for i in range(n):
html.append('第%s页'%i)
return locals()
html:
{% load mytag %}
{{ i|myfilter:1 }}
{% mt 1 2 3 4 %}
{% index 10 %}
模板的继承与导入
1.模板的继承
1.1模板
{% block 名字 %}
模板内容
{% endblock %}
1.2子板
{% extends 'html文件名' %}
{% block 名字 %}
子板内容
{% endblock %}
'一般情况下母板中至少应该有三个区域使得扩展性更高'
2.模板的导入
将html页面的某个部分当做模块的形式导入使用
{% include 'menu.html' %}