WEB应用就是服务器上的程序,它接受客户端(浏览器)的请求,并响应请求发送字符串给客户端.
2.1socket套节字网络数据传输必须要用到socket,(其实本地电脑的应用程序和操作系统之间也需要socket)
2.2实例:一个简单的WEB应用程序
#一个简单的WEB应用程序importsocketsock=socket.socket()sock.bind(("127.0.0.1",8800))sock.listen(5)while1:print('serverwaiting......')conn,addr=sock.accept()data=conn.recv(1024)print('data',data)#conn.send(b"helloluffycity")#用浏览器访问时,显示该网页无法正常运作127.0.0.1发送的响应无效。ERR_INVALID_HTTP_RESPONSE.因为浏览器无法识别发过来的数据.conn.send(b"HTTP/1.1200OK\r\n\r\nhelloluffycity")#规范的WEB请求格式,浏览器的页面可以正常显示了.conn.close()一个简单的WEB应用程序三.WEB应用程序23.1发送字符串,让浏览器渲染出带html标签
的字符串
3.2WEB应用程序读取html文件,并发送到客户端,客户端浏览器进行渲染
4.1包含以下三个部分:
(每一个小块数据用\r\n区隔开)
a.请求首行包含:请求方式(get或post)请求路径(url)协议(HTTP/1.1)
b.请求头(若干个键值对)常包含:HostConnectioncontent-Type等
c.请求体连续两个\r\n后的就是请求体只有post请求才有请求体,get请求没有请求体
4..2请求数据实例
GET/HTTP/1.1\r\nHost:127.0.0.1:8899\r\nConnection:keep-alive\r\nUpgrade-Insecure-Requests:1\r\nUser-Agent:Mozilla/5.0(WindowsNT6.1;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/86.0.4240.75Safari/537.36\r\nAccept:text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\nSec-Fetch-Site:none\r\nSec-Fetch-Mode:navigate\r\nSec-Fetch-User:1\r\nSec-Fetch-Dest:document\r\nAccept-Encoding:gzip,deflate,br\r\nAccept-Language:zh-CN,zh;q=0.9\r\n\r\n'ViewCode
4.3get与post的使用区别
get一般应用于查询,post应用于更新数据库数据
只有POST请求才有请求体
服务器的接收到的请求(末尾黄色字是请求体,即浏览器用户输入的用户名和密码):
一个典型的服务器端post请求源代码
-get提交的数据会放在URL之后,以分割URL和传输数据,参数之间以&相连,如EditBookname=test1&id=123456.POST方法是把提交的数据放在HTTP包的请求体中.
-get提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制.
-get与post请求在服务端获取请求数据方式不同.
6.2响应格式(浏览器接收到服务器发来的信息)
6.3自定义响应头(黄色字符部分)
conn.send(b"HTTP/1.1200OK\r\nContent-Type:text\r\n\r\n%s"%data)
6.4响应状态码
状态码如200OK,以3位数字和原因成。数字中的一位指定了响应别,后两位无分。响应别有以5种。
重定向的解释:浏览器向服务器发送请求,服务器接收到后再发送响应信息给浏览器,该响应信息告诉浏览器需要(浏览器再发一次请求)转到另外一个资源.
-wsgi是接口协议
7.1wsgiref模块功能
-按照HTTP请求协议格式进行解包(解析数据)
-按照HTTP响应协议封装数据
-wgiref模块封装了socket
-让WEB应用开发者专注于WEB业务开发
-wsgiref做的简单的,根据用户不的输入,实现不同网页的效果
-路由的解释
9.1浏览器默认会发送图标请求
-此响应时,浏览器只接收图片,如果发送字符串,则字符串不会显示.
-其实也是解了耦合
增添功能,只需要修改路由文件,视图文件,模板等就可以了.
如果没有数据库,就没有什么意义.
大而全,组建特别多
14.1mvc和mtv模型(模型的主要目的是解耦合)
15.1cmd纯命令行,安装Django模块命令
pipinstallDjango#注意:Django首字母大写
如果提示pip错误,则先python.exe-mpipinstall--upgradepip,注意该命令前面不能带路径
15.2cmd纯命令行,在当前文件夹下创建一个mysite项目
django-admin.pystartprojectmysite#注意首字母d是小写
项目的文件夹树,manage.py为启动文件,相当于之前的main.py
manage.py----Django项目里面的工具,通过它可以调用djangoshell和数据库
settings.py----包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作的变量
urls.py----负责把URL模式映射到应用程序
15.3cmd纯命令行,在mysite目录下创建应用blog(注意:mysite是项目文件夹,blog是应用程序文件夹,一个项目中可以包含多个应用程序)
首先cdmysite文件夹,进入sysite项目根目录
然后pythonmanage.pystartappblog创建blog应用程序
下图为创建blog应用后的文件夹
下图为blog应用程序的文件结构
15.4cmd命令下,启动Django项目
pythonmanage.pyrunserver8000
16.1.1创建一个Django项目
16.1.2生成的一个fisrt_pro项目,新建一个app01程序的目录
16.1.3几个文件的代码
16.2Django服务(请求)执行过程(MPV过程)
---->1.urls.py(由它决定用户发送的路径交给哪个视图函数处理)---->2.views.py(主要逻辑处理)---->3.models.py(涉及到数据库的从这里取)---->4.timer.html(最终的返回页面的模板)---->
17.1什么叫静态文件
项目中的css,js都应当处理为静态文件.项目中的任何文件都需要Django去找,最终都是由客户端的浏览器去执行的,引入jquery-3.1.1.js时就需要注意文件路径问题(不能当成客户端的本地文件去执行),js文件需要写成服务器的地址.
17.2如何配置静态文件
在项目的根目录下创建static文件夹,所有静态文件都放入其中.此时通过客户端浏览器无法直接访问该文件,因为(Django采用虚拟文件夹的方式访问)客户端的所有访问路径都经过urls.py路由处理,而urls.py中没有添加关于js的路由.在settings.py中配置一下就可以通过别名访问了.配置方法在下面.
处理settings.py文件
STATIC_URL='/static/'#路径别名(虚拟目录),客户端浏览器输入地址(路径)可直接访问了STATICFILES_DIRS=[os.path.join(BASE_DIR,'statics'),#实际路径,这里是方便为了区分才使用statics这个名字,正式使用时,实际目录和别名都用static]模板文件引入jquery-3.5.1.js,文字点击变为红色效果timer.html
18.1html文件中引入css和js
css文件和js文件也是静态文件,需要放到项目中的static文件夹下,针对不同的应用可以在static文件夹下再建立应用的子文件夹,比如app01,将app01应用程序的css和js文件放到app01文件夹下.这里需要注意的是,在html中引入css\js文件时需要使用static静态目录.
文件目录如下:
19.1re_path模块,Django1版本的路由
路由配置:路径-------->视图函数
采用正则表达式re匹配路径,(路径中加括号的分组)
fromdjango.shortcutsimportrender,HttpResponse#HttpResponse#Createyourviewshere.deftimer(request):importtimectime=time.time()returnrender(request,'timer.html',{'ctime':ctime})defspecial_case_2003(request):returnHttpResponse("special_case_2003")defyear_archive(request,year):returnHttpResponse(year)defmonth_archive(request,year,month):returnHttpResponse(year+"-"+month)defarticle_detail(request,year,month,date):returnHttpResponse(year+"-"+month+"-"+date)视图View.py
19.2注意:
-若要从URL中获取一值,只需要在它周围放置一对圆括号.
-不需要添加一个前导的反斜杠,应为每个URL都有.例如,应该是^articles而不是^/articles.
-每个正则表达式前面的"r"是可选的,但建议加上.它告诉python这个字符串是"原始的"----字符串中任何字符都不应该转义.
20.1为路径中的分组起名字,关键字参数传参
全局urls.py和一个app应用程序的urls.py,文件结构
21.2两个URLS.py代码
全局urls.py中的关键代码
第二次是在login页面点击提交按钮,这是POST请求
#'django.middleware.csrf.CsrfViewMiddleware',
23.1用别名指代URL.在模板中进行反向解析
urls.py中,对于路径采用别名.应用场景:当产品经理要求更改访问路径的时候,只需要改urls.py中的路径名就可以了,其它文件无需改动.
使用urls.py中使用别名,增加参数name='别名',注意在模板文件中把action中的路径改为规定的格式{%url"别名"%}.views.py中的函数名称与别名要保持一致.
24.1在视图函数中进行反向解析
可以在后台获取到用户访问的完整路径
需要在视图函数中导入反向解析函数reverse,需要注意的是,如果urls.py路径中包含正则表达式,则需要在视图函数中增加args参数
/app/articles/2005/
25.1名称空间(namespace),也叫命名空间,是表示标示符的可见范围.
由于name没有作用域,Django在反解析URL时,会在项目全局顺序搜索,当查找到第一个name指定URL时,立即返回,我们在开发项目时,会经常使用name属性反解除URL,当不小心在不同的app的urls中定义相同的name时,可能会导致URL反解错误,为了避免这种事情发生,引入命名空间.
25.2实例
25.2.1使用pycharm的命令行窗口创建新应用app02
25.2.2创建新应用后的目录如下:
25.2.3为全局urls.py添加app02的路由分发
fromdjango.contribimportadminfromdjango.urlsimportpath,re_path,includefromappimportviews,urlsurlpatterns=[re_path(r'^app/',include("app.urls")),#分发到app中re_path(r'^app02/',include("app02.urls")),#分发到app02中]全局urls.py文件25.2.4为app02增加index视图
fromdjango.shortcutsimportrender,HttpResponse#Createyourviewshere.defindex(request):returnHttpResponse("index2")app02的views.py25.2.5为app02的urls.py增加index的路由解析
25.2.7为app应用添加index视图和路由,以及访问的效果.
25.2.8分别为app和app01下的两个index加别名
应用程序中的urls.py文件中路由解析
re_path('index/',views.index,name='index')
现在就有两个index,名字就重复了.
25.2.9两个index,反向解析,就出问题了.
先分别为两个app的views.py添加名称index的反向解析reverse('index')
分别访问两个index,反向解析路径,得到的路径是相同的,就出问题了.(覆盖了)
25.2.10下面解决名称相同,的反向解析相同的问题
25.2.11在全局urls.py中给include()路由分发添加名称空间namespace
urlpatterns=[path('admin/',admin.site.urls),path('timer/',views.timer),re_path('login.html',views.login,name='login'),re_path(r'^app/',include(("app.urls","app"))),#名称空间namespace="app"注意这里增加了一个元组re_path(r'^app02/',include(("app02.urls","app02"))),#名称空间namespace="app02"]全局urls.py25.2.12再给两个app的views.py文件中的反向解析添加上namespace的名称
27.1django2.0的path.re_path是django1.0版本的语法
re_path传的值是字符串,如果要使用数字,还需要进行转换.path方法就是解决这类问题而生的.
urlpatterns=[path('admin/',admin.site.urls),path('timer/',views.timer),path('login/',views.login),path("articles/
27.2path的5个转化器
str,匹配除了路径分隔符/之外的非空字符串,这是默认的形式
int,匹配正整数,包含0
slug,匹配字母,数字以及横杆,下划线组成的字符串
uuid,匹配格式化的uuid,如075194d3-6885-417e-a8a8-6c931e272f00
path,匹配任何非空字符串,包含了路径分隔符
28.1对于一些复杂或者复用的需要,可以定义自己的转化器.转化器是一个类或接口,它的要求有三点:
28.2自定义path转化器应用实例.(使用register_converter将其注册到URL配置中)
29.2有名分组按关键字传参
29.3分发include
29.4反向解析利用别名
29.5名称空间
29.6path
30.1在视图函数中获取用户的请求数据
先关闭settings.py中的一项设置项目才可正常运行
获取到的get请求数据,是个字典格式.
获取值:
request.GET.get("name")request.POST.get("name")
re_path("^$",views.index)或者path(r"",views.index),
30.3方法request.get_full_path(),获取完成的路径可保护get数据
下面来看看两个区别:
print(request.path)#只能获取路径
print(request.get_full_path())#路径+get请求的数据
后台显示结果:
31.1最终都是返回HttpResponse(),render()也会转化为HttpResponse()
31.1.1HttpResponse("
ok
")31.1.2render(request,"index.html",{"变量名":变量值})#把变量传递给模板,注意书写字典格式
模板文件index.html中使用{{变量名}}#模板语法,注意书写格式,双大括号
32.1字典,列表,对象,字符串,等更丰富的数据类型怎么嵌入到模板中
模板语法:渲染变量用{{}}用句点符深度查询,过滤器
渲染标签用{%%}
使用句点符达到的效果就是从字典,列表等数据中再获取指定位置的值
把视图中的变量按照某种形式在模板中渲染出来
33.1语法:
{{obj|filter_name:param}}33.2日期过滤器date
视图文件代码:
importdatetime
date=datetime.datetime.now()
模板文件代码:
{{date}}
显示效果:Jan.17,2021,1:06p.m.(显示的不友好){{date|date:'Y-m-d'}}
显示效果:2021-01-17这里date|date,两个date后面一个date是过滤器名称下图为显示效果对比:
33.3default过滤器,默认在数据为空的情况下的显示内容
视图文件代码:name_list=[]列表值为空
模板文件代码:
{{name_list}}
显示效果:[]{{name_list|default:"姓名数据为空"}}
显示效果:姓名数据为空33.4length过滤器,返回值的长度
{{value|length}}如果value是['a','b','c'],那么输出是3
33.5filesizeformat,将值格式化为一个"人类可读"文件尺寸.主要用于显示文件的大小
{{value|filesizeformat}}如果value是123456789,输出将会是117.7MB
33.6slice过滤器,将字符串切片
{{value|slice:"2:-1"}}如果value="helloword",将输出llowor
33.7truncatechars,截断过滤器,如果字符串字符多余指定的字符数量,那么会被截断.截断的字符串将以可翻译的省略号序列"..."结尾
{{value|truncatechars:9}}参数9,就是要显示(截断)的字符数包含...一共是9个字符,(注意一个字母就是一个字符)
{{hello_str|truncatewords:1}}truncatewords参数3,表示显示的单词数量,不包含...(注意hello表示一个单词)
下图为显示效果:
33.8safe过滤器,强调不转义,用在变量是html标签时
33.9add加法过滤器
{{l.0|add:100}}如果l.0=100,那么输出200
33.10upper转大写过滤器
{{name|upper}}如果name="hao",那么输出HAO
34.1标签看起来像这样的:{%tag%}.标签比变量更加复杂:一些在输出中创建文本,一些通过循环或逻辑来控制流程,一些加载其后的变量将使用到的额外信息到模板中.一些标签需要开始和结束标签(例如{%tag%}...标签内容...{%endtag%})
34.2最少需要掌握for标签和if标签
34.3for循环标签
遍历每一个元素:
{%forpersoninperson_list%}
{{person.name}}
{%endfor%}可以利用{%forobjinlistreversed%}反向完成循环。遍历一个字典:
{%forkey,valindic.items%}
{{key}}:{{val}}
{%endfor%}如果{%forkeyindic%}则只遍历key注:循环序号可以通过{{forloop}}显示
34.4for...empty数据为空时的处置.为空的时候不会渲染.当使用for...empty时就可以渲染指定的内容.
for标签带有一个可选的{%empty%}从句,以便在给出的组是空的或者没有被找到时,可以有所操作。
{%forpersoninperson_list%}
{{person.name}}
{%empty%}sorry,nopersonhere
{%endfor%}34.5if标签{%if%}会对一个变量求值,如果它的值是“True”(存在、不为空、且不是boolean类型的false值),对应的内容块会输出。
34.6with标签,把长名字缩减成短名字
{%withperson_list.1.nameasn%}
{{n}}使用n就相当于用person_list.1.name,当深度查询非常长的时候用
{%endwith%}
使用一个简单地名字缓存一个复杂的变量,当你需要使用一个“昂贵的”方法(比如访问数据库)很多次的时候是非常有用的
例如:
{%withtotal=business.employees.count%}{{total}}employee{{total|pluralize}}{%endwith%}34.7csrf_token这个标签用于跨站请求伪造保护
此功能与全局settings.py中的'django.middleware.csrf.CsrfViewMiddleware'有关系
在表单的post提交中会出现下面的提示Forbidden(403):
如果在模板中添加csrf_token就不会出现Forbidden(403)错误了.
34.1自定义标签与过滤器,流程固定,背下来
1、在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag.
2、在app中创建templatetags模块(模块名只能是templatetags)
3、创建任意.py文件,如:my_tags.py
4、在使用自定义simple_tag和filter的html文件中导入之前创建的my_tags.py
5、使用simple_tag和filter(如何调用)
注意:filter可以用在if等语句后,simple_tag不可以
34.2实例自定义乘法过滤器
34.2.1在settings.py中配置app
34.2.2在app中创建templatetags模块(模块名只能是templatetags)
34.2.3创建my_tag_filter.py文件,目录如下:
fromdjangoimporttemplateregister=template.Library()@register.filterdefmulti_filter(x,y):#自定义乘法过滤器returnx*y34.2.4在使用自定义multi_filter的html文件中导入之前创建的my_tag_filter.py
{%loadmy_tag_filter%}34.2.5使用自定义multi_filter(如何调用)
36.1{%include'advertise.html'%}在html模板文件中嵌入其它html模板文件
两个父子模板文件在目录中的位置
在index.html文件中的左侧嵌入advertise.html
advertise.html文件全部代码
最终效果,左侧三个面板为{%include'advertise.html'%}嵌入的内容:
建立一个新页面order.html该页面想和前面的index.html拥有相同的头部和左侧面板,这就用到了继承.
新建base.html基础模板页面,作为父页面,复制index.html中的内容到该业中,该页面中,包含css,头部和左侧面板,内容部分被删除,代替以block盒子{%blockcon%}在这个中间加入该页面独特内容{%endblock%},代码如下:
{#继承自base.html,包含头部,左侧等内容#}{%extends'base.html'%}{%blockcon%}{#index.html页面独特的内容#}
首页内容区域
首页内容区域
首页内容区域
首页内容区域
首页内容区域
首页内容区域
首页内容区域
首页内容区域
{%endblock%}index.html新建订单页面orders.html,继承base.html页面,{%extends'base.html'%}{%blockcon%}
订单页面
订单页面
订单页面
订单页面
订单页面
订单页面
订单页面
{%endblock%}orders.html可以在base.html页面中留多个盒子,甚至36.4注意事项
37.1Django的几大部分
url控制器,视图部分,模板部分,模型层
37.2模型层用于和数据库打交道.ORM就是用来控制数据库的.
ORM直接把python中的类转换为(翻译)mysql语句,以后我们直接编写Python类就可以控制数据库了.
注意ORM只能对表做操作,不能对库做操作.
38.1使用pycharm创建app01和orm数据库的Book表
38.1.1使用pycharm新建orm项目app01应用程序,使用cmd命令行创建orm数据库
cmd下连接mysql,进入mysql命令提示符,输入创建orm库的命令,完成数据库创建.
createdatabaseorm;
38.1.2在orm文件夹下的settings.py中修改DATABASES数据库设置如下:
importpymysqlpymysql.version_info=(1,4,13,"final",0)#防止Django版本引起错误pymysql.install_as_MySQLdb()orm下__init__.py文件中添加pymysql模块38.1.4在app01应用程序目录下的models.py文件中建立表的结构
pythonmanage.pymakemigrations#依照models.py中的类创建出表,创建迁移表
pythonmanage.pymigrate#迁移
38.1.6创建出的表,查看效果如下:
38.1.7如果想在orm转换过程中把对应的sql语句输出在后台,需要在settings中进行如下配置:
LOGGING={'version':1,'disable_existing_loggers':False,'handlers':{'console':{'level':'DEBUG','class':'logging.StreamHandler',},},'loggers':{'django.db.backends':{'handlers':['console'],'propagate':True,'level':'DEBUG',},}}ViewCode
39.1ORM主要用于增删改查数据记录
两种方法,一种是实例化类,一种的类的.objects.create方法
fromdjango.shortcutsimportrender,HttpResponsefromapp01.modelsimportBook#引入创建的表的类#Createyourviewshere.defindex(request):#添加表记录方法一#book_obj=Book(id=1,title='python红宝书',price=100,pub_date='2012-12-12',publish='人民出版社')#实例化Book对象#book_obj.save()#实例化对象的方法时,只有save一下数据才会保存到数据库中#添加表记录方法二book_obj=Book.objects.create(title='linux从入门到精通',price=80,pub_date='2013-01-25',publish='人民邮电出版社')#此种方法无需再用saveprint(book_obj.title)#.objects方法创建的,带有返回值,可以将值打印出来.print(book_obj.price)print(book_obj.pub_date)print(book_obj.publish)returnHttpResponse("ok")app01下的views.py
40.1单表查询接口,需要了解清楚的
QuerySet数据类型,Django特有的数据类型,该类型有点像列表,可以想列表一样来处理QuerySet,支持索引,支持for循环
弄清楚查询表的接口的,1每个方法的返回值2以及每个方法是谁来调用的
在app01下的models.py中的Book类中添加def__str__(self)方法用于print打印指定的数据
#app01下的models.pyfromdjango.dbimportmodels#Createyourmodelshere.classBook(models.Model):id=models.AutoField(primary_key=True)title=models.CharField(max_length=32)pub_date=models.DateField()price=models.DecimalField(max_digits=8,decimal_places=2)publish=models.CharField(max_length=32)def__str__(self):#此处功能是,在执行print命令时显示对象的titlereturnself.titleapp01下的models.py
40.2all方法:返回值是一个queryset对象,该方法由Book.objects管理器直接调用
all方法返回全部数据,all方法源代码:
fromdjango.shortcutsimportrender,HttpResponsefromapp01.modelsimportBook#Createyourviewshere.defindex(request):#查询表记录,all方法book_qs=Book.objects.all()print(book_qs)print('-')#遍历forobjinbook_qs:print(obj.title,obj.price)#输出书名,和价格print('-')#索引访问print(book_qs[1].title)#输出第二本书书名returnHttpResponse('OK')app01下的views.py后台输出效果:
40.3firsh,last方法,调用者是queryset对象,返回值是一个model对象
#查询记录,first,last方法,调用者是queryset对象,返回值是一个model对象book_obj=Book.objects.all().first()book_obj=Book.objects.all()[0]#和上面的等价book_obj=Book.objects.last()ViewCode40.4filter()筛选(过滤),根据条件筛选,返回值:queryset对象.该方法与all()方法类似.filter()方法也可以调用first()方法
#查询记录,filter()筛选,返回:queryset对象#filter()与all()的差别就是多个筛选条件,别的都一样.book_list=Book.objects.filter(price=80)#筛选出价格是80的所有记录print(book_list)#[obj1,obj2,...]book_obj=Book.objects.filter(price=80).first()ViewCode40.5get()有且只有一个查询结果时才有意义,有多个结果或没有查到时会报错.返回值:models对象
#查询记录,get()有且只有一个查询结果时才有意义,返回值:model对象book_obj=Book.objects.get(price=100)#book_obj=Book.objects.get(price=80)#因为有两本书价格是80,所以浏览器上会显示报错信息print(book_obj.title)ViewCode40.6本节app01下的views.py完整代码,包含上面4个常用的查询方法
41.1exclude()排除,方法,相当于!=不等于,所有符合条件的,然后取反.与filter()方法相反.注意:可以设置多个条件(多个条件是与的关系)
返回值是一个queryset对象,该方法由Book.objects管理器直接调用
#exclude()排除,返回值是:queryset对象.调用者:Book.objects管理器book_list=Book.objects.exclude(title='php',price=80)#可以设置多个排除条件,多个条件是与关系,也就是同时满足.filter()方法也是可以设多个条件的.print(book_list)ViewCode41.2order_by()排序,调用者:queryset对象,返回值:queryset对象
#order_by()排序ret=Book.objects.all().order_by('id')#按ID升序排列ret=Book.objects.all().order_by('-id')#条件前面加负号,按ID降序排列ret=Book.objects.all().order_by('price','id')#先按照price排序,如何price一样,则按照id排序print(ret)ViewCode41.3count()计数,调用者:queryset对象,返回值:int类型
#count()ret=Book.objects.all().count()print(ret)ViewCode41.4exist()判断表是否为空,调用者:queryset对象,返回值:布尔值True,False
#exist()判断是否为空#ret=Book.objects.all()#这种判断是否为空的方法太消耗资源(执行查询全部数据)ret=Book.objects.all().exists()#exists()方法只查询表中的一条记录,所以节约资源ifret:print('ok')ViewCode41.5queryset对象支持链式,多个方法串起来
42.1values()方法,获取对象中每个元素的值,输出列表套字典,返回值:queryset类型,调用者:queryset类型
ret=Book.objects.all().values("price")#values方法获取每个元素的值,默认可以省略all(),写成Book.objects.values("price")print(ret)print(ret[0].get('price'))#输出:
#values_list()方法ret=Book.objects.all().values_list('price')#这里只演示了一个price字段,可以有多个字段,values()方法也可以有多个字段print(ret)#输出:
#distinct()去重,返回值:queryset类型,调用者:queryset类型ret=Book.objects.all().values('price').distinct()#获得图书的价格,去除相同价格的.print(ret)#输出:
注意该方法需要配合order_by()方法使用,该方法是个鸡肋.这个方法只有在已经定义顺序的queryset上调用,才能对结果反向排序
#reverse()反向排序,鸡肋方法,没什么鸟用.ret=Book.objects.all().filter(price=80).order_by('id')ret2=Book.objects.all().filter(price=80).order_by('id').reverse()print(ret)print(ret2)ViewCode
42.4queryset对象支持链式,多个方法串起来
Book.objects.all().filter().order_by().filter().reverse().first()
大于小于的时候就需要用模糊查询,用双下划线.注意得到的仍然是queryset类型
43.1参数price__gt=80表示价格大于80
参数price__lt=200表示价格小于200
ret=Book.objects.filter(price__gt=80,price__lt=200)#查询价格大于80,且小于200的图书print(ret)ViewCode43.2参数title__startswith='py'表示标题以py开头的
参数title__contains='h'表示标题中包含字母h的
参数title__icontains='h'表示标题中包含字母h的,不区分大写
ret=Book.objects.filter(title__startswith='py')#查询书名以py开头的所有书ret=Book.objects.filter(title__contains='h')#查询书名中包含h的所有书ret=Book.objects.filter(title__icontains='h')#查询书名中包含h的所有书,不区分大小写print(ret)ViewCode43.4参数price__in=[80,100,200]表示只要是价格等于80或100或200
参数price__range=[80,100]查询价格在80到100之间的,包含80和100
ret=Book.objects.filter(price__in=[80,100,200])#查询只要是价格等于80或100或200的ret=Book.objects.filter(price__range=[80,100])#查询价格在80到100之间的,包含80和100print(ret)ViewCode43.5参数pub_date__year=2018查询日期是2018年的,月份和日随意,只有日期类型有此参数
参数pub_date__month=5查询月份是5月的.
ret=Book.objects.filter(pub_date__year=2021,pub_date__month=1)#查询年份是2018且月份是1月的print(ret)ViewCode43.6不止以上的这些个参数哦
44.1delete()方法,删除记录.返回值是删除的数据条数
delete()方法的调用对象是queryset对象,model对象也可以调用它.
#删除记录#ret=Book.objects.filter(price=100).delete()#queryset对象调用delete()#print(ret)#返回值:(1,{'app01.Book':1})Book.objects.filter(price=80).first().delete()#model对象调用delete()ViewCode44.2update()方法,修改记录.update()的调用者只能是queryset对象.
#修改记录Book.objects.filter(title='PHP').update(title='php零基础入门')#注意,筛选出多少条记录,就会修改多少条.返回值是条数ViewCode
系统功能简介:可以新建图书,查看图书数据,删除图书,修改图书信息.
1.建立数据库的表结构,即在models.py文件中设计Book表的结构,只要创建一个pythonBook类就可以了.
2.迁移数据库,即通过pycharm底部Terminal的,输入两条迁移命令.这里数据库使用了Django的默认sqlite3数据库.迁移完成后能看到在根目录中创建了db.sqlite3的数据库文件,pycharm窗口的的右侧可以打开查看db.效果如下,book表结构清晰可见:
3.由于本系统需要用到bootstrap等,所以需要对文件目录进行修改
3.1新增静态目录(包)static,用于存放bootstrap,在settings.py中增加static的设置
3.2复制bootstrap到static目录中
4.由于数据库中暂时没有数据,所有,下面,进行'新增图书'的设计.
4.1建立'新增图书的'路由设置
4.2建立'新增图书'的视图创建
4.3创建'新增图书'的模板,注意在表单部分的最前面增加{%csrf_token%},防止跨域403错误
模板注意使用class="container"制作外框,class="row"class="col-md-6col-lg-push-3(右移3)"建立模型
5.所有'图书'信息查看的设计,基本步骤和4一致.注意图书出版日期的显示{{book.pub_date|date:'Y-m-d'}}
6.'删除'功能.注意.注意路由设计re_path(r'books/(\d+)/delete/',views.delbook),
7.修改功能,注意点和6一样
8.完整代码:
51.1多表,为啥要用多个表
避免存储大量重复数据.把大表拆成多个表.
51.2一对多表,一个出版社对应多本书.
51.3总结:一旦确定表关系是一对多:创建关联字段,上图的publish_id是关联字段,创建关联字段要在多的表中
52.1多对多表,一本书对应多个作者,一个作者对应多本书.
52.2总结:一旦确定表关系是多对多:要创建第三张关系表,如上图Book2Author
53.1一对一表,本质是把一张表中的几个字段抽离出来组建一个新表.
一对多与一对一的差别.一对一的关联字段加上unique约束.关联字段放在哪张表都可以.
53.2总结:一旦确定是一对一的关系:在两张表中的任意一张表中建立关联字段+unique
建关联关系是为了查询,建约束关系是为了维护数据的完整.
约束关系存在的目的,删除被关联表的一条数据,如果两表只有关联字段,无约束关系,则会直接删除.如果有约束关系,则无法直接删除,会有提示,无法删除.
如上表,如果删除publish表中的第1条数据,则再查下时将无法查出php书籍的出版社信息.所以增加了约束关系,使得操作者无法随意删除.
若只有关联关系而无约束关系,就可以直接删除.
上图的publsish_id字段是两表的关联字段,上图的foreignkey就是建立约束关系