1、HTML中的表单:用来提交数据给服务器的,不管后台的服务器用的是Django还是PHP语言还是其他语言

2、Django中的表单:

1、渲染表单模板

2、表单验证数据是否合法, 回显功能(验证错误,输入数据不会被清空)

3、 可保留用户上次提交的数据

4、 数据类型转换(转换成相应的python类型)

说明:

  1. 要先导入forms模板
  2. 所有的表单类都要继承forms.Form类
  3. 每个表单字段都有自己的字段类型比如CharField,它们分别对应一种HTML语言中<form>内的一个input元素。这一点和Django模板系统的设计非常相似。
  4. label参数用于设置<label>标签
  5. max_length 限制字段输入的最大长度。它同时起到两个作用,一是在浏览器页面限制用户输入不可超过字符数,二是在后端服务器验证用户输入的长度也不可超过。
  6. widget = forms.PasswordInput 用于指定该字段在form表单里表现为 <input type='password'> ,也就是密码输入框。


一,表单form

为了接收用户的投票选择,我们需要在前段页面显示一个投票界面,让我们重写之前的polls/detail.html文件,代码如下:

{{ question.question_text }}

{% if error_message %}
{{ error_message }}
{% endif %}
{% csrf_token %}
{% for choice in question.choice_set.all %}
{{ choice.choice_text }}
{% endfor %}



简要说明:

  • 上面的模板显示一系列单选按钮,按钮的值时选项的ID,按钮的名字是字符串“choice”。这意味着,当你选择了其中某个按钮,并提交表单,一个包含数据choice=# 的POST请求将被发送到指定的url,#是被选择的选项的ID,这就是HTML表单的基本概念。
  • 如果你有一定的前端知识,那么form标签的action属性和method属性应该很清楚其含义,action表示你要发送的目的url,method表示提交数据的方式,一般分为POST和GET。
  • forloop.counter是Django模板系统专门提供的一个变量,用来表示你当前循环的次数,一般用来给循环项目添加有序数标。forloop其他用法:
  • forloop.counter: 值是一个整数,表示循环的次数。这个属性的值从 1 开始,因此第一次循环时,forloop.counter 等于 1
  • forloop.counter0: forloop.counter0 forloop.counter 类似,不过是从零开始的。第一次循环时,其值为 0 。
  • forloop.revcounter: 值是一个整数,表示循环中剩余的元素数量。第一次循环时, forloop.revcounter 的值是序列中要遍历的元素总数。最后一次循环时, forloop.revcounter 的值为 1 。
  • forloop.revcounter0: forloop.revcounter 类似,不过索引是基于零的。第一次循环时, forloop.revcounter0 的值是序列中元素数量减去一。最后一次循环时, forloop.revcounter0 的值为 0 。
  • forloop.first: forloop.first 是个布尔值,第一次循环时为 True 。需要特殊处理第一个元素时很方便:
  • {% for object in objects %}    {% if forloop.first %}  {% else %}             {% endif %}     {{ object }}     {% endfor %}


forloop.last: 是个布尔值,最后一次循环时为 True 。经常用它在一组链接之间放置管道符号:


{% for link in links %}
{{ link }}{% if not forloop.last %} | {% endif %}
{% endfor %}


  • 由于我们发送了一个POST请求,就必须考虑一个跨扎请求伪造的安全问题,简称CSRF,Django为你提供了一个简单的方法来避免这个困扰,那就是在form表单内添加一条{ %  csrf_token %} 标签,标签名不可更改,固定格式,位置任意,只要是在form表单内。这个方法对form表单的提交方式方便好使,但如果是用ajax的方式提交数据,就不能用这个方法了。

现在,让我们创建一个处理提交过来的数据视图,前面我们已经写了一个“占坑”的vote视图的url(polls/urls.py)

1

​url(r​ ​​ ​'^(?P​ ​​ ​, views.vote, name=​ ​​ ​'vote'​ ​​ ​),​

以及占坑的vote视图函数(polls.views.py),我们把坑填起来:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

​from​ ​ ​ ​django.shortcuts import get_object_or_404, render​

​from​ ​ ​ ​django.http import HttpResponseRedirect, HttpResponse​

​from​ ​ ​ ​django.urls import reverse​

​from​ ​ ​ ​.models import Choice, Question​

​# ...​

​def vote(request, question_id):​

​question = get_object_or_404(Question, pk=question_id)​

​try​ ​​ ​:​

​selected_choice = question.choice_set.​ ​​ ​get​ ​​ ​(pk=request.POST[​ ​​ ​'choice'​ ​​ ​])​

​except (KeyError, Choice.DoesNotExist):​

​# 发生choice未找到异常时,重新返回表单页面,并给出提示信息​

​return​ ​ ​ ​render(request, ​ ​​ ​'polls/detail.html'​ ​​ ​, {​

​'question'​ ​​ ​: question,​

​'error_message'​ ​​ ​: ​ ​​ ​"You didn't select a choice."​ ​​ ​,​

​})​

​else​ ​​ ​:​

​selected_choice.votes += 1​

​selected_choice.save()​

​# 成功处理数据后,自动跳转到结果页面,防止用户连续多次提交。​

​return​ ​ ​ ​HttpResponseRedirect(reverse(​ ​​ ​'polls:results'​ ​​ ​, args=(question.id,)))​

有些新的东西,我们要解释一下:

  • request.POST是一个类似字典的对象,允许你通过键名访问提交的数据,本例中,request.POST['choice'] 返回被选择选项的ID,并且值的类型永远是string字符串,哪怕它看起来像数字!同样的,你也可以用类似的手段获取GET请求发送过来的数据,一个道理。
  • request.POST['choice'] 有可能触发一个KeyError异常,如果你的POST数据里没有提供choice键值,在这种情况下,上面的代码会返回表单页面并给出错误提示,PS:通常我们会给个默认值,防止这种异常的产生,例如request.POST['choice',None],一个None解决所有问题。
  • 在选择计数器加一后,返回的是一个HttpResponseRedirect而不是先前我们常用的HTTPResponse,HttpResponseRedirect需要一个参数:重定向的URL。这里有一个建议,当你成功处理POST数据后,应当保持一个良好的习惯,始终返回一个HttpResponseRedirect。这里不仅仅是对Django而言,它是一个良好的WEB开发习惯。
  • 我们再上面HttpResponseRedirect的构造器中使用了一个reverse()函数,它能帮助我们避免在视图函数中硬编码URL。它首先需要一个我们再URLconf中指定的name,然后是传递的数据。例如'polls/3/results/’ ,其中的3是某个question.id的值,重定向后将进入polls:results对应的视图,并将question.id传递给它,白话来讲,就是把活扔给另一个路由对应的视图去干。

当有人对某个问题投票后,vote()视图重定向到了问卷的结果显示页面,下面我们来写这个处理结果页面的视图(polls/views.py):

1

2

3

4

5

​from​ ​ ​ ​django.shortcuts import get_object_or_404, render​

​def results(request, question_id):​

​question = get_object_or_404(Question, pk=question_id)​

​return​ ​ ​ ​render(request, ​ ​​ ​'polls/results.html'​ ​​ ​, {​ ​​ ​'question'​ ​​ ​: question})​

同样,还需要些个模板polls/templates/polls/results.html (路由,视图,模板,模型都是这个套路)

1

2

3

4

5

6

7


​{{ question.question_text }}​

​{% ​ ​​ ​for​ ​ ​ ​choice ​ ​​ ​in​ ​ ​ ​question.choice_set.all %}​

​{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}​

​{% endfor %}​

​<a href=​ ​​ ​"{% url 'polls:detail' question.id %}"​ ​​ ​>Vote again?​

现在你可以到浏览器中访问/polls/1/ 了 ,投票了。你会看到一个结果页面,每投一次,它的内容就会更新一次。如果你提交的时候没有选择项目,则会得到一个错误提示。

如果你在前面漏掉了一部分操作没做,比如没有创建choice选项对象,那么可以按下面的操作,补充一下:

1

2

3

4

5

6

7

8

9

10

11

12

​D:\Django\mysite>python  manage.py shell​

​Python 3.7.1 (v3.7.1:260ec2c36a, Oct 20 2018, 14:57:15) [MSC v.1915 64 bit (AMD64)] ​ ​​ ​on​ ​ ​ ​win32​

​Type ​ ​​ ​"help"​ ​​ ​, ​ ​​ ​"copyright"​ ​​ ​, ​ ​​ ​"credits"​ ​ ​ ​or ​ ​​ ​"license"​ ​ ​ ​for​ ​ ​ ​more information.​

​(InteractiveConsole)​

​>>> ​ ​​ ​from​ ​ ​ ​polls.models import Question​

​>>> q = Question.objects.​ ​​ ​get​ ​​ ​(pk=1)​

​>>> q.choice_set.create(choice_text = ​ ​​ ​'Not much'​ ​​ ​,votes=0)​

​>>> q.choice_set.create(choice_text = ​ ​​ ​'The sky'​ ​​ ​,votes=0)​

​>>> q.choice_set.create(choice_text = ​ ​​ ​'Just hacking again'​ ​​ ​,votes=0)​

为了方便,我将当前状态的各主要内容一并贴出,依次可以对照参考!

1  ——完整的mysite/urls.py文件如下:

1

2

3

4

5

6

7

​from​ ​ ​ ​django.conf.urls import url,include​

​from​ ​ ​ ​django.contrib import admin​

​urlpatterns = [​

​url(r​ ​​ ​'^admin/'​ ​​ ​, admin.site.urls),​

​url(r​ ​​ ​'^polls/'​ ​​ ​, include(​ ​​ ​'polls.urls'​ ​​ ​)),​

​]​

2 ——完整的mysite/settings.py文件如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

​import os​

​# Build paths inside the project like this: os.path.join(BASE_DIR, ...)​

​BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))​

​# Quick-start development settings - unsuitable for production​

​# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/​

​# SECURITY WARNING: keep the secret key used in production secret!​

​SECRET_KEY = ​ ​​ ​'85vvuta(p05ow!4pz2b0qbduu0%pq6x5q66-ei*pg+-lbdr#m^'​

​# SECURITY WARNING: don't run with debug turned on in production!​

​DEBUG = True​

​ALLOWED_HOSTS = []​

​# Application definition​

​INSTALLED_APPS = [​

​'polls'​ ​​ ​,​

​'django.contrib.admin'​ ​​ ​,​

​'django.contrib.auth'​ ​​ ​,​

​'django.contrib.contenttypes'​ ​​ ​,​

​'django.contrib.sessions'​ ​​ ​,​

​'django.contrib.messages'​ ​​ ​,​

​'django.contrib.staticfiles'​ ​​ ​,​

​]​

​MIDDLEWARE = [​

​'django.middleware.security.SecurityMiddleware'​ ​​ ​,​

​'django.contrib.sessions.middleware.SessionMiddleware'​ ​​ ​,​

​'django.middleware.common.CommonMiddleware'​ ​​ ​,​

​'django.middleware.csrf.CsrfViewMiddleware'​ ​​ ​,​

​'django.contrib.auth.middleware.AuthenticationMiddleware'​ ​​ ​,​

​'django.contrib.messages.middleware.MessageMiddleware'​ ​​ ​,​

​'django.middleware.clickjacking.XFrameOptionsMiddleware'​ ​​ ​,​

​]​

​ROOT_URLCONF = ​ ​​ ​'mysite.urls'​

​TEMPLATES = [​

​{​

​'BACKEND'​ ​​ ​: ​ ​​ ​'django.template.backends.django.DjangoTemplates'​ ​​ ​,​

​'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'​ ​​ ​,​

​],​

​},​

​},​

​]​

​WSGI_APPLICATION = ​ ​​ ​'mysite.wsgi.application'​

​# Database​

​# https://docs.djangoproject.com/en/1.11/ref/settings/#databases​

​DATABASES = {​

​'default'​ ​​ ​: {​

​'ENGINE'​ ​​ ​: ​ ​​ ​'django.db.backends.sqlite3'​ ​​ ​,​

​'NAME'​ ​​ ​: os.path.​ ​​ ​join​ ​​ ​(BASE_DIR, ​ ​​ ​'db.sqlite3'​ ​​ ​),​

​}​

​}​

​# Password validation​

​# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators​

​AUTH_PASSWORD_VALIDATORS = [​

​{​

​'NAME'​ ​​ ​: ​ ​​ ​'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'​ ​​ ​,​

​},​

​{​

​'NAME'​ ​​ ​: ​ ​​ ​'django.contrib.auth.password_validation.MinimumLengthValidator'​ ​​ ​,​

​},​

​{​

​'NAME'​ ​​ ​: ​ ​​ ​'django.contrib.auth.password_validation.CommonPasswordValidator'​ ​​ ​,​

​},​

​{​

​'NAME'​ ​​ ​: ​ ​​ ​'django.contrib.auth.password_validation.NumericPasswordValidator'​ ​​ ​,​

​},​

​]​

​# Internationalization​

​# https://docs.djangoproject.com/en/1.11/topics/i18n/​

​LANGUAGE_CODE = ​ ​​ ​'en-us'​

​TIME_ZONE = ​ ​​ ​'Asia/Shanghai'​

​USE_I18N = True​

​USE_L10N = True​

​USE_TZ = True​

3  ——完整的polls/views.py 应该如下所示:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

​from​ ​ ​ ​django.shortcuts import reverse​

​from​ ​ ​ ​django.shortcuts import HttpResponseRedirect​

​from​ ​ ​ ​django.shortcuts import get_object_or_404​

​from​ ​ ​ ​django.shortcuts import HttpResponse​

​from​ ​ ​ ​django.shortcuts import render​

​from​ ​ ​ ​.models import Choice​

​from​ ​ ​ ​.models import Question​

​from​ ​ ​ ​django.template import loader​

​# Create your views here.​

​def index(request):​

​latest_question_list = Question.objects.order_by(​ ​​ ​'-pub_date'​ ​​ ​)[:5]​

​template = loader.get_template(​ ​​ ​'polls/index.html'​ ​​ ​)​

​context = {​

​'latest_question_list'​ ​​ ​: latest_question_list,​

​}​

​return​ ​ ​ ​HttpResponse(template.render(context, request))​

​def detail(request, question_id):​

​question = get_object_or_404(Question, pk=question_id)​

​return​ ​ ​ ​render(request, ​ ​​ ​'polls/detail.html'​ ​​ ​, {​ ​​ ​'question'​ ​​ ​: question})​

​def results(request, question_id):​

​question = get_object_or_404(Question, pk=question_id)​

​return​ ​ ​ ​render(request, ​ ​​ ​'polls/results.html'​ ​​ ​, {​ ​​ ​'question'​ ​​ ​: question})​

​def vote(request, question_id):​

​question = get_object_or_404(Question, pk=question_id)​

​try​ ​​ ​:​

​selected_choice = question.choice_set.​ ​​ ​get​ ​​ ​(pk=request.POST[​ ​​ ​'choice'​ ​​ ​])​

​except (KeyError, Choice.DoesNotExist):​

​return​ ​ ​ ​render(request, ​ ​​ ​'polls/detail.html'​ ​​ ​, {​

​'question'​ ​​ ​: question,​

​'error_message'​ ​​ ​: ​ ​​ ​"You didn't select a choice."​ ​​ ​,​

​})​

​else​ ​​ ​:​

​selected_choice.votes += 1​

​selected_choice.save()​

​return​ ​ ​ ​HttpResponseRedirect(reverse(​ ​​ ​'polls:results'​ ​​ ​, args=(question.id,)))​

4  ——完整的polls/urls.py 应该如下所示:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

​from​ ​ ​ ​django.conf.urls import url​

​from​ ​ ​ ​. import views​

​app_name = ​ ​​ ​'polls'​

​urlpatterns = [​

​# ex: /polls/​

​url(r​ ​​ ​'^$'​ ​​ ​, views.index, name=​ ​​ ​'index'​ ​​ ​),​

​# ex: /polls/5/​

​url(r​ ​​ ​'^(?P​ ​​ ​, views.detail, name=​ ​​ ​'detail'​ ​​ ​),​

​# ex: /polls/5/results/​

​url(r​ ​​ ​'^(?P​ ​​ ​, views.results, name=​ ​​ ​'results'​ ​​ ​),​

​# ex: /polls/5/vote/​

​url(r​ ​​ ​'^(?P​ ​​ ​, views.vote, name=​ ​​ ​'vote'​ ​​ ​),​

​]​

5  ——完整的polls.model.py文件如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

​from​ ​ ​ ​django.db import models​

​import datetime​

​from​ ​ ​ ​django.utils import timezone​

​# Create your models here.​

​class​ ​ ​ ​Question(models.Model):​

​question_text = models.CharField(max_length=200)​

​pub_date = models.DateTimeField(​ ​​ ​'date published'​ ​​ ​)​

​def was_published_recently(self):​

​return​ ​ ​ ​self.pub_date >= timezone.now() - datetime.timedelta(days=1)​

​def __str__(self):​

​return​ ​ ​ ​self.question_text​

​class​ ​ ​ ​Choice(models.Model):​

​question = models.ForeignKey(Question, on_delete=models.CASCADE)​

​choice_text = models.CharField(max_length=200)​

​votes = models.IntegerField(​ ​​ ​default​ ​​ ​=0)​

​def __str__(self):​

​return​ ​ ​ ​self.choice_text​

6  ——完整的polls/admin.py 文件如下:

1

2

3

4

5

6

7

​from​ ​ ​ ​django.contrib import admin​

​# Register your models here.​

​from​ ​ ​ ​.models import Question​

​admin.site.register(Question)​

7  ——完整的templates/polls/index.html  文件如下:

1

2

3

4

5

6

7

8

9

​{% ​ ​​ ​if​ ​ ​ ​latest_question_list %}​

​{% ​ ​​ ​for​ ​ ​ ​question ​ ​​ ​in​ ​ ​ ​latest_question_list %}​

​<a href=​ ​​ ​"/polls/{{ question.id }}/"​ ​​ ​>{{ question.question_text }}​

​{% endfor %}​

​{% ​ ​​ ​else​ ​ ​ ​%}​


​No polls are available.​

​{% endif %}​

8 ——完整的templates/polls/detail.html 文件如下:

1

2

3

4

5

6

7

8

9

10

11

12


​{{ question.question_text }}​

​{% ​ ​​ ​if​ ​ ​ ​error_message %}​

{{ error_message }}

​{% endif %}​

​<form action=​ ​​ ​"{% url 'polls:vote' question.id %}"​ ​ ​ ​method=​ ​​ ​"post"​ ​​ ​>​

​{% csrf_token %}​

​{% ​ ​​ ​for​ ​ ​ ​choice ​ ​​ ​in​ ​ ​ ​question.choice_set.all %}​

​<input type=​ ​​ ​"radio"​ ​ ​ ​name=​ ​​ ​"choice"​ ​ ​ ​id=​ ​​ ​"choice{{ forloop.counter }}"​ ​ ​ ​value=​ ​​ ​"{{ choice.id }}"​ ​ ​ ​/>​

​<label ​ ​​ ​for​ ​​ ​=​ ​​ ​"choice{{ forloop.counter }}"​ ​​ ​>{{ choice.choice_text }}

​{% endfor %}​

​<input type=​ ​​ ​"submit"​ ​ ​ ​value=​ ​​ ​"Vote"​ ​ ​ ​/>​

9 ——完整的templates/polls/results.html 文件如下:

1

2

3

4

5

6

7


​{{ question.question_text }}​

​{% ​ ​​ ​for​ ​ ​ ​choice ​ ​​ ​in​ ​ ​ ​question.choice_set.all %}​

​{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}​

​{% endfor %}​

​<a href=​ ​​ ​"{% url 'polls:detail' question.id %}"​ ​​ ​>Vote again?​

vote()视图没有对应的HTML 模板,它直接跳转到results视图去了。

运行服务器,测试各功能如下:

这是问卷列表页面:

Django学习笔记(3)—— Form表单_Django Template

这是“What's up” 问卷选项页面:

Django学习笔记(3)—— Form表单_Django Template_02

这是选择结果的页面:

Django学习笔记(3)—— Form表单_Django Template_03

这是没有选择选项时,提示错误信息的页面:

Django学习笔记(3)—— Form表单_Django Template_04



二、知识储备:HTML表单form学习

表单,在前端页面中属于最常见的一个东西了。基本上网站信息的提交都用到了表单,所以下面来学习Django中优雅的表单系统:Form

表单的主要作用是在网页上提供一个图形用户页面,用作采集和提供用户输入数据。

表单的基本结构:

1,from表单常用属性

  • action :表单提交的服务器地址,也就是服务器接收表单数据的url地址
  • method:表单提交数据的方法(一般为get/post)
  • name:最好是name属性的唯一性
  • enctype:表单数据提交时使用的编码类型,默认使用"pplication/x-www-form-urlencoded",如果使用post请求,则请求头中的content-type指定值就是该值。如果表单中有上传文件,编码需要使用"multipart/form-data"类型才能完成传递文件数据。

1.1  提交方式 get和post

get:使用URL传参:http://服务器地址?name1 = value&name2=value2(?表示传递参数,?后面采用name=value的形式传递,多个参数之间,用&链接)URL传参不安全,所有信息可在地址栏看到,并且可以通过地址栏随机传递其他数据。URL传递数据量有限,只能传递少量数据。

post:使用HTTP请求传递数据。URL地址栏不可见,比较安全。且传递数据量没有限制。

表单提交中中get和post方式的区别

  • 1,get是从服务器获取数据,post是向服务器传送数据
  • 2,get安全性非常低,post安全性非常高
  • 3,get传送的数据量较小,不能大于2kb,post传送的数据量较大,一般被默认为不受限制。但是理论上,IIS4中最大量为80KB,IIS5中为100KB。
  • 4,对于get方式,服务器端用request.QueryString获取变量的值,对于post方式,服务器端用Request.Form获取提交的数据。
  • 5,get请求不用添加{% csrf_token  %},也不会报csrftoken的错
  • 6,post请求的话,就需要添加{ %  csrf_token %}标签,而且需要使用 $.ajax()方法,将token传递到服务端。

1.2  浏览器提交表单时,会执行如下步骤

  • 1,识别出表单中表单元素的有效项,作为提交项
  • 2,构建出一个表单数据集
  • 3,根据form表单中的enctype属性的值作为content-type对数据进行编码
  • 4,根据form表单中的action属性和method属性向指定的地址发送数据


2,input标签

input标签是输入框,是表单中最重要的部分。

2.1  表单的type属性:

​<form action=​ ​​ ​"外部链接路径"​ ​​ ​.method=​ ​​ ​"get/post"​ ​​ ​.name=​ ​​ ​"#"​ ​​ ​>​

​<input type=​ ​​ ​"text"​ ​​ ​>输入文本框​

​<input type=​ ​​ ​"password"​ ​​ ​>输入密码框​

​<input type=​ ​​ ​"button"​ ​​ ​>输入按钮​

​<input type=​ ​​ ​"reset"​ ​​ ​>重置​

​<input type=​ ​​ ​"submit"​ ​​ ​>提交​

​<input type=​ ​​ ​"file"​ ​​ ​>文件​

​<input type=​ ​​ ​"checkbox"​ ​​ ​>多选框​

​<input type=​ ​​ ​"checkbox"​ ​ ​ ​checked​ ​​ ​>代表多选框默认选择项​

​<input type=​ ​​ ​"radio"​ ​​ ​>单选框,注意name需一样​

​<input type=​ ​​ ​"date"​ ​​ ​>时间​

​<input type=​ ​​ ​"checkbox"​ ​​ ​>多选框​



name:是指名字,因为提交的是键值对,所以必须要指定名字,否则无法提交,即使提交了也没有意义。

value:文本框的内容,一般用在不能输入的类型中,如改变按钮的名字等。

placeholder:占位内容,通常用于显示

readonly:只读模式,设置后无法修改输入框的内容

disabled:禁用状态

size:由于输入框是单行的,所以只能设置宽度

maxlength:限制输入框最大输入的字符个数

2.1  表单提交方式

开发中表单提交是很常见的,表单的提交方式也有很多种。

1,使用submit按钮提交表单

​<input type=​ ​​ ​"submit"​ ​value=​ ​​ ​"提交"​ ​​ ​>​


2,使用button按钮提交表单

​<input type=​ ​​ ​"button"​ ​value=​ ​​ ​"提交"​ ​​ ​>​


3,使用js进行表单提交,将form表单进行标记,将form表单中的某个元素设置成点击事件,点击时候调用js函数,再用JS。

​$(​ ​​ ​"#id"​ ​​ ​).submit()​


3,label 标签—— for 属性

label元素不会向用户呈现任何特殊效果。不过,它为鼠标用户改进了可用性。如果您在label元素内点击文本,就会触发此控件。也就是说,当用户选择该标签时,浏览器就会自动将焦点转到和标签相关的表单控件上。

3.1  实例

带有两个输入字段和相关标记的简单HTML表单:

Django学习笔记(3)—— Form表单_Django Template_05

        Title 
用户名: 密码: 密码确认: 爱好: basketball football skating
性别: boy girl
邮箱:
住址:


4,Form表单名的功能

  • 自动生成HTML表单元素
  • 检查表单数据的合法性
  • 回显功能(验证错误,输入数据不会被清空)
  • 数据类型转换(转换成相应的python类型)

表单提交数据就是由HTML表单向后台传递信息,后台通过request.GET() 或者request.POST()获取。



三,Django内置插件

12345678910111213141516171819202122

​TextInput(Input)​ ​​ ​NumberInput(TextInput)​ ​​ ​EmailInput(TextInput)​ ​​ ​URLInput(TextInput)​ ​​ ​PasswordInput(TextInput)​ ​​ ​HiddenInput(TextInput)​ ​​ ​Textarea(Widget)​ ​​ ​DateInput(DateTimeBaseInput)​ ​​ ​DateTimeInput(DateTimeBaseInput)​ ​​ ​TimeInput(DateTimeBaseInput)​ ​​ ​CheckboxInput​ ​​ ​Select​ ​​ ​NullBooleanSelect​ ​​ ​SelectMultiple​ ​​ ​RadioSelect​ ​​ ​CheckboxSelectMultiple​ ​​ ​FileInput​ ​​ ​ClearableFileInput​ ​​ ​MultipleHiddenInput​ ​​ ​SplitDateTimeWidget​ ​​ ​SplitHiddenDateTimeWidget​ ​​ ​SelectDateWidget​

四,常用选择插件——widget

widget是form表单最重要的参数之一,指定渲染Widget时使用的widget类,举个例子:就是说这个form字段在HTML页面中为文本输入框,密码输入框,单选框,多选框。。。。。

4.1,密码输入框

12345

​pwd = forms.CharField(​ ​​ ​min_length=6,​ ​​ ​label=​ ​​ ​"密码"​ ​​ ​,​ ​​ ​widget=forms.widgets.PasswordInput()​

4.2,单radioSelect

单radio值为字符串

123456

​user_type_choice = (​ ​​ ​(0, u​ ​​ ​'普通用户'​ ​​ ​),​ ​​ ​(2, u​ ​​ ​'高级用户'​ ​​ ​),​ ​​ ​)​ ​​ ​user_type = forms.IntegerField(initial=2,​ ​​ ​widget=forms.widgets.RadioSelect(choices=user_type_choice,))​

Django学习笔记(3)—— Form表单_Django Template_06

4.3,单选select

123456

​user_type_choice = (​ ​​ ​(0, u​ ​​ ​'普通用户'​ ​​ ​),​ ​​ ​(2, u​ ​​ ​'高级用户'​ ​​ ​),​ ​​ ​)​ ​​ ​user_type = forms.IntegerField(initial=2,​ ​​ ​widget=forms.widgets.Select(choices=user_type_choice,))​

Django学习笔记(3)—— Form表单_Django Template_07

4.4,多选select

123456

​user_type_choice = (​ ​​ ​(0, u​ ​​ ​'普通用户'​ ​​ ​),​ ​​ ​(2, u​ ​​ ​'高级用户'​ ​​ ​),​ ​​ ​)​ ​​ ​user_type = forms.IntegerField(initial=[1, ],​ ​​ ​widget=forms.widgets.SelectMultiple(choices=user_type_choice,))​

Django学习笔记(3)—— Form表单_Django Template_08

4.5,单选checkbox

1

​user_type = forms.CharField(widget=forms.widgets.CheckboxInput())​

Django学习笔记(3)—— Form表单_Django Template_09

4.6,多选checkbox

值为列表

12345678

​user_type_choice = (​ ​​ ​(0, u​ ​​ ​'普通用户'​ ​​ ​),​ ​​ ​(2, u​ ​​ ​'高级用户'​ ​​ ​),​ ​​ ​)​ ​​ ​user_type = forms.CharField( initial=[2, ],​ ​​ ​widget=forms.widgets.CheckboxSelectMultiple(​ ​​ ​choices=user_type_choice,​ ​​ ​))​

Django学习笔记(3)—— Form表单_Django Template_10

4.7  关于choice的注意事项

在使用选择标签的时候,需要注意choices的选项可以从数据库获取,但是由于是静态子弹,获取的值无法更新,那么需要自定义构造方法从而达到目的。

5,如何上传文件和图片的方法

5.1,FileField

1

​class​ ​ ​ ​FileField(upload_to=None, max_length=100, **options)[source]​

上传文件字段(不能设置为主键)。默认情况下,该字段在HTML中表现为一个ClearableFileInput 标签。在数据库内,我们实际保存的是一个字符串类型,默认最大长度为100,可以通过max_length 参数自定义。真实的文件是保存在服务器的文件系统内的。

重要参数upload_to 用于设置上传地址的目录和文件名。如下例所示:

123456

​class​ ​ ​ ​MyModel(models.Model):​ ​​ ​# 文件被传至`MEDIA_ROOT/uploads`目录,MEDIA_ROOT由你在settings文件中设置​ ​​ ​upload = models.FileField(upload_to=​ ​​ ​'uploads/'​ ​​ ​)​ ​​ ​# 或者​ ​​ ​# 被传到`MEDIA_ROOT/uploads/2015/01/30`目录,增加了一个时间划分​ ​​ ​upload = models.FileField(upload_to=​ ​​ ​'uploads/%Y/%m/%d/'​ ​​ ​)​

Django很人性化的帮我们实现了根据日期生成目录的方式!

upload_to 参数也可以接收一个回调函数,该函数返回具体的路径字符串,如下例:

123456

​def user_directory_path(instance, filename):​ ​​ ​#文件上传到MEDIA_ROOT/user_​ ​​ ​return​ ​ ​ ​'user_{0}/{1}'​ ​​ ​.format(instance.user.id, filename)​ ​ ​ ​class​ ​ ​ ​MyModel(models.Model):​ ​​ ​upload = models.FileField(upload_to=user_directory_path)​

例子中,user_directory_path 这种回调函数,必须接收两个参数,然后返回一个Unix风格的路径字符串。参数instace代表一个定义了FileField的模型的实例,说白了就是当前数据记录。filename是原本的文件名。

5.2,ImageField

1

​class​ ​ ​ ​ImageField(upload_to=None, height_field=None, width_field=None, max_length=100, **options)[source]​

用于保存图像文件袋额字段。其基本用法和特征与FileField一样,只不过多了两个属性height和width。默认清洗下,该字段在HTML中表现为一个ClearableFileInput 标签。在数据库内,我们实际保存的是一个字符串类型。默认最大长度100,可以通过max_length 参数自定义。真实的图片是保存在服务器的文件系统内的。

  • height_field参数:保存有图片高度信息的模型字段名
  • width_field参数:保存有图片宽度信息的模型字段名

使用Django的ImageField需要提前安装pillow模块

使用FileField或者ImageField字段的步骤:

  • 1,在settings文件中宏,配置MEDIA_ROOT,作为你上传文件在服务器中的基本路径(为了性能考虑,这些文件不会被存储在数据库中)。再配置个MEDIA_URL ,作为公用URL,指向上传文件的基本路径。请确保Web服务器的用户账号对该目录具有写的权限。
  • 2,添加FileField或者ImageField字段到你的模型中,定义好upload_to参数,文件最终会放在MEDIA_ROOT目录的“upload_to”子目录中。
  • 3,所有真正被保存在数据库中的,只是指向你上传文件路径的字符串而已。可以通过url属性,在Django的模板中方便的访问这些文件。例如,假设你有一个ImageField字段,名为mug_shot,那么在Django模块的HTML文件中,可以使用{{ object.mug_shot.url }} 来获取该文件。其中的object 用你具体的对象名称代替。
  • 4,可以通过name 和 size 属性,获取文件的名称和大小信息。

安全建议

无论你如何保存上传的文件,一定要注意他们的内容和格式,避免安全漏洞!务必对所有上传文件进行安全检查,确保他们不出问题! 如果你不加任何检查就盲目的让任何人上传到你的服务器文档根目录内,比如上传了一个CGI 或者PHP脚本,很可能就会被访问的用户执行,这具有致命的危害。

5.3,FilePathField

1

​class​ ​ ​ ​FilePathField(path=None, match=None, recursive=False, max_length=100, **options)[source]​

一种用来保存文件路径信息的子段。在数据表内以字符串的形式存在,默认最大长度100,可以通过max_length参数设置。

他们包含有下面的一些参数:

  • path:必须指定的参数。表示一个系统绝对路径
  • match:可选参数,一个正则表达式,用于过滤文件名。只匹配基本文件名,不匹配路径。例如foo.*\.txt$ ,只匹配文件名 foo23.txt,不匹配bar.txt 与 foo23.png 。
  • recursive:可选参数,只能是True或者FALSE。默认为FALSE。决定是否包含子目录,也就是是否递归的意思。
  • allow_files:可选参数,只能是True或者False。默认为True,决定是否应该将文件名包括在内。它和allow_folders其中,必须有一个为True。
  • allow_folders:可选参数,只能是True或者Flase。默认为False,决定是否应该将目录名包括在内。

比如:

1

​FilePathField(path=​ ​​ ​"/home/images"​ ​​ ​, match=​ ​​ ​"foo.*"​ ​​ ​, recursive=True)​

他只匹配/home/images/foo.png ,但是不匹配 /home/images/foo/bar.png ,因为默认情况,只匹配文件名,而不管路径怎么样的。

5.4,UUIDField

数据库无法为自己生成uuid,因此需要如下使用default参数:

123456

​import uuid     # Python的内置模块​ ​​ ​from​ ​ ​ ​django.db import models​ ​ ​ ​class​ ​ ​ ​MyUUIDModel(models.Model):​ ​​ ​id = models.UUIDField(primary_key=True, ​ ​​ ​default​ ​​ ​=uuid.uuid4, editable=False)​ ​​ ​# 其它字段​

5.5,上传文件实例

views.py

1234567891011121314151617181920

​from​ ​ ​ ​django.shortcuts import render, HttpResponse​ ​​ ​import os​ ​  ​ ​def upload(request):​ ​​ ​if​ ​ ​ ​request.method == ​ ​​ ​'GET'​ ​​ ​:​ ​​ ​# return HttpResponse("OK")​ ​​ ​return​ ​ ​ ​render(request, ​ ​​ ​'user8_book/upload.html'​ ​​ ​)​ ​​ ​elif request.method == ​ ​​ ​'POST'​ ​​ ​:​ ​​ ​# print("OK")​ ​​ ​# return HttpResponse("OK")​ ​ ​ ​obj = request.FILES.​ ​​ ​get​ ​​ ​(​ ​​ ​'file'​ ​​ ​)​ ​ ​ ​print(obj.name)​ ​​ ​f = open(os.path.​ ​​ ​join​ ​​ ​(​ ​​ ​'static/upload'​ ​​ ​, obj.name), ​ ​​ ​'wb'​ ​​ ​)​ ​​ ​for​ ​ ​ ​line ​ ​​ ​in​ ​ ​ ​obj.chunks():​ ​​ ​f.write(line)​ ​​ ​f.close()​ ​​ ​return​ ​ ​ ​HttpResponse(​ ​​ ​'上传成功'​ ​​ ​)​

urls.py

1234567891011

​from​ ​ ​ ​django.conf.urls import url, include​ ​​ ​from​ ​ ​ ​django.contrib import admin​ ​​ ​from​ ​ ​ ​user8_book import views​ ​​ ​from​ ​ ​ ​django.urls import path​ ​ ​ ​urlpatterns = [​ ​​ ​path(​ ​​ ​'book/'​ ​​ ​, views.book),​ ​​ ​path(​ ​​ ​'upload.html/'​ ​​ ​, views.upload),​ ​  ​ ​]​

models.py

12345678

​from​ ​ ​ ​django.db import models​ ​  ​ ​# Create your models here.​ ​ ​ ​class​ ​ ​ ​Upload(models.Model):​ ​​ ​text = models.CharField(max_length=100)​ ​​ ​file = models.FileField(max_length=128)​

upload.html

12345678910111213141516171819

​<html lang=​ ​​ ​"en"​ ​​ ​>​ ​​ ​<meta charset=​ ​​ ​"UTF-8"​ ​​ ​>​ ​ ​ ​{# 文件上传的form#}​ ​​ ​{#<form method=​ ​​ ​"post"​ ​ ​ ​enctype=​ ​​ ​"multipart/form-data"​ ​​ ​>#}​ ​​ ​<form method=​ ​​ ​"post"​ ​ ​ ​action=​ ​​ ​"/user8_book/upload.html/"​ ​ ​ ​enctype=​ ​​ ​"multipart/form-data"​ ​​ ​>​ ​​ ​{% csrf_token %}​

​<input id=​

​"name"​ ​ ​ ​type=​ ​​ ​"text"​ ​  ​ ​name=​ ​​ ​"input-name"​ ​ ​ ​placeholder=​ ​​ ​"请输入文件名称"​ ​ ​ ​>​

​<input id=​

​"file"​ ​ ​ ​type=​ ​​ ​"file"​ ​ ​ ​name=​ ​​ ​"file"​ ​​ ​>​

​<input id=​

​"submit"​ ​ ​ ​type=​ ​​ ​"submit"​ ​ ​ ​value=​ ​​ ​"submit"​ ​​ ​>​

5.6,上传文件报错及其解决方法

报错内容:

Django学习笔记(3)—— Form表单_Django Template_11

解决方法:

查看自己的HTML文件中,表单的action属性值结尾是否添加了“/”,我就是因为没有添加,找了半天错误,真尴尬。粗心大意

Django学习笔记(3)—— Form表单_Django Template_12

Django:Form表单(验证,定制错误信息,Select)

1,Django from流程

  • 1,创建类,继承form.Form
  • 2,页面根据类的对象自动创建HTML标签
  • 3,提交,request.POST 封装到类的对象里,obj=UserInfo(request.POST)
  • 4,用户输入是否合法  obj.is_valid()
  • 5,全部合法,获取全部内容   obj.claen()
  • 6,只有有不合法 obj.errors

2,Form表单使用建议

我们可以在APP目录下新建立一个myforms.py文件,然后再建立form。为什么要新建一个myforms.py呢?其好处显而易见:

  • 所有的表单在一个文件里,非常便于后期维护,比如增添或者修订字段。
  • myform.py可以通过clean方法自定义表单验证,非常便捷,不用在views.py里再进行表单验证(比如检查用户是否已经存在等等),逻辑更加清晰

3,定制表单

一般情况下,使用一种东西就会受制于一种东西,但是这并不是Django的意愿。并非你接受了django表单的方便就需要接受这么丑陋的页面。Django表单时可以随你心愿定制的。

我们不但可以对标签名进行定制化,还可以限制输入的位数,比如下面代码,我们限制了输入九位,第十位就无法输入,而且并非所有的信息都是强制填的,可以根据需要来抉择,同样看下面代码,即使email空着不填,表单也能正常提交。

12345

​class​ ​ ​ ​UserInfo(forms.Form):​ ​​ ​email = forms.EmailField(required=False)​ ​​ ​host = forms.CharField(max_length=9)​ ​​ ​port = forms.CharField(max_length=4)​ ​​ ​mobile = forms.CharField(max_length=11)​

4,美化表单

每个表单字段都有一个对应的Widget class,它对应一个HTML表单Widget,我们可以使用Forms中的widget来对我们的前端表按照我们的要求进行改造

4.1 示例1:长文本输入框

比如当我们需要做一个长文本输入框时候:

123456

​class​ ​ ​ ​UserInfo(forms.Form):​ ​​ ​email = forms.EmailField(required=False)​ ​​ ​host = forms.CharField(max_length=9)​ ​​ ​port = forms.CharField(max_length=4)​ ​​ ​mobile = forms.CharField(max_length=11)​ ​​ ​comment = forms.CharField(widget=forms.Textarea)​

html代码如下:

​+ View Code​

效果如下:

Django学习笔记(3)—— Form表单_Django Template_13

4.2  示例二:下拉框

当我们想做一个下拉框的时候:

其views.py代码如下:

​+ View Code​

HTML代码如下:

​+ View Code​

结果展示如下:

Django学习笔记(3)—— Form表单_Django Template_14

4.3  示例三:自己定制输入框

对ChoiceField字段,Form默认的是集成select的widget,即使用HTML的列表形式

views.py 的代码如下(这里只修改了comment的代码):

1

​comment = forms.CharField(widget=forms.TextInput(attrs={​ ​​ ​'size'​ ​​ ​:​ ​​ ​'40'​ ​​ ​}))​

我们为其设置了attrs,也就是HTML中的css属性。(要是想为整个表单或者更深度的定制一些css以及JavaScript,可以前往Django官方文档了解)

效果如下:

Django学习笔记(3)—— Form表单_Django Template_15

5,Form表单字段

5.1 Field.clean(value)

虽然字段类主要使用在表单类中,但是我们也可以直接实例化他们来使用,以便更好地了解他们是如何工作的。每个字段实例都有一个clean()方法,它接受一个参数,然后返回“清洁的”数据或者抛出一个django.forms.

12345678

​>>> ​ ​​ ​from​ ​ ​ ​django import forms​ ​​ ​>>> f = forms.EmailField()​ ​​ ​>>> f.clean(​ ​​ ​'foo@example.com'​ ​​ ​)​ ​​ ​'foo@example.com'​ ​​ ​>>> f.clean(​ ​​ ​'invalid email address'​ ​​ ​)​ ​​ ​Traceback (most recent call last):​ ​​ ​...​ ​​ ​ValidationError: [​ ​​ ​'Enter a valid email address.'​ ​​ ​]​

每个字段类的构造函数至少接受这些参数。有些字段类接受额外的,字段特有的参数,但以下参数应该总能接受:

5.2  Field.required

默认情况下,每个字段都假设必须有值,所以如果你传递一个空的值——不管是None,还是空字符串(" ")——clean() 都将引发一个ValidationError异常。

1234567891011121314151617

​>>> ​ ​​ ​from​ ​ ​ ​django import forms​ ​​ ​>>> f = forms.CharField()​ ​​ ​>>> f.clean()​ ​​ ​Traceback (most recent call last):​ ​​ ​File ​ ​​ ​""​ ​​ ​, line 1, ​ ​​ ​in​ ​ ​ ​TypeError: clean() missing 1 required positional argument: ​ ​​ ​'value'​ ​​ ​>>> f.clean(​ ​​ ​""​ ​​ ​)​ ​​ ​Traceback (most recent call last):​ ​​ ​File ​ ​​ ​""​ ​​ ​, line 1, ​ ​​ ​in​ ​ ​ ​File ​ ​​ ​"C:\Users\Administrator\AppData\Local\Programs\Python\Python37\lib\site-packages\django\forms\fields.py"​ ​​ ​, line 148, ​ ​​ ​in​ ​ ​ ​clean​ ​​ ​self.validate(value)​ ​​ ​File ​ ​​ ​"C:\Users\Administrator\AppData\Local\Programs\Python\Python37\lib\site-packages\django\forms\fields.py"​ ​​ ​, line 126, ​ ​​ ​in​ ​ ​ ​validate​ ​​ ​raise ValidationError(self.error_messages[​ ​​ ​'required'​ ​​ ​], code=​ ​​ ​'required'​ ​​ ​)​ ​​ ​django.core.exceptions.ValidationError: [​ ​​ ​'This field is required.'​ ​​ ​]​ ​ ​ ​>>> f.clean(​ ​​ ​"12"​ ​​ ​)​ ​​ ​'12'​

5.3  Field.label

正如前面“输出表单为HTML”中解释的,字段默认label是通过将字段名中所有的下划线转换成空格并大写第一个字母生成的。如果默认的标签不合适,可以指定label。


12345678910

​>>> ​ ​​ ​from​ ​ ​ ​django import forms​ ​​ ​>>> ​ ​​ ​class​ ​ ​ ​CommentForm(forms.Form):​ ​​ ​...     name = forms.CharField(label=​ ​​ ​'Your name'​ ​​ ​)​ ​​ ​...     url = forms.URLField(label=​ ​​ ​'Your Web site'​ ​​ ​, required=False)​ ​​ ​...     comment = forms.CharField()​ ​​ ​>>> f = CommentForm(auto_id=False)​ ​​ ​>>> print(f)​

Your name:

<input type=​ ​"text"​ ​ ​ ​name=​ ​​ ​"name"​ ​ ​ ​/>​

Your Web site:

<input type=​ ​"url"​ ​ ​ ​name=​ ​​ ​"url"​ ​ ​ ​/>​

Comment:

<input type=​ ​"text"​ ​ ​ ​name=​ ​​ ​"comment"​ ​ ​ ​/>​

5.4  Field.label_suffix

label_suffix参数让你基于每个字段覆盖表单的label_suffix

123456789

​>>> ​ ​​ ​class​ ​ ​ ​ContactForm(forms.Form):​ ​​ ​...     age = forms.IntegerField()​ ​​ ​...     nationality = forms.CharField()​ ​​ ​...     captcha_answer = forms.IntegerField(label=​ ​​ ​'2 + 2'​ ​​ ​, label_suffix=​ ​​ ​' ='​ ​​ ​)​ ​​ ​>>> f = ContactForm(label_suffix=​ ​​ ​'?'​ ​​ ​)​ ​​ ​>>> print(f.as_p())​

​<label ​

​for​ ​​ ​=​ ​​ ​"id_age"​ ​​ ​>Age?<input id=​ ​​ ​"id_age"​ ​ ​ ​name=​ ​​ ​"age"​ ​ ​ ​type=​ ​​ ​"number"​ ​ ​ ​/>​

​<label ​

​for​ ​​ ​=​ ​​ ​"id_nationality"​ ​​ ​>Nationality?<input id=​ ​​ ​"id_nationality"​ ​ ​ ​name=​ ​​ ​"nationality"​ ​ ​ ​type=​ ​​ ​"text"​ ​ ​ ​/>​

​<label ​

​for​ ​​ ​=​ ​​ ​"id_captcha_answer"​ ​​ ​>2 + 2 =<input id=​ ​​ ​"id_captcha_answer"​ ​ ​ ​name=​ ​​ ​"captcha_answer"​ ​ ​ ​type=​ ​​ ​"number"​ ​ ​ ​/>​

5.5  Field.initial

initial 参数让你指定渲染未绑定的表单中的字段时使用的初始值。

5.6  Field.widget

widget参数让你指定渲染表单时使用的Widget类,更多信息参见上面。

5.7  Filed.help_text

5.8  Field.error_messages

error_messages 参数让你覆盖字段引发的异常中的默认信息。传递的是一个字典,其键为你想覆盖的错误信息。

5.9  Field.validators

validators 参数让你可以为字段提供一个验证函数的列表。

5.10  Field.localize

localize 参数启用表单数据的本地化,包括输入和输出。

5.11  Field.has_changed()

has_changed() 方法用于决定字段的值是否从初始值发送了变化。返回True或者False。

6,form关于clean及其cleaned_data的说明

django表单验证中比较有用的就是clean和cleaned_data了。

clean是在is_valid()内部调用的,cleaned_data主要用来检查字段是否符合定义的格式,读取表单返回的值,如果是则返回类型为字段dict型。

比如email = cleaned_data['email']  读取name为“email”的表单提交值,并赋予email变量。

cleaned_data中的值类型与字段定义的Field类型一致。如果字段定义charfield,那么clean方法返回的cleaned_data中对应的字段值就是字符型,定义为ModelChoiceField,那么cleaned_data中字段值是某个model实例。定义为ModelMultipleChoiceField,则cleaned_data中字段值是model实例list。

Django:表单实例

首先我们看一下下面的案例:

1234567891011121314151617181920212223

​#/usr/bin/env python​ ​​ ​#-*- coding:utf-8 -*-​ ​​ ​from​ ​ ​ ​django.shortcuts import render​ ​ ​ ​# Create your views here.​ ​  ​ ​def user_list(request):​ ​​ ​host = request.POST.​ ​​ ​get​ ​​ ​(​ ​​ ​'host'​ ​​ ​)​ ​​ ​port = request.POST.​ ​​ ​get​ ​​ ​(​ ​​ ​'port'​ ​​ ​)​ ​​ ​mail = request.POST.​ ​​ ​get​ ​​ ​(​ ​​ ​'mail'​ ​​ ​)​ ​​ ​mobile = request.POST.​ ​​ ​get​ ​​ ​(​ ​​ ​'mobile'​ ​​ ​)​ ​​ ​#这里有个问题,如果,这个from表单有20个input,你在这里是不是的取20次?​ ​ ​ ​#验证:​ ​​ ​#输入不能为空,并且有的可以为空有的不可以为空​ ​​ ​#如果email = 11123123  这样合法吗?​ ​​ ​#如果mobile = 11123123  这样合法吗?​ ​​ ​#如果ip = 11123123  这样合法吗?​ ​​ ​''​ ​​ ​'​ ​​ ​你在这里是不是需要做一大堆的输入验证啊?并且有很多这种页面会存在这种情况,如果每个函数都这样做估计就累死了​ ​​ ​''​ ​​ ​'​ ​​ ​return​ ​ ​ ​render(request,​ ​​ ​'user_list.html'​ ​​ ​)​

针对于上面的问题,如何解决呢?——那就是Form表单

Django中form表单的作用:

  • 1,自动生成HTML表单元素
  • 2,用来做用户提交的验证
  • 3,检查表单数据的合法性
  • 4,回显功能(验证错误,输入数据不会被清空)
  • 5,数据类型转换(转换成相应的python类型)

通常提交表单数据就是由HTML表单向后台传递信息,后台通过request.GET() 或者 request.POST()获取。

一,构建一个简单表单的流程,并提交信息给数据库

1.1,建立一个django项目

建一个Blog项目,并在template下新建两个html页面,一个注册页面命名为register,一个欢迎页面为welcome。

123456789101112131415

​1,创建project​ ​ ​ ​django-admin startproject  Blog​ ​ ​ ​2,创建APP​ ​ ​ ​python  manage.py startapp  user1​ ​ ​ ​3,修改settings配置​ ​ ​ ​在INSTALLED_APPS中添加APP:user1​ ​ ​ ​在TEMPLATES中查看“DIRS”内容,如果有template,请保持原样,如果没有,则添加​ ​ ​ ​'DIRS'​ ​​ ​: [os.path.​ ​​ ​join​ ​​ ​(BASE_DIR, ​ ​​ ​'templates'​ ​​ ​)]​

项目目录如下:

Django学习笔记(3)—— Form表单_Django Template_16

1.2, 填充HTML文件内容

给template下两个html页面register和welcome填充内容。

register.html

12345678910111213141516171819

​<html lang=​ ​​ ​"en"​ ​​ ​>​ ​​ ​<meta charset=​ ​​ ​"UTF-8"​ ​​ ​>​ ​ ​ ​<form action=​ ​​ ​"/user/register/"​ ​ ​ ​method=​ ​​ ​"post"​ ​​ ​>​ ​ ​ ​{% csrf_token %}​

​用户名:<input type=​

​"text"​ ​ ​ ​name=​ ​​ ​"username"​ ​​ ​>​

​密码:<input type=​

​"password"​ ​ ​ ​name=​ ​​ ​"password"​ ​​ ​>​ ​​ ​<input type=​ ​​ ​"submit"​ ​ ​ ​value=​ ​​ ​"submit"​ ​​ ​>​

Django学习笔记(3)—— Form表单_Django Template_17

welcome.html

123456789101112

​<html lang=​ ​​ ​"en"​ ​​ ​>​ ​​ ​<meta charset=​ ​​ ​"UTF-8"​ ​​ ​>​

​welcome to ​

​this​ ​ ​ ​page​

1.3,在models中创建表结构

在user1/models.py中创建表结构,代码如下:

1234567

​from​ ​ ​ ​django.db import models​ ​ ​ ​# Create your models here.​ ​​ ​class​ ​ ​ ​BlogUser(models.Model):​ ​​ ​username = models.CharField(max_length=200, unique=True)​ ​​ ​password = models.CharField(max_length=200)​

ChariField 字符串字段,用于较短的字符串,需要max_length来指定VARCHAR数据库字段的大小。

同时,修改Bolg/settings.py的内容:

123456789101112131415161718192021222324

​找到下面这段代码,并注释掉:​ ​​ ​DATABASES = {​ ​​ ​'default'​ ​​ ​: {​ ​​ ​'ENGINE'​ ​​ ​: ​ ​​ ​'django.db.backends.sqlite3'​ ​​ ​,​ ​​ ​'NAME'​ ​​ ​: os.path.​ ​​ ​join​ ​​ ​(BASE_DIR, ​ ​​ ​'db.sqlite3'​ ​​ ​),​ ​​ ​}​ ​​ ​}​ ​ ​ ​然后写入下面代码:​ ​ ​ ​import pymysql​ ​​ ​pymysql.install_as_MySQLdb()​ ​ ​ ​DATABASES = {​ ​​ ​'default'​ ​​ ​: {​ ​​ ​# 这里可以指定使用的数据库类型,例如mysql​ ​​ ​'ENGINE'​ ​​ ​: ​ ​​ ​'django.db.backends.mysql'​ ​​ ​,​ ​​ ​'NAME'​ ​​ ​: ​ ​​ ​'blog_demo'​ ​​ ​,​ ​​ ​'USER'​ ​​ ​:​ ​​ ​'root'​ ​​ ​,​ ​​ ​'PASSWORD'​ ​​ ​:​ ​​ ​'******'​ ​​ ​,​ ​​ ​'HOST'​ ​​ ​:​ ​​ ​'localhost'​ ​​ ​,​ ​​ ​'PORT'​ ​​ ​:​ ​​ ​'3306'​ ​​ ​,​ ​​ ​}​ ​​ ​}​

如果这里不熟悉请参考: Django连接MySQL数据库

并且,映射数据库,这一步不能忘记:

123456789

​在终端创建表​ ​ ​ ​1,生成同步数据库的代码:​ ​ ​ ​python manage.py makemigrations​ ​ ​ ​2,同步数据库(也就是对数据库执行真正的迁移动作):​ ​ ​ ​python manage.py migrate​

Django学习笔记(3)—— Form表单_Django Template_18

1.4,以创建对象的方式操作数据库

我们重构views.py中的代码

123456789101112131415

​from​ ​ ​ ​django.shortcuts import render​ ​ ​ ​# Create your views here.​ ​​ ​from​ ​ ​ ​user1.models import  BlogUser​ ​ ​ ​def register(request):​ ​​ ​if​ ​ ​ ​request.method ==​ ​​ ​'GET'​ ​​ ​:​ ​​ ​return​ ​ ​ ​render(request, ​ ​​ ​'register.html'​ ​​ ​)​ ​​ ​elif request.method == ​ ​​ ​'POST'​ ​​ ​:​ ​​ ​bloguser = BlogUser()​ ​​ ​bloguser.username = request.POST.​ ​​ ​get​ ​​ ​(​ ​​ ​'username'​ ​​ ​)​ ​​ ​bloguser.password = request.POST.​ ​​ ​get​ ​​ ​(​ ​​ ​'password'​ ​​ ​)​ ​​ ​bloguser.save()​ ​ ​ ​return​ ​ ​ ​render(request, ​ ​​ ​'welcome.html'​ ​​ ​)​

get() 中的username和password是取的register 里的username的值。以获取(request)注册的信息,保存为save()。

然后运行项目,并注册信息,代码如下:

12345678

​1, 运行项目​ ​ ​ ​python manage.py  runserver​ ​  ​ ​2,在浏览器中输入:​ ​ ​ ​http:​ ​​ ​//127.0.0.1:8000/user/register/​

然后我们注册信息,并提交。我们可以看到上面的register.html中用户名是唯一的,所以当我们注册相同的名称时候回报错500,并且传输失败。

下面在数据库看一下我们的注册信息

Django学习笔记(3)—— Form表单_Django Template_19

其中,3,5不显示,因为我输入了相同的用户名。如果输入不重复,则显示下面界面。

Django学习笔记(3)—— Form表单_Django Template_20

二,构建一个简单表单的流程,了解Form知识

在上面的基础上,我们再实现一个表单流程,继续了解form表单的知识。

2.1,首先创建对应的视图函数  views.py内容如下:

12345678910111213141516171819

​from​ ​ ​ ​django.shortcuts import render, HttpResponse​ ​ ​ ​# Create your views here.​ ​​ ​from​ ​ ​ ​django import forms​ ​ ​ ​class​ ​ ​ ​LoginForm(forms.Form):​ ​​ ​account = forms.CharField()​ ​​ ​password = forms.CharField()​ ​​ ​email = forms.CharField()​ ​  ​ ​def login(request):​ ​​ ​if​ ​ ​ ​request.method == ​ ​​ ​"POST"​ ​​ ​:​ ​​ ​form = LoginForm(request.POST)​ ​​ ​if​ ​ ​ ​form.is_valid():​ ​​ ​return​ ​ ​ ​HttpResponse(​ ​​ ​"登录成功"​ ​​ ​)​ ​​ ​else​ ​​ ​:​ ​​ ​form = LoginForm()​ ​​ ​return​ ​ ​ ​render(request, ​ ​​ ​'user6/login.html'​ ​​ ​,{​ ​​ ​'form'​ ​​ ​:form})​

2.2,建立对应的模板 login.html

123456789101112131415161718

​<html lang=​ ​​ ​"en"​ ​​ ​>​ ​​ ​<meta charset=​ ​​ ​"UTF-8"​ ​​ ​>​ ​ ​ ​<div align=​ ​​ ​"center"​ ​ ​ ​style=​ ​​ ​"height: 400px; width: 100px;"​ ​​ ​>​ ​​ ​<form action=​ ​​ ​"#"​ ​ ​ ​method=​ ​​ ​"post"​ ​​ ​>​ ​​ ​{% csrf_token %}​ ​​ ​{{ form }}​ ​​ ​<button type=​ ​​ ​"submit"​ ​ ​ ​id=​ ​​ ​"sum"​ ​​ ​>submit​

然后,去配置urls一些基本的配置(比如模板,路由等)。

我们直接点开login.html 内容如下:

Django学习笔记(3)—— Form表单_Django Template_21

我们打开Django项目,从127.0.0.1:8000/user6/login/ 进入,如下:

Django学习笔记(3)—— Form表单_Django Template_22

直接访问地址就显示出这样一个简单的界面,由HTML文件可以看到并没有js代码对数据有效性进行验证,我们随机输入账号,密码,邮箱,则提交,显示登陆成功。如下:

Django学习笔记(3)—— Form表单_Django Template_23

三,定制表单

从上面的代码我们发现,前端一个 {{ form }} 就能做出一个完整强大的表单。但是我们只能用account  password 做名称吗?

不是的,这里我们可以定制其名字,并且可以限制输入位数等等各种操作。

3.1,如何给form表单设置自定义报错内容

在form里有一个参数:error_messages 在他这里就可以定义报错内容

1234567

​class​ ​ ​ ​UserInfo(forms.Form):​ ​​ ​# required是否可以为空,如果为False,则说明可以为空​ ​​ ​email = forms.EmailField(required=False,error_messages={​ ​​ ​'required'​ ​​ ​:u​ ​​ ​'邮箱不能为空'​ ​​ ​})​ ​​ ​# 如果required 不写默认为Ture​ ​​ ​host = forms.CharField(error_messages={​ ​​ ​'required'​ ​​ ​:u​ ​​ ​'主机不能为空'​ ​​ ​})​ ​​ ​port = forms.CharField(error_messages={​ ​​ ​'required'​ ​​ ​:u​ ​​ ​'端口不能为空'​ ​​ ​})​ ​​ ​mobile = forms.CharField(error_messages={​ ​​ ​'required'​ ​​ ​:u​ ​​ ​'手机不能为空'​ ​​ ​})​

Django学习笔记(3)—— Form表单_Django Template_24

3.2,如何给form表单添加一个属性

12345678910

​class​ ​ ​ ​UserInfo(forms.Form):​ ​​ ​# required是否可以为空,如果为False,则说明可以为空​ ​​ ​email = forms.EmailField(required=False,error_messages={​ ​​ ​'required'​ ​​ ​:u​ ​​ ​'邮箱不能为空'​ ​​ ​})​ ​​ ​# 如果required 不写默认为Ture​ ​​ ​host = forms.CharField(error_messages={​ ​​ ​'required'​ ​​ ​:u​ ​​ ​'主机不能为空'​ ​​ ​})​ ​​ ​port = forms.CharField(error_messages={​ ​​ ​'required'​ ​​ ​:u​ ​​ ​'端口不能为空'​ ​​ ​})​ ​​ ​mobile = forms.CharField(error_messages={​ ​​ ​'required'​ ​​ ​:u​ ​​ ​'手机不能为空'​ ​​ ​},​ ​​ ​# 这里默认是TextInput 标签​ ​​ ​widget = forms.TextInput(attrs={​ ​​ ​'class'​ ​​ ​:​ ​​ ​'form-control'​ ​​ ​,​ ​​ ​'placeholder'​ ​​ ​:u​ ​​ ​'手机号码'​ ​​ ​}))​

Django学习笔记(3)—— Form表单_Django Template_25

3.3,如何给form表单添加一个备注

12345678910111213

​class​ ​ ​ ​UserInfo(forms.Form):​ ​​ ​# required是否可以为空,如果为False,则说明可以为空​ ​​ ​email = forms.EmailField(required=False,error_messages={​ ​​ ​'required'​ ​​ ​:u​ ​​ ​'邮箱不能为空'​ ​​ ​})​ ​​ ​# 如果required 不写默认为Ture​ ​​ ​host = forms.CharField(error_messages={​ ​​ ​'required'​ ​​ ​:u​ ​​ ​'主机不能为空'​ ​​ ​})​ ​​ ​port = forms.CharField(error_messages={​ ​​ ​'required'​ ​​ ​:u​ ​​ ​'端口不能为空'​ ​​ ​})​ ​​ ​mobile = forms.CharField(error_messages={​ ​​ ​'required'​ ​​ ​:u​ ​​ ​'手机不能为空'​ ​​ ​},​ ​​ ​# 这里默认是TextInput 标签​ ​​ ​widget = forms.TextInput(attrs={​ ​​ ​'class'​ ​​ ​:​ ​​ ​'form-control'​ ​​ ​,​ ​​ ​'placeholder'​ ​​ ​:u​ ​​ ​'手机号码'​ ​​ ​}))​ ​​ ​# 我们再这里新增一个备份​ ​​ ​memo = forms.CharField(required=False,​ ​​ ​widget=forms.Textarea(attrs={​ ​​ ​'class'​ ​​ ​:​ ​​ ​'form-control'​ ​​ ​,​ ​​ ​'placeholder'​ ​​ ​:u​ ​​ ​'备份'​ ​​ ​}))​

同样的HTML代码也要新增:

12345678

​<form action=​ ​​ ​"/user_list/"​ ​ ​ ​method=​ ​​ ​"post"​ ​​ ​>​

​主机 : {{ obj.host }}{{ errors.host }}​

​端口 : {{ obj.port }}{{ errors.port }}​

​邮箱 : {{ obj.email }}{{ errors.email }}​

​手机 : {{ obj.mobile }}{{ errors.mobile }}​

​备注:{{ obj.memo }}{{ errors.memo }}​

​<input type=​ ​​ ​"submit"​ ​ ​ ​value=​ ​​ ​"submit"​ ​​ ​>​

Django学习笔记(3)—— Form表单_Django Template_26

3.4,自定义正则表达式增加判断规则

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051

​import re​ ​​ ​from​ ​ ​ ​django import forms​ ​​ ​from​ ​ ​ ​django.core.exceptions import ValidationError​ ​ ​ ​def mobile_validate(value):​ ​​ ​# 正则匹配​ ​​ ​mobile_re = re.compile(r​ ​​ ​'^(13[0-9]|15[0123456789]|18[0-9]|14[57])[0-9]{8}$'​ ​​ ​)​ ​​ ​if​ ​ ​ ​not mobile_re.match(value):​ ​​ ​raise ValidationError(​ ​​ ​"手机号码格式错误"​ ​​ ​)​ ​ ​ ​class​ ​ ​ ​UserInfo(forms.Form):​ ​​ ​# required是否可以为空,如果为False,则说明可以为空​ ​​ ​email = forms.EmailField(required=False, error_messages={​ ​​ ​'required'​ ​​ ​: u​ ​​ ​'邮箱不能为空'​ ​​ ​})​ ​​ ​host = forms.CharField(error_messages={​ ​​ ​'required'​ ​​ ​: u​ ​​ ​'主机不能为空'​ ​​ ​})​ ​​ ​port = forms.CharField(error_messages={​ ​​ ​'required'​ ​​ ​: u​ ​​ ​'端口不能为空'​ ​​ ​})​ ​​ ​mobile = forms.CharField(# 应用我们自己定义的规则​ ​​ ​validators=[mobile_validate,],​ ​​ ​error_messages={​ ​​ ​'required'​ ​​ ​: u​ ​​ ​'手机不能为空'​ ​​ ​},​ ​​ ​# 这里默认使用TextInput 标签​ ​​ ​widget=forms.TextInput(attrs={​ ​​ ​'class'​ ​​ ​: ​ ​​ ​'form-control'​ ​​ ​,​ ​​ ​'placeholder'​ ​​ ​: u​ ​​ ​'手机号码'​ ​​ ​}))​ ​​ ​# 我们新增一个备份​ ​​ ​memo = forms.CharField(required=False,​ ​​ ​widget=forms.TextInput(attrs={​ ​​ ​'class'​ ​​ ​: ​ ​​ ​'form-control'​ ​​ ​,​ ​​ ​'placeholder'​ ​​ ​: u​ ​​ ​'备份'​ ​​ ​}))​ ​  ​ ​def user_list(request):​ ​​ ​# 创建了这个对象​ ​​ ​obj = UserInfo()​ ​​ ​if​ ​ ​ ​request.method == ​ ​​ ​'POST'​ ​​ ​:​ ​​ ​# 获取用户输入一句话就搞定​ ​​ ​user_input_obj = UserInfo(request.POST)​ ​ ​ ​# 判断用户输入是否合法​ ​​ ​if​ ​ ​ ​user_input_obj.is_valid():​ ​​ ​# 获取用户输入​ ​​ ​data = user_input_obj.clean()​ ​​ ​print(data)​ ​​ ​else​ ​​ ​:​ ​​ ​# 如果发生错误,捕获异常​ ​​ ​# 这里原来什么都没写,默认是ul的样式,默认是as_ul(),​ ​​ ​# 如果我们写成as_data()返回的就是一个原生的字符串​ ​​ ​# 还有一个as_json​ ​​ ​error_msg = user_input_obj.errors.as_data()​ ​​ ​# 然后把错误信息返回​ ​​ ​print(error_msg)​ ​​ ​# 然后把对象传给html,在把错误信息传递过去​ ​​ ​return​ ​ ​ ​render(request, ​ ​​ ​'user6/register.html'​ ​​ ​, {​ ​​ ​'obj'​ ​​ ​: obj, ​ ​​ ​'errors'​ ​​ ​: error_msg,})​ ​​ ​# 将对象传给html​ ​​ ​return​ ​ ​ ​render(request, ​ ​​ ​'user6/register.html'​ ​​ ​, {​ ​​ ​'obj'​ ​​ ​:obj,})​

当我们输入不合法的时候,或者不是email格式的时候,会出现如下错误:

Django学习笔记(3)—— Form表单_Django Template_27

Django学习笔记(3)—— Form表单_Django Template_28

这样后端我们就有一套验证的机制了,就是通过is_valid()来判断用户输入是否合法!如果不合法就把返回的信息发送出去,如果合法获取数据,继续操作即可!

3.5,生成select标签

12345678910111213141516171819

​class​ ​ ​ ​UserInfo(forms.Form):​ ​​ ​user_type_choice = (​ ​​ ​(0,u​ ​​ ​'普通用户'​ ​​ ​),​ ​​ ​(1,u​ ​​ ​'高级用户'​ ​​ ​),​ ​​ ​)​ ​​ ​user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,​ ​​ ​attrs={​ ​​ ​'class'​ ​​ ​:​ ​​ ​'form-control'​ ​​ ​}))​ ​​ ​# required是否可以为空,如果为False,则说明可以为空​ ​​ ​email = forms.EmailField(required=False,error_messages={​ ​​ ​'required'​ ​​ ​:u​ ​​ ​'邮箱不能为空'​ ​​ ​})​ ​​ ​# 如果required 不写默认为Ture​ ​​ ​host = forms.CharField(error_messages={​ ​​ ​'required'​ ​​ ​:u​ ​​ ​'主机不能为空'​ ​​ ​})​ ​​ ​port = forms.CharField(error_messages={​ ​​ ​'required'​ ​​ ​:u​ ​​ ​'端口不能为空'​ ​​ ​})​ ​​ ​mobile = forms.CharField(error_messages={​ ​​ ​'required'​ ​​ ​:u​ ​​ ​'手机不能为空'​ ​​ ​},​ ​​ ​# 这里默认是TextInput 标签​ ​​ ​widget = forms.TextInput(attrs={​ ​​ ​'class'​ ​​ ​:​ ​​ ​'form-control'​ ​​ ​,​ ​​ ​'placeholder'​ ​​ ​:u​ ​​ ​'手机号码'​ ​​ ​}))​ ​​ ​# 我们再这里新增一个备份​ ​​ ​memo = forms.CharField(required=False,​ ​​ ​widget=forms.Textarea(attrs={​ ​​ ​'class'​ ​​ ​:​ ​​ ​'form-control'​ ​​ ​,​ ​​ ​'placeholder'​ ​​ ​:u​ ​​ ​'备份'​ ​​ ​}))​

HTML内更改如下:

123456789

​<form action=​ ​​ ​"/user_list/"​ ​ ​ ​method=​ ​​ ​"post"​ ​​ ​>​

​用户类型:{{ obj.user_type }}{{ errors.user_type }}​

​主机 : {{ obj.host }}{{ errors.host }}​

​端口 : {{ obj.port }}{{ errors.port }}​

​邮箱 : {{ obj.email }}{{ errors.email }}​

​手机 : {{ obj.mobile }}{{ errors.mobile }}​

​备注:{{ obj.memo }}{{ errors.memo }}​

​<input type=​ ​​ ​"submit"​ ​ ​ ​value=​ ​​ ​"submit"​ ​​ ​>​

Django学习笔记(3)—— Form表单_Django Template_29

3.6.关于后端验证

这个后端验证是必须要有验证机制的,前端可以不写但是后端必须写,前端的JS是可以被禁用掉的,在实际的生产环境中比如登录和验证的时候,我们一般都使用  JQuery+AJAX  来判断用户的输入是否为空,假如JS被禁用(浏览器端可以设置禁用JS效果)的话,我们这个认证屏障是不是就消失了呢?(虽然一般不会禁用但是还是存在风险),所以我们一般做两种认证,在前端做一遍认证,在后端做一遍认证。

Django学习笔记(3)—— Form表单_Django Template_30

3.7,代码总结

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051

​import re​ ​​ ​from​ ​ ​ ​django import forms​ ​​ ​from​ ​ ​ ​django.core.exceptions import ValidationError​ ​ ​ ​#自定义方法​ ​​ ​def mobile_validate(value):​ ​​ ​mobile_re = re.compile(r​ ​​ ​'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$'​ ​​ ​) #正则匹配​ ​​ ​if​ ​ ​ ​not mobile_re.match(value):​ ​​ ​raise ValidationError(​ ​​ ​'手机号码格式错误'​ ​​ ​) #如果没有匹配到主动出发一个错误​ ​  ​ ​class​ ​ ​ ​UserInfo(forms.Form):​ ​ ​ ​user_type_choice = (​ ​​ ​(0, u​ ​​ ​'普通用户'​ ​​ ​),​ ​​ ​(1, u​ ​​ ​'高级用户'​ ​​ ​),)​ ​ ​ ​user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,attrs={​ ​​ ​'class'​ ​​ ​:​ ​​ ​'form-control'​ ​​ ​}))​ ​ ​ ​email = forms.EmailField(required=True,error_messages={​ ​​ ​'required'​ ​​ ​:u​ ​​ ​'邮箱不能为空'​ ​​ ​}) #required是否可以为空,如果为False说明可以为空​ ​​ ​host = forms.CharField(error_messages={​ ​​ ​'required'​ ​​ ​:u​ ​​ ​'主机不能为空'​ ​​ ​}) #如果required不写默认为Ture​ ​​ ​port = forms.CharField(error_messages={​ ​​ ​'required'​ ​​ ​:u​ ​​ ​'端口不能为空'​ ​​ ​})​ ​ ​ ​#默认mobile里有一个默认为空的机制,我们在原有的参数里增加怎们自定义的方法​ ​​ ​mobile = forms.CharField(validators=[mobile_validate,],#应用咱们自己定义的规则​ ​​ ​error_messages={​ ​​ ​'required'​ ​​ ​:u​ ​​ ​'手机不能为空'​ ​​ ​},​ ​​ ​widget=forms.TextInput(attrs={​ ​​ ​'class'​ ​​ ​:​ ​​ ​'form-control'​ ​​ ​,​ ​​ ​'placeholder'​ ​​ ​:u​ ​​ ​'手机号码'​ ​​ ​})​ ​​ ​#这里默认是TextInput,标签​ ​​ ​)​ ​​ ​#咱们在新增一个备注​ ​​ ​memo = forms.CharField(required=False,​ ​​ ​widget=forms.Textarea(attrs={​ ​​ ​'class'​ ​​ ​:​ ​​ ​'form-control'​ ​​ ​,​ ​​ ​'placeholder'​ ​​ ​:u​ ​​ ​'备注'​ ​​ ​}))​ ​ ​ ​def user_list(request):​ ​​ ​obj = UserInfo() #创建了这个对象​ ​​ ​if​ ​ ​ ​request.method == ​ ​​ ​'POST'​ ​​ ​:​ ​​ ​#获取用户输入一句话就搞定​ ​​ ​user_input_obj = UserInfo(request.POST)​ ​ ​ ​if​ ​ ​ ​user_input_obj.is_valid(): #判断用户输入是否合法​ ​​ ​data = user_input_obj.clean() #获取用户输入​ ​​ ​print data​ ​​ ​else​ ​​ ​:​ ​​ ​#如果发生错误,捕捉错误​ ​​ ​error_msg = user_input_obj.errors.as_data()#这里原来什么都没写,默认是ul的样式,默认是as_ul(),如果我们写成as_data()返回的就是一个原生的字符串​ ​​ ​#还有一个as_json​ ​ ​ ​print error_msg #打印一下然后看下他的类型​ ​​ ​#然后把错误信息返回​ ​​ ​return​ ​ ​ ​render(request,​ ​​ ​'user_list.html'​ ​​ ​,{​ ​​ ​'obj'​ ​​ ​:obj,​ ​​ ​'errors'​ ​​ ​:error_msg,})#然后把对象传给html,在把错误信息传递过去​ ​​ ​return​ ​ ​ ​render(request,​ ​​ ​'user_list.html'​ ​​ ​,{​ ​​ ​'obj'​ ​​ ​:obj,})#然后把对象传给html​





python 一分钟执行一次 python每秒运算多少次

为机甲的计时API写了如下例程,想对比一下PC上的Python性能(注:作为性能测试非常粗糙,因为主要是想作最简单的演示之用):def 开始(): 工具.计时器(常量.开始) 总耗时 = 0 次数 = 0 while 次数 < 10: 算三角函数() 工具.计时器(常量.暂停) 总耗时 = 工具.累计计时()