视图函数(或简称视图)只是一个Python函数,它接受Web请求并返回Web响应。此响应可以是网页的HTML内容,重定向,404错误,XML文档或图像。。。
无论视图本身包含什么逻辑,都要返回响应
。代码写在哪里都可以,只要在 Python 目录下面,一般放在项目的 views.py 文件中。
每个视图函数都负责返回一个 HttpResponse 对象,对象中包含生成的响应。视图层中有两个重要的对象:请求对象(request)与响应对象(HttpResponse)。
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')] # 这里修改文件名
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
STATIC_URL = '/static/'
# 配置静态文件的名字,这里写的和上面同名,以后的静态文件就可以存放在当前目录下了
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
ROOT_URLCONF = 'untitled4.urls'
django.urls.path
或
django.urls.url
函数进行包裹,这个函数会根据传入的参数返回URLPattern或者是URLResolver的对象,如下:
from app01 import views
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index),
]
django.core.handlers.wsgi.WSGIRequest
对象),同时返回结果必须是
HttpResponseBase对象或者子类的对象。
HttpRequest 对象传给视图模板
。可以是一个字符串或一个html标签...
渲染到视图模板里
,用的相对是比较多的。每种方法都有相应的用武之地,这里我们先拿HttpResponse举例。
def index(request):
return HttpResponse('我是字符串,我后面的是一个html标签')
from app01 import views
from django.urls import path
urlpatterns = [
path('index/', views.index),
]
显然,可以传入一个或多个参数。
需要注意:
视图函数中的参数名必须与urls.py中尖括号中的参数名保持一致,否则会出错。
from django.shortcuts import render, HttpResponse
def index(request):
return HttpResponse('我是字符串,我后面的是一个html标签')
def index_detail(request, index_id, index_name):
return HttpResponse('我的id是%s我的名字是%s' % (index_id, index_name))
from django.urls import path
from app01 import views
urlpatterns = [
path('index/',views.index),
# 这里是可以自行定义类型的哦,类型不同就会报错~
path('index/int:/' , views.index_detail),
]
不仅如此,django还可以提供关键字传参,取参数值从request取值使用get()
方法获取,且关键字能写多个,即:127.0.0.1:8000/index/?id=1&name=sehun
,需要注意的是视图函数中的参数名必须与urls.py中尖括号中的参数名保持一致,否则会出错
。
from django.shortcuts import render, HttpResponse
def index(request):
return HttpResponse('我是字符串,我后面的是一个html标签')
def index_detail(request, index_id, index_name):
return HttpResponse('我的id是%s我的名字是%s' % (index_id, index_name))
def index_list(request):
index_id = request.GET.get('id')
index_name = request.GET.get('name')
return HttpResponse('id:%s 名字:%s' % (index_id, index_name))
from django.urls import path
from app01 import views
urlpatterns = [
path('index/',views.index),
path('index//' , views.index_detail),
path('index_list/',views.index_list),
]
显然什么都不写也不会报错,只是会返回一个none(空)
的参数。
在项目中,一般不可能只有一个app,而是有多个app,如果把所有app的views中的视图都放在urls.py中进行映射,肯定会让代码显得冗长混乱,后期维护也不方便。并且还不能同时导入views会重名,必须使用 as 别名 来实现不重名
相当麻烦,因此Django提供了一个机制,即URL模块化,可以在app内部包含自己的url匹配规则,而在项目的urls.py中再统一包含这个app的urls,这需要用到include函数
。
from django.urls import path
from . import views
urlpatterns = [
path('', views.index),
path('index_detail//' , views.index_detail),
path('index_list/', views.index_list),
]
然后,我们通过python manage.py startapp app02
命令再创建一个app名为app02。
在app02下新建urls.py
from django.urls import path
from . import views
urlpatterns = [
path('login/', views.login),
]
from django.contrib import admin
from django.urls import path, include
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('app01/', include('app01.urls')),
path('app02/', include('app02.urls')),
]
from django.shortcuts import render, HttpResponse, redirect
def login(request):
if request.method == 'GET':
return render(request, 'login.html')
else:
user = request.POST.get('username')
pwd = request.POST.get('password')
if user == 'root' and pwd == '123':
# 重定向到app01下的index
return redirect('/app01/index/')
else:
return render(request, 'login.html', {
'msg': '用户名或密码错误'})
render和HttpResponse的区别是多了可传参数的渲染和html模板
,而redirect相当于重定向到目标路由位置
。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/app02/login/" method="post">
{
% csrf_token %}
<p>用户
<input type="text" name="username"><span style="color: red;">{
{
msg }}</span>
</p>
<p>密码
<input type="password" name="password">
</p>
<input type="submit" value="提交">
</form>
</body>
</html>
模板语言标记:
先渲染在返回给浏览器
。数据名字要和后台视图传来的要一致
,不然拿不到。{ {msg.keys}}
来获取value值,而列表的可以通过{ {msg.0(列表下标从0开始)}}
来获取。csrf_token:相当于一个登陆验证(留着以后再讲,明白是个登陆验证,不写是使用不了post请求的)
可以看到,此时访问每个视图函数,必须加上在主目录/urls.py中path方法中传入的第一个参数,如访问app01下的app就必须在url中加入app01前缀
;
include方法的作用是拼接主目录/urls.py中path方法的第一个参数与每个app中urls.py中定义的路由,以形成完整的路由。
随着功能的增加,路由层的 url 发生变化,就需要去更改对应的视图层和模板层的 url,非常麻烦,不便维护。
这时我们可以利用反向解析,当路由层 url 发生改变,在视图层和模板层动态反向解析出更改后的 url,免去修改的操作。
反向解析一般用在模板中的超链接及视图中的重定向。
拿上面的例子做比方
from django.shortcuts import render, HttpResponse, redirect
def login(request):
if request.method == 'GET':
return render(request, 'login.html')
else:
user = request.POST.get('username')
pwd = request.POST.get('password')
if user == 'root' and pwd == '123':
# 重定向到app01下的index
return redirect('/app01/index/')
else:
return render(request, 'login.html', {
'msg': '用户名或密码错误'})
这里我们用了重定向的方法,访问到了app01下的index,但是如果在重定向较多,而代码的路由发生了更改,那么就要一个一个的更改,显然,这是让人头大的,稍有不慎,就会显入万劫不复…
所以django的路由模块中,还有一个方式。
from django.urls import path
from . import views
urlpatterns = [
path('index/', views.index,name='index'),
path('index_detail//' , views.index_detail),
path('index_list/', views.index_list),
]
此时app01下的index被我们取了一个index的别名。
但是要怎么样可以告诉redirect呢,此时name的好兄弟reverse
来了,它不仅可以给redirect渲染,还可以给html模板的post请求的
<form action="{% url 'index' %}" method="post">
from django.shortcuts import render, HttpResponse, redirect, reverse
def login(request):
if request.method == 'GET':
return render(request, 'login.html')
else:
user = request.POST.get('username')
pwd = request.POST.get('password')
if user == 'root' and pwd == '123':
return redirect(reverse('index'))
else:
return render(request, 'login.html', {
'msg': '用户名或密码错误'})
效果还是一样的。
有时候定义url匹配需要使用正则表达式来实现一些复杂的需求,这时候我们可以使用re_path
来实现,其参数和path一致,只不过第一个参数即route参数可以是一个正则表达式。
还有django.conf.urls.url
也支持正则表达式匹配路由,其底层也是调用的re_path(regex, view, kwargs, name)
方法。
显然,定义路由时path(’’, views.music)
,等价于re_path(r’^$’, views.music)
。
from django.contrib import admin
from django.urls import path, re_path, reverse, include
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('app01/', include('app01.urls', namespace='app01')),
path('app02/', include('app02.urls', namespace='app02')),
# 首页
re_path(r'music.html$', views.music),
# 匹配默认参数
path('page', views.page),
# 匹配一般参数
path('page/' , views.page),
# 正则表达式
# re_path(r'^$', views.music),
re_path(r'retest/(?P\d{4})$' , views.year_re),
re_path(r'retest/(?P\d{2})$' , views.month_re),
]
其中,(?P\d{4})
是给正则表达式分组\d{4}
取名,即通过?P<>
给正则表达式分组取名,来与视图函数中的参数名匹配。
from django.shortcuts import render, HttpResponse
def index(request):
return HttpResponse('我是字符串,我后面的是一个html标签')
def index_detail(request, index_id, index_name):
return HttpResponse('我的id是%s我的名字是%s' % (index_id, index_name))
def index_list(request):
index_id = request.GET.get('id')
index_name = request.GET.get('name')
return HttpResponse('id:%s 名字:%s' % (index_id, index_name))
def login(request):
return render(request, 'login.html')
def music(request):
return HttpResponse('音乐网站首页')
def page(request, page_num=1):
return HttpResponse('音乐 第%s页' % page_num)
def year_re(request, year):
return HttpResponse('年份为:%s' % year)
def month_re(request, month):
return HttpResponse('月份为:%s' % month)
此时访问127.0.0.1:8000/music.html显示:
最后实现了自动匹配了。
命名空间(英语:Namespace)是表示标识符的可见范围:
存在问题:路由别名 name 没有作用域,Django 在反向解析 URL 时,会在项目全局顺序搜索
,当查找到第一个路由别名 name 指定 URL 时,立即返回。当在不同的 app 目录下的urls 中定义相同的路由别名 name 时
,可能会导致 URL 反向解析错误。
解决:使用命名空间
。
比如app01/urls.py和app02/urls.py修改如下:
from django.urls import path
from . import views
urlpatterns = [
path('index/', views.index,name='index'),
path('index_detail//' , views.index_detail),
path('index_list/', views.index_list),
]
from django.urls import path
from . import views
urlpatterns = [
path('login/', views.login),
path('index/', views.index,name='index'),
]
from django.shortcuts import render, HttpResponse, redirect, reverse
def index(request):
return HttpResponse('app02主页面')
此时访问127.0.0.1:8000/app02/login/显示:
很显然,reverse已经不知道是哪个index别名了,所以我们需要在用namespace='实例命名空间’
来实例命名空间。
from django.contrib import admin
from django.urls import path reverse, include,re_path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('app01/', include('app01.urls', namespace='app01')),
path('app02/', include('app02.urls', namespace='app02')),
re_path(r'login.html$', views.music),
]
from django.urls import path
from . import views
# 设定命名空间
app_name = 'app01'
urlpatterns = [
path('index/', views.index,name='index'),
path('index_detail//' , views.index_detail),
path('index_list/', views.index_list),
]
from django.urls import path
from . import views
# 设定命名空间
app_name = 'app02'
urlpatterns = [
path('login/', views.login),
path('index/', views.index,name='index'),
]
from django.shortcuts import render, HttpResponse, redirect, reverse
def index(request):
return HttpResponse('app02主页面')
def login(request):
if request.method == 'GET':
return render(request, 'login.html')
else:
user = request.POST.get('username')
pwd = request.POST.get('password')
if user == 'root' and pwd == '123':
return redirect(reverse('app01:index'))
else:
return render(request, 'login.html', {
'msg': '用户名或密码错误'})
此时访问127.0.0.1:8000/app02/login/如下:
此时两者相同的命名就已经分开了,不再覆盖彼此。
from django.shortcuts import render, HttpResponse, redirect, reverse
def index(request):
return HttpResponse('app02主页面')
def login(request):
if request.method == 'GET':
return render(request, 'login.html')
else:
user = request.POST.get('username')
pwd = request.POST.get('password')
if user == 'root' and pwd == '123':
return redirect(reverse('app01:index_detail'))
else:
return render(request, 'login.html', {
'msg': '用户名或密码错误'})
from django.urls import path
from . import views
app_name = 'app01'
urlpatterns = [
path('index/', views.index, name='index'),
path('index_detail//' , views.index_detail, name='index_detail'),
path('index_list/', views.index_list),
]
此时访问127.0.0.1:8000/app02/login/并登陆成功会报错。
NoReverseMatch at /app02/login/
Reverse for 'index_detail' with no arguments not found. 1 pattern(s) tried: ['app01/index_detail/(?P[0-9]+)/(?P[^/]+)$' ]
很明显,reverse()
方法中没有传入index_id,index_name参数,路径参数是通过kwargs
以字典形式来传递的。
from django.shortcuts import render, HttpResponse, redirect, reverse
def index(request):
return HttpResponse('app02主页面')
def login(request):
if request.method == 'GET':
return render(request, 'login.html')
else:
user = request.POST.get('username')
pwd = request.POST.get('password')
if user == 'root' and pwd == '123':
return redirect(reverse('app01:index_detail', kwargs={
'index_id': 2, 'index_name': 'sehun'}))
else:
return render(request, 'login.html', {
'msg': '用户名或密码错误'})
此时访问127.0.0.1:8000/app02/login/如下:
显然,也获取到了参数。