Django实战(7)—— 表单处理

前文

Django 实战 (1)—— 创建第一个Django项目
Django 实战 (2)—— 视图与 URL 配置
Django 实战 (3)—— Django 是怎么处理请求的?
Django 实战 (4)—— 连接 MySQL
Django 实战 (5)—— 数据库操作
Django 实战 (6)—— Admin 管理

使用 request 获取数据

之前我们学习了 HttpResponse ,但是没有讲到 HttpRequest,我们看下代码:

from django.http import HttpResponse

def hello(request):
    return HttpResponse("Hello Django")

党请求页面时,Django 会创建一个 HttpRequest 对象,其中包含有关请求的元数据。然后 Django 加载适当的视图,将 HttpRequest 作为第一个参数传递给 view 函数。每个视图负责返回一个 HttpResponse 对象

HttpRequest 对象

属性

除非另有说明,否则所有属性都应被视为只读

用法

方法 说明 举例
request.path 一个字符串,代表请求的页面的完整路径。不包括方案领域 “/music/bands/the_beatles/”
request.get_host() 主机名(比如,通常说的域名) “127.0.0.1:8000” or “www.baidu.com”
request.get_full_path() 请求路径,可能包含查询的字符串 “/hello/>print=true”
request.is_secure() 如果通过 HTTPS 访问,则此方法返回 True,否则返回 False 返回 True 或 False
request.method 一个字符串,表示请求中使用的 HTTP 方法,且必须保证是大写的 if request.method == ‘GET’:

在 view 函数中,要始终使用 request 属性或方法来得到 URL,而不要手动输入。这回使得代码更加灵活,以便在其它地方重用

HttpRequest.META

包含所有可用的 HTTP 标头的字典。可用的标头取决于客户端和服务器端,以下是一些示例:

  • CONTENT_LENGTH -请求主体的长度(以字符串形式)。
  • CONTENT_TYPE -请求主体的MIME类型。
  • HTTP_ACCEPT -可接受的响应内容类型
  • HTTP_ACCEPT_ENCODING -响应的可接受编码。
  • HTTP_ACCEPT_LANGUAGE -可接受的响应语言。
  • HTTP_HOST -客户端发送的HTTP Host标头。
  • HTTP_REFERER -推荐页面(如果有)。
  • HTTP_USER_AGENT -客户端的用户代理字符串。
  • QUERY_STRING -查询字符串,作为单个(未分析)字符串。
  • REMOTE_ADDR -客户端的IP地址。
  • REMOTE_HOST -客户端的主机名。
  • REMOTE_USER -由Web服务器验证的用户(如果有)。
  • REQUEST_METHOD-诸如"GET"或的字符串"POST"。
  • SERVER_NAME -服务器的主机名。
  • SERVER_PORT -服务器的端口(以字符串形式)。

除了CONTENT_LENGTH和之外CONTENT_TYPE,如上所述,META通过将所有字符都转换为大写字母,用下划线替换所有连字符,并HTTP_在名称中添加前缀,将请求中的所有HTTP标头转换为键。因此,例如,称为的标头X-Bender将映射到METAkey HTTP_X_BENDER

注意:因为 request.META 是一个普通的字典,因此当你视图访问一个不存在的 key 时,会触发一个 KeyError 异常。(HTTP header 信息是由用户的浏览器所提交的、不应该给予信任的 “额外” 数据,因此你总是应该好好设计你的应用以便当一个特定的 Header 数据不存在时,给出一个优雅的回应)你应该用 try/except 语句,或者使用 Python 字典的 get() 方法来处理这些 “可能不存在的key”

# 不建议这么做
def display_user_agent(request):
    info = request.META['HTTP_USER_AGENT']  # 可能会出现 KeyError 异常
    return HttpResponse("your brower is %s" %info)
# 推荐
def display_user_agent(request):
    try:
        info = request.META['HTTP_USER_AGENT']  # 可能会出现 KeyError 异常
    except KeyError:
        info = 'unkown key'
    return HttpResponse("your brower is %s" %info)

表单处理

新建一个表单页面

我们先来编写一个 form 表单

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
    <form action="/login/" method="post">
        {% csrf_token %}
        <table>
            <tr>
                <td><label for="username">Name:</label></td>
                <td><input type="text" id="username" name="username"></td>
            </tr>
            <tr>
                <td>Age:</td>
                <td><input type="text" name="age"></td>
            </tr>
            <tr>
                <td><button type="submit">Submit</button></td>
            </tr>
        </table>
    </form>
</body>
</html>

页面效果是这样的:(页面太丑,大佬轻点喷)
在这里插入图片描述
我们通过 Django 将页面返回到浏览器
在 views.py 中编写以下代码

from django.shortcuts import render

def login(request):
    return render('login.html')       # 将页面返回到浏览器

然后在 urls 中增加访问路径:

from django.contrib import admin
from django.urls import path
from webapp import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login_page/',views.login),
]

OK,我们启动一下项目,访问一下 http://127.0.0.1:8000/login_page/,哦豁,报错了,怎么回事?
在这里插入图片描述
原来是我们的代码中少了个 request 参数,原因上边有说到,这里我们把 request 加上

def login_page(request):
    return render(request,'login.html')

如果你使用的是 PyCharm ,左边还会有个图标提示,说你这段代码返回的是一个html页面
在这里插入图片描述
OK,我们再启动一下项目,再次访问 http://127.0.0.1:8000/login_page/ ,OK,正常显示我们的页面了
在这里插入图片描述

在Django 中构建一张表单

页面我们创建好了,但是好像还差点什么东西,对了,细心的朋友们应该发现我们表单中的 action 指向的路径是 /login/,在这之前我们需要先构建一张表单,那么如何构建呢?

Form 类

我们在我们的 app 中新建一个 forms.py 文件
在这里插入图片描述
forms.py 文件中的代码如下:

from django import forms

class NameForm(forms.Form):
    username = forms.CharField(label='username',max_length=100)
  • 它定义了一个只包含一个字段(username)的 Form 类,我们已经为这个字段提供了友好的标签,当它渲染后会显示在 < label>中(在这种情况下,如果我们省略之前指定的 label,它还是会自动生成一个一样的标签)
  • 字段的最大长度由 max_length 来定义,它主要做了两件事情。首先它会在 HTML 的 < input>上增加了 maxlength=“100”(这样浏览器就会在第一时间阻止用户输入超过这个数量的字符串)。其次它还会在 Django 收到浏览器传过来的表单时,对数据长度进行验证(也就是服务器端验证)

在 views.py 编写逻辑代码

表单我们构建好了,只有一个 username 的字段,但是作为演示已经可以了。接下来我们在 views.py 编写以下代码:

from django.shortcuts import render
from django.http import HttpResponse
from webapp.models import Test
from .forms import NameForm
from django.http import HttpResponseRedirect

# 输出表单信息
def login(request):
    if request.method == 'POST':
        form = NameForm(request.POST)
        if form.is_valid():
            print(form) # 打印一下
            # 重定向
            return HttpResponseRedirect('/success/')
    else:
        pass

# 返回成功信息
def success(request):
    return HttpResponse("success")

Form 实例具有 is_valid()方法,该方法为其所有字段运行验证例程。 调用此方法时,如果所有字段都包含有效数据,它将:

  • 返回 True
  • 将表单的数据放到它的属性 cleaned_data 中

当我们访问这个视图用的是 GET 请求的时候,它会创建一个空的表单实例并将其放置在模板上下文中进行渲染。这是我们首次访问这个 URL 时能预料到会发生的情况

如果表单提交用到的是 POST 请求,那么该视图将再次创建一个表单实例并使用请求中的数据填充它: form = NameForm(request.POST) 这叫 “绑定数据到表单”(现在它是一张绑定的表单)

当我们调用 is_valid() 方法时:如果不为 True,带着表单返回到模板。这次表单不再为空(未绑定),所以 HTML 表单将用之前提交的数据进行填充,放到可以根据需要进行编辑和修正的位置

如果 is_valid() 为 True,我们就能在其 cleaned_data 属性中找到所有通过验证的表单数据。我们可以在发送一个 HTTP 重定向告诉浏览器下一步去向之前用这些数据更新数据库或者做其他处理


当然了,我们编写了 views.py 文件之后还要在 urls.py 中添加途径

from django.contrib import admin
from django.urls import path
from webapp import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login_page/',views.login_page),
    path('login/',views.login),
    path('success/',views.success),
]

OK,我们重启一下服务,访问 http://127.0.0.1:8000/login_page/
在这里插入图片描述
点击 submit 提交,报错了
在这里插入图片描述
通过报错信息我们可以知道

  • CSRF验证失败。请求中止
  • 在模板中,{% csrf_token %}每个POST表单内都有一个模板标记,该标记以内部URL为目标
  • 如果您没有使用CsrfViewMiddleware,那么您必须 csrf_protect在使用csrf_token template标签的所有视图以及接受POST数据的视图上使用。
  • 该表单具有有效的CSRF令牌。登录另一个浏览器选项卡或登录后单击“后退”按钮后,您可能需要使用表单重新加载页面,因为登录后令牌会旋转

这个报错解决很简单,在报错信息已经为我们提出了需要在表单中增加 {% csrf_token %},如下:
在这里插入图片描述
我们再次访问一下:
在这里插入图片描述
点击提交
在这里插入图片描述
OK,已经返回成功信息,我们看下控制台的输出
在这里插入图片描述
可以看到我们在表单中输入的值已经绑定到表单中了

发布了184 篇原创文章 · 获赞 864 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/Woo_home/article/details/103786136