路由用于将URL映射到相应的视图函数,使得用户可以通过URL访问到相应的页面或数据
path函数的用法/路由须知
path函数涉及四个参数 route,view我在这里主要讲后两种
路由须知:
我们在路由中使用视图时,在要在前面加上引用
from . import views
route参数
必须是字符串类型,用来匹配域名
比如输入 admin/ 就会匹配 http://127.0.0.1:8000/admin 地址
view参数
用于设置视图函数,后面会讲到
name参数
为路由进行命名,后面会讲到
URL转发(设置分路由)
URL转发可以把路由分散到其他文件夹中,避免都在主文件夹中,造成堵塞。[wazhantest/urls.py ],转化为副项目名 [fruits/urls.py]。
urls.py,需要自己创建。复制以下代码:
from . import views
from django.urls import path
urlpatterns = [
path('sub',views.shop1) #在该域名下设置视图函数
]
定义视图函数view.py
from django.http import HttpResponse
def shop1(request):
return HttpResponse("你好呀!我是大帅哥")
之后,打开主项目的urls.py文件,在里面加上以下内容:
from django.urls import includes
path('fruits/',include('fruits.urls')) #第一个参数是app的名字,第二个是域名的名字
之后运行服务器即可。
设置路由变量
当调用的视图对象过多时,可以设置路由变量来方便维护,路由变量可以支持
类型 | 用法 |
---|---|
字符型(str) | 可以匹配除了 " \ " 以外的字符串,时默认值 |
整形(int) | 匹配0以及任何整数 |
slug型 | 匹配任意ASCll字母,数字,连字符和下滑线,如代表最新商品展示信息的网页路由地址 Dood-2022-7-7-1 |
uuid型 | 匹配一个格式化的UUID唯一序列号,所有字符必须小写,并且用"-"连接 |
下面来看一个案例:
在根路由的views.py的urlpatterns路由列表中加入以下代码:
from django.http import HttpResponse
def MPage(request,year,day,mouth):
return HttpResponse("我在"+str(year)+"-"+str(day)+"-"+str(mouth)+"号真帅")
在根路由的urls.py下加(在urlpatterns中)
from wanzhantest.views import MPage
path('<int:year>/<int:mouth>/<slug:day>',MPage)
完成后运行服务器,输入网址 http://127.0.0.1/2023/3/7 就会出现我们输入的url了
进入网址:点我进入
路由命名+视图中使用模板
创建一个新的应用 background 应用:
python manage.py startapp background
为路由命名需要path的一个参数name实现
命名路由是指给 URL 路由分配一个名称。这个名称可以在应用程序的其他部分中引用(比如html中),而不用直接使用 URL 地址 (从一个模板中跳到另一个模板中的时候用 {% url })
在分路由的urls.py中加入代码:
path('1/',views.index,name='index'),
path('r/',views.register,name='register')
我们已经把"r/“命名为register(相当于把"register相当于”/")
在分路由的view.py中加入:
def index (request):
return HttpResponse("你好呀!我是大帅哥1")
def register (request):
return render(request,'register.html') #render函数在这里用来说明视图如何
为了调用模板,我们要在backgroud目录下建立templates子目录
并在templates目录下创建html文件register.html
把这些复制过去,这里把a中的跳转更改为路由名,点击jump to 就可以跳转到这个页面(函数)了。
“{%url ‘register’ %}” 为路由名(就是我们命名的/r,可以相当于打注释)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册管理模板</title>
</head>
<body>
<br>
<h1 style = "text-align:center"><a href = "{%url 'register' %}">jump to</a></h1>
</body>
</html>
最后,完成主项目的urls.py的总路由
path('back',include('background.urls'))
运行服务器,如果出现找不到模板问题
需要在根项目的setting.py中的INSTALLED_APPS和TEMPLATES
BASE_DIR/“templates”
命名路由空间
命名路由空间可以解决 在不同app下使用相同的路由名导致url反向解析出错。
命名空间使得即使在不同的app中定义了相同的url名称,也能够正确的实现 url 反向解析。
为路由命名会在这种情况下引发问题。我们需要使用命名空间
假设我们在 background的目录 和 fruits的目录 下有:
两者的urls.py:(输入的url不同,但是路由命名相同)
|background|:
|fruits|:
两者的函数(在视图函数中,路由名相同)相同,都为:
根路由urls.py
之后运行服务器,输入:
127.0.0.1/app1/ww 会发现:
显然,这并不是我们想要的结果。
django在反向解析URL时,会在项目全局顺序搜素,当查找到第一个name指向的URL时,便立即返回。所以上面访问不同URL,反向解析得到相同的path。
就是为了防止在不同app下使用相同的路由名所引发的问题,我们才使用命名空间
用include 来管项目URL,并进行namespace(命名空间)
在根项目的目录下修改代码为:(在include函数中修改)
path('app1/',include('background.urls',namespace='app1')),
path('app2/',include('fruits.urls',namespace='app2')),
在background/urls.py修改代码:(声明命名空间)
app_name = 'app1'
在fruits/urls.py修改代码:(声明命名空间)
app_name = 'app2'
之后,修改视图函数:
语法为:namespace:name
就完成了
反向解析(回环地址)
每个视图函数都有一个和其相对应的路由,但是如果它们之间的匹配关系发生了变化,那么与之对应的访问地址也会跟着发生改变,这是极其不方便的
反向路由的主要作用是简化代码编写和维护,并且使得更改路由规则时的代价更小
因为我们更改url的时候,其他的程序不会进行改动
Django 提供了不同的方式来实现 URL 反向解析:
1.在模板层使用 {% url %} 模板标签;
2.在视图函数的 Python 代码中:使用 reverse() 函数;我们主要讲解第二点
我们现在在根路由的urls.py中输入:
path('i/',include(('fruits.urls'),namespace='index1'))
解释一下include参数:
之后,在fruits.urls文件中输入:
path('',views.Shop,name='Show'),
path('Show1/',views.ShowGoods,name='Show2')
解释一下:第一个参数是一个空字符串 ‘’ 。这表示该路由将匹配来自父URL配置的任何请求。也可以用来匹配空url
随后,添加视图函数
def Shop(request):
url = reverse('index1:Show2')
print(url)
return HttpResponseRedirect(url)
def ShowGoods(request):
return HttpResponse("荔枝大卖,最后98天!")
下面是解释:
第一行路由配置path(‘’,views.Shop,name=‘Show’)表示当用户访问站点根目录时,会调用名为Shop的视图函数,并将其命名为Show。
第二行路由配置path(‘Show1/’,views.ShowGoods,name=‘Show2’)表示当用户访问/Show1/路径时,会调用名为ShowGoods的视图函数,并将其命名为Show2。
在Shop视图函数中,使用了reverse方法,通过参数index1:Show2获取到了名为Show2的视图函数所对应的URL地址。然后,又使用HttpResponseRedirect方法将请求重定向到该地址,在浏览器中展示给用户的结果就是ShowGoods视图函数返回的内容:荔枝大卖,最后98天! (reverse函数会实现路由空间:路由名的反向解析)
总的来说,这段代码实现的功能是:当用户访问站点根目录时,自动跳转到/Show1/路径,并显示ShowGoods视图函数的返回结果。
完成了,登录网址127.0.01/i/Show1即可:点我进入
PS:因为回环地址的出现,当我们输入空字符串的时候(也就是127.0.0.1/i)也会返回一样的结果
加载静态资源
更改静态资源的时候要先清除cookies
Ctrl + F //清除cookies
django默认是没有办法加载js,css,图片之类的静态资源,我们需要创建一个static文件夹,用来专门放静态资源
1.我们需要在setting.py中加入下面这段代码:
STATICFILES_DIRS = [
os.path.join(BASE_DIR,"static")
]
2.创建一个static文件夹,把静态文件放在里面
3.用下面的命令来加入
{% load static %} //在模板中的 <head> 中加入
<link href="{% static 'css/style.css' %}" rel="stylesheet"/> //css样式
<script src="{% static "js/jquery-3.1.1.min.js" %}" type="text/javascript"></script> //js样式
<img src="{% static "email.png" %}" alt="图片加载失败"> //图片
4.案例
<!DOCTYPE html>
<html lang="en">
<head>
{% load static %} //必须要有
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>导航</title>
</head>
<body>
<nav>
<ul>
<li><a href="{%url 'register2' %}">首页lkj</a></li>
<li><a href="#">关于我们</a></li>
<li><a href="#">联系我们</a></li>
<p>图片的测试</p>
<img src="{% static "3.png" %}" alt=""> //图片
</ul>
</nav>
</body>
</html>
回环地址
就是改a标签
。比如<a href="index.html">
。
<a href="{% url 'index' %}">Index</a>
urlpatterns = [
path('', views.index, name='index'),
# 其他URL模式...
]
def index(request):
return render(request, 'index.html')
视图函数
基本的视图函数我们已经使用了很多次了,现在我们来讲解一下第二部分
关于响应码
状态码 | 功能说明 |
---|---|
100 | 该响应码表示请求已经成功,下面会返回响应结果,它只是一个临时状态 |
200 | 请求成功 |
204 | 服务器完成请求,而且无需返回内容 |
301 | 永久指向确定发网页地址 |
302 | 指向临时的网页地址 |
400 | 访问url有误,服务器不处理该请求 |
404 | 网页不存在或url无效 |
500 | 互联网出错 |
render函数(使用模板)
之前我们就使用过render函数来返回响应,事实上,如果我们项目的网页太多的话,会导致调整时不够灵活,因此我们会放到templates模板下,而这就是render函数的作用
render函数的使用格式如下:
from django.shortcuts import render #使用前需要导入
render(request,template_name)
参数说明:
request:必选参数,表示url请求访问信息
template_name:必选参数,用来指定模板文件的名称,也可以认为时一个静态的网页文件比如 index.html
context:可选参数,用于对模板内的变量赋值
content_type:可选参数,响应内容的数据格式,默认为text/html
status:响应状态码,默认为200
using:设置加载模板的模板引擎名称,用于解析模板,生成响应的网页内容
总之,我们把写好的html文件放到template中再完成对应的路由和视图函数就行
视图的重定向
当我们从正在访问的视图中访问到另一个视图的时候,比如返回到网站的首页,就可以使用重定向的方法。我们使用Django内置的HttpResponseRedirect方法,
使用HttpResponseRedirect需要导入:
from django.http import HttpResponseRedirect
再根文件下增加如下视图函数
def NewURL(request):
return HttpResponseRedirect('http://www.ifeng.com') #跳转到凤凰网
加入路由函数:
path('4/',NewURL)
这样,当我们输入网址127.0.0.1/4/的时候就会跳转到凤凰网:点我进入
错误提示视图
一般django会在你输入错误的网址的情况下显示一个错误视图:
一般而言,错误视图是给开发人员看,在真正的运行时我们要关闭这个界面,在根目录下的setting.py的 DEBUG更改为False,以及ALLOWED_HOST=[‘*’] 以防止出现安全问题
自定义错误提示视图
默认的视图错误信息都是英文的,而一般的中文网站希望提供中文的错误信息来处理404视图,500视图等。
我们需要进入setting.py文件下:修改如下两个参数
DEBUG=False # 关闭调试模式
ALLOWED_HOSTS=[‘*’] # * 代表允许所有的URL访问服务器,默认为 []
之后,我们创建一个模板用来存html文件,下面时404.html文件的代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>404错误提示信息</title>
</head>
<body>
<h1>无法访问,页面找不到--{{URL_path}}</h1>
</body>
</html>
{{URL_path}}为模板变量,用来接受错误提示视图中的变量值
在view.py中完成对全局404配置函数的书写:
def page_not_found(request, exception):
#自定义错误视图函数必须提供request,exception函数
path = {'URL_path': request.path}
return render(request, '404.html', path, status=404) #只能用于404错误
在路由文件urls.py中设置全局路由:(这里注意了,必须写到urlpatterns的[ ]的外面)
handler404='wanzhantest.views.page_not_found'
最后,我们输入一个不存在的路由地址:(比如127.0.0.1/ikunikunjojojojo),就会出现
PS:完成这节学习后,最好调回原版的错误提示界面,以方便我们的学习
HttpRequest对象
Django会把http数据包封装为HttpRequest对象并将其转递给每个视图函数的第一个参数request
在PyCharm中点击“终端”按钮并输入python manage.py shell以打开Django Shell
HttpRequest对象的方法
get_host方法
该方法用来获取请求访问的服务器的地址或域名,可以带上端口号
我们在视图函数view.py中加上:
def index(request):
host=request.get_host() #获取请求方法的服务器或域名
html='一个简单的返回信息!'+host
response = HttpResponse(html, status=200)
response.charset = 'utf-8' #很重要,用来转化为中文
return response
同时,加上路由:
from wanzhantest.views import index
path('1/',index)
之后,输入网址127.0.0.1/1,我们就可以知道请求的服务器了:点我进入
get_port()方法
该方法用来获取端口号,我们现在简单改一下代码
def index(request):
host = request.get_host()
port = request.get_port() #获得请求访问的服务器的地址
html = '一个简单的返回信息!' + host +'<br>' + 'get_port()方法获得:' + str(port)
#'<br>'是一个换行符
response = HttpResponse(html, status=200)
response.charset = 'utf-8'
return response
现在,我们输入网址 http://127.0.0.1:80/1/就会出现:(80时默认端口)
PS:值得一提的是,当我们运行django服务器的时候如果输入
python manage.py runserver 0.0.0.0:800 代表我们把本地的端口改为了800
这时我们就要输入http://127.0.0.1:800/1/
get_full_path()方法
该方法用于获得完整的url地址,改动代码
def index(request):
host = request.get_full_path()
port = request.get_port() #获得请求访问的服务器的地址
html = '一个简单的返回信息!' + host +'<br>' + 'get_port()方法获得:' + str(port)
response = HttpResponse(html, status=200)
response.charset = 'utf-8'
return response
返回:
is_secure()方法
该方法用于判断知否是安全的访问(https)如果是,返回True,否则,返回False
改动代码:
def index(request):
host = request.is_secure()
port = request.get_port() #获得请求访问的服务器的地址
html = '一个简单的返回信息!' + str(host) +'<br>' + 'get_port()方法获得:' + port
response = HttpResponse(html, status=200)
response.charset = 'utf-8'
return response
会返回:
文件上传
这一章我们完成"文件上传"的操作,我们在这里可以看到前端和后端的联动
第一步"建立模板":
在template文件夹下建立 upload.html 文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>上传文件模板</title>
</head>
<body>
<form enctype="multipart/form-data" action="/uploadfile/" method="post">
{% csrf_token %} <!--防CSRF攻击-->
<input type="file" name="newfile" />
<br/>
<input type="submit" value="上传文件"/>
</form>
</body>
</html>
参数解析
enctype属性: 用来指定上传文件给服务器之前对表单数据进行的编码方式,这里必须指定为 “multipart/form-data” 表示不对字符进行编码,支持通过文件上传的方式将数据发给服务端。
action属性: 用来指定需要上传的目标的URL,这里指定了/uploadfile 地址 ,必须在项目路径下建立 upuploadfile 字目录路径,即建立一个空的目录
method属性:用来指定post值(必须指定),表示使用post方法提交表单
{% csrf_token %}: 用来防止攻击,后面会细讲
第二步,完成视图函数:
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
def upload_file(request):
if request.method == "POST": # 请求方法为POST时,可以读取文件数据
newFile =request.FILES.get("newfile", None) #获取上传文件数据,若没有文件则返回None
if not newFile: #如果没有文件
return HttpResponse("提交无效,没有文件上传!",status=200) #返回无效操作提示,终止视图函数执行
to_path=open(os.path.join(BASE_DIR,'uploadfile',newFile.name),'wb+') #打开特定的文件进行二进制的写操作
for chunk in newFile.chunks(): # 分块写入文件
to_path.write(chunk)
to_path.close()
return HttpResponse("上传成功!")
else:
return HttpResponse('非表单提交访问!')
第三部,在视图函数中调用上传模板的视图函数(主要用于返回模板)
def login1(request):
return render(request,'upload.html') #返回模板给访问的浏览器
最后,完成路由
path('file/',login1), #使用template目录下的upload.html视图
path('uploadfile/',upload_file) #调用上传文件的视图函数
我们输入网址http://127.0.0.1/file/进行确认:点我进入
点击上传文件,并选中一个图片进行上传
PS:我们建立的 uploadfile目录必须放在项目的根目录下,而不是同名的应用下
|
文件下载
Django提供4种下载文件的方式:HttpResponse,StreamingHttpResponse,FileResponse以及JsonResponse
使用这4种方式时都需要导入:
from django.http import HttpResponse,StreamingHttpResponse,FileResponse,JsonResponse
我们主要讲最简单的HttpResponse
我们需要在根目录下创建一个给用户下载的文件夹,里面放入一张图片,即创建目录"download"里面放个图片
第二部,我们创建一个下载的模板download.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>下载文件</title>
</head>
<body>
<br>
<div class="col-md-4"><a href="{% url 'index:download' %}" rel="external nofollow" >点击下载文件</a></div>
</body>
</body>
</html>
第三步,建立下载的视图函数
from django.http import Http404
def download(request):
filename='cats.jpg'
try:
download_path = open(os.path.join(BASE_DIR, 'download',filename ), 'rb') #读取指定地址下的文件
print(download_path)
d=HttpResponse(download_path)
d['content_type']='application/octet-stream'
d['Content-Disposition']='attachment;filename='+filename #下载文件
return d
except:
raise Http404('下载文件'+filename+'失败!')
完成路由:
from wanzhantest.views import download
path('download1/',download)
最后输入网址(http://127.0.0.1/download1,居然直接下载了:点我下载
视图类
视图类是另一种使用视图的方法,视图类比起普通的定义视图会显得更直观
内置显示视图类
内置显示视图主要将模型数据,模板展示在用户访问的浏览器上,Django为此提供了5种视图类:View,TemplateView,RedirectView,ListView,DetailView
View视图类
View类用来响应各种来自前端的请求。
需要导入:(视图类在使用时必须实例化,下面会说)
from django.views import View
第一步,我们在background/view.py文件下增加视图:
from django.views import View
class firstClassView(View):
def get(self,request):
return HttpResponse(request.path)
def post(self,request):
if request.POST!=None:
return HttpResponse('Post请求访问结果=有值')
else:
return HttpResponse('Post请求访问结果=无值')
第二步:在urls.py下添加视图(必须使用as_view()实例化)
path('Go1/',views.firstClassView.as_view()),
第三步:在根路由urls.py下添加视图:
path('bg/',include('background.urls'))
最后,运行服务器输入网址http://127.0.0.1/bg/Go1/ 点我进入
因为从地址栏访问都是get请求,所以会返回输入的地址
模板视图类
TemplateView类用于模板处理响应与展示的视图类,需要导入
from django.views.generic.base import TemplateView
该类的父类是:TemplateResponseMixin类,查看父类的方法是:
选中TemplateView并按下 Ctrl + B可以跳转到该类的定义处,可以在这里查看父类
这是其父类的属性
第一步,在background应用下增加如下视图类
class T_View(TemplateView):
template_name = 'T_home.html' #设置模板
def get_context_data(self, **kwargs): #重写方法
context=super().get_context_data(**kwargs) #继承方法
context['address']='天津' #传递变量及值
context['name']='刘瑜'#传递变量及值
context['oet']='猫猫' #传递变量及值
return context
第二步,加入模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板视图的模板</title>
</head>
<body>
<table border="1" cellpadding="5">
<tr>
<th>地址:</th>
<th>{{address}}</th>
</tr>
<tr>
<td>姓名:</td>
<td>{{name}}</td>
</tr>
<tr>
<td>宠物:</td>
<td>{{pet}}</td>
</tr>
</table>
</body>
</html>
第三步,加入路由在background/urls.py处加入(必须使用as.view()实例化)
path('v1/',views.T_View.as_view()),
第四步,在根路由中加入
path('bg/',include('background.urls')),
最后,输入网址http://127.0.0.1/bg/v1/可以看到:点我进入
重定向视图类
RedirectView用来完成视图的重定向
在该类中,我们在 127.0.0.1/bg/3/ 网页中跳转到 127.0.0.1/bg/3/k=10 (也就是show方法处)
该类还是需要导入:
from django.views.generic.base import RedirectView
该类同样拥有四个属性:
第一步:我们在background/view.py下加入:
class R_View(RedirectView):
pattern_name ='index2:www' #指定重定向到应用的 命名空 间及对应的 命名路由
query_string =True #允许请求路由传递查询参数值给重定向路由地址
def login(request): #先访问的网页
return render(request,'login.html')
def show(request): #重定向到的网页(可以是模板)
return HttpResponse("数据操作成功!")
第二步:加入路由:
path('3/', login, name='first'),
path('f/', R_View.as_view(), name='Redirect'),
ath('ff/', show, name='www'),
第三步:在根路由下加入
path('bg1/',include('background.urls','first'),namespace='index2')
第四步:加入模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>RedirectView</title>
</head>
<body>
<br>
<a href="{%url 'index2:Redirect' %}?k=10">Go</a>
</body>
</html>
最后,我们输入网址 http://127.0.0.1/bg/3/ 点我进入
点击 GO
列表视图类
使用前需要导入:
from django.views.generic import ListView
第一步:在background/views.py文件下:
from django.views.generic import ListView
from fruits.models import goods #从模型中导入 goods类
class ListView1(ListView):
model = goods # 指向 goods 模型
context_object_name = 'MyGoods' #把 goods 模型命名为 MyGoods 并传递该模板(数据传递给模板的变量名)
template_name = 'ListView.html' #指定模板
第二步:加入模板(background下的模板)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>水果店信息</h2>
<ul>
{% for one in MyGoods %}
<li>名称:{{ one.name }} 数量:{{ one.number}} 单价:{{ one.price}}</li>
{% endfor %}
</ul>
</body>
</html>
第三步:background.urls 加入子路由:(必须使用as.view()实例化)
from . import views
path('s/',views.ListView1.as_view(),name='Show')
第四步:加入总路由
path('bg/',include('background.urls'))
最后,输入网址http://127.0.0.1/bg/s/ : 点我进入
一条记录视图类
DetailView也是用于获取模型的类,它于ListView类唯一区别就是一次只可以处理一条记录
使用该类需要引用:
from django.views.generic import DetailView
第一步:在background/views.py文件下加入
from django.views.generic import DetailView
from fruits.models import goods
class DetailView1(DetailView):
model = goods #指定模型
template_name = 'DetailView.html' #指定模板
slug_field = 'name' #指定需要查询的字段
slug_url_kwarg = 'name' #于slug_field一致,用于指定URL请求访问的变量名
pk_url_kwarg = 'pk' #指定了 URL 中捕获主键的关键字参数的名称,对应下面的URL
第二步,加入模板:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>DetailView</title>
</head>
<body>
<h1>名称{{goods.name}}</h1>
<h2>数量{{goods.number}}</h2>
<h2>单价{{goods.price}}</h2>
</body>
</html>
第三步:完成子路由:(必须使用as.view()实例化)
from . import views
path('<pk>/<name>.html',views.DetailView1.as_view(),name='One') #使用<pk>值表示商品的主键值
注意了,URL参数后面加上 .html 用来限制变量输入的内容,以防止输入太多无关值(只要没用特殊的输入,输入什么都行)
http://127.0.0.1/bg/2/ikunaaaa.html
http://127.0.0.1/bg/2/ikunbbbbhtml
http://127.0.0.1/bg/2/ikuncccc.html
等这些(没有特殊值的,都是可以的)
第四步:完成根路由
path('bg/',include('background.urls'))
之后我们输入网址:http://127.0.0.1/bg/4/爱坤.html :点我进入
(正好对应了数据库中 id=4 name=爱坤 的数据)
如果我们输入 http://127.0.0.1/bg/4/爱坤dddddd.html (数据库中没有 id=4 name=爱坤dddddd 的数据),会出现
可见,输入正确的pk值(主键值,默认为id),也是可以的,如果输入完整的url可以更好(因为有时name参数值相同)的定位
再试一次,输入 http://127.0.0.1/bg/2/ikun.html (我们建的表中有两个name=ikun的参数):点我进入
可见,跳出了第二条记录
内置编辑视图类
对于上网展示的数据,往往需要增,删,改,查等操作,比如提交个人信息给服务端,服务器通过django给数据库进行操作,Djano有四种内置编辑视图类用来实现该功能,分别是:FromView,CreateView,UpdateView,DeleteView
验证数据类
FromView主要用于验证数据,响应验证结果,显示表单数据。(显示提交成功或者出错)
使用前需要导入:
from django.view.generic.edit import FormView
第一步,在background/urls.py中加入:
class GoodsForm(forms.ModelForm):
class Meta:
model=goods #指定模型
fields='__all__' #获取模型goods的所有属性(字段)
class FormView1(FormView):
template_name ='FormView.html' #调用视图对应的模板
form_class =GoodsForm #用于指定表单类
success_url ='../OK/' #用于指定提交成功的重定向路由地址
def ShowOK(request):
return HttpResponse('数据提交成功!')
第二步,加入模板:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>表单类显示及提交</title>
</head>
<body>
<form method="post">
{% csrf_token %}
<table>
<tr><th>水果名称</th><td>{{ form.name }}</td></tr>
<tr><th>数 量</th><td>{{ form.number }}</td></tr>
<tr><th>单 价</th><td>{{ form.price }}</td></tr>
<tr><td colspan="2"><input type="submit" value="提交"/></td></tr>
</table>
</form>
</body>
</html>
第三步,加入子路由:(必须使用as.view()实例化)
path('fv/',views.FormView1.as_view()),
path('OK/',views.ShowOK,name='OK')
第四步,加入总路由:
path('bg/',include('background.urls'))
最后,输入网址http://127.0.0.1/bg/fv/进行查看:(图中的数据是自己输入的)点我进入
不会修改数据库中的数据
新建记录类
CreateView用于指定模型新增记录并返回新建成功提示,需要导入
from django.views.generic.edit import CreateView
第一步,在background/views.py中加入:
class CreateView1(CreateView):
initial = {'name':'西瓜','number':10,'price':1.2} #初始化的值,会直接显示在界面里
template_name = 'CreateView.html' #指定模板的名字
#form_class =GoodsForm #指定表单对应的模型类,方法一
model =goods #用model、fields指定模型对象,方法二
fields =['name','number','price'] #指定视图需要的字段
success_url = '../OK/' # 指定提交成功路由,
第二步,加入模板:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>为模型对应表增加记录</title>
</head>
<body>
<h2>请新增水果记录</h2>
<form method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="保存">
</form>
</body>
</html>
第三步,加入子路由:(必须使用as.view()实例化)
path('OK/',views.ShowOK,name='OK'),
path('c/',views.CreateView1.as_view())
第四步,加入总路由:
path('bg/',include('background.urls'))
最后,我们输入网址 http://127.0.0.1/bg/c/ 会出现 点我进入
更新记录类
UpdateView类用于通过表单界面为模型修改数据
使用前需要导入:
from django.views.generic.edit import UpdateView
第一步,在background/urls.py中加入:
class UpdateView1(UpdateView):
template_name ='UpdateView.html' #指定需要更新操作的模板名称
model =goods #指定需要更新的模板名
fields =['name','number','price'] #指定表单需要显示的字段
slug_field = 'name' #指定需要修改的数据的字段(比如姓名)
slug_url_kwarg ='name' #指定URL传递变量给slug_field,联合查询
context_object_name ='goods' #指定传递给模板的模型变量名
success_url ='../OK/' #指定提交成功路由
#注意了 我们在之前的代码中使用过了一次success_url = '.../OK/'
#因此,这里应该更改为 OK/ 否则还是使用 ../OK/ (开发中必须注意)
第二步,加入模板:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>更新记录视图类调用模板</title>
</head>
<body>
<h2>水果名为:{{goods.name}}</h2>
<form method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="更新">
</form>
</body>
</html>
第三步,加入子路由:(必须使用as.view()实例化)
from django.urls import path,re_path #多导入一个re_path
from . import views
path('cc/<name>',views.UpdateView1.as_view()),
第四步,加入总路由:
path('bg/',include('background.urls'))
最后,我们输入网址 http://127.0.0.1/bg/cc/香翅捞饭 会出现 点我进入
如果表中有两条同名的记录,会爆出异常,可以向URL中传递唯一的id字段值来解决
删除视图类
DeleteView用于删除模型的记录,使用前需要导入
from django.views.generic.edit import DeleteView
第一步,在background/urls.py中加入:
class DeleteView1(DeleteView):
template_name ='DeleteView.html' #指定需要删除操作的模板
model = goods #指定需要删除操作的模板名
context_object_name = 'goods' # 指定传递给模板的模型变量名
success_url = 'OK/' # 指定提交成功路由
第二步,加入模板:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>删除记录视图调用</title>
</head>
<body>
<form method="post">{% csrf_token %}
<p>需要删除该记录么?"{{ goods.name }}"?</p>
<input type="submit" value="删除提交">
</form>
</body>
</html>
第三步,加入子路由:(必须使用as.view()实例化)
path('<pk>.html',views.DeleteView1.as_view())
第四步,加入总路由:
path('bg/',include('background.urls'))
最后,我们输入 http://127.0.0.1/bg/1.html (序数代表商品的 id ):点我进入
我已经删除了第一二条记录啦!
内置日期视图类
Django支持7个内置日期视图类:
ArchiveView:
YearArchiveView(本章重点介绍):指定需要按年份查询的日期字段,把复合条件的表返回到网页中
使用前需要导入:
from django.views.generic.dates import YearArchiveView
第一步,我们在 background/model.py 下 新加入水果报废模型
class scrap(models.Model): #水果报废记录模型
idGoods = models.SmallIntegerField(primary_key=True)#商品ID号
name = models.CharField(max_length=20) #报废水果名
number = models.FloatField() #报废数量
price = models.DecimalField(max_digits=10, decimal_places=3)#报废价格
BackDate= models.DateTimeField() #报废时间
并且创建一些数据:(随便创建就行)
第二步,加入视图类
from django.views.generic.dates import YearArchiveView
from background.models import scrap
class YearView(YearArchiveView):
allow_empty = True #允许表单数据为空
allow_future = True #表示表单允许显示当前日期后面的日期记录
#model =scrap #指定模型
date_field = 'BackDate' #指定查找的日期字段
year_format = '%Y' #指定URL年份变量传递的格式为数字
queryset =scrap.objects.all() #查询模型的所有记录
#context_object_name ='T_scrap' #传递模型变量给模板
template_name = 'YearFindView.html' #指定模板
make_object_list = True #传递查询结果object_list变量给模板
#paginate_by =5 #指定5条记录为一页
第三部,建立模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>年查找视图</title>
</head>
<body>
<h1>水果退货记录</h1>
<h3>商品编号 水果名称 数量 单价 退货日期</h3>
<ul>
{% for date in object_list %}
<li>{{ date.idGoods }} {{ date.name}} {{ date.number}} {{ date.price}} {{ date.BackDate}}</li>
{% endfor %}
</ul>
</body>
</html>
第四步,完成子路由
path('aa/<int:year>.html',views.YearView.as_view())
我们可能要注释掉这个路由# path(‘/.html’,views.DetailView1.as_view(),name=‘One’),
第五步,完成总路由
path('bg/',include('background.urls')),
最后,输入网址http://127.0.0.1/bg/aa/2023.html 会返回:点我进入
前端集成Markdown格式文件
视图与数据库事务
事务为数据库同步多次访问操作提供安全可靠的操作的处理功能。使用 transaction模块 进行事务处理。使用前需要导入:
from django.db import transaction
from django.db.models import F
比如我们想要从一个表中 “拿出” 一些给另一个表,我们就可以使用事务操作。
第一步:我们先在 fruits/models,py中加入新的模型:
class Detail(models.Model): #明细表
name = models.CharField(max_length=20)
num = models.FloatField()
cost = models.DecimalField(max_digits=10, decimal_places=3)
别忘了把改变提交到数据库中去
python manage.py makemigrations fruits
python manage.py migrate
我们向数据库中加入一些数据:
现在,我们想要把 id=1 的 ikun1商品 放3个到上架表中
第二步,在 fruits/view.py 加入代码:
from fruits.models import Detail, goods #首先需要导入这两个模型
def trans1(request):
goNum=3 #上架商品的数量
try:
with transaction.atomic(): #使用事务
Detail.objects.filter(id=1).update(num=F("num")-goNum) #库存表中减少三个ikun1
goods.objects.create(name='ikun1',number=goNum,price=2) #上架表中转入3个 ikun1 商品
except Exception as e:
return HttpResponse("水果上架失败"+str(e))
return HttpResponse("水果上架成功!")
第三步,加入子路由:
path('t/',views.trans1)
第四步,加入总路由:
path('fruits/',include('fruits.urls')),
最后,输入网址http://127.0.0.1/fruits/t/查看:点我进入
现在我们查看数据库,Detail表中减少了三个数据
goods表新增了三个数据