一、MTV和MVC
1 django 是MTV架构,本质也是mvc
-M:model,数据库相关操作
-T:template,模板文件(就是mvc的v层)
-V:view,视图(urls+view=MVC的控制器)
2 MVC架构:主流的web框架都是mvc
-Web应用分为模型(M),控制器(C)和视图(V)
-M:model,数据库相关操作
-C:controler控制器,逻辑相关,逻辑代码
-V:视图,模板文件
二、Django的请求生命周期
三、有名分组和无名分组
# re模块演示
import re
res = re.search('([0-9]{4})/([0-9]{2})', '2020/10')
print(res.group[1]) =======> 2020 # 注意这里的起始位置是1
print(res.group[2]) =======> 10
res = re.search('(?P<year>[0-9]{4})/(?P<month>[0-9]{2})', '2020/10')
print(res.group('year')) =======> 2020
print(res.group('month')) =======> 10
#1 无名分组的使用
### 无名分组,把分组分出来的值,当作位置参数传递给视图函数
url(r'^login/([0-9]{4})/([0-9]{2})', views.login),
#2 有名分组的使用
### 有名分组,把分组出来的值,当作关键字参数传递给视图函数
url(r'^login/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})', views.login),
(127.0.0.1:8000/login/2020/10)
def login(request, year, month):
print(year) =======> 2020
print(month) =======> 10
return HttpResponse('login')
#3 有什么作用
可以从url地址中解析出参数,传递给视图函数使用
#4 案例
# 这种地址,把人名和id分出来
# 有名分组
# ilovejaney/p/13748739.html
url(r'^(?P<name>.*?)/p/(?P<num>\d+).html', views.article),
# 无名分组
url(r'^(.*?)/p/(\d+).html', views.article),
def article(request, name, num):
print(name)
print(nim)
return HttpResponse('你的名字是%s,你的文章num是%s'%(name,num))
# 5 伪静态
-原来是动态页面/login 做成/login.html 伪装成静态页面,便于seo优化
-seo优化:
-https://www.cnblogs.com/w/articles/9509792.html
四、路由的分发
1 有一个总路径,根路由,总路由负责做分发
2 每个app有自己的路由和视图函数的对应关系
3 使用:
-1 在根路由中配置
# 路由分发
# 第一种方式
from django.conf.urls import url, include
url(r'^app01', include('app01.urls')),
url(r'^app02', include('app02.urls')),
# 第二种方式
from app01 import urls
url(r'^app01',include(urls)),
-2 在不同app中新建urls.py
from . import views
urlpatterns = [
url(r'/login/', views.login),
url(r'/home/', views.home),
]
-3 http://127.0.0.1:8000/app01/login/
先匹配app01,如果成功分发到app01的urls中继续匹配
五、反向解析
1 通过路由的别名,动态的解析出路由的地址
urlpatterns = [
url(r'/login/', views.login),
# url(r'/home/', views.home, name='home'),
url(r'/aaaaaaa/', views.home, name='home'),
]
2 用在视图函数中:
from django.shortcuts import render, HttpResponse, redirect, reverse
def login(request):
url = reverse('home') # home就是路由的别名
print(url) ====>'/aaaaaa/'
3 模板文件中使用
{% url 'home' %}
4 有什么作用
-动态根据路由别名获得路径,一旦路径改变,不需要改其他代码
六、名称空间
# 示例:
总路由:
url(r'^app01',include('app01.urls') ),
url(r'^app02',include('app02.urls') ),
app01:
urlpatterns = [
url(r'/login/', views.login,name='login'),
url(r'/home/', views.home, name='home'),
]
app02:
urlpatterns = [
url(r'/login/', views.login,name='login'),
url(r'/home/', views.home, name='home'),
]
{% url 'home' %} # 只会解析出app02中的,总路由中后配置的
1 路由做反向解析时,如果有同名路由,出现问题
2 在做路由分发时,给每个app的路径设置一个名称空间
3 使用步骤
-1 在总路由中设置
url(r'^app01',include('app01.urls',namespace='名称空间的名字') ),
-2、分路由中
url(r'/home/', views.index,name='home'),
-3 用在视图函数中:
url=reverse('名称空间的名字:home') # home就是路由的别名
print(url)
-4 模板文件中使用
{% url '名称空间的名字:home' %}
七、path中的转换器
1 5个内置转换器
'''
str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
int,匹配正整数,包含0。
slug,匹配字母、数字以及横杠、下划线组成的字符串。
uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)
'''
2 例子
-path('login/<int:year>', views.login),
-path('login/<str:year>', views.login),
-path('login/<path:p>', views.article),
3 高级例子
-实现匹配这种路径:http://127.0.0.1:8000/liuqingzheng/p/4444.html
-path('<str:name>/p/<int:id>.html', views.article),
-re_path(r'^(?P<name>.*?)/p/(?P<id>\d+).html$', views.login),
-url(r'^(?P<name>.*?)/p/(?P<id>\d+).html$', views.login),
# url在2.x以后不建议使用
4 转换器可以不可以在re_path中使用?不能!!!!
八、自定义的转换器
1 写一个类
-regex属性:这里写的正则表达式就能匹配
-to_python方法
-to_url 方法
2 在settings.py中注册这个类
register_converter(类名, 转化器名字)
3 在path中使用
path('<lqz:name>/', views.article),
class FourDigitYearConverter:
regex = '[0-9]{4}'
def to_python(self, value):
return int(value)
def to_url(self, value):
return '%04d' % value
from django.urls import register_converter, path
from . import converters, views
register_converter(converters.FourDigitYearConverter, 'yyyy')
urlpatterns = [
path('articles/2003/', views.special_case_2003),
path('articles/<yyyy:year>/', views.year_archive),
...
]
九、Django请求对象
def index(request):
'''
request:django封装的对象,它的类是WSGIRequest,它里面包含了所有http请求的东西
'''
print(request)
print(type(request))
# from django.core.handlers.wsgi import WSGIRequest
#######################1
print(request.method)
print(request.GET)
print(request.POST)
########################2 path,get_full_path,META,FIELS,body
# 自定制请求头
# 上传文件使用的编码方式是form-data,默认编码方式urlencoded
print(request.is_ajax()) # 是不是ajax请求
print(request.path) # 请求路径
print(request.get_full_path()) # 请求全路径,带数据
# print(request.body) # 请求体,二进制,如果传文件,这个报错
'''
使用form表单,默认情况下数据被转成name=wuxi&password=123放到请求体中
request.POST其实是从body中取出bytes格式的,转成了字典,如果不是用&连接的,POST取不出来
requet.GET其实是把路径中?后面的部分拆出来,转成了字典
'''
print(request.encoding) # 客户端向服务端传递时,使用的编码方法
print(request.META) #字典,一堆东西,请求用户的ip地址,请求头中数据,用户自定制请求头的数据
'''
把请求头的key值部分统一加HTTP_ 并且全部转成大写
'''
print(request.META['REMOTE_ADDR']) # 客户端的ip地址
print(request.FILES) # 客户端上传的文件
request.META
一个标准的Python 字典,包含所有的HTTP 首部。具体的头部信息取决于客户端和服务器,下面是一些示例:
取值:
CONTENT_LENGTH —— 请求的正文的长度(是一个字符串)。
CONTENT_TYPE —— 请求的正文的MIME 类型。
HTTP_ACCEPT —— 响应可接收的Content-Type。
HTTP_ACCEPT_ENCODING —— 响应可接收的编码。
HTTP_ACCEPT_LANGUAGE —— 响应可接收的语言。
HTTP_HOST —— 客服端发送的HTTP Host 头部。
HTTP_REFERER —— Referring 页面。
HTTP_USER_AGENT —— 客户端的user-agent 字符串。
QUERY_STRING —— 单个字符串形式的查询字符串(未解析过的形式)。
REMOTE_ADDR —— 客户端的IP 地址。
REMOTE_HOST —— 客户端的主机名。
REMOTE_USER —— 服务器认证后的用户。
REQUEST_METHOD —— 一个字符串,例如"GET" 或"POST"。
SERVER_NAME —— 服务器的主机名。
SERVER_PORT —— 服务器的端口(是一个字符串)。
从上面可以看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 之外,请求中的任何 HTTP 首部转换为 META 的键时,
都会将所有字母大写并将连接符替换为下划线最后加上 HTTP_ 前缀。
所以,一个叫做 X-Bender 的头部将转换成 META 中的 HTTP_X_BENDER 键。
########################3
print(request.COOKIES) # 空字典
print(request.session) # session对象
print(request.user) # 匿名用户
return HttpResponse('ok')
十、视图层之响应对象
from django.http import JsonResponse
def index(request):
# 三件套
# return HttpResponse('ok')
# return render(request,'index.html',context={'name':'wuxi','age':18})
# return redirect('/home') # 重定向自己的地址,重定向第三方地址,经常跟反向解析一起使用
# 向客户端返回json格式数据
# import json
# res=json.dumps({'name':'吴','age':18},ensure_ascii=False)
# return HttpResponse(res)
# django内置提供的JsonResponse
# 本质还是HttpResponse
# ensure_ascii
源码部分:
def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
json_dumps_params=None, **kwargs):
data = json.dumps(data, cls=encoder, **json_dumps_params)
# return JsonResponse({'name':'w','age':18},json_dumps_params={'ensure_ascii':False})
**将其拆包成ensure_ascii=False
# safe,转换除字典以外的格式,需要设置safe=False
return JsonResponse([13,'wuxi',[1,2,3],{'name':'wuxi','age':19}],safe=False, json_dumps_params={'ensure_ascii':False})
十一、CBV和FBV
# CBV基于类的视图(Class base view)和FBV基于函数的视图(Function base view)
# 写视图类(还是写在views.py中)
## 第一步,写一个类,继承View
from django.views import View
class Index(View):
def get(self, request): # 当url匹配成功,get请求,会执行它
return HttpResponse('ok')
def post(self,request):
return HttpResponse('post')
## 第二步:配置路由(django3.x版本)
path('index/', views.Index.as_view()), # 加括号
十二、form表单文件上传,提交地址
## html注意编码方式
<form action="/index/" method="post" enctype="multipart/form-data">
<p>用户名:<input type="text" name="name"></p>
<p>密码:<input type="password" name="password"></p>
<p><input type="file" name="myfile"></p>
<p><input type="submit" value="提交"></p>
</form>
# views.py
def index(request):
file=request.FILES.get('myfile')
# 打开一个空文件,写入
with open(file.name,'wb') as f:
for line in file.chunks():
f.write(line)
return HttpResponse('文件上传成功')
# action
#1 不写,默认向当前地址发送请求
#2 /index/,向当前域(http://127.0.0.1:8000/)的/index/发送请求
#3 http://127.0.0.1:8000/index/,向该地址发送请求(可以向第三方服务发送请求)
# method
# 1 post:发送post请求(默认编码情况下:以key=value&key=value的形式拼到请求体中)
# 2 get:发送get请求(以key=value&key=value的形式拼到路径中)
<form action="/index/" method="post">
<p>用户名:<input type="text" name="name"></p>
<p>密码:<input type="text" name="password"></p>
<p><input type="submit" value="提交"></p>
</form>
十三、前后端交互的编码方式
1 urlencoded---->传普通的数据,form表单默认就是这种---->request.POST
2 form-data-----》传文件和数据 ---->request.POST request.FILES
3 json----------》传json格式数据 ---->request.body中取出来自行处理
def index(request):
# 接收urlencoded编码
body体中:name=wuxi&age=18
# print(request.POST)
# 接收form-data编码
body体中:分两部分,一部分是数据,一部分是文件
数据部分:name=wuxi&age=18
---asdfasdfasdfgasgasgd---
文件部分(二进制)
#数据部分
# print(request.POST)
# #文件部分
# print(request.FILES)
# 接收json格式(通过posman发送json格式的数据)
body体中
{
"name": "wuxi",
"age": 18
}
# 这里没有
print(request.POST)
# 数据在这(自行处理)
print(request.body)
res = json.loads(request.body) # python3.6之后,json可以直接反序列化byte
return HttpResponse('ok')
十四、Django模板语法的使用
# 方式一:
now_date = datetime.datetime.now()
return render(request, 'index.html', context={'cdate': str(now_date)})
# 方式二:(页面静态化,提高网站并发量)
with open('index.html', mode='rt', encoding='utf-8') as f:
res = f.read()
t = Template(res)
c = Context({'cdate': str(now_date)})
html = t.render(c) # html是渲染后的字符串
return HttpResponse(html)
DTL:Django Template Language
1 模板中使用 {{ python变量 }}
############views.py
def index(request):
num = 10
ss = 'w is handsome'
b = False
ll = [1, 2, 43]
dic = {'name': 'w', 'age': 18}
def test():
print('我是test')
return 'test return'
class Person():
def __init__(self, name):
self.name = name
def print_name(self):
return self.name
def __str__(self):
return self.name
p = Person('w')
# return render(request, 'index.html', context={'num':num,'ss':ss,'b':b})
#locals() 把当前作用域下所有的变量,都传到context中
return render(request, 'index.html',locals())
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ ss }}</title>
</head>
<body>
<h1>模板语法之变量</h1>
<p>数字:{{ num }}</p>
<p>字符串:{{ ss }}</p>
<p>布尔:{{ b }}</p>
<p>列表:{{ ll }}</p>
<p>字典:{{ dic }}</p>
<p>函数:{{ test }}</p>
<p>对象:{{ p }}</p>
</body>
</html>
十五、模板语法之深度查询句点符
from django.utils.safestring import mark_safe
def index(request):
num = 10
ss = 'wuxi is handsome'
b = False
ll = [1, 2, 43, {'name': 'wen'}]
dic = {'name': 'wuxi', 'age': 18}
def test():
print('我是test')
return 'test----'
class Person():
def __init__(self, name):
self.name = name
def print_name(self):
return self.name
def __str__(self):
return self.name
p = Person('w')
link1 = '<a href="https://www.baidu.com">点我<a>'
link2 = mark_safe(link1)
input_1 = '<p>用户名:<input type="text" name="name"></p>'
input_2 = mark_safe(input_1)
script_1='''
<script>
alert('你被攻击了')
</script>
'''
script_2 = mark_safe(script_1)
return render(request, 'index.html', locals())
<h2>模板语法之句点符的深度查询</h2>
<p>列表的第一个元素:{{ ll.1 }}</p>
<p>字典的name对应的值:{{ dic.name }}</p>
<p>列表的第三个元素的name对应的值:{{ ll.3.name }}</p>
<p>函数执行,直接写函数名即可:{{ test }}</p>
<p>函数如果有参数?不支持</p>
<p>对象调用方法: {{ p.print_name }}</p>
<p>对象调用属性: {{ p.name }}</p>
<hr>
<a href="https://www.baidu.com">点我</a>
<p>a标签的字符串: {{ link1 }}</p>
<p>a标签的字符串,显示成a标签: {{ link2 }}</p>
<p>用户名:<input type="text" name="name"></p>
<p>input标签:{{ input_1 }}</p>
<p>input标签,显示成标签:{{ input_2 }}</p>
<p>js原封不动显示:{{ script_1 }}</p>
{{ script_2 }} 显示为js代码
from django.utils.safestring import mark_safe
link1 = '<a href="https://www.baidu.com">点我<a>'
link2 = mark_safe(link1)
{link1|safe}
十六、模板语法之过滤器
1 {{ 参数1|过滤器名字:'参数2' }}
{#注意:冒号后面不能加空格#}
2 过滤器最多传两个值,最少一个值 {{'w is'|slice:'2:3'}}
# 了解
{#如果变量为空,设置默认值,空数据,None,变量不存在,都适用#}
<p>{{ name |default:'数据为空' }}</p>
<p>过滤器之filesizeformat:{{ num|filesizeformat }}</p>
ss = 'w is handsome'
<p>过滤器之slice:{{ ss|slice:"7:11" }}</p>
第二个参数写0,1,2, 都是 ..., 最少从3开始
<p>过滤器之truncatechars:{{ ss|truncatechars:'30' }}</p>
<p>truncatewords:{{ ss|truncatewords:'2' }}</p>
# 记住
<p>过滤器之date:{{ ctime|date:'Y年m月d日-------H时i分s秒' }}</p>
<p>过滤器之safe:{{ link1|safe }}</p>
{#add 可以加负数,传数字字符串都可以#}
<p>{{ "10"|add:"-2" }}</p>
{#upper#}
<p>{{ name|upper }}</p>
<p>{{ 'WW'|lower }}</p>
十七、标签
1 {% 标签名 %}
2 标签for ,在标签for的内部一直有一个forloop对象,是个字典
counter0:从0开始,每循环一次加1
counter:从1开始,每循环一次加1
revcounter:从列表长度开始,每循环一次减一
first:判断是不是循环的第一个
last:判断是不是循环的最后一个
parentloop:父级forloop对象(for循环嵌套)
{'parentloop': {}, 'counter0': 0, 'counter': 1, 'revcounter': 6, 'revcounter0': 5, 'first': True, 'last': False}
3 if标签
# views.py
def index(request):
ll = ['w','u','x','i','nb']
# ll = []
dic = {'name':'w','age':19}
count = 1
wisnbplus = 'w'
# b = False
b = True
user_list = [{'name':'w','age':19},{'name':'u','age':18},{'name':'x','age':22},{'name':'i','age':99},{'name':'n','age':18},{'name':'b','age':18}]
return render(request, 'index.html', locals())
#index.html
<h1>模板语法之标签</h1>
<h2>for的用法</h2>
{% for l in ll %}
<p>{{ l }}</p>
<p><a href="http://127.0.0.1:8080/{{ l }}">{{ l }}</a></p>
{% endfor %}
<hr>
{% for k,v in dic.items %}
<p>key值为:{{ k }} , value值为{{ v }}</p>
{% endfor %}
<table border="1">
<tr>
<td>id号</td>
<td>用户名</td>
<td>年龄</td>
</tr>
{% for dic in user_list %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ dic.name }}</td>
<td>{{ dic.age }}</td>
</tr>
{% endfor %}
</table>
<hr>
<h2>for ----empty的用法</h2>
<ul>
{% for l in ll %}
<li>{{ l }}</li>
{% empty %}
<li>没有数据</li>
{% endfor %}
</ul>
<h2>forloop对象</h2>
{% for dic in user_list %}
{% for key,value in dic.items %}
{{ forloop.parentloop.counter }} # 获得父级counter编号
<p>{{ key }}:{{ value }}</p>
{% endfor %}
{% endfor %}
<h2>if</h2>
{% if b %}
<p>b是true的</p>
{% else %}
<p>b是false的</p>
{% endif %}
<h2>with重命名</h2>
{% with forloop.parentloop.counter as aaa %}
{{ aaa }}
{% endwith %}
{% with wisnbplus as a %}
{{ a }}
----{{ wisnbplus }}
{% endwith %}
<h2>csrf</h2>
{% csrf_token %}
<input type="hidden" name="csrfmiddlewaretoken" value="uC35XuP1J2Va74ArYiNw4TMZ0PaZ6V4qvVGCsUQcqiKF5Sr8IrWS0rzpmOmPBrjY">
</body>
十八、自定义标签和过滤器
-第一步:在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag
-第二步:在app中创建templatetags包(包名只能是templatetags,不能改)
-第三步:在包内,新建py文件(如:my_tags.py)
-第四步:写代码(过滤器)
from django import template
register = template.Library()
@register.filter
def my_upper(value):
return value.upper()
-第五步使用:(模板),先load,再使用
{% load my_tags %}
{{ 'aa'|my_upper }}
# 可以生成一片模板中的代码块
# 使用:5步
-第一步:在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag
-第二步:在app中创建templatetags包(包名只能是templatetags,不能改)
-第三步:在包内,新建py文件(如:my_tags.py)
-第四步:写代码(inclusion_tag)
# inclusion_tag,传一个模板文件
1、在my_tags.py中
@register.inclusion_tag('left.html')
def left(num):
# dic={0:第0页,1:第1页,2:第2页}
dic = {i: '第%s页' % i for i in range(num)}
# 固定返回的必须是字典
print(dic)
return {'data': dic}
@register.inclusion_tag('beautiful.html')
def beautiful(title, url):
return {'title': title, 'url': url}
2、在left.html中
{% for key,value in data.items %}
<p>key是:{{ key }} value是:{{ value }}</p>
{% endfor %}
-第五步使用:在index.html中,先load,再使用
{% load my_tags %}
{% left 5%}
{% beautiful '名字' '地址'%}
# 它跟tag有什么不同?
-tag需要再代码中写html的东西
-inclusion_tag代码跟模板分离
### 通过tag实现beautiful的功能
@register.simple_tag
def tab_beautiful(title, url):
return mark_safe('''
<div class="panel panel-danger">
<div class="panel-heading">
<h3 class="panel-title">%s</h3>
</div>
<div class="panel-body">
详情点击:<a href="%s">疯狂点我</a>
</div>
</div>
''' % (title, url))
-第一步:在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag
-第二步:在app中创建templatetags包(包名只能是templatetags,不能改)
-第三步:在包内,新建py文件(如:my_tags.py)
-第四步:写代码(过滤器)
from django import template
from django.utils.safestring import mark_safe
register = template.Library()
@register.simple_tag
def my_csrf():
import uuid
res=uuid.uuid4()
return mark_safe('<input type="hidden" name="csrfmiddlewaretoken" value="%s">'%res)
@register.simple_tag
def my_tag(value):
return value.isupper()
-第五步使用:(模板),先load,再使用
{% load my_tags %}
{% my_tag %}
{% my_tag 'WU' %}
十九、模板的应用和继承
-第一步:新建一个 xx.html,把好看的模板写入
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src='https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js'></script>
<link href="/static/bootstrap/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="panel panel-danger">
<div class="panel-heading">
<h3 class="panel-title">花开花落花满天</h3>
</div>
<div class="panel-body">
详情点击:<a href="http://www.baidu.com" target="_blank">红消香断有谁怜</a>
</div>
</div>
</div>
</div>
</body>
</html>
-第二步:再你想用的地方
{% include 'test1.html' %} # 引入!!!!!!!!!!!!!!!
-第一步:写一个母版,写空盒子
{% block top %} # 写在需要添加内容的位置
{% endblock %}
-第二步:某个页面要使用母版,引入,扩写盒子
{% extends 'base.html' %}
{% block top %}
index页面
{% endblock %}
二十、静态文件的连接
第一种: <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
第二种:
{% load static %}
<link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.min.css' %}">
第三种:
{% load static %}
<link rel="stylesheet" href="{% get_static_prefix %}bootstrap/css/bootstrap.min.css">
# 特殊用法(注意:若A.html继承其他母版时,需要写在母版中,方可在A.html使用)
{% load static %}
{% static "images/hi.jpg" as myphoto %}
<img src="{{ myphoto }}" alt="Hi!">
{% load static %}
{% get_static_prefix as static %}
<img src="{{ static }}images/hi.jpg" alt="Hi!" />
例子:
# 母版
<head>
<meta charset="UTF-8">
<title>Title</title>
{% load static %}
{% get_static_prefix as ssstatic %}
<script
</head>
# A.html
<body>
{% block top %}
<h1>一笑倾城</h1>
<img src="{{ ssstatic }}img/pexels-pixabay-416676.jpg" alt="chonglang" title="冲浪" style="width: 400px">
{% endblock %}
</body>