路径参数
url('gettime/(\\d+)/(\\d+)/(\\d+)', views.get_time),
添加views:
def get_time(request, hour, minute, second):
return HttpResponse('Time %s:%s:%s' % (hour, minute, second))
我们在后面添加了三个参数12/12/12成功返回响应:
但当我们改变参数位置时,响应数据也会发生改变
def get_time(request, hour, minute, second):
return HttpResponse('Time %s:%s:%s' % (minute, hour, second))
这是因为这种参数叫做位置参数,按照输入顺序12/1/12的顺序进行参数传递
想要不改变位置,我们可以采用关键字参数
添加新的url:
url('getdate/(?P<year>\\d+)/(?P<month>\\d+)/(?P<day>\\d+)', views.get_date),
我们这里采用?P<参数名称>
设置参数名称
views:
def get_date(request, year, day, month):
return HttpResponse('date %s-%s-%s' % (day, year, month))
url反向解析
- 在根urls中
path('views/', include(('ViewsLearn.urls',app_name),namespace='view')),
- 在子urls中
url('hello/(\d+)',views.hello,name='sayhello'),
- 在模板中使用
<a href="{% url 'view:sayhello'
year=2017 %}">Hello
year 的位置如果不指定名称按顺序算,指定名称按=算
- 在视图中使用
HttpResponseRedirect(reverse('view:sayhello',kwargs={}))
kwargs是字典
反向解析
- 根据根路由中注册的namespace和在子路由中注册name,这两个参数来动态获取我们的路径
- 在模板中使用 {% url 'namespace:name' %}
- 如果带有位置参数 {% url 'namespace:name' value1 value2 [valuen...] %}
- 如果带有关键字参数 {% url 'namespace:name' key1=value1 key2=value2 [keyn=valuen....] %}
使用反向解析优点
如果在视图,模板中使用硬编码连接,在url配置发生改变时,需要变更的代码会非常多,这样导致我们的代码结构不是很容易维护,使用反向解析可以提高我们代码的扩展性和可维护性。使用了反向解析后,我们可以动态获取路径。
实践:反向解析
在根urls中的two:
path('two/', include(('two.urls','two') namespace='second')),
# namespace 是命名空间,给two.urls指定一个命名空间名称second
在子路由中:
url('learn/', views.learn, name='learn'),
可以看到,我们给two/learn/添加了一个名字learn
VIEWS函数:
def learn(request):
return HttpResponse('LOVE LEARN')
反向解析转跳网页
我们也可以在之前的grade_list.html中添加地址,进行转跳
以下是硬编码地址,和反向解析方法:
<hr>
<a href="/two/learn/">硬编码连接</a>
{# 绝对定位 #}
<hr>
<a href="{% url 'second:learn' %}">反向解析</a>
{# 反向解析出地址 #}
我们可以看到结果,两者本质上没有区别,只是反向解析动态生成路径。
好处:变更应用路径时,反向解析自动变更地址
例如,将根路由中的two改为more
这时反向解析成功改变路径,而硬编码访问失败
带参反向解析转跳网页
为两个url添加name:
url('gettime/(\\d+)/(\\d+)/(\\d+)', views.get_time, name='get_time'),
url('getdate/(?P<year>\\d+)/(?P<month>\\d+)/(?P<day>\\d+)', views.get_date,name='get_date'),
在grade_list中添加:
<hr>
<a href="{% url 'second:get_time' 12 1 12 %}">时间带参数转跳</a>
{# 位置参数 #}
<hr>
<a href="{% url 'second:get_date' year=2018 month=11 day=12 %}"></a>
{# 关键字参数 #}
参数直接加载url后方,而且反向解析在模板中是{% url 'namespace:name' 参数 %}
作业注意
- 建立模型时候的外键
s_grade = models.ForeignKey(Grade, on_delete=models.CASCADE)
2.挖坑,填坑
{{}}在html挖坑
views中context=locals()填坑
3.获取每个班级学生名字的url,views
4.反向解析语法
5.怎么对应班级的学生进行解析?
视图
视图参数:
1.一个HttpRequest的实例
2.通过正则表达式获取过来的参数
位置:
错误视图:
- 404视图 (页面没找到)
- 400视图 (客户操作错误)
自定义错误视图
在工程的templates文件夹下创建对应的错误文件
获取请求路径{{ request_path }}
在文件中定义自己的错误样式
注意需要在关闭Debug的情况下才可以
没有关闭Debug的情况下会在界面中直接显示log实践:错误页面定制
- 在模板中重写对应错误状态码页面
- 关闭Debug
实现原则
- 就近原则,自己没有定义404界面,用的就是Django默认的404界面
双R
Request
内置属性
- method
- path
GET
- 类字典结构
- 一个key允许对应多个值
- get
- getlist
- POST
META
- 各种客户端元信息
- REMOTE_ADDR 远端访问IP
- Response
HttpRequest
服务器在接收到Http请求后,会根据报文创建HttpRequest对象
视图中的第一个参数就是HttpRequest对象
Django框架会进行自己的包装,之后传递给视图
属性:
- path 请求的完整路径
- method 请求的方法,常用GET,POST
- encoding 编码方式,常用utf-8
- GET 类似字典的参数,包含了get的所有参数
- POST 类似字典的参数,包含了post所有参数
- FILES 类似字典的参数,包含了上传的文件
- COOKIES 字典,包含了所有COOKIE
- session 类似字典,表示会话
方法: is_ajax() 判断是否是ajax(),通常用在移动端和JS中
实践:研究request参数
GET
def get_request(request):
print(request.path)
print(request.method)
print(request.GET)
print(request.POST)
return HttpResponse('REQUEST SUCCESS')
打印属性
/two/getrequest/ # 请求路径
GET
<QueryDict: {}> # 类字典结构
<QueryDict: {}>
字典结构:由key:value组成,key是由哈希表存储,保证不重复,而且查询速度快
而在Django中类字典结构中key允许重复
网页中?代表一种条件。一个接口。后面是种数据,这个数据要传输到这个网页中。网页根据问号后面的条件中的数据来调取相应的网页。
&,这个英文单词是and的意思,一个条件,同时还要符合另一个条件,这个符号是连接两个条件的符号。
我们可以看到类字典的结构还是核字典的结构一样,只不过把值放在了一起
现在我们要获取 GET里面的参数
hobby = request.GET.get('hobby')
print(hobby)
得到的是类字典结构中最后一个值
hobbies = request.GET.getlist('hobby')
print(hobbies)
POST
建立一个网页student.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>student</title>
</head>
<body>
<form action=""method = 'POST'>
<span>username:</span><input type="text" name="username" placeholder="please input username">
<button>submit</button>
</form>
</body>
</html>
解释:
标签被用来组合文档中的行内元素。
定义用户可输入文本的单行输入字段。placeholder是提示
起路由:url('createstudent', views.create_student),
views函数:
def create_student(request):
return render(request, 'student.html')
页面是这样的:
这时候我们提交数据,会发现报错
报错是403客户端出错,但是实际上,这是DJango自带的放跨站攻击的工具,目前没有学习,所以我们将这个BUG先屏蔽掉
我们将这行注释掉即可
接着我们点击sibmit目的是为了提交数据
所以将action中填写地址
<form action="{% url 'second:do_create_student' %}"
接着我们创建url,用来处理submit上来的数据
url('docreatestudent', views.do_create_student, name='do_create_student'),
views:
我们将传递上来的POST请求,进行打印,并且把提交上来的数据响应回去
def do_create_student(request):
print(request.method)
username = request.POST.get('username')
return HttpResponse(username)
报错重点
但到了这个时候我们点击submit的时候,竟然惊奇的发现返回的docreatestudent页面竟然还是createstudent的路由地址:
而且经过测试,最终路由并没有调用我们创建的do_create_student函数,仍然调用的是create_student
很显然,这是因为点击submit的时候,路由匹配时发生了错误
为了证明这个观点,我们将路由改为:
接着我们重新访问:
成功返回结果:
从而证明了在路由匹配时docreatestudent竟然匹配到了createstudent
原因是这样的:
路由匹配是按照从上到下的顺序匹配的,我们第一次访问createstudent时候没有问题,当我们接着访问docreatestudent时候,由于从上到下,发现createstudent完全包含在了docreatestudent中,所以只匹配上了他
解决方案,我们在url前添加^ 用来限定开头匹配:
url('^createstudent/', views.create_student),
url('^docreatestudent/', views.do_create_student, name='do_create_student'),
同理之前的$是限制匹配结尾
这样就完美解决问题
此处评论已关闭