本节知识点
URL:路由映射,两个
Views:在views中目前只会接收 get 请求, post 请求等,当然前端发过来的不止这些数据,还有请求头,会话和cookie
在views中:请求的其他信息,装饰器
Models操作:数据库操作。还有正向操作、反向操作(本节不涉及)
Templates:模板的使用,如xxx.html,还可以自定义函数。
cookie和session:用户认证(本节不涉及session)
分页(自定义的分页):可用于任何的 Python Web框架
Form验证:输入内容不合法,不能进行下一步操作(本节不涉及)
一、 上节内容回顾
1、 请求周期
url > 路由 > 函数或类 > 返回字符串或者模板语言给用户
Form 表单提交时:
提交 -> url -> 函数或类中的方法
HttpResponse('......')
render(request, 'index.html') # 经过处理后的字符串
redirect('/index/') #
用户 < < 返回字符串
(当接收到redirect时) 自动发起另外一个请求
--> url .....
form 表单提交举例:
假设 render(request, '', {'name': 123}) 这样返回,在 html 中:
{{ name }}
在这个 html 中,两处的 {{name}} 都会被替换为 123 返回给用户。
Ajax 提交,方法如下:
$.ajax({
url: '/index/',
type: 'POST',
data: {'k': 'v'}, // $(form对象).serialize(), 可通过这种方式打包获取。当有多选框,获取到的字典值是列表
traditional: true, // 加上这一句,data 字典的值可以是列表,这样后台才能接收到
dataType: 'JSON',
success: function(d){
location.reload(), // 刷新当前页面
location.href="要跳转的URL" // 跳转到指定 URL
}
})
Ajax 提交的请求周期:
提交 -> url -> 函数或类中的方法,返回给用户时:
HttpResponse("......") # 字符串
render(request, 'index.html', {'name': 'michael'}) # 使用 render 方法时会对模板进行替换,例如:
{{ name }}
-->michael
不能使用 redirect 方法,所以 Ajax 提交不能跳转
用户 <<< 字符串
如果要提交,在 Ajax 中的 success 的 function 方法中做跳转:
location.reload(), // 刷新当前页面
location.href="要跳转的URL" // 跳转到指定 URL
2、 路由系统URL
/index/ -> 函数或类
/index/(\d+) -> 函数或类
/index/(?P\d+) -> 函数或类,nid=\d+
/index/(?P\d+) name='root -> 函数或类,nid=\d+
reverse(),后台用这个方法可生成URL
{% url 'root' 1 %},前端用这个方法可生成URL
/crm/ include('app01.urls') 路由分发
默认值:下面这个URL后面的字典就是默认值,当有默认值的时候,对应的函数要去接收这个默认值
path('index/', views.index, {'name': 'root'}),
def index(request, name):
print(name)
return HttpResponse('Python')
命名空间:
假设在项目文件夹下的urls.py文件内容如下:
from django.urls import path, include
urlpatterns = [
path('a/', include("app01.urls", namespace='author')),
]
在app01文件夹下的urls.py文件内容如下:
from django.urls import path
from app01 import views
app_name = 'app01' # 注意这里要指定 app_name 才行
urlpatterns = [
path('index/', views.index, name='index')
]
此时 app01 文件夹下的 views.py文件的 index 函数代码如下所示:
def index(request):
return HttpResponse('Python')
此时访问 http://127.0.0.1:8000/a/index/ 页面显示 Python。
继续修改 app01 文件夹下的 views.py文件的 index 函数,使用 reverse 生成 URL,代码如下所示:
from django.urls import reverse
def index(request):
v = reverse('author:index')
print(v)
return HttpResponse('Python')
运行代码后地址栏输入 http://127.0.0.1:8000/a/index/ 页面显示 Python,后台输出 /a/index/ ,这就是命名空间的作用。在前端要获取 URL 的方式也是 author:index 方式。关于命名空间现总结如下:
/admin/ include('app01.urls', namespace='m1') # 项目文件夹下的 urls 指向同一个app 的 URL
/crm/ include('app01.urls', namespace='m1')
app01.urls
/index/ name = 'n1' # 在 app 的urls 中指定 name 值
reverse("m1:n1") # 在函数中通过命名空间名字与 app 中的 urls 的 name 值获取 URL
3、 FBV 和 CBV
FBV:URL对应views 的函数,FBV获取前端数据方法:
def func(request):
# 获取请求
request.POST
request.GET
request.FILES
request.getlist
request.method
request.path_info
# 返回数据
return render, HttpResponse, redirect
4、 模板中的常用方法
假设 render 方法返回数据到前端,前端可用的方法有下面这些:
render(request, 'index.html')
# for循环
# if 条件判断
# 字典通过索引点(.)取,有 keys, values, items等方法,都不加括号
5、 操作数据库
首先要在 models.py 中定义类:
class User(models.Model):
username = models.CharField(max_length=32)
email = models.EmailField()
在数据库中插入数据,更新数据,无验证功能的用法:
User.objects.create(username='root', email='root123456')
User.objects.filter(id=1).update(email='michael')
有验证功能:
Django Admin
接下来对数据进行增、删、改、查等操作
数据库一对多操作(外键),现假设有 UserType 表和 User 表的代码如下所示:
class UserType(models.Model):
name = models.CharField(max_length=32)
class User(models.Model):
username = models.CharField(max_length=32)
email = models.EmailField()
user_type = models.ForeignKey("UserType") # 数据库存储时的实际名称是 user_type_id
user_list = User.objects.all() # 查询所有数据,QuerySet对象类型列表
for obj in user_list: # 循环列表,获取数据方法有下面这些:
obj.username, obj.email, obj.user_type_id, # 获取 User 表数据
obj.user_type.name, obj.user_type.id # 获取 UserType 表数据
user = User.objects.get(id=1) # 获取单个对象
user.某个字段 # 直接用这个对象可获取数据
使用双下划线进行跨表操作
User.objects.all().values("username", "user_type__name",)
数据库多对多操作,现假设有 UserType、User、UserGroup 三张表的代码如下所示:
class UserType(models.Model):
name = models.CharField(max_length=32)
class User(models.Model):
username = models.CharField(max_length=32)
email = models.EmailField()
user_type = models.ForeignKey("UserType")
m = models.ManyToMany('UserGroup') # 自动创建多对多关系
class UserGroup(models.Model):
name = ......
obj = User.objects.get(id=1) # 查询到的是 User 对象
obj.m.add(2)
obj.m.add(2, 3)
obj.m.add(*[1,2,3])
obj.m.remove(...)
obj.m.clear()
obj.m.set([1,2,3,4,5])
# 多个组, UserGroup 对象
obj.m.all()
obj.m.filter(name='CTO')
二、 views 中的请求信息
当从前端发来请求的时候,后台通常使用 request 参数接收,请求数据中除了常用的 GET、POST、method、FILES等属性外,还有其它的很多数据可以接收。可以在函数中 print(type(request)),看下还有类型。
首先创建项目文件夹 michael_03 及 app 目录 app01,创建过程参考 “Python编程(二十八)”。
现在有 michael_03\michael_03\urls.py 文件代码如下所示:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('a/', include("app01.urls", namespace='author')),
]
michael_03\app01\urls.py 文件代码如下所示:
from django.urls import path
from app01 import views
app_name = 'app01'
urlpatterns = [
path('index/', views.index, name='index')
]
michael_03\app01\views.py 文件中的 index 函数代码如下所示:
def index(request):
print(type(request))
return HttpResponse('Python')
运行 michael_03 项目文件,在地址栏输入 http://127.0.0.1:8000/a/index/,后台输出内容如下:
从输出可以看出这是一个类,通过导入这个类,可以进入这个类的源代码看下,这个类提供了些什么方法。
from django.core.handlers.wsgi import WSGIRequest
通过查看 WSGIRequest 类源代码,可以看到这个类在初始化时有一个参数 environ,这个参数封装了所有的用户请求信息。例如将 index 函数的代码修改如下:
def index(request):
from django.core.handlers.wsgi import WSGIRequest
print(type(request))
# 封装了所有用户请求信息
print(request.environ)
return HttpResponse('Python')
在地址栏输入 http://127.0.0.1:8000/a/index/ 后,可以看第二个 print 语句输出了非常多的信息,信息以字典的形式输出,并且是原生的数据。可以循环输出这个字典。另外在函数中除了常用的 request.GET 和 equest.POST 方法外,还有 request.COOKIES 方法。修改后的 index 函数代码如下:
def index(request):
# request.GET
# request.POST
# request.COOKIES
from django.core.handlers.wsgi import WSGIRequest
print(type(request))
# environ封装了所有用户请求信息,字典形式的数据
print(request.environ)
for k, v in request.environ.items():
print(k, v)
return HttpResponse('Python')
在循环输出这个 request.environ 的时候,可以看到有一个 HTTP_USER_AGENT 请求头的信息,这个信息表示用户的终端类型。比如某些网站对手机访问的时候,返回给用户的页面与电脑上访问时返回给用户的页面就会不一样。获取这个请求头的方法是:
request.environ["HTTP_USER_AGENT"]
三、 templates(模板继承)
在项目文件夹下的 urls.py 文件中添加下面这3个 URL:
path('tpl1/', views.tpl1),
path('tpl2/', views.tpl2),
path('tpl3/', views.tpl3),
并且注释掉这个URL:
path('a/', include("app01.urls", namespace='author')),
在 app01\views.py 中增加下面这3个对应URL的函数:
def tpl1(request):
user_list = [1,2,3,4]
return render(request, 'tpl1.html', {'u': user_list})
def tpl2(request):
name = 'michael'
return render(request, 'tpl2.html', {'name': name})
def tpl3(request):
status = "已删除"
return render(request, 'tpl3.html', {'status': status})
接下来在 templates 目录下增加4个 html 文件:master.html,tpl1.html,tpl2.html,tpl3.html。通常看到的页面都有相同的头部、左侧菜单等,假设在每个页面中写下重复的 HTML 代码,会增加工作量,也会增加文件大小。这时可以把具有相同的代码写在一个模板文件中,在这里假设这个模板文件是 master.html,那么在 tpl1.html,tpl2.html,tpl3.html可以继承这个模板文件。可以在模板文件中写下有共用的HTML、CSS、JS等,在子文件中继承即可,当然在子文件中也可以写自己的CSS、JS代码。现假设有模板文件 master.html的代码如下所示。
template\master.html:
{% block title %}{% endblock %}.pg-header{
height: 48px;
background-color: seashell;
color: green;
}
{% block css %} {% endblock %}
{% block content %} {% endblock %}
{% block js %} {% endblock %}