一 路由系统进阶(urls.py)
动态路由
urls.py中通过正则表达式的分组匹配,捕获用户访问的url中的值,传递给视图函数
1 分组匹配(通过圆括号):
相当于给视图函数传递 位置参数
例子:
1 from django.conf.urls import url
2
3 from . import views
4
5 urlpatterns = [
6 url(r'^articles/2003/$', views.special_case_2003),
7 url(r'^articles/([0-9]{4})/$', views.year_archive),
8 url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
9 url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
10 ]
2 分组命名匹配:
相当于给视图函数传递 关键字参数
在Python的正则表达式中,分组命名正则表达式组的语法是(?P<name>pattern)
,其中name
是组的名称,pattern
是要匹配的模式。
例子:
1 from django.conf.urls import url
2
3 from . import views
4
5 urlpatterns = [
6 url(r'^articles/2003/$', views.special_case_2003),
7 url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
8 url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
9 url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
10 ]
3 name
防止将url硬编码到我们的业务逻辑代码中,给url起别名
通过别名,反向找到 url
配置:
在views.py中:
from django.urls import reverse
具体的url = reverse('url别名')
例子:
urls.py里面配置:
url(r'^publisher_list/$', views.publisher_list, name="alex")
vivews.py引用:
# def edit_publisher(request, edit_id):
# print(reverse('alex'))
# print("=" * 120)
# if request.method == "POST":
# new_name = request.POST.get("name888")
# # 去数据库修改出版社名字
# obj = models.Publisher.objects.get(id=edit_id)
# obj.name = new_name
# obj.save()
# return redirect(reverse('alex')) #返回一个url
# print(edit_id)
# publisher_obj = models.Publisher.objects.get(id=edit_id)
# return render(request, "edit_publisher.html", {"obj": publisher_obj})
4 传参数的两种写法(一不小心就被坑了)
例子一:url传参
1 urls.py配置:
url(r'^edit_publisher/$', views.edit_publisher),
2 views.py
3 def edit_publisher(request):
if request.method=="POST":
4 #获取用户更改的id
5 edit_id=request.POST.get("id")#从浏览器传的参数获取的id
6 new_name=request.POST.get("name")#从form表单获取的名字
7 #去数据库找到这条记录
8 obj=models.Publisher.objects.get(id=edit_id)
9 obj.name=new_name
10 obj.save()
11 return redirect("/publisher_list/")
12 else:
13 edit_id = request.GET.get("id")
14 publisher_edit = models.Publisher.objects.get(id=edit_id)
15 return render(request,"edit_publisher.html",{"obj":publisher_edit})
注意:#上面红色字体里面的的obj一定要和你相应的edit_publisher里面的value,里面的一致,比如value=obj.name 这里就一定用obj
3 html配置:
publisher_list.html
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>出版社列表</title>
6 <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
7 </head>
8 <body>
9 <div class="container">
10 <div class="row">
11 <div class="col-md-8 col-sm-offset-2">
12 <table class="table table-bordered">
13 <tr>
14 <th>#</th>
15 <th>id</th>
16 <th>出版社名字</th>
17 <th>操作</th>
18 </tr>
19
20 {# data这里一定要跟views里面的data一样#}
21 {% for publisher in data %}
22 <tr>
23 <td>{{ forloop.counter }}</td>
24 <td>{{ publisher.id }}</td>
25 <td>{{ publisher.name }}</td>
26 <td>
27 {# 这是动态传参#}
28 {# <a href="/edit_publisher/{{ publisher.id }}/" class="btn btn-info">编辑</a>#}
29 {# 这是浏览器传参数#}
30 <a href="/edit_publisher/?id={{ publisher.id }}" class="btn btn-info">编辑</a>
31 <a href="/del_publisher" class="btn btn-info">删除</a>
32 </td>
33 </tr>
34 {% endfor %}
35 </table>
36
37 </div>
38 </div>
39 </div>
40
41 </body>
42 </html>
edit_publisher.html
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>编辑</title>
6 <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
7 </head>
8 <body>
9 <form class="form-horizontal" action="" method="post">
10 <input type="text" name="id" value="{{ obj.id }}" style="display: none">
11 <div class="form-group">
12 <label for="inputEmail3" class="col-sm-2 control-label">出版社名称</label>
13 <div class="col-sm-10">
14 <input type="text" class="form-control" name="name" value="{{ obj.name }}" id="inputEmail3"
15 placeholder="新名称">
16 </div>
17 </div>
18
19 <div class="form-group">
20 <div class="col-sm-offset-2 col-sm-10">
21 <button type="submit" class="btn btn-default">提交</button>
22 </div>
23 </div>
24 </form>
25
26 </body>
27 </html>
例子二 动态传参
1 urls配置:
url(r'^edit_publisher/(\d+)/$', views.edit_publisher),
2 views.py配置
1 # def edit_publisher(request,edit_id):
2 # if request.method=="POST":
3 # #获取用户更改的id
4 #
5 # new_name=request.POST.get("name")#从form表单获取的名字
6 # #去数据库找到这条记录
7 # obj=models.Publisher.objects.get(id=edit_id)
8 # print(obj.name)
9 # obj.name=new_name
10 # obj.save()
11 # return redirect("/publisher_list/")
12 # else:
13 #
14 # publisher = models.Publisher.objects.get(id=edit_id)
15 # return render(request,"edit_publisher.html",{"obj":publisher})
3 html配置:
publisher_list.html
<a href="/edit_publisher/{{ publisher.id }}/" class="btn btn-info">编辑</a>
edit_publisher.html不变
二 视图函数进阶(views.py)
1. 1-views.py
1.基础必会三件套
1. HttpResponse('字符串')
2. render(request, "xx.html", {"key": value})
3. redirect("/其它的url/")
2. FBV(Function Base View) 基于函数的视图
通过request.method == "POST" 去判断
例子:
1 # def edit_publisher(request, edit_id):
2 # print(reverse('alex'))
3 # print("=" * 120)
4 # if request.method == "POST":
5 # new_name = request.POST.get("name888")
6 # # 去数据库修改出版社名字
7 # obj = models.Publisher.objects.get(id=edit_id)
8 # obj.name = new_name
9 # obj.save()
10 # return redirect(reverse('alex'))
11 # print(edit_id)
12 # publisher_obj = models.Publisher.objects.get(id=edit_id)
13 # return render(request, "edit_publisher.html", {"obj": publisher_obj})
3. CBV(Class Base View) 基于类的视图
1. 必须继承views.View -->在views.py里面导入: from django import views
2. 写一个自己的视图类
3. 通过定义不同的方法,来处理用户不同的请求
4. 在urls.py中注册视图的时候要写 views.类名.as_view()
urls.py中配置:
url(r'^edit_publisher/(?P<edit_id>\d+)/$', views.EditPublisher.as_view(), name="wusir"),
view.py配置:
例子:
1 class EditPublisher(views.View):
2 def get(self, request, edit_id):
3 publisher_obj = models.Publisher.objects.get(id=edit_id)
4 return render(request, "edit_publisher.html", {"obj": publisher_obj})
5
6 def post(self, request, edit_id):
7 new_name = request.POST.get("name888")
8 # 去数据库修改出版社名字
9 obj = models.Publisher.objects.get(id=edit_id)
10 obj.name = new_name
11 obj.save()
12 return redirect(reverse('alex'))
2.1 request对象的常用属性和方法(常用的几个)
request表示的是和用户请求相关的所有数据
1. request.method --> 用户当前请求的请求方法
2. request.GET --> 用户请求中url中的参数
3. request.POST --> 用户POST请求的数据
4. request.path_info --> 用户访问的url路径是什么
3.1 Django上传文件
1. 前端页面
1. form表单一定要有action,method必须是post
2. 一定要配置enctype="multipart/form-data
2. 后端:
def upload(request):
"""
保存上传文件前,数据需要存放在某个位置。默认当上传文件小于2.5M时,django会将上传文件的全部内容读进内存。从内存读取一次,写磁盘一次。
但当上传文件很大时,django会把上传文件写到临时文件中,然后存放到系统临时文件夹中。
:param request:
:return:
"""
if request.method == "POST":
# 从请求的FILES中获取上传文件的文件名,file为页面上type=files类型input的name属性值
filename = request.FILES["file"].name
# 在项目目录下新建一个文件
with open(filename, "wb") as f:
# 从上传的文件对象中一点一点读
for chunk in request.FILES["file"].chunks():
# 写入本地文件
f.write(chunk)
return HttpResponse("上传OK")
4.1 JsonResponse
专门用来返回JSON格式数据的响应对象
from django.http import JsonResponse
例子:
from django.http import JsonResponse
response = JsonResponse({'foo': 'bar'})
print(response.content)
b'{"foo": "bar"}'
默认只能传递字典类型,如果要传递非字典类型需要设置一下safe关键字参数。
例子:
urls.py
url(r'^json_test/$', views.JsonTest.as_view()),
views.py
class JsonTest(views.View):
def get(self, request):
res = {"code": 0, "data": "alex"}
res2 = ["alex", "污Sir", "金老板", "小姨妈", "MJJ"]
return JsonResponse(res2,safe=False)
三 模板引擎进阶
1 模板语法:
1. 两个语法:
1. {{ }} --> 跟变量相关的操作
2. {% %} --> 跟逻辑相关的操作
2. 变量相关
1. 传字典或对象类型的数据 obj.name/obj.age
2. 传数组类型的数据 obj.索引值
例子:
1 def template_test(request):
2 l = [11, 22, 33]
3 d = {"name": "alex"}
4
5 class Person(object):
6 def __init__(self, name, age):
7 self.name = name
8 self.age = age
9
10 def dream(self):
11 return "{} is dream...".format(self.name)
12
13 Alex = Person(name="Alex", age=34)
14 Egon = Person(name="Egon", age=9000)
15 Eva_J = Person(name="Eva_J", age=18)
16
17 person_list = [Alex, Egon, Eva_J]
18 return render(request, "template_test.html", {"l": l, "d": d, "person_list": person_list})
取值:
{# 取l中的第一个参数 #}
{{ l.0 }}
{# 取字典中key的值 #}
{{ d.name }}
{# 取对象的name属性 #}
{{ person_list.0.name }}
{# .操作只能调用不带参数的方法 #}
{{ person_list.0.dream }}
3. 日期格式化
<p>{{ today|date:"Y-m-d H:i:s"}}</p>
4. 显示真正的html代码
<p>{{ link|safe }}</p>
例子:
view配置:
1 def template_test(request):
2 data = ["金老板", "景女神", "MJJ"]
3 # data = ""
4 filesize = 1234567890
5 import datetime
6 today = datetime.datetime.today()
7 link = "<script>for(;;){alert(123)}</script>"
8
9
10 class Person(object):
11 def __init__(self, name, dream):
12 self.name = name
13 self.dream = dream
14
15 def dream(self):
16 return "我的梦想是学好Python!"
17 pw = Person("彭玮", "不去下一期!")
18
19 return render(request, "t.html", {
20 "data": data,
21 "file_size": filesize,
22 "today": today,
23 "link": link,
24 "person": pw
25 })
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
10 {#<p>{{ data.1 }}</p>#}
11 <p>{{ data|default:"暂无数据" }}</p>
12 <p>{{ file_size|filesizeformat }}</p>
13 <p>{{ today }}</p>
14
15
16 <p>{{ link }}</p>
17 {#<p>{{ link|safe }}</p>#}
18
19 <hr>
20
21 <p>
22 {% for teacher in data %}
23 {% if forloop.last %}
24 {{ teacher }}
25 {% else %}
26 {{ teacher }},
27 {% endif %}
28 {% endfor %}
29 </p>
30 {#<p>{% if 3 > 2 > 1 %}{% endif %}</p>#}(不支持这样写)
31 {##}
32 {#<p>{% if 3 > 2 and 2 > 1 %}{% endif %}</p>#}
33
34 <hr>
35
36 {{ person.name }}
37 {{ person.dream }}
38
39
40 </body>
41 </html>
2. 母板
1. 为什么要用母版?
不同的页面有大量重复的代码,我们可以把公用的部分提取出来放在单独一个文件
2. 怎么使用?
1.1. 在子页面 通过使用 {% extends ‘模板名’ %} --> 放在子页面的最上面
2. 1{% block xx %}{% endblock %}
母版例子:
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>{{ html_title }}</title>
6 <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
7 {% block page-css %}
8
9 {% endblock %}
10 </head>
11 <body>
12 {% include 'nav.html' %}
13 <div class="container">
14 <div class="row">
15 <div class="col-md-8 col-md-offset-2">
16
17 {% block page-main %}
18
19 {% endblock %}
20
21 </div>
22 </div>
23 </div>
24 <script src="/static/jquery.js"></script>
25 {% block page-js %}
26
27 {% endblock %}
28 </body>
29 </html>
3. 组件
可以将常用的页面内容如导航条,页尾信息等组件保存在单独的文件中,然后在需要使用的地方按如下语法导入即可。
使用 {% include '组件名' %}导入
如何继承母版例子:
1 {% extends 'mama.html' %}
2
3 {% block page-main %}
4 <table class="table table-bordered">
5 <thead>
6 <tr>
7 <th>#</th>
8 <th>id</th>
9 <th>出版社名称</th>
10 <th>操作</th>
11 </tr>
12 </thead>
13 <tbody>
14 {% for publisher in publisher_list %}
15 <tr>
16 <td>{{ forloop.counter }}</td>
17 <td>{{ publisher.id }}</td>
18 <td>{{ publisher.name }}</td>
19 <td>
20 <a href="/edit_publisher/{{ publisher.id }}/" class="btn btn-info">编辑</a>
21 <a href="/delete_publisher/" class="btn btn-danger">删除</a>
22 </td>
23 </tr>
24 {% endfor %}
25 </tbody>
26 </table>
27
28 {% endblock %}
29
30 {#我这个页面才用到的一个js文件#}
31 {% block page-js %}
32 <script src="/static/1.js"></script>
33 {% endblock %}
四 CSRF
1. 为什么要有csrf_token?
2. Django中如何使用?
在render的页面上写上{% csrf_token %}
3. 如果是form表单形式提交,必须放在form表单中
4 如果不加csrf_token默认是不让提交的报403错误
例子:
urls.py配置
1 url(r'^csrf_test/$', views.csrf_test),
views.py配置:
def csrf_test(request):
if request.method=="POST":
print(request.POST)
return HttpResponse("OK")
else:
return render(request,"csrf_test.html")
html配置:
<form action="" method="post">
{% csrf_token %}
<input type="text" name="name">
<input type="submit" value="提交">
</form>