web框架概念

框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构,使用框架可以帮你快速开发特定的系统。

对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。

  1. import socket
  2.  
  3. def handle_request(client):
  4.  
  5. buf = client.recv(1024)
  6. client.send("HTTP/1.1 200 OK\r\n\r\n".encode("utf8"))
  7. client.send("<h1 style='color:red'>Hello, yuan</h1>".encode("utf8"))
  8.  
  9. def main():
  10.  
  11. sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  12. sock.bind(('localhost',8001))
  13. sock.listen(5)
  14.  
  15. while True:
  16. connection, address = sock.accept()
  17. handle_request(connection)
  18. connection.close()
  19.  
  20. if __name__ == '__main__':
  21.  
  22. main()

socket模拟服务端

最简单的Web应用就是先把HTML用文件保存好,用一个现成的HTTP服务器软件,接收用户请求,从文件中读取HTML,返回。

  如果要动态生成HTML,就需要把上述步骤自己来实现。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。

正确的做法是底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档。因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口,让我们专心用Python编写Web业务。这个接口就是WSGI:Web Server Gateway Interface。

web框架概念解析

step1

  1. from wsgiref.simple_server import make_server
  2. #environ是用户请求的数据头
  3. def application(environ, start_response): #执行返回状态码和返回的配置信息,最后return的是浏览器真正渲染的数据
  4. start_response('200 OK', [('Content-Type', 'text/html')])
  5. return [b'<h1>Hello, web!</h1>']
  6. httpd = make_server('', 8080, application)
  7. print('Serving HTTP on port 8000...')
  8. # 开始监听HTTP请求:
  9. httpd.serve_forever()

最最基本的wsgi实现

  1. 整个application()函数本身没有涉及到任何解析HTTP的部分,也就是说,底层代码不需要我们自己编写,
  2. 我们只负责在更高层次上考虑如何响应请求就可以了。
  3.  
  4. application()函数必须由WSGI服务器来调用。有很多符合WSGI规范的服务器,我们可以挑选一个来用。
  5.  
  6. Python内置了一个WSGI服务器,这个模块叫wsgiref
  7.  
  8. application()函数就是符合WSGI标准的一个HTTP处理函数,它接收两个参数:
  9.  
  10. //environ:一个包含所有HTTP请求信息的dict对象;
  11.  
  12. //start_response:一个发送HTTP响应的函数。
  13.  
  14. application()函数中,调用:
  15.  
  16. start_response('200 OK', [('Content-Type', 'text/html')])
  17.  
  18. 就发送了HTTP响应的Header,注意Header只能发送一次,也就是只能调用一次start_response()函数。
  19. start_response()函数接收两个参数,一个是HTTP响应码,一个是一组list表示的HTTP Header,每
  20. Header用一个包含两个strtuple表示。
  21.  
  22. 通常情况下,都应该把Content-Type头发送给浏览器。其他很多常用的HTTP Header也应该发送。
  23.  
  24. 然后,函数的返回值b'<h1>Hello, web!</h1>'将作为HTTP响应的Body发送给浏览器。
  25.  
  26. 有了WSGI,我们关心的就是如何从environ这个dict对象拿到HTTP请求信息,然后构造HTML
  27. 通过start_response()发送Header,最后返回Body

python实现wsgi说明

step2

  1. from wsgiref.simple_server import make_server
  2.  
  3. def application(environ,start_response):
  4. path=environ.get("PATH_INFO")
  5. #取出来的是url的路径
  6. print("path",path)
  7. start_response("200 OK",[("ontent-Type","text/html")])
  8.  
  9. #根据url访问路径进行http路由
  10. if path=="/bob":
  11. f=open("index1.html","rb")
  12. data=f.read()
  13. f.close()
  14. return [data]
  15. elif path=="/hurry":
  16. f=open("index2.html","rb")
  17. data=f.read()
  18. f.close()
  19. return [data]
  20. else:
  21. return [b""]
  22.  
  23. httpd=make_server("",8080,application)
  24. httpd.serve_forever()

wsgi实现的http路由

step3

  1. from wsgiref.simple_server import make_server
  2.  
  3. def login(request):
  4. f = open("login.html", "rb")
  5. data = f.read()
  6. f.close()
  7. return [data]
  8. def auth(request):
  9. #取出来用户名进行判断
  10. user_union,pwd_union=request.get("QUERY_STRING").split("&")
  11. _,user=user_union.split("=")
  12. _,pwd=pwd_union.split("=")
  13. print(user,pwd)
  14. if user=="chen" and pwd=="":
  15. return [b"wo ai ni"]
  16. else:
  17. return [b"who are you"]
  18.  
  19. def bob(request):
  20. f = open(r"index1.html", "rb")
  21. data = f.read()
  22. f.close()
  23. return [data]
  24. def hurry(request):
  25. f = open("index2.html", "rb")
  26. data = f.read()
  27. f.close()
  28. return [data]
  29.  
  30. def routers():
  31. URLpattern=(
  32. ("/login",login),
  33. ("/auth",auth),
  34. ("/bob",bob),
  35. ("/hurry",hurry)
  36. )
  37. return URLpattern
  38.  
  39. def application(environ,start_response):
  40. path=environ.get("PATH_INFO")
  41. print("path",path)
  42. start_response("200 OK",[("ontent-Type","text/html")])
  43. urlpattern=routers()
  44. func=None
  45. for item in urlpattern:
  46. if path==item[0]:
  47. func=item[1]
  48. break
  49. if func:
  50. return func(environ)
  51. else:
  52. return [b""]
  53.  
  54. httpd=make_server("",8080,application)
  55.  
  56. httpd.serve_forever()

wsgi实现的简单登录1

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <!--<script src="../2017.8.14/jquery-3.2.1.js"></script>-->
  7. </head>
  8. <body>
  9. <div>
  10. <form action="http://127.0.0.1:8080/auth">
  11. <div>用户:<input type="text" name="user"></div>
  12. <div>密码:<input type="password" name="pwd"></div>
  13. <button type="submit">提交</button>
  14. </form>
  15.  
  16. </div>
  17.  
  18. </body>
  19. </html>

login.html

step4

进行模块化

  1. from wsgiref.simple_server import make_server
  2. from views import *
  3. import urls
  4.  
  5. def routers():
  6.  
  7. urls.URLpattern
  8.  
  9. return URLpattern
  10.  
  11. def application(environ,start_response):
  12.  
  13. path=environ.get("PATH_INFO")
  14. print("path",path)
  15. start_response('200 OK', [('Content-Type', 'text/html'),('Charset', 'utf8')])
  16.  
  17. urlpattern=routers()
  18. func=None
  19.  
  20. for item in urlpattern:
  21. if path==item[0]:
  22. func=item[1]
  23. break
  24.  
  25. if func:
  26.  
  27. return func(environ)
  28.  
  29. else:
  30. return [b""]
  31.  
  32. #return [b"<h1>hello world<h1>"]
  33.  
  34. if __name__ == '__main__':
  35.  
  36. t=make_server("",8800,application)
  37. t.serve_forever()

bin文件主运行文件

  1. def foo1(request):
  2. f = open("templates/bob.html", "rb")
  3. data = f.read()
  4. f.close()
  5.  
  6. return [data]
  7.  
  8. def foo2(request):
  9. f = open("templates/hurry.html", "rb")
  10.  
  11. data = f.read()
  12. f.close()
  13.  
  14. return [data]
  15.  
  16. def login(request):
  17. f = open("templates/login.html", "rb")
  18.  
  19. data = f.read()
  20. f.close()
  21.  
  22. return [data]
  23.  
  24. def reg(request):
  25. pass
  26.  
  27. def auth(request):
  28.  
  29. print("+++++",request)
  30.  
  31. user_union,pwd_union=request.get("QUERY_STRING").split("&")
  32. _,user=user_union.split("=")
  33. _,pwd=pwd_union.split("=")
  34.  
  35. if user=='yuan' and pwd=="":
  36. return ["登录成功".encode("utf8")]
  37.  
  38. else:
  39. return [b"user or pwd is wrong"]

views文件存放函数

  1. from views import *
  2. URLpattern = (
  3. ("/login", login),
  4. ("/auth", auth),
  5. ("/bob", foo1),
  6. ("/hurry", foo2),
  7. ("/reg", reg),
  8.  
  9. )

url文件存放路由

  1. #bob.html
  2. <!DOCTYPE html>
  3. <html lang="en">
  4. <head>
  5. <meta charset="UTF-8">
  6. <title>Title</title>
  7. </head>
  8. <body>
  9. <h1> Welcome Bob</h1>
  10. </body>
  11. </html>
  12.  
  13. #hurry.html
  14. <!DOCTYPE html>
  15. <html lang="en">
  16. <head>
  17. <meta charset="UTF-8">
  18. <title>Title</title>
  19. </head>
  20. <body>
  21. <h1> Welcome Hurry</h1>
  22. </body>
  23. </html>
  24.  
  25. #login.html
  26. <!DOCTYPE html>
  27. <html lang="en">
  28. <head>
  29. <meta charset="UTF-8">
  30. <title>Title</title>
  31. </head>
  32. <body>
  33. <h2>登录页面</h2>
  34. <form action="http://127.0.0.1:8800/auth">
  35. <p>姓名<input type="text" name="user"></p>
  36. <p>密码<input type="password" name="pwd"></p>
  37. <p>
  38. <input type="submit">
  39. </p>
  40. </form>
  41. </body>
  42. </html>

templates文件夹存放html文件

MVC和MTV模式

web框架:MVC(model view controller)和MTV(model templates view controller)

Django的MTV模式本质是各组件之间为了保持松耦合关系,Django的MTV分别代表:

Model(模型):负责业务对象与数据库的对象(ORM)

Template(模版):负责如何把页面展示给用户

View(视图):负责业务逻辑,并在适当的时候调用Model和Template

此外,Django还有一个url分发器,它的作用是将一个个URL的页面请求分发给不同的view处理,view再调用相应的Model和Template

  1. MVC 是一种使用 MVCModel View Controller 模型-视图-控制器)设计创建 Web 应用程序的模式:[1]
  2. Model(模型)表示应用程序核心(比如数据库记录列表)。
  3. View(视图)显示数据(数据库记录)。
  4. Controller(控制器)处理输入(写入数据库记录)。

mvc补充

注:用户的一次web请求,顺序:用户-服务器-web应用

Django基本命令

Django项目管理

创建Django项目
  1. django-admin startproject mysite

在当前目录生成mysite的项目,目录结构如下:

  • manage.py ----- Django项目里面的工具,通过它可以调用django shell和数据库等。
  • settings.py ---- 包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作的变量。
  • urls.py ----- 负责把URL模式映射到应用程序。
  • wsgi.py----默认测试用的web服务器
创建应用
  1. python manage.py startapp blog

进入到mysite目录创建应用

主要是models和views文件

启动项目
  1. python manage.py runserver 8000

默认启动的端口就是8000,访问:http://127.0.0.1:8000/

项目与应用:
  一个项目有多个应用
  一个应用可以被多个项目拥有

第一个Django项目

step1:urls.py文件,增加路由信息

  1. from django.conf.urls import url
  2. from django.contrib import admin
  3. from blog import views #导入
  4. urlpatterns = [
  5. url(r'^admin/', admin.site.urls),
  6. url(r'^$', views.index), #增加
  7. url(r'^index$', views.index), #增加
  8. ]

新增路由

step2:views.py修改视图函数

  1. from django.shortcuts import render,HttpResponse #导入
  2. # Create your views here.
  3.  
  4. def index(request): #request参数名字无所谓,必须要有一个参数
  5. return HttpResponse('INDEX')

新增视图函数

step3:访问

http://127.0.0.1:8080/

http://127.0.0.1:8080/index/

注:其他命令,用到时候补充

Django框架: 大而全

Flask框架: 小而精

同步更改数据库表或字段
  1. python manage.py syncdb
  2.  
  3. 注意:Django 1.7.1 及以上的版本需要用以下命令
  4. python manage.py makemigrations
  5. python manage.py migrate

这种方法可以创建表,当你在models.py中新增了类时,运行它就可以自动在数据库中创建表了,不用手动创建。

清空数据库
  1. python manage.py flush
  2. #此命令会询问是 yes 还是 no, 选择 yes 会把数据全部清空掉,只留下空表。
创建超级管理员
  1. python manage.py createsuperuser
  2. # 按照提示输入用户名和对应的密码就好了邮箱可以留空,用户名和密码必填
  3. # 修改 用户密码可以用:
  4. python manage.py changepassword username
终端环境
  1. python manage.py shell
  2. #这个命令和 直接运行 python 进入 shell 的区别是:你可以在这个 shell 里面调用当前项目的 models.py 中的 API,对于操作数据的测试非常方便。
数据库环境终端
  1. python manage.py dbshell
  2. Django 会自动进入在settings.py中设置的数据库,如果是 MySQL postgreSQL,会要求输入数据库用户密码。
  3.  
  4. 在这个终端可以执行数据库的SQL语句。如果您对SQL比较熟悉,可能喜欢这种方式。
更多命令
  1. python manage.py

路由分配系统

路由介绍

Django的路由分配系统,就是指的controller

功能:客户端访问的url的路径(path)与视图函数一一映射关系,通过唯一的路径访问到唯一的函数

语法:

  1. urlpatterns = [
  2. url(正则表达式, views视图函数,参数,别名),
  3. ]
  4. #参数说明:
  5. #一个正则表达式字符串,进行url路径匹配
  6. #一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
  7. #可选的要传递给视图函数的默认参数(字典形式)
  8. #一个可选的name参数

URLconf的正则表达式参数

参考python的正则表达式,该参数只会匹配路径,并不会匹配路径后的方法,而匹配到的参数或捕获到的值,永远为字符串

示例:

  1. urlpatterns = [
  2. url(r'^admin/', admin.site.urls), #admin/开头的
  3. url(r'^$', views.index), #匹配不带路径的
  4. url(r'^index$', views.index), #完全匹配index
  5. #url(r'index', views.index), #只要带index的
  6. url(r'^(\d{4})/$', views.show_year), #无名分组
  7. url(r'^(?P<year>\d{4})/(?P<month>\d{2})/$', views.year_month), #命名分组
  8. ]

当匹配成功的时候,会调用视图函数中的一系列函数,即views.py文件中的一些列函数,这些函数默认会传入一个请求头消息,所以这些函数必须要有一个参数进行数据接收。

正则匹配注意事项:

  1. 1、一旦匹配成功则不再继续下一条路由的匹配
  2. 2、若要从URL中捕获一个值,只需要在它周围放置一对圆括号,即分组的方式
  3. 3、不需要添加一个前导的反斜杠,因为每个URL都有。例如,应该是^path 而不是 ^/path
  4. 4、每个正则表达式前面的'r'是可选的但是建议加上,因为匹配时候可能会出现元字符
  1. #设置项是否开启URL访问地址后面不为/跳转至带有/的路径
  2. APPEND_SLASH=True
  3. #Django的seetings.py配置文件中默认没有 APPEND_SLASH这个参数,但Django默认这个参数为APPEND_SLASH=True

是否自动补全url中最后的/

无名分组匹配/h5>

当输入http://127.0.0.1:8000/2014/的时候,会匹配示例中的无名分组

views.show_year视图函数

  1. def show_year(request,year): #无名分组会将括号里面匹配到的值自动传入到对应的视图函数中,所以,视图函数必须要有一个参数接收值
  2. return HttpResponse(year)
命名分组匹配

当输入http://127.0.0.1:8000/2014/12/时候,会匹配到示例中的命名分组

views.year_month视图函数

  1. def year_month(request,month,year): #命名分组的名字必须和视图函数的参数名字对应,顺序无所谓
  2. return HttpResponse("year:"+year+"month:"+month)

接收值的参数可以设置一个默认值,那么该函数可以给其他的匹配项使用,不会出现接收值的数量的错误

Django应用的路由分发

不同于在全局的urls.py文件中将所有涉及到的页面全部写在里面,因为一个项目中可以有多个应用,每个应用的页面和其他应用的页面应该是不相通的,在这种情况下,可以将全局的urls.py文件所涉及的页面改成应用路由,即只通过该文件进行应用的跳转,应用下面的页面通过应用的urls.py文件进行跳转

示例:将mysite1项目下的全局urls.py文件作为应用路由文件,通过该文件跳转到blog应用下,而将blog应用下的urls.py文件作为blog应用下页面的路由文件

  1. #全局urls.py文件
  2. from django.conf.urls import url, include #导入include,支持应用跳转
  3. from django.contrib import admin
  4. from blog import views
  5. urlpatterns = [
  6. url(r'^admin/', admin.site.urls),
  7. url(r'^$', views.index), #首页
  8. url(r'^index$', views.index), #首页
  9. url(r'^blog/', include('blog.urls')) #应用路由,进行应用跳转
  10. ]
  11.  
  12. #blog应用的urls.py文件,负责页面的跳转
  13. from django.conf.urls import url
  14. from django.contrib import admin
  15. from blog import views
  16. urlpatterns = [
  17. url(r'^(\d{4})/$', views.show_year),
  18. url(r'^(?P<year>\d{4})/(?P<month>\d{2})/$', views.year_month),
  19. ]
  20.  
  21. #views.py的视图函数
  22. from django.shortcuts import render,HttpResponse
  23.  
  24. def show_year(request,year):
  25. return HttpResponse(year)
  26.  
  27. def year_month(request,month,year):
  28. return HttpResponse("year:"+year+"month:"+month)

应用路由示例

URLconf的别名

name参数,直接看示例:

  1. from django.conf.urls import url, include
  2. from django.contrib import admin
  3. from blog import views
  4. urlpatterns = [
  5. url(r'^admin/', admin.site.urls),
  6. url(r'^$', views.index), #首页
  7. url(r'^index$', views.index), #首页
  8. url(r'^regs/', views.reg,name="register"), #别名
  9. ]

视图函数

  1. def reg(request):
  2. if request.method=="POST":
  3. return HttpResponse("WO AI NI")
  4. return render(request,"register.html")

然后在templates文件夹里创建register.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8.  
  9. <!--action的写法-->
  10. <!--完整写法:<form action="http://127.0.0.1:8000/date" method="post">-->
  11. <!--简单写法:<form action="/date" method="post">,会自动加上协议、ip和端口-->
  12.  
  13. <!--别名涉及到模版渲染,后续说明,现在这么写就可以-->
  14. <form action="{% url "register" %}" method="post">
  15. <p>用户:<input type="text"></p>
  16. <p>密码:<input type="password"></p>
  17. <input type="submit">
  18. </form>
  19.  
  20. </body>
  21. </html>

以上,当urls.py文件中的匹配的url路径有变化的时候,不会影响到html文件数据的提交

注:如果提示“Forbidden (403)”页面,修改全局的setting.py文件

  1. MIDDLEWARE = [
  2. 'django.middleware.security.SecurityMiddleware',
  3. 'django.contrib.sessions.middleware.SessionMiddleware',
  4. 'django.middleware.common.CommonMiddleware',
  5. # 'django.middleware.csrf.CsrfViewMiddleware', #注释该行,这是Django的一个安全机制限制
  6. 'django.contrib.auth.middleware.AuthenticationMiddleware',
  7. 'django.contrib.messages.middleware.MessageMiddleware',
  8. 'django.middleware.clickjacking.XFrameOptionsMiddleware',
  9. ]

传递额外参数到视图函数

  1. URLconfs 具有一个钩子,让你传递一个Python 字典作为额外的参数传递给视图函数。
  2.  
  3. django.conf.urls.url() 函数可以接收一个可选的第三个参数,它是一个字典,表示想要传递给视图函数的额外关键字参数。
  4.  
  5. 例如:
  6.  
  7. from django.conf.urls import url
  8. from . import views
  9.  
  10. urlpatterns = [
  11. url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
  12. ]
  13. 在这个例子中,对于/blog/2005/请求,Django 将调用views.year_archive(request, year='2005', foo='bar')。
  14.  
  15. 这个技术在Syndication 框架中使用,来传递元数据和选项给视图。

了解

视图函数

视图函数即视图,本质上就是python函数,能够接受web请求,然后做出响应,响应的内容可以是任何东西,图片文本html重定向等

习惯上写到views.py文件中,但是其他文件也可以,只需要在urls.py文件中导入就可以

最简单的完整视图示例

  1. from django.shortcuts import render,HttpResponse
  2. #HttpResponse是响应消息调用的方法
  3. def show_time(request): #request接收的是请求头数据
  4. import datetime
  5. t=datetime.datetime.now()
  6. return HttpResponse("<h1>time<?h1> %s" %t) #响应的消息

注意:视图函数的函数名字完全自定义,只不过要和urls.py文件中的路由信息匹配上

http请求-响应过程中有两个核心对象

http请求对象:HttpRequest

http响应响应:HttpResponse

快捷函数

render函数

render(request, template_name[, context])

结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse对象。

参数:
  request: 用于生成响应的请求对象。

  template_name:要使用的模板的完整名称,可选的参数

  context:添加到模板上下文的一个字典。默认是一个空字典。如果字典中的某个值是可调用的,视图将在渲染模板之前调用它。

  content_type:生成的文档要使用的MIME类型。默认为DEFAULT_CONTENT_TYPE 设置的值。

  status:响应的状态码。默认为200。

redirect函数

不同于render函数,redirect用于连接的跳转

总结

render和redirect的区别

  redirect走的是路径

  render返回的是模板

示例:

  1. #全局urls.py
  2. from django.conf.urls import url, include
  3. from django.contrib import admin
  4. from blog import views
  5. urlpatterns = [
  6. url(r'^admin/', admin.site.urls),
  7. url(r'^login/', views.reg),
  8. url(r'^register/', views.reg,name="register")
  9. ]
  10.  
  11. #views.py文件
  12. from django.shortcuts import render,HttpResponse,redirect
  13. def reg(request):
  14. if request.method=="POST":
  15. return redirect("/login/") #需要导入redirect
  16. # return render(request,"login.html")
  17. return render(request,"register.html")
  18.  
  19. #login.html文件
  20. <!DOCTYPE html>
  21. <html lang="en">
  22. <head>
  23. <meta charset="UTF-8">
  24. <title>Title</title>
  25. </head>
  26. <body>
  27. <h1>登录</h1>
  28. <form action="" method="post">
  29. <p>用户:<input type="text"></p>
  30. <p>密码:<input type="password"></p>
  31. <input type="submit">
  32. </form>
  33. </body>
  34. </html>
  35.  
  36. #register.html文件
  37. <!DOCTYPE html>
  38. <html lang="en">
  39. <head>
  40. <meta charset="UTF-8">
  41. <title>Title</title>
  42. </head>
  43. <body>
  44. <h1>注册</h1>
  45. <form action="{% url "register" %}" method="post">
  46. <p>用户:<input type="text"></p>
  47. <p>密码:<input type="password"></p>
  48. <input type="submit">
  49. </form>
  50. </body>
  51. </html>

redirect和render

Template模板系统

为了将web页面的设计和Python的代码分离开,解决html代码和python代码的耦合性,使项目更干净简洁更容易维护,就是通过django提供的模板系统来解决该问题。

模板系统的组成其实就是:html代码+逻辑控制语句

只要带有模板语法的html文件都是模板

模板系统语法

变量引用

语法格式

  1. {{ var_name }}

Template和Context对象

  1. C:\DjangoProject\Mysite>python manage.py shell
  2. >>> from django.template import Context, Template
  3. >>> t = Template('My name is {{ name }}.')
  4. >>> c = Context({'name': 'Stephane'})
  5. >>> t.render(c)
  6. 'My name is Stephane.'

同一模板,多个上下文,一旦有了模板对象,就可以通过它渲染多个context对象,无论何时我们都可以像这样使用同一模板源渲染多个Context,只进行一次模板创建然后多次调用render()方法渲染

  1. # Low版
  2. for name in ('John', 'Julie', 'Pat'):
  3. t = Template('Hello, {{ name }}')
  4. print t.render(Context({'name': name}))
  5.  
  6. # Good版
  7. t = Template('Hello, {{ name }}')
  8. for name in ('John', 'Julie', 'Pat'):
  9. print t.render(Context({'name': name}))

变量引用方式

  1. #######views.py文件
  2. from django.shortcuts import render,redirect,HttpResponse
  3. from django.template import Template,Context
  4. # Create your views here.
  5. def index(request):
  6. import datetime
  7. t = datetime.datetime.now()
  8.  
  9. # 方式一
  10. # return HttpResponse("<h1>It is %s </h1>"%str(t))
  11.  
  12. # 方式二和方式三为推荐
  13. # 方式二,将变量以键值对的方式进行导入,index.html文件调用的时候通过键来调用
  14. # return render(request, "index.html", {"times": t})
  15.  
  16. # 方式三,locals()是把当前函数的所有变量都导入到index.html文件中进行渲染
  17. return render(request,"index.html",locals())
  18.  
  19. # 方式四
  20. # text=Template('<html><body>现在时刻是:<h1 style="color:red">{{ current_date }}</h1></body></html>')
  21. # c=Context({'current_date':t})
  22. # html=text.render(c)
  23. # return HttpResponse(html)
  24.  
  25. #####index.html文件
  26. <!DOCTYPE html>
  27. <html lang="en">
  28. <head>
  29. <meta charset="UTF-8">
  30. <title>Title</title>
  31. </head>
  32. <body>
  33. <h1>index</h1>
  34. {#方式二#}
  35. {{ times }}
  36. {#方式三#}
  37. {{ t }}
  38. </body>
  39. </html>

Django模板变量引用方式

深度变量的引用

除了上述的字符串变量的处理,类似于列表、字典等复杂数据的处理是通过句点字符 “ ” 来进行处理的。

  1. #####views.py文件
  2. from django.shortcuts import render,redirect
  3. # Create your views here.
  4. class Person():
  5. def __init__(self, first_name, last_name):
  6. self.first_name, self.last_name = first_name, last_name
  7. def index(request):
  8. import datetime
  9. #####深度变量引用
  10. # 列表处理
  11. item=[11,25,32,88]
  12.  
  13. # 字典处理
  14. dic={"name":"bob","age":22}
  15.  
  16. # 对象数据处理
  17. t = datetime.datetime.now()
  18.  
  19. # 引用对象方法
  20. s = "abc"
  21.  
  22. # 自定义类
  23. p=Person("Jhon","Smith")
  24.  
  25. return render(request, "index.html", locals())
  26.  
  27. ######index.html文件
  28. <!DOCTYPE html>
  29. <html lang="en">
  30. <head>
  31. <meta charset="UTF-8">
  32. <title>Title</title>
  33. </head>
  34. <body>
  35. {#列表处理,取索引1#}
  36. <p>The number is {{ item.1 }}</p>
  37.  
  38. {#字典处理,取键值对#}
  39. <p>My name is {{ dic.name }}</p>
  40.  
  41. {#对象处理,取对象属性#}
  42. <p>Year is {{ t.year }}</p>
  43.  
  44. {#对象方法调用#}
  45. <p>Upper {{ s.upper }}</p>
  46. <p>Isdigit {{ s.isdigit }}</p>
  47.  
  48. {#自定义类#}
  49. <p>First name is {{ p.first_name }}</p>
  50. <p>Last name is {{ p.last_name }}</p>
  51.  
  52. </body>
  53. </html>

深度变量引用

注,只能调用不传参数的方法

变量过滤器

语法格式

  1. {{ obj|filter:param }}

示例

  1. #######views.py
  2. from django.shortcuts import render,HttpResponse,redirect
  3. import datetime
  4. # Create your views here.
  5.  
  6. def index(request):
  7. value1=5 #给变量加上相应的值
  8. value2="aBcd" #大写转换
  9. value3="he llo wo r ld" #移除制定字符
  10. value4=datetime.datetime.now() #格式化日期
  11. value5=[] #给空值设置默认值
  12. value6="<a href='http://www.baidu.com'>" #跳转
  13. value7="1a3b" #字符串操作
  14. return render(request,"index.html",locals())
  15.  
  16. ########index.html
  17. <!DOCTYPE html>
  18. <html lang="en">
  19. <head>
  20. <meta charset="UTF-8">
  21. <title>Title</title>
  22. </head>
  23. <body>
  24. {{ value1|add:6 }}
  25. {{ value2|upper }}
  26. {{ value3|cut:" " }}
  27. {{ value4|date:"Y-m-d" }}
  28. {{ value5|default:"这是空的" }}
  29.  
  30. {#{% autoescape off %}#}
  31. {# {{ value6 }}#}
  32. {#{% endautoescape %}#}
  33. {#{{ value6 }} 转义 #}
  34.  
  35. {{ value7|filesizeformat }} {# 统计大小 #}
  36. {{ value7|first }} {# 取第一个字符 #}
  37. {{ value7|length }} {# 统计长度 #}
  38. {{ value7|slice:":-2" }} {# 字符串切片 #}
  39.  
  40. </body>
  41. </html>

过滤器

标签tag的使用

语法

  1. {% tags %}
if标签
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8.  
  9. {% if num >= 100 and 8 %}
  10. {% if num > 200 %}
  11. <p>num大于200</p>
  12. {% else %}
  13. <p>num大于100小于200</p>
  14. {% endif %}
  15. {% elif num < 100 %}
  16. <p>num小于100</p>
  17. {% else %}
  18. <p>num等于100</p>
  19. {% endif %}
  20.  
  21. </body>
  22. </html>

if标签接受and,or或者not来测试多个变量值或者否定一个给定的变量

if标签不允许同一标签里同时出现and和or,否则逻辑容易产生歧义,例如下面的标签是不合法的:

{% if obj1 and obj2 or obj3 %}

for标签

遍历一个序列中的各个元素,每次循环模板系统都会渲染{% for %}和{% endfor %}之间的所有内容

  1. <ul>
  2. {% for obj in list %}
  3. <li>{{ obj.name }}</li>
  4. {% endfor %}
  5. </ul>
  6.  
  7. #在标签里添加reversed来反序循环列表:
  8.  
  9. {% for obj in list reversed %}
  10. ...
  11. {% endfor %}
  12.  
  13. #{% for %}标签可以嵌套:
  14.  
  15. {% for country in countries %}
  16. <h1>{{ country.name }}</h1>
  17. <ul>
  18. {% for city in country.city_list %}
  19. <li>{{ city }}</li>
  20. {% endfor %}
  21. </ul>
  22. {% endfor %}
  23.  
  24. #系统不支持中断循环,系统也不支持continue语句,{% for %}标签内置了一个forloop模板变量,
  25. #这个变量含有一些属性可以提供给你一些关于循环的信息
  26.  
  27. 1,forloop.counter表示循环的次数,它从1开始计数,第一次循环设为1:
  28.  
  29. {% for item in todo_list %}
  30. <p>{{ forloop.counter }}: {{ item }}</p>
  31. {% endfor %}
  32. 2,forloop.counter0 类似于forloop.counter,但它是从0开始计数,第一次循环设为0
  33. 3,forloop.revcounter
  34. 4,forloop.revcounter0
  35. 5,forloop.first当第一次循环时值为True,在特别情况下很有用:
  36.  
  37. {% for object in objects %}
  38. {% if forloop.first %}<li class="first">{% else %}<li>{% endif %}
  39. {{ object }}
  40. </li>
  41. {% endfor %}
  42.  
  43. # 富有魔力的forloop变量只能在循环中得到,当模板解析器到达{% endfor %}时forloop就消失了
  44. # 如果你的模板context已经包含一个叫forloop的变量,Django会用{% for %}标签替代它
  45. # Django会在for标签的块中覆盖你定义的forloop变量的值
  46. # 在其他非循环的地方,你的forloop变量仍然可用
  47.  
  48. #{% empty %}
  49.  
  50. {{li }}
  51. {% for i in li %}
  52. <li>{{ forloop.counter0 }}----{{ i }}</li>
  53. {% empty %}
  54. <li>this is empty!</li>
  55. {% endfor %}
  56.  
  57. # [11, 22, 33, 44, 55]
  58. # 0----11
  59. # 1----22
  60. # 2----33
  61. # 3----44
  62. # 4----55
csrf_token标签

用于生成csrf_token的标签,用于防治跨站攻击验证。 其实,这里是会生成一个input标签,和其他表单标签一起提交给后台的。

url标签

引用路由配置的地址

  1. <form action="{% url "bieming"%}" >
  2. <input type="text">
  3. <input type="submit"value="提交">
  4. {%csrf_token%}
  5. </form>
with标签

用更简单的变量名替代复杂的变量名

  1. {% with total=fhjsaldfhjsdfhlasdfhljsdal %}
  2. {{ total }}
  3. {% endwith %}
verbatim标签

禁止render

  1. {% verbatim %}
  2. {{ hello }}
  3. {% endverbatim %}
load标签
  1. ######setting.py文件增加代码
  2. STATICFILES_DIRS=(
  3. BASE_DIR,'bookapp/static',
  4. )
  5.  
  6. ######html文件首行
  7. {% load staticfiles %}
  8.  
  9. ######html文件的head标签内
  10. <link rel="stylesheet" href="{% static 'dashboard/css/bootstrap.min.css' %}">
  11. <link rel="stylesheet" href="{% static 'dashboard/css/dashboard.css' %}">
  12. <link rel="stylesheet" href="{% static 'dashboard/css/my-style.css' %}">
  13. <link rel="stylesheet" href="{% static 'dashboard/css/font-awesome/css/font-awesome.min.css' %}">
  14. <link rel="stylesheet" href="{% static 'dashboard/css/ie10-viewport-bug-workaround.css' %}">

自定义过滤器和标签

a、在app中创建templatetags模块(必须的),是一个py包

b、创建任意 .py 文件,如:my_tags.py

  1. from django import template
  2. from django.utils.safestring import mark_safe
  3.  
  4. register = template.Library() #register的名字是固定的,不可改变
  5.  
  6. @register.filter
  7. def filter_multi(v1,v2):
  8. return v1 * v2
  9.  
  10. @register.simple_tag
  11. def simple_tag_multi(v1,v2):
  12. return v1 * v2
  13.  
  14. @register.simple_tag
  15. def my_input(id,arg):
  16. result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
  17. return mark_safe(result)

c、在使用自定义simple_tag和filter的html文件中导入之前创建的 my_tags.py :{% load my_tags %}

d、使用simple_tag和filter(如何调用)

  1. -------------------------------.html
  2. {% load xxx %} #首行
  3.  
  4. # num=12
  5. {{ num|filter_multi:2 }} #
  6.  
  7. {{ num|filter_multi:"[22,333,4444]" }}
  8.  
  9. {% simple_tag_multi 2 5 %} 参数不限,但不能放在if for语句中
  10. {% simple_tag_multi num 5 %}

e、在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag.

filter可以用在if等语句后,simple_tag不可以

  1. {% if num|filter_multi:30 > 100 %}
  2. {{ num|filter_multi:30 }}
  3. {% endif %}

extend模板继承

一个常见的 Web 开发问题: 在整个网站中,如何减少共用页面区域(比如站点导航)所引起的重复和冗余代码?Django 解决此类问题的首选方法是使用模板继承

本质上来说,模板继承就是先构造一个基础框架模板,而后在其子模板中对它所包含站点公用部分和定义块进行重载。

创建基础模板

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <style>
  7.  
  8. *{
  9. margin: 0;
  10. padding: 0;
  11. }
  12. .header{
  13. width: 100%;
  14. height: 48px;
  15. background-color: dodgerblue;
  16. position: fixed;
  17. top: 0;
  18. left: 0;
  19. }
  20.  
  21. .left{
  22. width: 200px;
  23. position: fixed;
  24. top: 48px;
  25. bottom: 0;
  26. left: 0;
  27. background-color: lightgrey;
  28. }
  29.  
  30. .right{
  31. position: fixed;
  32. top:48px;
  33. left: 200px;
  34. right: 0;
  35. bottom: 0;
  36. overflow: auto;
  37.  
  38. }
  39. </style>
  40. </head>
  41. <body>
  42.  
  43. <div class="header"></div>
  44. <div class="content">
  45. <div class="left">
  46. <ul class="title">
  47. <li><a href="/blog/2017/">菜单一</a></li>
  48. <li><a href="/blog/2016/">菜单二</a></li>
  49. <li><a href="/blog/2015/">菜单三</a></li>
  50.  
  51. </ul>
  52.  
  53. </div>
  54. <div class="right">
  55. #block标签为子html可修改的内容
  56. {% block con %}
  57. <h4>con</h4>
  58. {% endblock %}
  59.  
  60. {% block page %}
  61. <h4>PAGE</h4>
  62. {% endblock %}
  63. </div>
  64. </div>
  65.  
  66. </body>
  67. </html>

基板

子模板的作用就是重载、添加或保留基板里面块的内容。

子模板继承

  1. {% extends "base.html" %} #继承基板的内容
  2.  
  3. {% block con %}
  4. {{ block.super}}
  5. <h4>conn222</h4>
  6. {% endblock %}
  7.  
  8. {% block page %}
  9. <h4>2222</h4>
  10. <h4>2222</h4>
  11. {% endblock %}

子html文件

继承的步骤

  1. <1> 创建 base.html 模板,在其中定义站点的主要外观感受。 这些都是不常修改甚至从不修改的部分。
  2. <2> 为网站的每个区域创建 base_SECTION.html 模板(例如, base_photos.html 和 base_forum.html )。这些模板对base.html 进行拓展,
  3. 并包含区域特定的风格与设计。
  4. <3> 为每种类型的页面创建独立的模板,例如论坛页面或者图片库。 这些模板拓展相应的区域模板。

注意点

  1. <1>如果在模板中使用 {% extends %} ,必须保证其为模板中的第一个模板标记。 否则,模板继承将不起作用。
  2.  
  3. <2>一般来说,基础模板中的 {% block %} 标签越多越好。 记住,子模板不必定义父模板中所有的代码块,因此
  4. 你可以用合理的缺省值对一些代码块进行填充,然后只对子模板所需的代码块进行(重)定义。 俗话说,钩子越
  5. 多越好。
  6.  
  7. <3>如果发觉自己在多个模板之间拷贝代码,你应该考虑将该代码段放置到父模板的某个 {% block %} 中。
  8. 如果你需要访问父模板中的块的内容,使用 {{ block.super }}这个标签吧,这一个魔法变量将会表现出父模
  9. 板中的内容。 如果只想在上级代码块基础上添加内容,而不是全部重载,该变量就显得非常有用了。
  10.  
  11. <4>不允许在同一个模板中定义多个同名的 {% block %} 。 存在这样的限制是因为block 标签的工作方式是双向的。
  12. 也就是说,block 标签不仅挖了一个要填的坑,也定义了在父模板中这个坑所填充的内容。如果模板中出现了两个
  13. 相同名称的 {% block %} 标签,父模板将无从得知要使用哪个块的内容。

数据库与ORM

配置数据库

1、Django默认支持sqlite、mysql、oracle、postgresql数据库

django默认使用sqlite的数据库,默认自带sqlite的数据库驱动 , 引擎名称:django.db.backends.sqlite3

mysql的引擎名称:django.db.backends.mysql

2、Mysql驱动程序

  • MySQLdb(mysql python)
  • mysqlclient
  • MySQL
  • PyMySQL(纯python的mysql驱动程序)

3、更改项目数据库

settings.py配置文件,更改DATABASES

  1. DATABASES = {
  2. 'default': {
  3. 'ENGINE': 'django.db.backends.mysql',
  4. 'NAME': 'books', #你的数据库名称
  5. 'USER': 'root', #你的数据库用户名
  6. 'PASSWORD': '', #你的数据库密码
  7. 'HOST': '', #你的数据库主机,留空默认为localhost
  8. 'PORT': '', #你的数据库端口
  9. }
  10. }
  1. NAME即数据库的名字,在mysql连接前该数据库必须已经创建,而上面的sqlite数据库下的db.sqlite3则是项目自动创建
  2.  
  3. USERPASSWORD分别是数据库的用户名和密码。
  4.  
  5. 设置完后,再启动我们的Django项目前,我们需要激活我们的mysql
  6.  
  7. 然后,启动项目,会报错:no module named MySQLdb
  8.  
  9. 这是因为django默认你导入的驱动是MySQLdb,可是MySQLdb对于py3有很大问题,所以我们需要的驱动是PyMySQL
  10.  
  11. 所以,我们只需要找到项目名文件下的__init__,在里面写入:
  12.  
  13. import pymysql
  14. pymysql.install_as_MySQLdb()
  15.  
  16. 问题解决!

注意点及问题

ORM表模型

表模型的创建

实例:我们来假定下面这些概念,字段和关系

作者模型:一个作者有姓名。

作者详细模型:把作者的详情放到详情表,包含性别,email地址和出生日期,作者详情模型和作者模型之间是一对一的关系(one-to-one)(类似于每个人和他的身份证之间的关系),在大多数情况下我们没有必要将他们拆分成两张表,这里只是引出一对一的概念。

出版商模型:出版商有名称,地址,所在城市,省,国家和网站。

书籍模型:书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many),一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many),也被称作外键。

  1. from django.db import models<br>
  2. class Publisher(models.Model):
  3. name = models.CharField(max_length=30, verbose_name="名称")
  4. address = models.CharField("地址", max_length=50)
  5. city = models.CharField('城市',max_length=60)
  6. state_province = models.CharField(max_length=30)
  7. country = models.CharField(max_length=50)
  8. website = models.URLField()
  9.  
  10. class Meta:
  11. verbose_name = '出版商'
  12. verbose_name_plural = verbose_name
  13.  
  14. def __str__(self):
  15. return self.name
  16.  
  17. class Author(models.Model):
  18. name = models.CharField(max_length=30)
  19. def __str__(self):
  20. return self.name
  21.  
  22. class AuthorDetail(models.Model):
  23. sex = models.BooleanField(max_length=1, choices=((0, '男'),(1, '女'),))
  24. email = models.EmailField()
  25. address = models.CharField(max_length=50)
  26. birthday = models.DateField()
  27. author = models.OneToOneField(Author)
  28.  
  29. class Book(models.Model):
  30. title = models.CharField(max_length=100)
  31. authors = models.ManyToManyField(Author)
  32. publisher = models.ForeignKey(Publisher)
  33. publication_date = models.DateField()
  34. price=models.DecimalField(max_digits=5,decimal_places=2,default=10)
  35. def __str__(self):
  36. return self.title

表创建代码

代码分析 

  1. < 1 > 每个数据模型都是django.db.models.Model的子类,它的父类Model包含了所有必要的和数据库交互的方法。并提供了一个简介漂亮的定义数据库字段的语法。
  2.  
  3. < 2 > 每个模型相当于单个数据库表(多对多关系例外,会多生成一张关系表),每个属性也是这个表中的字段。属性名就是字段名,它的类型(例如CharField)相当于数据库的字段类型(例如varchar)。大家可以留意下其它的类型都和数据库里的什么字段对应。
  4.  
  5. < 3 > 模型之间的三种关系:一对一,一对多,多对多。
  6. 一对一:实质就是在主外键(author_id就是foreignkey)的关系基础上,给外键加了一个UNIQUE=True的属性;
  7. 一对多:就是主外键关系;(foreignkey)
  8. 多对多:(ManyToManyField)自动创建第三张表(当然我们也可以自己创建第三张表:两个foreignkey)
增删查改之增

create和save

  1. from app01.models import *
  2. #直接创建
  3. #create方式一: Author.objects.create(name='Alvin')
  4. #create方式二: Author.objects.create(**{"name":"alex"})
  5. #**解字典、*解列表
  6. #通过对象方式
  7. #save方式一: author=Author(name="alvin")
  8. author.save()
  9. #save方式二: author=Author()
  10. author.name="alvin"
  11. author.save()

重点

创建存在一对多或多对多关系的一本书的信息呢?(如何处理外键关系的字段如一对多的publisher和多对多的authors)

  1. #一对多(ForeignKey):
  2.  
  3. #方式一: 由于绑定一对多的字段,比如publish,存到数据库中的字段名叫publish_id,所以我们可以直接给这个
  4. # 字段设定对应值:
  5. Book.objects.create(title='php',
  6. publisher_id=2, #这里的2是指为该book对象绑定了Publisher表中id=2的行对象
  7. publication_date='2017-7-7',
  8. price=99)
  9.  
  10. #方式二:
  11. # <1> 先获取要绑定的Publisher对象:
  12. pub_obj=Publisher(name='河大出版社',address='保定',city='保定',
  13. state_province='河北',country='China',website='http://www.hbu.com')
  14. OR pub_obj=Publisher.objects.get(id=1)
  15.  
  16. # <2>将 publisher_id=2 改为 publisher=pub_obj

一对多

  1. #多对多(ManyToManyField()):
  2.  
  3. author1=Author.objects.get(id=1)
  4. author2=Author.objects.filter(name='alvin')[0]
  5. book=Book.objects.get(id=1)
  6. book.authors.add(author1,author2)
  7. #等同于:
  8. book.authors.add(*[author1,author2])
  9. book.authors.remove(*[author1,author2])
  10. #-------------------
  11. book=models.Book.objects.filter(id__gt=1)
  12. authors=models.Author.objects.filter(id=1)[0]
  13. authors.book_set.add(*book)
  14. authors.book_set.remove(*book)
  15. #-------------------
  16. book.authors.add(1)
  17. book.authors.remove(1)
  18. authors.book_set.add(1)
  19. authors.book_set.remove(1)
  20.  
  21. #注意: 如果第三张表是通过models.ManyToManyField()自动创建的,那么绑定关系只有上面一种方式
  22. # 如果第三张表是自己创建的:
  23. class Book2Author(models.Model):
  24. author=models.ForeignKey("Author")
  25. Book= models.ForeignKey("Book")
  26. # 那么就还有一种方式:
  27. author_obj=models.Author.objects.filter(id=2)[0]
  28. book_obj =models.Book.objects.filter(id=3)[0]
  29.  
  30. s=models.Book2Author.objects.create(author_id=1,Book_id=2)
  31. s.save()
  32. s=models.Book2Author(author=author_obj,Book_id=1)
  33. s.save()

多对多

增删查改之删
  1. Book.objects.filter(id=1).delete()
  2. #表面上删除了一条信息,实际却删除了三条,因为删除的这本书在Book_authors表中有两条相关信息,这种删除方式就是django默认的级联删除。

解除绑定关系

  1. # book_obj=Book.objects.get(id=2)
  2. # book_obj.authors.clear() #解除所有的绑定
  3.  
  4. # author=Author.objects.get(name="name")
  5. # book_obj.authors.remove(author) #只解除指定的
增删查改之改
  1. author=Author.objects.get(id=5)
  2. author.name="tenglan"
  3. author.save()
  4.  
  5. #Publisher.objects.filter(id=2).update(name="American publisher")

注意:

<1> 第二种方式修改不能用get的原因是:update是QuerySet对象的方法,get返回的是一个model对象,它没有update方法,而filter返回的是一个QuerySet对象(filter里面的条件可能有多个条件符合,比如name='alvin',可能有两个name='alvin'的行数据)。

<2>在“插入和更新数据”小节中,我们有提到模型的save()方法,这个方法会更新一行里的所有列。 而某些情况下,我们只需要更新行里的某几列。

  1. #---------------- update方法直接设定对应属性----------------
  2. models.Book.objects.filter(id=3).update(title="PHP")
  3. ##sql:
  4. ##UPDATE "app01_book" SET "title" = 'PHP' WHERE "app01_book"."id" = 3; args=('PHP', 3)

update更新

  1. #--------------- save方法会将所有属性重新设定一遍,效率低-----------
  2. obj=models.Book.objects.filter(id=3)[0]
  3. obj.title="Python"
  4. obj.save()
  5. # SELECT "app01_book"."id", "app01_book"."title", "app01_book"."price",
  6. # "app01_book"."color", "app01_book"."page_num",
  7. # "app01_book"."publisher_id" FROM "app01_book" WHERE "app01_book"."id" = 3 LIMIT 1;
  8. #
  9. # UPDATE "app01_book" SET "title" = 'Python', "price" = 3333, "color" = 'red', "page_num" = 556,
  10. # "publisher_id" = 1 WHERE "app01_book"."id" = 3;

save更新

此外,update()方法对于任何结果集(QuerySet)均有效,这意味着你可以同时更新多条记录update()方法会返回一个整型数值,表示受影响的记录条数。

注意,这里因为update返回的是一个整形,所以没法用query属性;对于每次创建一个对象,想显示对应的raw sql,需要在settings加上日志记录部分:

  1. LOGGING = {
  2. 'version': 1,
  3. 'disable_existing_loggers': False,
  4. 'handlers': {
  5. 'console':{
  6. 'level':'DEBUG',
  7. 'class':'logging.StreamHandler',
  8. },
  9. },
  10. 'loggers': {
  11. 'django.db.backends': {
  12. 'handlers': ['console'],
  13. 'propagate': True,
  14. 'level':'DEBUG',
  15. },
  16. }
  17. }

Mysql日志记录

增删查改之查

查询API

  1. # 查询相关API:
  2.  
  3. # <1>filter(**kwargs): 它包含了与所给筛选条件相匹配的对象
  4.  
  5. # <2>all(): 查询所有结果
  6.  
  7. # <3>get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
  8.  
  9. #-----------下面的方法都是对查询的结果再进行处理:比如 objects.filter.values()--------
  10.  
  11. # <4>values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列
  12.  
  13. # <5>exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象
  14.  
  15. # <6>order_by(*field): 对查询结果排序
  16.  
  17. # <7>reverse(): 对查询结果反向排序
  18.  
  19. # <8>distinct(): 从返回结果中剔除重复纪录
  20.  
  21. # <9>values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
  22.  
  23. # <10>count(): 返回数据库中匹配查询(QuerySet)的对象数量。
  24.  
  25. # <11>first(): 返回第一条记录
  26.  
  27. # <12>last(): 返回最后一条记录
  28.  
  29. # <13>exists(): 如果QuerySet包含数据,就返回True,否则返回False
  1. ---------------了不起的双下划线(__)之单表条件查询----------------
  2.  
  3. # models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值
  4. #
  5. # models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据
  6. # models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in
  7. #
  8. # models.Tb1.objects.filter(name__contains="ven")
  9. # models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
  10. #
  11. # models.Tb1.objects.filter(id__range=[1, 2]) # 范围bettwen and
  12. #
  13. # startswith,istartswith, endswith, iendswith,
QuerySet与惰性机制

所谓惰性机制:Publisher.objects.all()或者.filter()等都只是返回了一个QuerySet(查询结果集对象),它并不会马上执行sql,而是当调用QuerySet的时候才执行。

特点:<1>  可迭代的  <2>  可切片

  1. #objs=models.Book.objects.all()#[obj1,obj2,ob3...]
  2.  
  3. #QuerySet: 可迭代
  4.  
  5. # for obj in objs:#每一obj就是一个行对象
  6. # print("obj:",obj)
  7. # QuerySet: 可切片
  8.  
  9. # print(objs[1])
  10. # print(objs[1:4])
  11. # print(objs[::-1])
  1. <1>Django的queryset是惰性的
  2.  
  3. Django的queryset对应于数据库的若干记录(row),通过可选的查询来过滤。例如,下面的代码会得
  4. 到数据库中名字为‘Dave’的所有的人:person_set = Person.objects.filter(first_name="Dave")
  5. 上面的代码并没有运行任何的数据库查询。你可以使用person_set,给它加上一些过滤条件,或者将它传给某个函数,
  6. 这些操作都不会发送给数据库。这是对的,因为数据库查询是显著影响web应用性能的因素之一。
  7.  
  8. <2>要真正从数据库获得数据,你可以遍历queryset或者使用if queryset,总之你用到数据时就会执行sql.
  9. 为了验证这些,需要在settings里加入 LOGGING(验证方式)
  10. obj=models.Book.objects.filter(id=3)
  11. # for i in obj:
  12. # print(i)
  13.  
  14. # if obj:
  15. # print("ok")
  16.  
  17. <3>queryset是具有cache的
  18. 当你遍历queryset时,所有匹配的记录会从数据库获取,然后转换成Django的model。这被称为执行
  19. (evaluation).这些model会保存在queryset内置的cache中,这样如果你再次遍历这个queryset,
  20. 你不需要重复运行通用的查询。
  21. obj=models.Book.objects.filter(id=3)
  22.  
  23. # for i in obj:
  24. # print(i)
  25. ## models.Book.objects.filter(id=3).update(title="GO")
  26. ## obj_new=models.Book.objects.filter(id=3)
  27. # for i in obj:
  28. # print(i) #LOGGING只会打印一次
  29.  
  30. <4>
  31. 简单的使用if语句进行判断也会完全执行整个queryset并且把数据放入cache,虽然你并不需要这些
  32. 数据!为了避免这个,可以用exists()方法来检查是否有数据:
  33.  
  34. obj = Book.objects.filter(id=4)
  35. # exists()的检查可以避免数据放入queryset的cache。
  36. if obj.exists():
  37. print("hello world!")
  38.  
  39. <5>当queryset非常巨大时,cache会成为问题
  40.  
  41. 处理成千上万的记录时,将它们一次装入内存是很浪费的。更糟糕的是,巨大的queryset可能会锁住系统
  42. 进程,让你的程序濒临崩溃。要避免在遍历数据的同时产生queryset cache,可以使用iterator()方法
  43. 来获取数据,处理完数据就将其丢弃。
  44. objs = Book.objects.all().iterator()
  45. # iterator()可以一次只从数据库获取少量数据,这样可以节省内存
  46. for obj in objs:
  47. print(obj.name)
  48. #BUT,再次遍历没有打印,因为迭代器已经在上一次遍历(next)到最后一次了,没得遍历了
  49. for obj in objs:
  50. print(obj.name)
  51.  
  52. #当然,使用iterator()方法来防止生成cache,意味着遍历同一个queryset时会重复执行查询。所以使
  53. #用iterator()的时候要当心,确保你的代码在操作一个大的queryset时没有重复执行查询
  54.  
  55. 总结:
  56. queryset的cache是用于减少程序对数据库的查询,在通常的使用下会保证只有在需要的时候才会查询数据库。
  57. 使用exists()和iterator()方法可以优化程序对内存的使用。不过,由于它们并不会生成queryset cache,可能
  58. 会造成额外的数据库查询。

惰性机制的使用

对象查询
  1. #--------------------对象形式的查找--------------------------
  2. # 正向查找
  3. ret1=models.Book.objects.first()
  4. print(ret1.title)
  5. print(ret1.price)
  6. print(ret1.publisher)
  7. print(ret1.publisher.name) #因为一对多的关系所以ret1.publisher是一个对象,而不是一个queryset集合
  8.  
  9. # 反向查找
  10. ret2=models.Publish.objects.last()
  11. print(ret2.name)
  12. print(ret2.city)
  13. #如何拿到与它绑定的Book对象呢?
  14. print(ret2.book_set.all()) #ret2.book_set是一个queryset集合
单表条件查询
  1. #---------------了不起的双下划线(__)之单表条件查询----------------
  2.  
  3. # models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值
  4. #
  5. # models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据
  6. # models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in
  7. #
  8. # models.Tb1.objects.filter(name__contains="ven")
  9. # models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
  10. #
  11. # models.Tb1.objects.filter(id__range=[1, 2]) # 范围bettwen and
  12. #
  13. # startswith,istartswith, endswith, iendswith,
多表条件关联查询
  1. #----------------了不起的双下划线(__)之多表条件关联查询---------------
  2.  
  3. # 正向查找(条件)
  4.  
  5. # ret3=models.Book.objects.filter(title='Python').values('id')
  6. # print(ret3)#[{'id': 1}]
  7.  
  8. #正向查找(条件)之一对多
  9.  
  10. ret4=models.Book.objects.filter(title='Python').values('publisher__city')
  11. print(ret4) #[{'publisher__city': '北京'}]
  12.  
  13. #正向查找(条件)之多对多
  14. ret5=models.Book.objects.filter(title='Python').values('author__name')
  15. print(ret5)
  16. ret6=models.Book.objects.filter(author__name="alex").values('title')
  17. print(ret6)
  18.  
  19. #注意
  20. #正向查找的publisher__city或者author__name中的publisher,author是book表中绑定的字段
  21. #一对多和多对多在这里用法没区别
  22.  
  23. # 反向查找(条件)
  24.  
  25. #反向查找之一对多:
  26. ret8=models.Publisher.objects.filter(book__title='Python').values('name')
  27. print(ret8)#[{'name': '人大出版社'}] 注意,book__title中的book就是Publisher的关联表名
  28.  
  29. ret9=models.Publisher.objects.filter(book__title='Python').values('book__authors')
  30. print(ret9)#[{'book__authors': 1}, {'book__authors': 2}]
  31.  
  32. #反向查找之多对多:
  33. ret10=models.Author.objects.filter(book__title='Python').values('name')
  34. print(ret10)#[{'name': 'alex'}, {'name': 'alvin'}]
  35.  
  36. #注意
  37. #正向查找的book__title中的book是表名Book
  38. #一对多和多对多在这里用法没区别

注意:条件查询即与对象查询对应,是指在filter,values等方法中的通过__来明确查询条件。

聚合查询和分组查询

<1> aggregate(*args,**kwargs):

通过对QuerySet进行计算,返回一个聚合值的字典。aggregate()中每一个参数都指定一个包含在字典中的返回值。即在查询集上生成聚合。

  1. from django.db.models import Avg,Min,Sum,Max
  2.  
  3. 从整个查询集生成统计值。比如,你想要计算所有在售书的平均价钱。Django的查询语法提供了一种方式描述所有
  4. 图书的集合。
  5.  
  6. >>> Book.objects.all().aggregate(Avg('price'))
  7. {'price__avg': 34.35}
  8.  
  9. aggregate()子句的参数描述了我们想要计算的聚合值,在这个例子中,是Book模型中price字段的平均值
  10.  
  11. aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的
  12. 标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定
  13. 一个名称,可以向聚合子句提供它:
  14. >>> Book.objects.aggregate(average_price=Avg('price'))
  15. {'average_price': 34.35}
  16.  
  17. 如果你也想知道所有图书价格的最大值和最小值,可以这样查询:
  18. >>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price'))
  19. {'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}

<2> annotate(*args,**kwargs):

可以通过计算查询结果中每一个对象所关联的对象集合,从而得出总计值(也可以是平均值或总和),即为查询集的每一项生成聚合。

查询alex出的书总价格      

查询各个作者出的书的总价格,这里就涉及到分组了,分组条件是authors__name

查询各个出版社最便宜的书价是多少

聚合查询和分组查询

仅仅靠单一的关键字参数查询已经很难满足查询要求。此时Django为我们提供了F和Q查询:

  1. # F 使用查询条件的值,专门取对象中某列值的操作
  2.  
  3. # from django.db.models import F
  4. # models.Tb1.objects.update(num=F('num')+1)
  5.  
  6. # Q 构建搜索条件
  7. from django.db.models import Q
  8.  
  9. #1 Q对象(django.db.models.Q)可以对关键字参数进行封装,从而更好地应用多个查询
  10. q1=models.Book.objects.filter(Q(title__startswith='P')).all()
  11. print(q1)#[<Book: Python>, <Book: Perl>]
  12.  
  13. # 2、可以组合使用&,|操作符,当一个操作符是用于两个Q的对象,它产生一个新的Q对象。
  14. Q(title__startswith='P') | Q(title__startswith='J')
  15.  
  16. # 3、Q对象可以用~操作符放在前面表示否定,也可允许否定与不否定形式的组合
  17. Q(title__startswith='P') | ~Q(pub_date__year=2005)
  18.  
  19. # 4、应用范围:
  20.  
  21. # Each lookup function that takes keyword-arguments (e.g. filter(),
  22. # exclude(), get()) can also be passed one or more Q objects as
  23. # positional (not-named) arguments. If you provide multiple Q object
  24. # arguments to a lookup function, the arguments will be “AND”ed
  25. # together. For example:
  26.  
  27. Book.objects.get(
  28. Q(title__startswith='P'),
  29. Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
  30. )
  31.  
  32. #sql:
  33. # SELECT * from polls WHERE question LIKE 'P%'
  34. # AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')
  35.  
  36. # import datetime
  37. # e=datetime.date(2005,5,6) #2005-05-06
  38.  
  39. # 5、Q对象可以与关键字参数查询一起使用,不过一定要把Q对象放在关键字参数查询的前面。
  40. # 正确:
  41. Book.objects.get(
  42. Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
  43. title__startswith='P')
  44. # 错误:
  45. Book.objects.get(
  46. question__startswith='P',
  47. Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))

补充:admin的配置

admin是django强大功能之一,它能共从数据库中读取数据,呈现在页面中,进行管理。默认情况下,它的功能已经非常强大,如果你不需要复杂的功能,它已经够用,但是有时候,一些特殊的功能还需要定制,比如搜索功能,下面这一系列文章就逐步深入介绍如何定制适合自己的admin应用。

如果你觉得英文界面不好用,可以在setting.py 文件中修改以下选项

  1. LANGUAGE_CODE = 'en-us' #LANGUAGE_CODE = 'zh-hans'

ModelAdmin

管理界面的定制类,如需扩展特定的model界面需从该类继承。

注册medel类到admin

<1>   使用register的方法

  1. admin.site.register(Book,MyAdmin)

<2>   使用register的装饰器

  1. @admin.register(Book)
注册medel类到admin
  • list_display:     指定要显示的字段
  • search_fields:  指定搜索的字段
  • list_filter:        指定列表过滤器
  • ordering:       指定排序字段
  1. from django.contrib import admin
  2. from app01.models import *
  3. # Register your models here.
  4.  
  5. # @admin.register(Book)#----->单给某个表加一个定制
  6. class MyAdmin(admin.ModelAdmin):
  7. list_display = ("title","price","publisher")
  8. search_fields = ("title","publisher")
  9. list_filter = ("publisher",)
  10. ordering = ("price",)
  11. fieldsets =[
  12. (None, {'fields': ['title']}),
  13. ('price information', {'fields': ['price',"publisher"], 'classes': ['collapse']}),
  14. ]
  15.  
  16. admin.site.register(Book,MyAdmin)
  17. admin.site.register(Publish)
  18. admin.site.register(Author)

Django基础-Lesson1的更多相关文章

  1. Python之路-(js正则表达式、前端页面的模板套用、Django基础)

    js正则表达式 前端页面的模板套用 Django基础 js正则表达式: 1.定义正则表达式 /.../  用于定义正则表达式 /.../g 表示全局匹配 /.../i 表示不区分大小写 /.../m ...

  2. Django 基础教程

    Django 基础教程 这是第一篇 Django 简介 »  Django 是由 Python 开发的一个免费的开源网站框架,可以用于快速搭建高性能,优雅的网站! 你一定可以学会,Django 很简单 ...

  3. python的django基础篇

    一.Django基础 Django 是用Python开发的一个免费开源的Web框架,可以用于快速搭建高性能,优雅的网站! Django的特点: 强大的数据库功能:拥有强大的数据库操作接口(QueryS ...

  4. Python学习(二十六)—— Django基础一

    转载自:http://www.cnblogs.com/liwenzhou/p/8258992.html 一.Web框架本质 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的 ...

  5. Django基础(一)

    Django基础(一) 知识预览 Django基本命令 二 路由配置系统(URLconf) 三 编写视图 四 Template 五 数据库与ORM admin的配置 一 什么是web框架? 框架,即f ...

  6. python3之Django基础篇

    一.Django基础 Django 是用Python开发的一个免费开源的Web框架,可以用于快速搭建高性能,优雅的网站! Django的特点: 强大的数据库功能:拥有强大的数据库操作接口(QueryS ...

  7. DJango 基础 (1)

    django基础 知识点: 基本认知 工具准备 新建项目 目录及文件说明 开发服务器 创建视图函数 新建应用(app) 1.基本认知 Django是用Python开发的一个免费开源的Web框架,可以用 ...

  8. Django基础和基本使用

    Django基础 Django是Python下的一款著名的Web框架 框架 任何语言进入到高级部分时,会有认证.session.http.连接数据库等等功能操作,没有框架时需要自己实现 框架 是整个或 ...

  9. {Django基础十之Form和ModelForm组件}一 Form介绍 二 Form常用字段和插件 三 From所有内置字段 四 字段校验 五 Hook钩子方法 六 进阶补充 七 ModelForm

    Django基础十之Form和ModelForm组件 本节目录 一 Form介绍 二 Form常用字段和插件 三 From所有内置字段 四 字段校验 五 Hook钩子方法 六 进阶补充 七 Model ...

随机推荐

  1. <转>Android APP字体大小,不随系统的字体大小变化而变化的方法

    从android4.0起系统设置的”显示“提供设置字体大小的选项.这个设置直接会影响到所有sp为单位的字体适配,所以很多app在设置了系统字体后瞬间变得面目全非.下面是解决方案 Resources r ...

  2. Sysmon + NXlog构建简单的windows安全监控

    工具: Sysmon (sysmon 5.0) ,NXlog(nxlog-ce-2.9.1716.msi) . Sysmon监控系统并生成windows event log,   NXlog将wind ...

  3. MySQL实现强制查询走索引和强制查询不缓存

    0.表结构如下:(包含两个索引) Create Table: CREATE TABLE `user` ( `userID` ) NOT NULL, `userCode` ) DEFAULT NULL, ...

  4. 【NOIP题解】NOIP2017 TG D2T3 列队

    列队,NOIP2017 TG D2T3. 树状数组经典题. 题目链接:洛谷. 题意: Sylvia 是一个热爱学习的女孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. ...

  5. FPGA quartus开发中常见的错误处理

    1.Warning: An incorrect timescale is selected for the Verilog Output (.VO) file of this PLL design. ...

  6. The data protection operation was unsuccessful. This may have been caused by not having the user profile loaded for the current thread's user context,

    在iis7.0布署网站后运行的错误,大致意思是:数据保护操作是不成功的.这可能是由于没有为当前线程的用户加载用户配置文件的导致 解决办法: 先为自己的网站新建一个应用程序池,然后新建的应用程序池上右键 ...

  7. thinkphp5 url传参

    url('index/blog/read',['id'=>5,'name'=>'thinkphp']); 手册https://www.kancloud.cn/manual/thinkphp ...

  8. HDU 1054 Strategic Game(最小路径覆盖)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1054 题目大意:给你一棵树,选取树上最少的节点使得可以覆盖整棵树. 解题思路: 首先树肯定是二分图,因 ...

  9. linux下Ctrl命令组合

    1.键盘组合键操作 ctrl-c 发送 SIGINT 信号给前台进程组中的所有进程.常用于终止正在运行的程序. ctrl-z 发送 SIGTSTP 信号给前台进程组中的所有进程,常用于挂起一个进程.  ...

  10. redux-saga印象

    saga作为redux的中间件,用来处理异步任务. 先收集资料: 贴个文章(2)中的图先: 注意:参考文献(4)是redux-saga作者写的. 参考文章: (1)https://redux-saga ...