• <学习笔记>从零开始自学Python-之-web应用框架Django( 八)Django表单


            HTML 表单是交互式网站的基本组成部分,用户提交信息、搜索内容、与后台数据交互都要用到表单。

    1、从请求对象中获取数据

            view视图函数的第一个参数都是 request,这个request就是请求获得的HttpRequest对象。里面包含中有一些关于当前所请求 URL 的信息,如下图

    HttpRequest对象的方法和属性
    属性/方法说明示例
    request.path完整的路径,不含域名,但是包 含前导斜线“/hello/”
    request.get_host()主机名(即通常所说的“域名”)“127.0.0.1:8000”或www.newweb.com
    request.get_full_path()包含查询字符串(如果有的话) 的路径“/hello/?print=true”
    request.is_secure()通过 HTTPS 访问时为 True,否 则为 FalseTrue 或 False

    2、关于请求的其他信息

            request.META 的值是一个 Python 字典,包含请求的所有 HTTP 首部,例如用户的 IP 地址和用户代理(user agent,通常是 Web 浏览器的名称和版本)。

            注意,具体包含哪些首部取决于用户发送了什么首部,以及 Web 服务器返回了什么首部。

    这个字典中常见的几个键有:

    • HTTP_REFERER:入站前的 URL(可能没有)。(注意,要使用错误的拼写,即 REFERER。)

    • HTTP_USER_AGENT:浏览器的用户代理(可能没有)。例如:"Mozilla/5.0 (X11; U; Linux i686; frFR; rv:1.8.1.17) Gecko/20080829 Firefox/2.0.0.17"。

    • REMOTE_ADDR:客户端的 IP 地址,例如 "12.345.67.89"。(如果请求经由代理,这个首部的值可能是一 组 IP 地址,以逗号分隔,例如 "12.345.67.89,23.456.78.90"。)

    注意,因为 request.META 是个普通的 Python 字典,所以尝试访问不存在的键时,抛出 KeyError 异常。 (HTTP 首部是外部数据,即由用户的浏览器提交,因此不能完全相信,当某个首部为空或不存在时,应该让应用程序优雅失败。)为了处理未定义的键,应该使用 try/except 子句,或者 get() 方法:

    1. # 用try语句
    2. def ua_display_good1(request):
    3. try:
    4. useragent = request.META['HTTP_USER_AGENT']
    5. except KeyError:
    6. useragent = 'unknown'
    7. return HttpResponse("Your browser is %s" % useragent)
    8. # 用get方法
    9. def ua_display_good2(request):
    10. useragent = request.META.get('HTTP_USER_AGENT', 'unknown')
    11. return HttpResponse("Your browser is %s" % useragent)

    也可以编写一个简单的视图,显示 request.META 中的所有信息,以便查阅。

    1. def display_meta(request):
    2. values = request.META.items()
    3. values
    4. html = []
    5. for k, v in values:
    6. html.append('%s%s' % (k, v))
    7. return HttpResponse('%s
      '
      % '\n'.join(html))

    3、用表单实现查询功能

            除了关于请求的基本元数据之外,HttpRequest 对象还有两个属性包含用户提交的信息:request.GET 和 request.POST。这两个属性的值都是类似字典的对象,分别用于获取 GET 和 POST 数据。POST 数据一般由 HTML 表单提交,而 GET 数据既可以来自表单,也可以来自页面 URL 中的查询字符串。

            我们利用request.GET 和 request.POST就可以实现前后端之间的通信,让用户提交的信息传递给服务器,服务器进行响应。

            我们前面的案例中说到可以用url传输信息给后端,但那不是个好办法,现在我们改用表单传输数据,实现查询功能。我们先在之前的 'notice/'  url 对应的 class3.html 增加一个查询表单(纯属偷懒,表单应该放到页面合适的地方去)

    1. <form action="/search/" method="get">
    2. <h3>根据姓名查找同学h3>
    3. <input type="text" name="chaxun">
    4. <input type="submit" value="查询">
    5. form>

    这里 method = ‘get’表示请求的方法为  get

    这一行是标题,告诉用户这个表单是干嘛的,应该填什么数据,可要可不要

    第一个input 的 name='chaxun' 这是后面我们找数据是要用到的标签名称

    第二个input 的 type = 'submit' 表示这是一个提交按钮,value='查询' 表示它在页面上显示为“查询”

    看一下页面:

     然后我们来写个视图函数 chaxun1

    1. def chaxun1(request):
    2. studentName = request.GET['chaxun']
    3. s = Student.objects.get(name=studentName)
    4. return HttpResponse('你要查询的{}同学信息如下:姓名:{},年龄{},性别{},成绩{},武力值{}'.format(s.name,s.name,s.age,s.sex,s.score,s.skill))

    然后我们在上面的文本框中输入 “黄蓉”,点击查询按钮,得到如下结果:

     4、改进表单

           上面这个表单虽然实现了我们预期的功能,但是还不完善。比如如果用户提交的是个空表单怎么办,如果用户提交的信息数据库里查不到怎么办,我们不能总是报错啊,现在我们来着手改进这个表单:

    1. if request.GET and request.GET['chaxun']: #确保GET方法获得了值,并且'chaxun'标签(就是那个提交查询内容的输入框)不为空
    2. studentName = request.GET['chaxun']
    3. try: #确保要查询的数据存在
    4. s = Student.objects.get(name=studentName)
    5. result = '你要查询的{}同学信息如下:姓名:{},年龄{},性别{},成绩{},武力值{}'.format(s.name,s.name,s.age,s.sex,s.score,s.skill)
    6. context['result']=result
    7. except:
    8. context['result']='查无此人' #如果查不到,显示“查无此人”并返回同一个页面
    9. return render(request,'class3.html',context=context,status=200)
    10. else: #如果输入为空,曾刷新页面,重新填写
    11. return render(request, 'class3.html')

    这样改造后,我们再查询页面,就可以直接看到结果了,输入空值则会返回当前页面继续填写

    5、Django的表单类

            用户在填写表单的时候,谁也不知道用户会写些什么,为了数据能够按规范填写,就需要对用户的填写行为进行约束,也就是表单的验证。我们当然可以自己手动去写这些验证方法,不过Django已经贴心地为我们准备好了内置的表单库,django.forms,它能处理从显示 HTML 表单到验证的大多数问题,即开即用。

            我们用一个例子来演示一下这个表单类怎么用。比如上面那个查询功能,我们现在用forms表单类把它集成实现。

            首先新建一个forms.py文件(当然也可以直接写在views.py,不过一般Django风格都是给forms单独一个文件)我们定义一下我们需要的字段。这里的字段其实是显示在前端给用户看的,所以想要让用户输入什么字段,就在这里定义,比如我们这里打算让用户可以通过 姓名、年龄 和 成绩这三个条件来查询:

    1. from django import forms #注意这里要从django引入forms库
    2. class chaxunForm(forms.Form): #定义一个查询类
    3. #这里label就是前端显示的输入框的提示文字,max_length是输入的最大长度,
    4. #required=False是允许这个值为空,因为我们期望的是通过每个条件单独都可以查询
    5. name = forms.CharField(label="名字",max_length=10,required=False)
    6. #这里可以定义输入数值的大小,用max_value 和 min_value 参数来设定上下限
    7. age = forms.IntegerField(label="年龄",required=False,max_value=100,min_value=10)
    8. score = forms.IntegerField(label="成绩",required=False)

    为了方便演示,我们另外写了个HTML页面文件 chaxun.html,反正用模板继承很方便

    1. {% extends "base.html" %}
    2. {% block title %}武侠三班的小窝{% endblock %}
    3. {% block main %}
    4. <h1>查询页面,在这里可以查找你想了解的同学h1>
    5. <form action="" method="post">{% csrf_token %}
    6. <h3>根据条件查找同学h3>
    7. {{form}}
    8. <input type="submit" value="查询">
    9. form>
    10. <P>
    11. {% for result in results %}
    12. <div>{{result}}div>
    13. {% endfor %}
    14. P>
    15. {% endblock %}

    注意这里页面上的输入框不用我们自己手动写了,form类会自动把自定义的字段转成input输入框  然后我们去views.py调用这个类,

    1. from classManage.forms import chaxunForm
    2. ........
    3. #其他代码
    4. ........
    5. def chaxun4(request):
    6. context={}
    7. form=chaxunForm(request.POST)
    8. if request.method == 'POST': #这里要注意确认一下方法为POST
    9. form = chaxunForm(request.POST) #实例化一个我们在forms.py里面定义的chaxunForm类
    10. context['form']=form #把form实例赋值给字典的 'form',方便前端调用
    11. results = []
    12. if form.is_valid(): #确保form的数据有效,这个验证工作forms类帮我们做了
    13. stuName = form.cleaned_data.get('name') #cleaned_data是经过清洗的数据
    14. stuAge = form.cleaned_data.get('age')
    15. print(stuAge)
    16. if stuName:
    17. #名字一般是唯一的,但是为了上下统一用一个函数比较方便,我们统统用filter,而不是get,然后把数据放到一个列表中去遍历
    18. stus=Student.objects.filter(name=stuName)
    19. elif stuAge:
    20. stus=Student.objects.filter(age=stuAge)
    21. elif stuScore:
    22. stus=Student.objects.filter(score=stuScore)
    23. else:
    24. pass
    25. for s in stus:
    26. result = '你要查询的{}同学信息如下:姓名:{},年龄{},性别{},成绩{},武力值{}'.format(s.name,s.name,s.age,s.sex,s.score,s.skill)
    27. results.append(result)
    28. print('postresult:',results)
    29. context['results']=results
    30. return render(request,'class3.html',context=context,status=200)
    31. else:
    32. form = chaxunForm()
    33. context['form']=form #把form对象整个赋值给字典的 'form'方便前端调用
    34. return render(request,'chaxun.html',context=context,status=200)

    我们去访问页面 http://127.0.0.1:8000/cha/ 看看效果

    可以看到出现了 名字、年龄、成绩 三个查询框,我们任意填其中一个,实现查询功能

     

     我们测试一下forms的验证效果,我们在年龄框里面输入汉字,发现根本不给输入,然后我们在年龄这里输入数字5,点击查询后发现它提示我数字必须大于10:

    当然这里这个提示不太美观,可以自定义来定制验证信息。总之,forms类可以帮我们进行数据审查,比如如果我们定义了一个forms类的email字段,它会自动审查输入是否为一个email格式,这真的大大简化了我们的工作啊。

    所以我们一般做登录、注册表单或者信息提交表单的时候,用这个forms类真的很方便。 

  • 相关阅读:
    k8s集群安装Ingress,KubeSphere可视化界面安装K8s
    Anaconda全网最全conda命令行(新建、复制、重命名、删除、国内源加速等)
    HTTP 长连接和 TCP 长连接有什么区别
    linux信号==Linux应用编程5
    layui中使用JavaScript监听下拉框(select)的变化,根据选中的值来决定是否显示或隐藏input元素
    C++函数模板
    图解LeetCode——1470. 重新排列数组(难度:简单)
    邮件群发软件
    C++设计模式之代理模式(结构型模式)
    《计算机体系结构量化研究方法第六版》1.5 集成电路中的功耗和能耗趋势
  • 原文地址:https://blog.csdn.net/qq_41597915/article/details/127239321