当前位置 : 主页 > 编程语言 > python >

95django_form

来源:互联网 收集:自由互联 发布时间:2022-10-14
目录 ​ ​​ form 1 ​​ ​ ​​ HTML 中 GET 和 POST : 1 ​​ ​ ​​ 例 1 , form 处理: 2 ​​ ​ ​​ django form : 4 ​​ ​ ​​ 例 2 ,自动生成表单: 6 ​​ ​ ​​ 例 3 ,手动渲染


目录

​​form 1​​

​​HTMLGETPOST 1​​

​​1form处理: 2​​

​​django form 4​​

​​2,自动生成表单: 6​​

​​3,手动渲染字段: 11​​

​​form field 11​​

​​form field args 12​​




form​


HTML中GET和POST:

处理表单时候只会用到POST 和 GET 方法。


Django 的登录表单使用POST 方法,在这个方法中浏览器组合表单数据、对它们进行编码以用于传输、将它们发送到服务器然后接收它的响应。


相反,GET 组合提交的数据为一个字符串,然后使用它来生成一个URL。 这个URL 将包含数据发送的地址以及数据的键和值。 如果你在Django 文档中做一次搜索,你会立即看到这点,此时将生成一个https://docs.djangoproject.com/search/?q=forms&release=1 形式的URL。


POST 和GET 用于不同的目的。


用于改变系统状态的请求 —— 例如,给数据库带来变化的请求 —— 应该使用POST。 GET 只应该用于不会影响系统状态的请求。


GET 还不适合密码表单,因为密码将出现在URL 中,以及浏览器的历史和服务器的日志中,而且都是以普通的文本格式。 它还不适合数据量大的表单和二进制数据,例如一张图片。 使用GET 请求作为管理站点的表单具有安全隐患:攻击者很容易模拟表单请求来取得系统的敏感数据。 POST,如果与其它的保护措施结合将对访问提供更多的控制,例如Django 的CSRF protection。


另一个方面,GET 适合网页搜索这样的表单,因为这种表示一个GET 请求的URL 可以很容易地作为书签、分享和重新提交。



例1,form处理:


mysite/polls/templates/polls/detail.html

<h1>{{ question.question_text }}</h1>


{% if error_message %}

<P><strong>{{ error_message }}</strong></P>

{% endif %}


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

{% 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 }}</label><br />

{% endfor %}

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

</form>



mysite/polls/views.py

from django.shortcuts import render, get_object_or_404, reverse

from django.http import HttpResponse, HttpResponseRedirect

from .models import Question, Choice

from django.template import loader

# from django.core.urlresolvers import reverse


# def index(request):

# latest_question_list = Question.objects.order_by('-pub_date')[:4]

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

# context = {'latest_question_list': latest_question_list}

# # output = ', '.join([q.question_text for q in latest_question_list])

# return HttpResponse(template.render(context))

def index(request):

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

context = {'latest_question_list': latest_question_list}

return render(request, 'polls/index.html', context)


def detail(request, question_id):

# try:

# question = Question.objects.get(id=question_id)

# except Question.DoesNotExist:

# return HttpResponse('Not Found', status=404)

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)

print(request)

if request.method == 'POST':

choice_id = request.POST.get('choice', 0)

try:

selected_choice = question.choice_set.get(pk=choice_id)

except Choice.DoesNotExist:

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

'question': question, 'error_message': 'You did not select a choice',

})

else:

selected_choice.votes += 1

selected_choice.save()

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



mysite/polls/templates/polls/results.html

<h1>{{ question.question_text }}</h1>


<ul>

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

<li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>

{% endfor %}

</ul>


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



django form:


模型类的属性映射到数据库表中的字段;

表单类的属性映射到HTML form的input元素;

所有的表单类都作为django.forms.Form的子类创建,包括ModelForm;


<form>{% csrf_token %}</form>,django原生支持一个简单易用的protection against cross site request forgeries,当提交一个启用CSRF防护的POST表单时,必须使用{ % csrf_token %}模板标签;

forms.py中,在定义表单时,若有URLField、EmailField或其它整数字段类型,django将使用number、url和email这样的HTML5输入类型,默认browser会对这些字段进行它们自身的验证,这些验证比django验证严格,如果要禁用HTML5中的验证,在模板中加上form的novalidate属性或指定一个不同的字段TextInput;


若打算直接用来添加和编辑django模型,ModelForm可节省时间、精力、代码,因为它将根据Model类构建一个表单及适当的字段和属性;


绑定表单和未绑定表单:

form.is_bound属性返回True|False;

不包含数据的表单称为未绑定表单,当render给用户时,它将为空或包含默认的值;

包含数据的表单称为绑定表单,可验证数据是否合法,如果render一个不合法的绑定表单,它将给browser抛错,让用户纠正数据;


widget,窗口小部件,每个表单字段都有一个对应的widget class,它对应一个HTML表单widget,如<input type="text">;大部分情况下,字段都具有一个合理默认widget,如CharField具有一个TextInput Widget,它在HTML中生成一个<input type="text">,如果需要message,在定义表单字段时应指定一个合适的widget,如message = forms.CharField(widget=forms.Textarea)


表单呈现选项:

form.as_p()

form.as_table() #在模板中需自己提供<table>或<ul>元素

form.as_ul()


HTML的label标签为input元素定义标注,label标签的for属性应与相关元素的id属性相同;

定义表单字段时用了label标签,使用form.as_p自动生成label的for为id_<field-name>,对应的input中的id也是id_<field-name>;


渲染表单错误信息:

模板中,{{ form.non_field_errors }},查找每个字段的错误,并展示到上方;

| Returns an ErrorList of errors that aren't associated with a particular

| field -- i.e., from Form.clean(). Returns an empty ErrorList if there

| are none.

模板中,{{ form.<field-name>.errors }},显示表单错误的一个清单,并渲染成一个<ul>;


循环表单字段:

​​https://yiyibooks.cn/xx/Django_1.11.6/topics/forms/index.html#html-forms​​

若表单使用相同的html,可循环迭代每个字段来减少重复代码;

{% for field in form %}

<div class="fieldWrapper">

{{ field.errors }}

{{ field.label_tag }} {{ field }}

{% if field.help_text %}

<p class="help">{{ field.help_text|safe }}</p>

{% endif %}

</div>

{% endfor %}


{{ field }}属性:

{{ field.label }},字段的label,如Email;

{{ field.label_tag }},包含在HTML label标签中的字段label,它包含表单的label_suffix,如默认label_suffix是冒号;

{{ field.id_for_label }},手动渲染字段用到,如<label for="id_email">Email:</label>,lable的for对应{{ field.id_for_label }};

{{ field.value }},字段的值,如someone@ane56.com;

{{ field.html_name }},输入元素的name属性中将使用的名称,它将考虑到表单的前缀;

{{ field.help_text }},与该字段关联的提示信息(帮助文档);

{{ field.errors }},输出一个<ul>,包含这个字段的验证错误信息;


表单验证:

view中在调用form.is_valid()时验证;

模板中{{ form.non_filed_errors }}、{{ field.errors }}访问errors属性时隐式调用;


field手动校验:

>>> form = forms.EmailField()

>>> form.clean('jowin@ane56.com')

'jowin@ane56.com'

>>> form.clean('test')

……

raise ValidationError(errors)

django.core.exceptions.ValidationError: ['Enter a valid email address.']



>>> from django import forms

>>> class NameForm(forms.Form):

... your_name = forms.CharField(label='your name', max_length=100)

...

>>> form = NameForm()

>>> form.is_bound

False

>>> form.as_p() #表单呈现选项,将其渲染在<p>标签中;label标签为input元素定义标注,label标签的for属性应与相关元素的id属性相同

'<p><label for="id_your_name">your name:</label> <input type="text" name="your_name" maxlength="100" required id="id_your_name" /></p>'

>>> form.as_table() #以表格形式将其渲染在<tr>中

'<tr><th><label for="id_your_name">your name:</label></th><td><input type="text" name="your_name" maxlength="100" required id="id_your_name" /></td></tr>'

>>> form.as_ul() #将其渲染在<li>标签中

'<li><label for="id_your_name">your name:</label> <input type="text" name="your_name" maxlength="100" required id="id_your_name" /></li>'


>>> form=NameForm({'your_name':'jowin'})

>>> form.is_bound #绑定表单和未绑定表单

True

>>> form

<NameForm bound=True, valid=Unknown, fields=(your_name)>

>>> form.cleaned_data['your_name'] #访问数据前没有form.is_valid()抛no attribute

Traceback (most recent call last):

File "<console>", line 1, in <module>

AttributeError: 'NameForm' object has no attribute 'cleaned_data'

>>> form.is_valid() #做2件事,1为所有字段运行验证的程序,若所有字段都是合法数据返回True,2并将表单的数据放到cleaned_data属性中

True

>>> form.cleaned_data['your_name']访问数据前要先执行form.is_valid()

'jowin'


>>> form=NameForm({})

>>> form.is_bound

True

>>> form.is_valid()

False

>>> form.errors

{'your_name': ['This field is required.']}


>>> form = NameForm({'your_name':'jowin'*50})

>>> form.is_bound

True

>>> form.is_valid()

False

>>> form.errors

{'your_name': ['Ensure this value has at most 100 characters (it has 250).']}



例2,自动生成表单:


出版社、作者、书籍案例;

模板中用{{ form }}自动生成;

<form method="post" action="">

{% csrf_token %}

{{ form }}

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

</form>


(webproject) C:\webproject\mysite>django-admin startapp books


(webproject) C:\webproject\mysite>pip install django-bootstrap3


​​https://github.com/dyve/django-bootstrap3​​


mysite/mysite/settings.py

INSTALLED_APPS = [

'bootstrap3',



mysite/books/models.py

from django.db import models

from django import forms


class Publisher(models.Model):

name = models.CharField(max_length=30)

address = models.CharField(max_length=50)

city = models.CharField(max_length=60)

state_province = models.CharField(max_length=30)

country = models.CharField(max_length=50)

website = models.URLField()


def __str__(self):

return self.name


class Author(models.Model):

first_name = models.CharField(max_length=30)

last_name = models.CharField(max_length=40)

email = models.EmailField()


def __str__(self):

return '{} {}'.format(self.first_name, self.last_name)


class Book(models.Model):

title = models.CharField(max_length=100)

authors = models.ManyToManyField(Author)

publisher = models.ForeignKey(Publisher)

publication_date = models.DateField()


def __str__(self):

return self.title



mysite/books/forms.py

from django import forms


class PublisherForm(forms.Form):

name = forms.CharField(label='Your name', max_length=30)

address = forms.CharField(max_length=50)

city = forms.CharField(max_length=60)

state_province = forms.CharField(max_length=30)

country = forms.CharField(max_length=20)

website = forms.CharField(max_length=50)



mysite/books/views.py

from django.shortcuts import render, redirect

from .models import Publisher

from .forms import PublisherForm

from django.http import HttpResponse


# def publisher_add(request): #ver1,验证用户输入(验证用户输入和model的约束重复)、返回用户error、html构造form、代码冗长,用django form解决

# if request.method == 'POST':

# name = request.POST.get('name', '')

# address = request.POST.get('address', '')

# city = request.POST.get('city', '')

# state_province = request.POST.get('state_province', '')

# country = request.POST.get('country', '')

# website = request.POST.get('website', '')

#

# error_message = []

# if not name:

# error_message.append('name is required')

# if len(name) > 100:

# error_message.append('name should be short than 100')

# if not address:

# error_message.append('address is required')

#

# if error_message:

# return render(request, 'books/book_add.html', {'error_message': error_message})

# else:

# publisher = Publisher(name=name, address=address, city=city, state_province=state_province,

# country=country, website=website)

# # return redirect('books:publisher-detail', kwargs={'publisher_id': publisher.id})

# publisher.save()

# return HttpResponse('add succeed')

# else:

# return render(request, 'books/publisher_add.html')


def publisher_add(request): #ver2,用户的输入不用手动获取;用户输入验证自动完成;模板中的表单不用手写html;带来的问题,需要编写Form结构(和model重复),需要手动获取内容保存到数据库,解决,使用modelform

if request.method == 'POST': #若使用POST请求提交表单,将创建一个表单实例,并用browser传来的数据填充,这被称为将数据绑定到表单

form = PublisherForm(request.POST) #将数据绑定到表单

if form.is_valid():

publisher = Publisher(

name=form.cleaned_data['name'], #form.cleaned_data('name')访问数据前要先form.is_valid(),form.is_valid()会将数据放到cleaned_data属性中 address=form.cleaned_data['address'],

city=form.cleaned_data['city'],

state_province=form.cleaned_data['state_province'],

country=form.cleaned_data['country'],

website=form.cleaned_data['website']

)

publisher.save() #用form.cleaned_data['website']找到所有合法的表单数据,在发送HTTP重定向给browser告诉它下一步的去向前,用这些数据更新DB

return HttpResponse('add successed')

else: #form.is_valid()不是True,返回到表单的模板,这时表单不再为空(未绑定),HTML表单将用之前提交的数据填充,再根据要求编辑并改正它

return render(request, 'books/books_add.html', {'form': form})

else: #如果是GET请求,将创建一个空的表单实例并将其放置在要渲染的模板的上下文中

form = PublisherForm()

return render(request, 'books/books_add.html', {'form': form})



mysite/books/templates/books/publisher_add.html #ver1

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>Title</title>

</head>

<body>

<form method="post" action="">

{% csrf_token %}

<label>Name: </label>

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

<br>

<label>Address: </label>

<input type="text" name="address">

<br>

<label>City: </label>

<input type="text" name="city">

<br>

<label>State Province: </label>

<input type="text" name="state_province">

<br>

<label>Country: </label>

<input type="text" name="country">

<br>

<label>Website: </label>

<input type="text" name="website">

<br>


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

</form>

</body>

</html>



mysite/books/templates/books/books_add.html #ver2

<!--<form method="post" action="">-->不用bootstrap的样式展示

<!--{% csrf_token %}--> #django原生支持一个简单易用的protection against cross site request forgeries,当提交一个启用CSRF防护的POST表单时,必须使用{ % csrf_token %}模板标签

<!--{{ form }}--> #django会根据模型类的字段和属性,在HTML中自动生成对应表单标签和标签属性,生成的标签会放置在{{ form }}位置

<!--<input type="submit" value="Submit">-->

<!--</form>-->

{% load bootstrap3 %}


<html>使用bootstrap样式展示

<head>

<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" >

<script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

</head>


<div class="container">

<form method="post" class="form">

{% csrf_token %}

添加</h1>

{% bootstrap_form form %}

{% buttons %}

<button type="submit" class="btn btn-primary">

{% bootstrap_icon "star" %} Submit

</button>

{% endbuttons %}

</form>

</div>

</html>



(webproject) C:\webproject\mysite>python manage.py makemigrations

(webproject) C:\webproject\mysite>python manage.py migrate



mysite/books/urls.py

from django.conf.urls import url

from . import views


app_name = 'books'


urlpatterns = [

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

]



mysite/mysite/urls.py

urlpatterns = [

url(r'^books/', include('books.urls')),

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

]


(webproject) C:\webproject\mysite>python manage.py runserver

95django_form_django_form




例3,手动渲染字段:


自己对展示的表单字段进行先后排序;


from django import forms


class ContactForm(forms.Form):

subject = forms.CharField(max_length=100)

message = forms.CharField(widget=forms.Textarea)

sender = forms.EmailField()

cc_myself = forms.BooleanField(required=False)



{{ form.non_field_errors }} #

<div class="fieldWrapper">

{{ form.subject.errors }}

<label for="{{ form.subject.id_for_label }}">Email subject:</label>

{{ form.subject }}

</div>

<div class="fieldWrapper">

{{ form.message.errors }}

<label for="{{ form.message.id_for_label }}">Your message:</label>

{{ form.message }}

</div>

<div class="fieldWrapper">

{{ form.sender.errors }}

<label for="{{ form.sender.id_for_label }}">Your email address:</label>

{{ form.sender }}

</div>

<div class="fieldWrapper">

{{ form.cc_myself.errors }}

<label for="{{ form.cc_myself.id_for_label }}">CC yourself?</label>

{{ form.cc_myself }}

</div>



form field:


​​https://docs.djangoproject.com/en/2.1/ref/forms/fields/​​


BooleanField

CharField

ChoiceField

DateField

DateTimeField

DecimalField

EmailField #实际是CharField的子类,只不过是在其基础上加了些验证

FileField

FilePathField

FloatField #py float

ImageField

IntergerField #py int



form field args:


required

label

label_suffix

widget

help_text

error_messages


95django_form_django_form_02


【文章出处:香港服务器 https://www.68idc.cn欢迎留下您的宝贵建议】
上一篇:python 快速去除list中的空字符串
下一篇:没有了
网友评论