内容:
1.课前复习
2.django路由规则
3.django视图函数
4.django ORM
5.模板
django预备知识:https://www.cnblogs.com/wyb666/p/9444150.html
django基础参考:http://www.cnblogs.com/wupeiqi/articles/5237704.html
一、课前复习
1.HTTP协议消息格式
1 请求(request): 2 请求方法 路径 HTTP/1.1\r\n 3 k1:v1\r\n 4 ...\r\n 5 \r\n 6 请求体 <-- 可以有,可以没有 7 8 响应(response): 9 HTTP/1.1 状态码 状态描述符\r\n 10 k1:v1\r\n 11 Content-Type: text/html; charset=utf8\r\n 12 \r\n 13 响应正文 <-- HTML内容
2.python的web框架本质
- 收发socket消息 --> 按照HTTP协议消息格式去解析消息
- 路径和要执行的函数的对应关系 --> 主要的业务逻辑
- 字符串替换 --> 模板(特殊符号 --> 数据)
3.一个完整的请求过程:
- 启动服务端,等待客户端(用户的浏览器)来连接
- 在浏览器地址栏输入URL,与服务端建立连接,浏览器发送请求
- 服务端收到请求消息,解析请求消息,根据路径和函数的对应关系,找到将要执行的函数
- 执行函数,打开HTML文件,进行字符串替换,得到一个最终要返回的HTML内容
- 按照HTTP协议的消息格式要求,把HTML内容回复给用户浏览器(发送响应)
- 浏览器收到响应的消息之后,按照HTML的规则渲染页面.
- 关闭连接
二、django路由系统
在django程序中,可以通过urls.py文件对所有的url进行任务的分配,根据路由规则的定义选择不同的业务处理函数进行处理,urls.py中规定的对应规则可以说是路由系统(URLconf)
关于路由规则的详细内容:http://www.cnblogs.com/liwenzhou/p/8271147.html
1.基本路由规则
基本格式(1.x版本):
1 from django.conf.urls import url 2 3 urlpatterns = [ 4 url(正则表达式, views视图函数,参数,别名), 5 ]
- 正则表达式:一个正则表达式字符串
- views视图函数:一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
- 参数:可选的要传递给视图函数的默认参数(字典形式)
- 别名:一个可选的name参数
Django 2.0版本路由系统的写法:
1 from django.urls import path 2 3 urlpatterns = [ 4 path('articles/', views.articles), 5 path('articles/<int:year>/', views.year_archive), 6 path('articles/<int:year>/<int:month>/', views.month_archive), 7 path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail), 8 ]
2.路由系统正则表达式详解
基础样例 - 分组匹配:
1 from django.conf.urls import url 2 from . import views 3 4 urlpatterns = [ 5 url(r'^articles/2003/$', views.special_case_2003), 6 url(r'^articles/([0-9]{4})/$', views.year_archive), 7 url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), 8 url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail), 9 ]
注意:
- urlpatterns中的元素按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续
- 若要从URL中捕获一个值,只需要在它周围放置一对圆括号(分组匹配)
- 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles
- 每个正则表达式前面的'r' 是可选的但是建议加上
上面的示例使用简单的正则表达式分组匹配(通过圆括号)来捕获URL中的值并以位置参数形式传递给视图;在更高级的用法中,可以使用分组命名匹配的正则表达式组来捕获URL中的值并以关键字参数形式传递给视图
在Python的正则表达式中,分组命名正则表达式组的语法是(?P<name>pattern),其中name是组的名称,pattern是要匹配的模式
分组命名匹配:
1 from django.conf.urls import url 2 from . import views 3 4 urlpatterns = [ 5 url(r'^articles/2003/$', views.special_case_2003), 6 url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive), 7 url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive), 8 url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail), 9 ]
这个实现与前面的示例完全相同,只有一个细微的差别:捕获的值作为关键字参数而不是位置参数传递给视图函数,另外注意无论哪种方法每个在路由中捕获的参数都作为一个普通的Python字符串传递给视图
另外views.py中可以给视图函数的参数设置默认值:
3.django路由分发
1个Django 项目里面有多个APP目录大家共有一个 url容易造成混淆,于是路由分发让每个APP的拥有了自己单独的url:
项目目录下的urls.py:
1 from django.conf.urls import url, include 2 from django.contrib import admin 3 4 urlpatterns = [ 5 # 分发到APP的路由 6 url(r'^basic/', include('basic.urls')), 7 url(r'^app1/', include('app1.urls')), 8 url(r'^app2/', include('app2.urls')), 9 ]
basic这个APP下的urls.py:
1 from django.conf.urls import url 2 from basic import views 3 4 urlpatterns = [ 5 url(r'^index/', views.index), 6 url(r'^login/', views.login), 7 url(r'^register/', views.register), 8 ]
完成上述设置后,basic这个APP的路由只需在自己APP下的urls.py配置即可,访问时前面带上basic路径即可
4.命名URL和URL反向解析
(1)前言
在使用Django 项目时,一个常见的需求是获得URL的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。
人们强烈希望不要硬编码这些URL(费力、不可扩展且容易产生错误)或者设计一种与URLconf 毫不相关的专门的URL 生成机制,因为这样容易导致一定程度上产生过期的URL。
换句话讲,需要的是一个DRY 机制。除了其它有点,它还允许设计的URL 可以自动更新而不用遍历项目的源代码来搜索并替换过期的URL。
获取一个URL 最开始想到的信息是处理它视图的标识(例如名字),查找正确的URL 的其它必要的信息有视图参数的类型(位置参数、关键字参数)和值。
Django 提供一个办法是让URL 映射是URL 设计唯一的地方。你填充你的URLconf,然后可以双向使用它:
- 根据用户/浏览器发起的URL 请求,它调用正确的Django 视图,并从URL 中提取它的参数需要的值
- 根据Django 视图的标识和将要传递给它的参数的值,获取与之关联的URL
(2)命名URL和URL反向解析
前言中第一种方式是我们在前面的章节中一直讨论的用法,是直接获得url的最终形式,可以称之为命名URL
而第二种方式叫做反向解析URL或者简单的URL 反查
在需要URL 的地方,对于不同层级,Django 提供不同的工具用于URL 反查:
- 在模板中:使用url模板标签。
- 在Python 代码中:使用django.core.urlresolvers.reverse() 函数。
- 在更高层的与处理Django 模型实例相关的代码中:使用get_absolute_url() 方法。
反向解析URL本质上就是给url匹配模式起别名,然后用过别名拿到具体的URL路径
用法如下:
1 起别名: 在url匹配模式中,定义name="别名" 2 3 1. 在模板语言里面使用: 4 {% url "别名" %} --> 得到具体的URL路径 5 6 7 2. 在视图中如何使用: 8 from django.urls import reverse 9 10 reverse("别名") --> 得到具体的URL路径 11 12 13 3. 如何传参数? 14 模板语言中: 15 {% url "别名" 2018 "nb" %} 16 17 视图函数中 18 传位置参数: reverse("别名", args=(2018, "nb")) 19 传关键字参数: reverse("别名" kwargs={"year": 2018, "title": "nb"}) 20 21 22 4. namespace 23 为了防止不同的app下面的url匹配模式有重复的别名,可以给app起别名
(3)实例如下:
urls.py:
1 urlpatterns = [ 2 url(r'^admin/', admin.site.urls, name="admin"), 3 # 分发到APP的路由 4 url(r'^basic/', include('basic.urls', namespace="basic")), 5 ]
1 urlpatterns = [ 2 url(r'^user_list/', views.user_list, name="user_list"), 3 url(r'^add_user/', views.add_user, name="add_user"),
4 ]
views.py:
1 def user_list(request): 2 res = models.UserInfo.objects.all() 3 return render(request, "user/user_list.html", {"user_list": res}) 4 5 def add_user(request): 6 err_msg = "" 7 if request.method == "POST": 8 new_name = request.POST.get("username", None) 9 new_pwd = request.POST.get("password", None) 10 if new_name and new_pwd: 11 models.UserInfo.objects.create(username=new_name, password=new_pwd) 12 return redirect(reverse("basic:user_list")) 13 else: 14 err_msg = "用户名或密码不能为空!" 15 return render(request, "user/add_user.html", {"error": err_msg})
HTML:
1 <a class="btn btn-default" href="{% url "basic:add_user" %}" role="button">添加用户</a>
三、django视图系统
视图系统简称视图,可以是一个简单的Python 函数,它接受Web请求并且返回Web响应。无论视图本身包含什么逻辑,都要返回响应。
views.py中(一般为了模块化都是放在APP的views里)
关于视图系统详细:http://www.cnblogs.com/liwenzhou/articles/8305104.html
1.最简单的视图
不论什么视图都包含两个对象:
- request:用户请求的相关所有信息,在django中是HttpRequest对象
- response:响应信息(字符串 or HTML or 图片、、、),在django中是HttpResponse对象
最简单的视图:
1 from django.shortcuts import HttpResponse 2 3 def easy_view(request): 4 # 每个视图函数都使用HttpRequest对象作为第一个参数,并且通常称之为request 5 return HttpResponse("hello world!")
视图函数,围绕着两个对象进行:HttpResponse和HttpRequest
2.HttpRequest
(1)属性
1 request.path 获取访问文件路径 2 request.path_info 获取用户请求的路径(不包含IP和端口和URL参数) 3 request.method 获取请求中使用的HTTP方式(POST/GET) 4 request.body 含所有请求体信息 是bytes类型 5 request.GET GET请求的数据(类字典对象) 请求头中的url中?后面拿值 6 request.POST POST请求的数据(类字典对象) 请求体里拿值 7 8 request.FILES: 包含所有上传文件的类字典对象;FILES中的每一个Key都是<input type="file" name="" />标签中 9 name属性的值,FILES中的每一个value同时也是一个标准的python字典对象,包含下面三个Keys: 10 filename: 上传文件名,用字符串表示 11 content_type: 上传文件的Content Type 12 content: 上传文件的原始内容 13 14 request.user: 是一个django.contrib.auth.models.User对象,代表当前登陆的用户。如果访问用户当前 15 没有登陆,user将被初始化为django.contrib.auth.models.AnonymousUser的实例。你 16 可以通过user的is_authenticated()方法来辨别用户是否登陆: 17 if req.user.is_authenticated();只有激活Django中的AuthenticationMiddleware 18 时该属性才可用 19 20 request.COOKIES 包含所有cookies的标准Python字典对象;keys和values都是字符串。 21 request.session 唯一可读写的属性,代表当前会话的字典对象;自己有激活Django中的session支持时该属性才可用
属性实例 - 上传文件:
1 def upload(request): 2 """ 3 保存上传文件前,数据需要存放在某个位置。默认当上传文件小于2.5M时,django会将上传文件的全部内容读进内存。从内存读取一次,写磁盘一次。 4 但当上传文件很大时,django会把上传文件写到临时文件中,然后存放到系统临时文件夹中。 5 :param request: 6 :return: 7 """ 8 if request.method == "POST": 9 # 从请求的FILES中获取上传文件的文件名,file-name为页面上type=files类型input的name属性值 10 filename = request.FILES["file-name"].name 11 # 在项目目录下新建一个文件 12 with open(filename, "wb") as f: 13 # 从上传的文件对象中一点一点读 14 for chunk in request.FILES["file-name"].chunks(): 15 # 写入本地文件 16 f.write(chunk) 17 return HttpResponse("上传OK")
(2)方法
1 request.GET.get('name', None) 拿到GET请求里name的值(不存在就为None) 2 request.POST.get('username', None) 拿到GET请求里username的值(不存在就为None) 3 如果某个键对应有多个值,则不能直接用get取值,需要用getlist,如:request.POST.getlist("hobby")
4
5 获取请求路径:
6 请求url: http://127.0.0.1:8000/index.html/23?a=1
7 request.path 结果: /index.html/23
8 request.get_full_path() 结果: /index.html/23?a=1
3.HttpResponse
对于HttpRequest请求对象来说,是由django自动创建的,但是,HttpResponse响应对象就必须我们自己创建。每个view请求处理方法必须返回一个响应。HttpResponse类在django.http.HttpResponse
可以由HttpResponse对象上扩展出多种常用方法,如下所示
(1)HttpResponse函数
1 from django.shortcuts import HttpResponse 2 3 4 # 最简单的视图函数 5 def easy_view(request): 6 # 返回最简单的一个响应(一个字符串): hello world! 7 return HttpResponse("hello world!")
补充 - JsonResponse
JsonResponse是HttpResponse的子类,专门用来生成JSON编码的响应:
1 from django.http import JsonResponse 2 3 response = JsonResponse({'foo': 'bar'}) 4 print(response.content) 5 6 b'{"foo": "bar"}'
默认只能传递字典类型,如果要传递非字典类型需要设置一下safe关键字参数:
response = JsonResponse([1, 2, 3], safe=False)
(2)render函数
作用:将特点页面渲染后返回给浏览器
渲染 -> 给页面中的参数赋值
render(request, template_name[, context])
结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse 对象
参数如下:
- request: 用于生成响应的请求对象
- template_name:要使用的模板的完整名称,可选的参数
- context:添加到模板上下文的一个字典。默认是一个空字典。如果字典中的某个值是可调用的,视图将在渲染模板之前调用它
- content_type:生成的文档要使用的MIME类型。默认为DEFAULT_CONTENT_TYPE 设置的值
- status:响应的状态码。默认为200
render实例:
1 from django.shortcuts import render 2 3 def my_view(request): 4 # 视图的代码写在这里 5 return render(request, 'index.html', {'foo': 'bar'})
1 def render(request, template_name, context=None, content_type=None, status=None, using=None): 2 """ 3 Returns a HttpResponse whose content is filled with the result of calling 4 django.template.loader.render_to_string() with the passed arguments. 5 """ 6 content = loader.render_to_string(template_name, context, request, using=using) 7 return HttpResponse(content, content_type, status)