视图函数介绍
视图一般都写在app的views中,并且视图的第一个参数永远都是request(HttpRequest)对象。这个对象存储了请求过来的所有信息,包括携带的参数以及一些头部信息等。再视图中,一般完成逻辑相关的操作,比如这个请求是添加一篇博客,那么可以通过request来接收到这些数据,然后存储到数据库中,最后再把执行的结果返回给浏览器。
视图函数的返回结果必须是HttpResponseBase对象或者HttpResponseBase子类的对象。
django与flask传递参数区别:flask不需要传递这个request,是一个全局变量,django的request必须传递过来才能使用;
from django.http import HttpResponse def index(request):
return HttpResponse(u"花花")
URL映射
1.为什么回去urls.py文件中寻找映射呢?
因为在settings.py中配置了ROOT_URLCONF为urls.py:
ROOT_URLCONF = 'first.urls'
2.在urls.py中我们所有的映射都应该放在urlpatterns这个变量中
urlpatterns = [
path('admin/', admin.site.urls),
]
3.所有的映射不是随便写的,而是通过path函数或者re_path函数进行包装的。
path = partial(_path, Pattern=RoutePattern)
re_path = partial(_path, Pattern=RegexPattern)
4、默认首页映射查找
在没有写任何url映射时,django会给到一个默认的页面,如果一旦有映射其他url页面,就要写个视图函数,url映射到空字符串,给到一个首页;
urlpatterns = [
path('admin/', admin.site.urls),
re_path(r'',views.index),
]
URL中传递参数给视图函数
1、采用在url中使用变量的方式
在path的第一个参数中,使用<参数名>的方式可以传递参数。然后在视图函数中也要写一个参数,视图函数中的参数必须和url中的参数名称保持一致,不然就找不到这个参数。另外,url中可以传递多个参数
views.py
from django.http import HttpResponse def index(request):
return HttpResponse(u"花花首页") def book(request):
return HttpResponse("图书") def book_detail(request,book_id,category_id):
text = "您获取的图书id是:%s,图书分类是%s" % (book_id,category_id)
return HttpResponse(text)
urls.py
from django.contrib import admin
from django.urls import path,re_path
from cmdb import views urlpatterns = [
path('admin/', admin.site.urls),
path(r'',views.index),
path(r'book/',views.book),
path(r'book_detail/<book_id>/<category_id>/',views.book_detail),
]
结果:
2、采用查询字符串的方式
在url中,不需要单独的匹配查询字符串的部分。只需要在视图函数中使用request.GET.get('参数名称')的方式来获取。示例代码如下:
path('book_author/',views.author_detail), def author_detail(request):
author_id = request.GET['id'] #request包括客户端和浏览器请求过来的所有数据
text = '作者的id是:%s' % author_id
return HttpResponse(text)
访问:http://127.0.0.1:8000/book_author/?id=2 即可将参数传递过去。
因为查询字符串使用的是`GET`请求,所以我们通过`request.GET`来获取参数。并且因为`GET`是一个类似于字典的数据类型,所有获取值跟字典的方式都是一样的。
django内置的URL转换器
1、如何限制参数类型:
可以使用django内置的url转换器(converters)。我们可以从converters包中了解所有的转换器,首先在urls.py中导入urls包引入转换器,(快速打开converters.py方法:写一行 "from django.urls import converters" 鼠标放在converters下ctrl+b)
from django.urls import converters
打开converters.py后可以了解到所有的转换器:
2、类型总结:
int类型:1个或者多个0-9的数字;
str类型:除了/
其余都可以作为str类型,默认时str转换器;
uuid类型:uuid转换器具有唯一性,只满足uuid.uuid4()
类型的 ,如:923c3f5f-edeb-4d2b-ac70-a99eb4425b0b(print(uuid.uuid4()));
slug类型:数字、大小写字母、-满足,其余不行;
path类型:str转换器不能有/
而path转换器是可以包含任意字符的,包括/;
3、格式规范
只要在url,path中<参数名>前加格式类型即可
path(r'publisher_detail/<int:publisher_id>/',views.publisher_detail), #参数名前面加上格式类型 def publisher_detail(request,publisher_id):
text = '出版社的id是:%s' % (publisher_id)
return HttpResponse(text)
4、如何生成uuid?
进入python函数,uuid是python内置库
>>> import uuid
>>> print(uuid.uuid4())
74858df0-7b95-4366-ae6c-dc54aa9402c6 #自动生成uuid
>>>
url分层模块化
当项目越来越大,url也会变得越来越多。如果放在主"urls.py"文件中,将会不好管理。因此我们可以将每个app自己的urls放在自己的app中进行管理,一般我们会在app中新建一个urls.py文件用来存储所有和此app相关的url。
1、在app文件夹下新建一个urls.py文件,并写入相关app的urls,注意要import 视图函数
from django.urls import path
from . import views urlpatterns = [ path(r'',views.book),
path(r'detail/<book_id>/<category_id>/',views.book_detail),
path('author/',views.book_author),
path(r'publisher/<int:publisher_id>/',views.book_publisher), ##参数名前面加上格式类型
]
2、在主urls.py中调入app的url
from django.urls import path,include #导入include模块 path(r'',include('cmdb.urls')), #这边我写个空代表会找到urls表里的第一个path映射的view
path('book/',include('cmdb.urls')),
#url是会根据主 urls.py 和 app中的 urls.py 进行拼接,因此这边book加了'/',app中的拼接前面就不需要加'/'了
3、需要注意的地方:
1) url模块化是为了方便管理,即将每个APP中各建立自己的urls.py文件 。
2) 在项目下有一个总的urls.py文件,这个文件的主要作用是将每个APP去找各自的urls.py文件,在该文件中,应该使用include函数包含urls.py,且是相对于项目路径 。
3) 在APP中的urls.py文件,所有的匹配也应该放在urlpatterns中 。
4) 最终的url是根据主url.py和APP的url.py进行拼接的,因此,不可多加或少加/。
URL命名与反转URL
1.新建一个项目 在项目中创建cms和fomt两个app。
2. 在cms应用的views.py文件里输入如下代码:
from django.http import HttpResponse def index(request):
return HttpResponse('CMS首页') def login(request):
return HttpResponse('CMSlogin登录页面')
3. 在fomt应用的views.py文件里输入如下代码:
from django.http import HttpResponse def index(request):
return HttpResponse('前台首页') def login(request):
return HttpResponse('前台登录页面')
4. 在cms和fomt两个app里各创建一个urls.py文件,分别写下文件中代码如下:
from django.urls import path
from . import views urlpatterns = [
path('',views.index),
path('login/',views.login),
]
5. 在项目的urls.py文件中更新代码如下:
from django.urls import path,include urlpatterns = [
#path('admin/', admin.site.urls),
path('',include('fomt.urls')),
path('cms/',include('cms.urls')),
]
6. 实现url反转
调整fomt应用views.py里的代码,实现未登陆用户调转到登陆页面的功能。
调整后的代码如下:
from django.shortcuts import render
from django.http import HttpResponse
from django.shortcuts import redirect #redirect重定向 def index(request):
username = request.GET.get('username') #获取查询字符串
if username:
return HttpResponse('前台首页')
else:
return redirect('/login/') #重定向到登录页面 def login(request):
return HttpResponse('前台登录页面')
访问127.0.0.1:8000 直接跳转到前台登录页面
访问http://127.0.0.1:8000/?username=huahua 跳转到前台首页
7. url命名
为什么需要给url命名?
因为url是经常变化的。如果在代码中写死可能会经常改代码。给url取个名字,以后使用url的时候就使用他的名字进行反转就可以了,就不需要写死url了。
在fomt应用中views.py代码修改如下:
from django.http import HttpResponse
from django.shortcuts import redirect,reverse #redirect重定向 ,增加了reverse函数 def index(request):
username = request.GET.get('username') #获取查询字符串
if username:
return HttpResponse('前台首页')
else:
login_url=reverse('login') #urls.py中的url的name print(login_url)#在控制台可查看打印的东西
return redirect(login_url) # 将login反转的url赋值给login_url def login(request):
return HttpResponse('前台登录页面')
如何给url指定名称?
在'path'函数中,传递一个'name'参数可以指定。
在front应用中urls.py代码修改如下:
from django.urls import path
from . import views urlpatterns = [
path('',views.index,name='index'),
path('signin/',views.login,name='login'),
] # 后期如果想将login改为signin,只需要将前面的“login/”修改为“signin/”即可,别的不用动。
访问http://127.0.0.1:8000/自动跳到http://127.0.0.1:8000/signin/前台登录页面;
应用(app)命名空间
在多个app之间,有可能产生同名的url。这时候为了避免反转url的时候产生混淆,可以使用应用命名空间,来做区分。定义应用命名空间非常简单,只要在app的urls.py中定义一个叫做app_name的变量,来指定这个应用的命名空间即可。
’cms’的app应用views.py文件中给url命名:
from django.urls import path
from . import views urlpatterns = [
path('',views.index,name = 'index'),
path('login',views.login,name = 'login'),
]
访问:http://127.0.0.1:8000/cms/login
发现跳转至了cms登录页面去了,而我们是想让他跳转至前台登录页面啊!
这是因为我们现在的项目中有两个app,在这两个app中我们都将各自的主页url取名为‘index’,登录页面也都是命名为’login’,在
return redirect( reverse('login') )
进行反转的时候,Django不能准确的找到需要跳转的页面,所以他就会跳转至找到的第一个’login’的页面。这个时候我们就需要让Django明确的知道需要跳转的页面,所以我们在每个app中的urls.py中添加一个变量app_name
1、fomt中的urls.py中添加:
#应用命名空间
#应用命名空间的变量叫做app_name
app_name = 'fomt'
2、在cms中的urls.py中添加:
app_name = 'cms'
3、然后我们需要明确的指出需要跳转的页面,在front中的views.py中的index函数修
这样以后左反转的时候就可以使用'应用命名空间:url名称'的方式进行反转;
def index(request):
username = request.GET.get('username')
if username:
return HttpResponse('前台首页')
else:
login_url=reverse('fomt:login') #urls.py中的url的name
return redirect(login_url)
访问:http://127.0.0.1:8000 这样Django就明确的知道需要跳转至哪一个页面了。
实例命名空间
一个app,可以创建多个实例。即可以使用多个url映射同一个app。所以这就会产生一个问题。以后在做反转的时候,如果使用应用命名空间,那么就会发生混淆。为了避免这个问题。我们可以使用实例命名空间。实例命名空间也是非常简单,只要在include函数中传递一个namespace变量即可。
1.在主urls.py中对cms添加两个映射,然后实例化命名
from django.urls import path,include urlpatterns = [
#path('admin/', admin.site.urls),
path('',include('fomt.urls')),
path('cms1/',include('cms.urls',namespace='cms1')),
path('cms2/',include('cms.urls',namespace='cms2')),
]
2.然后修改下cms的views.py中index函数的代码,没有传入用户名进来时直接跳转至登录页面
from django.shortcuts import reverse,redirect
def index(request):
username = request.GET.get("username")
if username:
return HttpResponse('CMS首页')
else:
# 获取当前的命名空间
current_namespace = request.resolver_match.namespace
return redirect(reverse("%s:login" % current_namespace))
们就使用cms1进入时,就会进入cms1的登录页面,使用cms2进入,就会进入cms2的登录页面,http://127.0.0.1:8000/cms2/login
include函数用法
1、include
(module,namespace = None):
module:子url的模块字符串;
namespace:实例命名空间,如果指定实例命名空间,前提必须要先指定应用命名空间,也就是在子'urls.py'中添加'app_name'变量‘
2、include
(pattern_list):'pattern_list'是一个列表,这个列表中装的是'path'或者're_path'函数;
3、include
((pattern_list,app_namespace),namespace = None): include函数的第一个参数既可以为一个字符,也可以为一个元祖,如果是元组,那么元组的第一个参数是’urls.py‘
模块的字符串,元组的第二个参数是应用命名空间,也就是说,应用命名空间既可以在子'urls.py'中通过'app_name'指定,也可以在'include'函数中指定;
re_path和path的区别
1、re_path和path的作用都是一样的。只不过re_path是在写url的时候可以用正则表达式,功能更加强大。
2、写正则表达式都推荐使用原生字符串。也就是以r开头的字符串。
3、在正则表达式中定义变量,需要使用圆括号括起来。这个参数是有名字的,那么需要使用(?P<参数的名字>)。然后在后面添加正则表达式的规则。
4、编写路由需要用的正则表达式,
r 字符串前面加“ r ”是为了防止字符串中出现类似“\t”字符时被转义。
^ 匹配字符串开头;在多行模式中匹配每一行的开头。 ^abc abc
$ 匹配字符串末尾;在多行模式中匹配每一行末尾
例如:
re_path(r"^list/(?P<year>\d{4})/$",views.article_list),
re_path(r"^list/(?P<month>\d{2})/$",views.article_list_month)
第一个表示以list开始,中间需要有4个数字,一个都不能多也不能少,再以 ‘/’ 结尾。
形如list/2222/这样的字符窜才能被识别,
同理,第二句是需要形如list/22/这样的字符窜才能被识别。
例2:
from django.urls import path,re_path urlpatterns = [
re_path(r'^search_phone/$',views.search_phone),
re_path(r'^sign_index/(?P<event_id>[0-9]+)/$', views.sign_index),
re_path(r'^sign_index_action/(?P<event_id>[0-9]+)/$', views.sign_index_action),
如果不是特别要求。直接使用path就够了,除非是url中确实是需要使用正则表达式来解决才使用re_path。
reverse 函数补充
1、如若在反转url时,需要添加参数,那么可以传递 kwargs 参数到 reverse 函数中,实例代码如下:
views.py
from django.shortcuts import render,reverse,redirect
from django.http import HttpResponse def index(request):
username = request.GET.get('username')
if username:
return HttpResponse('首页')
else:
detail_url = reverse('detail', kwargs={"article_id":''}) #使用 kwargs 参数到 reverse 函数中,也可添加多个参数;
#detail_url = reverse('login') +"?next=/"
return redirect(detail_url) def login (request):
return HttpResponse('登录页面') def detail(request,article_id):
text = '您的文章id是:%s' % article_id
return HttpResponse(text)
urls.py
from django.urls import path
from front import views urlpatterns = [
path('', views.index),
path('login/', views.login),
path('detail/<article_id>', views.detail,name='detail'),
]
2、如若想添加查询字符串参数,则必须手动进行url拼接,
#detail_url = reverse('login') +"?next=/"
指定默认参数
使用path或者re_path时,在route中都可以包含参数,而有时想指定默认参数,通过以下方式完成
url.py
path('', views.books),
path('book/<int:page>/', views.books),
views.py
from django.http import HttpResponse
book_list=[
'自动化',
'python',
'selenium'
] def books (request,page=0):
return HttpResponse(book_list[page])
当访问book的时候,因为没有传递page参数,所以会匹配到第一个url,这时候view.books这个视图函数,而在books函数中,又有page=0这个默认参数,因此这是就可以不用传递参数,而如果访问book/1的时候,因为在传递参数的时候传递了page,因此会匹配到第二个url,这时候也会执行views.books,然后把传递进来的参数传给books函数中的page。