Django之请求和响应

    所谓请求和响应就是一种对话式或者说应答式的交互过程。请求是值用户使用浏览器通过http协议发送给服务段的数据,响应是值服务端接收到请求后做响应的处理回复给浏览器的数据。常用的方法就是GET,POST,HEAD,DELETE,TRACE等。

1.请求和响应概述

    Django中的请求实际就是视图函数view中的第一个参数,就是固定为request,其为HttpRquest对象,Django接收到http请求后,会根据请求数据创建HttpRequest对象,该对象涵盖了很多包括属性,其涵盖了请求的相关信息。这里介绍几个常用的属性:
  • path_info:URL字符串
  • method:请求方法,比如‘GET’和‘POST’方法等
  • GET:QueryDict查询字典的对象,包含get请求方法的所有数据
  • POST:QueryDict查询字典的对象,包含post请求方法的所有数据
  • FILES:类似字典的对象,包含所有的上传文件的信息

这里在urls中新增test_req路由

path('test_req',views.test_request)

在视图函数中新增一个test_request函数

def rest_request(request):
    print('path info is:',request.path_info)
    print('method is :',request.method)
    print('request.GET is :', request.GET)

    return HttpResponse("test is ok")

运行工程,并在终端进行查看
在这里插入图片描述
Django响应中,经常使用的是HttpResponse函数,其参数调用格式如下
HttpResponse(content=响应体,contenttype=响应体数据类型,status=状态码)
常见的contentType有:
text/html 默认的html
text/plain 纯文本
text/css css 文件
text/javascript js文件
multipart/form-data 文件提取
application/json json传输
application/xml xml文件

2.GET和POST请求

无论是GET还是POST请求,统一都是由视图函数接收,通过判断request.method区分是哪种方法,代码一般为

if request.method == 'GET':
    处理get请求的逻辑
elif request.method =='POST':
    处理post请求的逻辑
else:
    其他处理逻辑

创建一个mysite2的工程,如何创建工程参考 Django之url和视图函数,在mysite2同名文件下的urls.py的urlpatterns新增路由

    # http:127.0.0.1:8000/test_get_post
    path('test_get_post',views.test_get_post),

在mysite2同名文件下的views.py中定义函数test_get_post

def test_get_post(request):
    if request.method == 'GET':
        pass
    elif request.method == "POST":
        pass
    else:
        pass
    return HttpResponse('--test get post is ok-- ')

因此get和post请求的总体框架如上所示,接着详细介绍下

2.1 GET请求

GET请求动作,一般用于向浏览器获取/查询数据,能够产生GET请求的场景有:

  • 浏览器地址栏输入url,点击回车
  • < a href=“地址?key1=value1&key2=value2”>
  • form表单中的method方法为GET
    如果是GET请求方式,可以给服务端传递数据,通过使用查询字符串(Query String),由于是明文传递,因此切忌不要传递敏感数据
get请求URL格式
xxx?key1=value1&key2=value2
eg:http://127.0.0.1:8000/page=1&a=12

使用查询字符串传递数据的时候,可以使用如下方法获取请求对象的属性

request.GET['参数名']
request.GET.get('参数名','默认值')
request.GET.getlist('参数名')

在mysite2的同名文件夹下的urls.py的url_pattern中新增

path('test_get_post',views.test_get_post),

再视图函数views.py中定义视图函数test_get_post

def test_get_post(request):
    if request.method == 'GET':
        print(request.GET)
        print(request.GET['a'])
        print(request.GET.get('c','there is no c'))
        print(request.GET.getlist('a'))
    elif request.method == "POST":
        pass
    else:
        pass
    return HttpResponse('--test get post is ok-- ')

运行python mange.py runserver
在这里插入图片描述
在终端处查看如下结果

<QueryDict: {'a': ['100', '300', '400']}>
400
there is no c
['100', '300', '400']

这里注意到,查询字符串中输入的是?a=100&a=200&a=400,使用request.GET[‘a’]输出的是最后一个a

2.2 POST请求

POST请求,一般用于向服务器提交数据,客户端通过表单等POST请求将数据传递给服务器,其格式如:

<form method='post' action='login'>
    姓名:<input type=text name='username>
    <input type='submit' value='登录>
</form>

服务端在views.py中,通过request.method进行判断

request.method == "POST":

使用post方法传递数据的时候,可以使用如下方法获取请求对象的属性

request.POST['参数名']
request.POST.get('参数名','默认值')
request.POST.getlist('参数名')

注意这里在settings.py中的MIDDLEWARE中取消csrf验证,否则Post提交会提示csrf 403的报错

MIDDLEWARE = [
    ...
    # 'django.middleware.csrf.CsrfViewMiddleware',
    ...

在views.py新增变量

POST_FORM = '''
<form method = 'post' action = '/test_get_post'>
     用户名:<input type = 'text' name = 'uname'>
     <input type='submit' value='提交'>
</form>
'''
def test_get_post(request):
    if request.method == 'GET':
        print(request.GET)
        print(request.GET['a'])
        print(request.GET.get('c','there is no c'))
        print(request.GET.getlist('a'))
        return HttpResponse(POST_FORM)
    elif request.method == "POST":
        request.POST.get['uname']
        return HttpResponse('post is ok')
    else:
        pass
    return HttpResponse('--test get post is ok-- ')

输入http:127.0.0.1:80000?a=40
在这里插入图片描述

3.模板层

Django中的是MTV模式,Model-Template-View
在这里插入图片描述

模板是可以根据字典数据动态变化的Html页面。模板可以根据视图中传递的字典数据动态的生成相应的Html网页

3.1 模板配置

创建模板文件夹<项目名>/templates,即在mysite项目问价下创建templates普通文件夹。
在这里插入图片描述
在setttings.py中TEMPPLATES配置项中,做如下配置:
1.BACKEND:指定模板引擎
2.DIRS:模板的搜索目录
3.APP_DIRS:是否要在应用的templates文件夹搜索模板文件
4.OPPTIONS:有关模板的选项
配置项目中,需要做如下修改:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        #修改DIRS目录
        'DIRS': [os.path.join(BASE_DIR,'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

3.2模板加载

之前我们都是使用return HttpResposne加载返回一个字符串对象,实际开发的时候,很少会直接返回一个HttpResponse对象,这里创建了模板并使用模板,那如何进行加载模板,主要有以下两种方式:
方式一:
通过loader获取模板,通过HttpResponse进行相应,在视图函数中一般处理为:
from django.template import loader
#1.通过loader加载模板
t = loader.get_template('模板文件名')
#2.将t装换成HTML字符串
html = t.render(字典数据)
#3.用响应对象将转换的字符串内容返回给浏览器
return HttpResponse(html)

因此这里配置好setttings.py中的TEMPLATES .DIRS后,在url_patterns中新增一个路由

path('test_html',views.test_html),

在文件夹templates下新建一个test_html.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板层</title>
</head>
<body>
<p>是模板层输出</p>
</body>
</html>

接着在视图函数中新增一个test_html函数

from django.template import loader
def test_html(reqeust):
    t = loader.get_template('test_html.html')
    html = t.render()
    return HttpResponse(html)

再次刷新界面,展示如下所示
在这里插入图片描述
方式二:
使用render()直接加载并响应模板,在视图函数中:

from django.shortcuts import render
return render(request,'模板文件名',字典数据)
from django.template import loader
from django.shortcuts import render
def test_html(reqeust):
    # 方案1
    # t = loader.get_template('test_html.html')
    # html = t.render()
    # return HttpResponse(html)

    #方案2
    return render(reqeust, 'test_html.html')

这里既然render提到了字典数据,那视图层与模板层之间的数据如何交互呢?
1.视图函数中可以Python变量封装到字典中传递到模板

def xxx_view(request):
    dic = {
        'key1':'value1',
        'key2':'value2',
    }
return render(request,'xxx.html',dic)

2.模板中,可以使用{{ 变量名 }}的语法,调用视图传递进来的变量,这里的变量名就是字典中的key1,key2…
将视图函数views.py中的方案2修改如下:

    #方案2
    dic = {
        'username':'django',
        'age':18,
    }
    return render(reqeust, 'test_html.html',dic)

接着修改test_html.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>模板层</title>
</head>
<body>
<p>
    客户为{{ username }}年龄为{{ age }}的模板层展示
</p>
</body>
</html>

结果展示为:
在这里插入图片描述

3.3 模板层变量

在3.2中已经使用了模板的变量,在视图函数view中,使用字典传递参数,那可以给模板传递哪些数据类型呢?

  • str 字符串 int 整形

  • list 列表 tuple 元组

  • dict 字典 func 方法

  • obj 类实例化的对象
    对应的在模板中使用变量的语法如下所示:

  • {{ 变量名 }}

  • {{ 变量名.index }}

  • {{ 变量名.key }}

  • {{ 对象.方法名 }}

  • {{ 函数名 }}
    接着上面的示例,在urls.py中新增一个路由

path('test_html_param',views.test_html_param),

新增一个模板为test_html_param.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h3>int{{ int }}</h3>
<h3>str{{ str }}</h3>
<h3>lst 是 {{ lst }}</h3>
<h3>lst 是 {{ lst.0 }}</h3>
<h3>dict{{ dict.a }}</h3>
<h3>dict['a']{{ dict }}</h3>
<h3>functions 是 {{ func }}</h3>
<h3>class_obj 是 {{ class_obj.say }}</h3>

</body>
</html>

在视图函数中,新增test_html_view函数

def test_html_param(request):
    dic = {}
    dic['int'] = 88
    dic['str'] = 'django'
    dic['lst'] = ['tom','jack','Liky']
    dic['dict'] = {'a':9,'b':10}
    dic['func'] = say_hi
    dic['class_obj'] = Dog()
    return render(request,'test_html_param.html',dic)
def say_hi():
    return 'hello'
class Dog:
    def say(self):
        return "Dog"

输出结果如下所示:
在这里插入图片描述

3.4 模板标签

将一些服务器端的功能嵌入到模板中,例如流程控制。标签的语法是

{% 标签 %}
...
{% 结束标签 %}

if标签

{% if 条件表达式1 %}
...
{% elif 条件表达式2 %}
...
{% else %}
...
{% endif %}

这里针对标签,举例如下所示:
在urls.py中新增一个路由

path("mycal",views.test_cal)

在templates下新增一个mycal.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>计算器</title>
</head>
<body>

<form action="/mycal" method="post">
    <input type="text" name="x" value="{{ x }}">
    <select name="op">
        <option value="add">+</option>
        <option value="sub">-</option>
        <option value="mul">*</option>
        <option value="div">+/</option>
    </select>
    <input type="text" name="y" value="{{ y }}"> = 

    <span>{{ result }}</span>
    <div><input type="submit" value="开始计算"></div>
</form>
</body>
</html>

视图函数views.py中新增

def test_mycal(request):
    if request.method == "GET":
        return render(request,"mycal.html")
    elif request.method == "POST":
        # 处理计算
        x = request.POST['x']
        y = request.POST['y']
        op = request.POST['op']

        result = 0
        x,y = int(x),int(y)
        if op == 'add':
            result = x + y
        elif op == 'mul':
            result = x * y
        elif op == 'sub':
            result = x - y
        elif op == 'dic':
            result = x / y
        else:
            pass

        # 还要能展示用户上次选择的和填写数据
        return  render(request,'mycal.html',locals())

在这里插入图片描述
运行中发现一个问题,每次选择的运算符号之后,运算之后,运算符号都会停留在+加号,这里没哟记录
了解到select中有一个属性为selected,如果某个选项设置了selected属性,则会把其作为第一项进行显示。结合这个属性,对mycal.html做如下调整

<form action="/mycal" method="post">
    <input type="text" name="x" value="{{ x }}">
    <select name="op">
        <option value="add" {% if op == 'add' %}selected{% endif %}>+</option>
        <option value="sub" {% if op == 'sub' %}selected{% endif %}>-</option>
        <option value="mul" {% if op == 'sub' %}selected{% endif %}>*</option>
        <option value="div" {% if op == 'sub' %}selected{% endif %}>/</option>
    </select>
    <input type="text" name="y" value="{{ y }}"> =

    <span>{{ result }}</span>
    <div><input type="submit" value="开始计算"></div>
</form>

另一个常用的标签是for标签

{% for 变量 in 可迭代对象 %}
   ...循环语句
{% empty %}
   ...可迭代对象无数据是填充的语句
{% endfor %}

3.5 模板层继承

继承的思想在面向对象编程中常常有体现,在目标层也可以利用这样的思想,从而事项模板层的代码复用。
我们村查看豆瓣电影中的界面,看看所谓模板继承的原理。
在这里插入图片描述
点击选电影和,电视剧发现界面布局完全一样,唯一不同的就是中间部分展示的内容有所不同。类似如下风格:
在这里插入图片描述
模板继承可以使用父模板的内容,子模板直接继承父模板的全部内容并可以覆盖父模板中的相应的块。语法如下所示:

  • 定义父模板中的block标签
  • 标识出哪些在子模板中是允许被修改的
  • block标签,在父模板中定义,可以在子模板中覆盖

定义子模板可以如下操作

  • 继承模板 extends标签,写在模板文件的第一行。如{% extends 'base.html %}
  • 子模板 重写父模板中的内容块
{% block block_name %}
子模板块用来覆盖父模板中 block_name块的内容
{% endblock block_name %}

这里举例说明
在路由urls.py中新增如下路由

    path('base_index',views.base_view),
    path('music_index',views.music_view),
    path('sport_index',views.sport_view),

在视图函数views.py中新增

def base_view(request):
    return render(request,'base.html')
def music_view(request):
    return render(request, 'music.html')
def sport_view(request):
    return render(request, 'sport.html')

在templates文件夹下新增base.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    {% block mytitle %}
    <title>主页</title>
    {% endblock %}
</head>
<body>
<a href="/music_index">音乐频道</a>
<a href="/sport_index">体育频道</a>
</br>


{% block info %}
    这是主页
{% endblock %}

</br>

<h3>有问题,请联系123456xxxx</h3>
</body>
</html>

由于前文提到父模板可以继承的部分就是在父模板中使用block标注出来的部分,在子模板中extends之后并重写该部分,新增music.html和sport.html

{% extends 'base.html' %}

{% block mytitle %}
    <title>音乐频道</title>
{% endblock %}

{% block info %}
    欢迎来到音乐频道
{% endblock %}

运行之后如下所示:
在这里插入图片描述
项目整体结构如下所示
在这里插入图片描述

4.url反向解析

url在代码中一般出现在如下两个地方:

  1. 超链接 点击之后,跳转到对应的链接url
  2. 模板表单中的数据,用post提交至url
  3. 视图函数中-302跳转 HttpResponseRedirect(‘url’)将用户地址栏中的地址跳转至对应的url
    url反向解析,指在视图或者模板中,用Path定义的名称动态查找或计算出相应的路由。path语法为:
path(route,views,name=别名)
path(page,views.page_view,name=page_url)
根据path中的name=关键字传参给url确定个唯一确定的名字,在模板或者视图中,可以通这个名字反向推断出此url信息,因为实际开发中url很长,使用反向解析可以很大程度上降低写错的可能性。

4.1 url反向解析-模板

url反向解析在模板中-通过url标签实现地址的反向解析

{% url '别名' %}
{% url '别名' '参数值1' '参数值2' %}
#url中参数一律使用字符串传参
eg:
{% url 'pagen'  '400' %}  
{% 'person' age='18' name='django' %}

在urls.py下新增两个路由

    # http://127.0.0.1:8000/test/url
    path('test/url',views.test_url),
    path('test_url_result_display',views.test_url_result_display,name='turs'),
    这里的url很长,我们需要做个简短的别名进行处理,设置别名为turs

新增视图函数views.py下的处理函数

def test_url(request):
    return render(request,'test_url.html')
def test_url_result_display(request):
    return HttpResponse('--test url result is ok--')

templates模板下新增一个模板,test_url.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>测试url</title>
</head>
<br>
<a href="http://127.0.0.1:8000/test_url_result_display">绝对地址</a>
<a href="/test_url_result_display">相对地址</a>

</br>
<a href="{% url 'turs' %}">url反向解析</a>
</body>
</html>

那携带参数的url反向解析如何实现呢?
新增一个path路由

path('test_url_result_display/<int:pageNumber>',views.test_url_result_display,name='turs'),

视图函数变更,新增一个参数用于接收

def test_url_result_display(request,pageNumber):
    return HttpResponse('--test url result is ok--')

模板中

<a href="{% url 'turs'  '100' %}">url反向解析带参数</a>

结果如下所示:
在这里插入图片描述
url反向解析,还有很重要的一个功能,比如上文中定义的path变化了,将

path('test_url_result_display_xxx/<int:pageNumber>',views.test_url_result_display,name='turs'),

发现其他的几个都不能访问了,但是反向解析的版本仍然可以使用,这就是url “动态的”绑定。

4.2 url反向解析-视图

上面介绍了url反向解析在模板中如何使用,现在介绍下url反向解析如何在视图函数中使用。

from django.url import reverse
reverse('别名',args[],kwargs=[])
ex:
print(reverse('pagen',args=[300]))
print(reverse('person',kwargs={'name':'django','age':20}))

继续上面的介绍,给url_pattern做如下修改

path('test/url',views.test_url,name='tu'),

视图函数做如下修改

def test_url_result_display(request,pageNumber):
    # return HttpResponse('--test url result is ok--')

    # 跳转302
    from django.urls import reverse
    url = reverse('tu')
    return HttpResponse(url)

进入之后,点击跳转成功,这里浏览器是如何得知,跳转的位置,通过Loaction进行定位

上一篇:Django之url和视图函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值