上一篇主要讲了模板层的内容,戳链接:https://blog.jixiaob.cn/?post=40
——————————————————————————————————————————————
View层(视图)
用于接受外部请求,并作出相应。
大约分问两大类:①以json形式返回 ②以网页形式返回
视图的本质就算一个函数。
视图参数:1.一个HttpRequest的实例 2.通过正则表达式获得的参数
自定义错误页面:在模板文件夹新建如 404.html ,重写对应错误码的页面,即可自定义
双R
服务器在接收到HTTP请求之后,会根据报文创建HttpRequest对象
视图中的第一个参数就算HttpResponse对象
request
response
属性:
path 请求完整路径 method 请求方法(get,post)encoding 编码方式
GET 类似字典的参数,包含了get的所有参数。
POST类似字典的参数,包含了上传的文件。Files类似字典的参数,包含了上传的文件。
COOKIES:字典,包含了所有的COOKIE。session 类似字典,表示会话。
方法:
is_ajax()判断是否为ajax() 通常用在移动端和js中
request.GET和POST都是类字典结构(key允许重复(对应多个值))
request.META 元信息 request.META.get('key')
那么如何获取到GET的数据呢?
比如我们请求这个网页:http://127.0.0.1:8000/Two/haverequest?hobby=coding&a=b&hobby=sleeping
def have_request(request): print(request.path, request.method, request.GET, request.POST) hobby = request.GET.get('hobby') print(hobby) # 这样只能获得最后一个hobby sleeping hobbies = request.GET.getlist('hobby') print(hobbies) # 这样可以获取一个List ['coding', 'sleeping'] return HttpResponse('喵')怎么实现POST请求呢?在HTML里面新建一个提交的页面:
<form action="{% url 'second:do_create_student' %}" method="post"> <span>Username:</span> <input type="text" name="username" placeholder="请输入username"> <button>提交</button> </form>然后进入网页,写内容提交。这时候你获得了一个403页面,这是Django的防跨站。
可以先在settings里面的MIDDLEWARE里面注释掉:
# 'django.middleware.csrf.CsrfViewMiddleware',
然后写一个接受post的页面:
path(r'^docreatestudent', views.do_create_student, name='do_create_student') # 这里用url会报错,还是Django版本问题
def do_create_student(request): print(request.method) username = request.POST.get('username') return HttpResponse(username)
HttpResponse:
服务器返回给客户端的数据,由程序员自己创建。
1.不使用模板,直接HttpResponse()
2.调用模板,进行渲染(先load模板再渲染或者直接render)
render(request, template_name, {context})
request 请求对象体 template_name 模板路径 context 字典参数,用来填坑
属性:
content 返回的内容 charset 编码格式 status_code 响应状态码 content-type MIME类型(类似于拓展名的作用)
响应状态码可以自定义,就算请求成功了也可以给它返回404(反爬虫)
def hello(request): response = HttpResponse() response.content = "德玛西亚" response.status_code = 404 # 作用:一是真的显示404,二是防爬取 return responseMIME:指定传输的数据使用哪种形式打开 格式:大类型/小类型 image/png image/jpg
方法:
init 初始化 write()直接写出文本 flush()冲刷缓冲区 不管写(write)了多少都得刷
set_cookie(key,value='xxx',max_age=None,exprise=None)
delete_cookie(key) 设置cookie和删除cookie
子类:
HttpResponse子类:响应重定向,可以实现服务器内部跳转302
301:永久转移(不用了,不维护了HttpResponsePermanentRedirect) 302:临时转移
return HttpResponseRedict('/show/')
这里建议写反向解析的地址。 url = reverse('namespace:name') # 导包导的是django.urls.reverse()
这个还有个缩写rediect() # 在django.shortcuts包里面
HttpResponseBadRequest 400
HttpResponseNotFound 404
HttpResponseForbidden 403
HttpResponseNotAllowed 405 请求方法不被支持
HttpResponseServerError 500
Http404 Exception(引发异常)
raise 主动抛异常出来
JsonResponse子类:用于前后端分离或ajax请求服务器,做差量更新的时候(异步请求)
JsonResponse(dict) 也可以用__init__(self, data)设置数据,Convent-type是application/json
Json中有两种数据:JsonObjest(Json对象,key value)和JsonArray(Json数组,列表中可以是普通数据类型,可可以是JsonObject)二者可相互嵌套
什么时候用?移动端、Ajax
def get_info(request): data = { 'status': 200, 'msg': 'ok' } return JsonResponse(data=data)
需要注意的是,如果返回的信息包含中文的话,会默认转换为ascii码的形式表示。
比如
data = {
'msg': 'success',
'context': request.path_info,
'信息': '正常'
}
会被表示为:{"msg": "success", "context": "/get_data", "\u4fe1\u606f": "\u6b63\u5e38"}
如何让他直接显示中文的返回呢?只需在JsonResponse后面加上这样一条参数:
return JsonResponse(data, json_dumps_params={'ensure_ascii': False})
就能正常返回中文了,就像这样:{"msg": "success", "context": "/get_data", "信息": "正常"}
另外,如果你发现返回的json是字符串,而且有很多转义字符(斜杠)
这个解决方案是先把字符串转化为json对象json.loads('字符串'),然后再进行JsonResponse
浏览器上方便的Json格式化插件:JsonFomatter、JsonView
url正则匹配是按照列表书写顺序从上到下进行遍历,没有最优匹配的概念,匹配到就不会继续往后查找了。
我们通常直接指定以^开头,在结尾处直接添加反斜线。如果需要固定匹配,结尾需要加上$
获取URL路径上的参数
url的组成:
协议(schema):HTTP、HTTPS、FTP、RTMP
域名(domain):ip:port HTTP没有书写端口默认80端口。HTTPS 443。
路径(path):相对于主机的绝对路径
参数(QueryString):GET请求参数
锚点:#footer 用于页面定位
获取路径上的参数和URL有关系,后面的参数就没关系了。
正则获取数据:用括号()
url(r'^student/(\d+)/', views.student), 这里获取的是一串数字
在这里多写一个圆括号,views里面对应的函数就要多一个参数,个数对应必须一致不加会引起服务器错误。
def student(request, s_id):
return HttpResponse('获取一个学生信息成功')
收到的信息类型变为字符串。
rander()里面可以写context=locals(),内置函数,将局部变量使用字典的方式打包,key是变量名,value是数据。
如点击班级列表的链接,获取该班级里面的学生信息:
# views里面 def get_grade(request): gread_list = Grade.objects.all() return render(request, 'gradelist.html', locals()) def get_students(request, g_id): grade = Grade.objects.get(pk=g_id) students = grade.student_set.all() context = { "students": students } return render(request, 'students.html', context=context) # urls里面 url('getgrade/', views.get_grade), url('getstudents/(\d+)/', views.get_students), # gradelist.html 这里面的<a></a>是超链接 <ul> {% for greads in gread_list %} <li><a href="/app/getstudents/{{ greads.id }}/">{{greads.g_name}}</a></li> {% endfor %} <li></li> </ul>多个参数:
url(r'^gettime/(\d+)/(\d+)/(\d+)', views.get_time), def get_time(request, hour, minute, second): return HttpResponse('传入时间 %s:%s:%s' % (hour, minute, second))路径参数默认是位置参数,按照书写顺序进行匹配。
当然也可以写关键字参数
url(r'^getdate/(?P<year>\d+)/(?P<month>\d+)/(?P<day>\d+)', views.get_date), def get_date(request, day, month, year): return HttpResponse('日期:%s-%s-%s' % (year, month, day))
URL反向解析
需要先在跟路由上加一个参数
url('Two/', include('Two.urls', namespace='second')),
子路由添加一个name
url(r'^learn/', views.learn, name='learn'),
这样就可以根据namespace和name找到了
然后你运行的时候又会获得一个报错:
'Specifying a namespace in include() without providing an app_name '
django.core.exceptions.ImproperlyConfigured: Specifying a namespace in include() without providing an app_name is not supported. Set the app_name attribute in the included module, or pass a 2-tuple containing the list of patterns and app_name instead.
这是django1和django2的区别导致的,有两种解决方法:
1.在include中传入第二个参数——app的名字 url('Two/', include(('Two.urls', 'Two'), namespace='second')),
2.在每一个app的urls里面添加app_name变量 app_name = 'Two'
详见这篇博客:https://blog.csdn.net/Martin_Yan/article/details/84982056
怎么找呢?在HTML模板里面这样写:
<a href="{% url 'second:learn' %}">去学习</a>second是namespace,learn是name,这样可以动态获取链接
<a href="{% url 'second:get_time' 15 31 48 %}">Time</a>关键字直接写 变量名=值 就行
本文地址:https://blog.jixiaob.cn/?post=41
版权声明:若无注明,本文皆为“赵苦瓜のBlog~”原创,转载请保留文章出处。