Jonathan1314

导航

Django Form

案例需求:

出版社,作者,书籍 后台管理

from django.db import models

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 '%s %s' % (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

 

# books/templates/books/publisher_add.html
<form method="post">
{% csrf_token %}
<p style="color: red">{{ error_message }}</p>
<label for="name">Name: </label><input id="name" name="name" type="text"/><br/>
<label for="address">Address: </label><input id="address" name="address" type="text"/><br/>
<label for="city">City: </label><input id="city" name="city" type="text"/><br/>
<label for="state_province">State_province: </label><input id="state_province" name="state_province" type="text"/><br/>
<label for="country">Country: </label><input id="country" name="country" type="text"/><br/>
<label for="website">Website: </label><input id="website" name="website" type="text"/><br/>
<input type="submit" value="Submit"/>
</form>

# books/views.py
def publisher_add(request):
    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) > 30:
            error_message.append('Name should be shorter than 30')

        if not address:
            error_message.append('Address ia required')
        if len(address) > 50:
            error_message.append('Address should be shorter than 50')

        if error_message:
            return render(request, 'books/publisher_add.html', {'error_message': error_message})
        else:
            return HttpResponse('添加成功')
    else:
        return render(request, 'books/publisher_add.html')

分析:

  • 验证用户输入

  • 返回用户error

  • html构造form

  • 验证用户输入和model的约束重复

  • 代码冗长

 

用Django Form来解决这些问题:

先了解Django Form组件常见用法,models.Model是转换为sql语句,那forms.Form是做什么的呢

 

说明:

  • class NameForm(forms.Form),自定义Form类

  • form = NameForm(),实例化定义From类

  • form.is_bound,定义Form时是否传入数据,如form=NameForm() 为False;form=NameForm({'key':'value'})为True

  • from.as_p(),form.as_table(),form.as_ul,from对象可以转换为html标签

  • form.is_valid(),验证输入数据合法性

  • form.cleaned_data['key'],必须先执行is_valid(),输入合法后会转换为Python合适的数据类型,并以字典分装

  • from.errors,输入不合法

 

需求实现:

# 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=50)
    website = forms.CharField(max_length=50)

# views.py
from django.shortcuts import render, redirect
from django.http import HttpResponse, HttpResponseRedirect
from .forms import PublisherForm
from .models import Publisher
def publisher_add(request):
    if request.method == "POST":
        form = PublisherForm(request.POST)  # 用户数据获取
        if form.is_valid():  # 用户数据校验
            publisher = Publisher(
                name=form.cleaned_data['name'],
                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()
            return HttpResponse('添加成功')
        else:
            return render(request, 'books/publisher_add.html', {'form': form})
    else:
        form = PublisherForm()
        return render(request, 'books/publisher_add.html', {'form': form})

# books/publisher_add.html
<form method="post">
<h1>添加出版社</h1>
{{ form }}
{% csrf_token %}
<input type="submit" value="提交"/>
</form>

Form解决的问题:

  • 用户的输入不用手动获取

  • 用户输入的验证自动完成

  • 表单编写不用手写html

带来或未解决问题:

  • 需要编写Form结构(和models重复)

  • 需要手动获取内容保存到数据库

 

再来一个案例:

前端模板可以整体使用 {{ form }},也可以单独使用 { form.field.相关属性}}

# forms.py
from django import forms

class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100,help_text='dadada')
    message = forms.CharField(widget=forms.Textarea)
    sender = forms.EmailField()
    cc_myself = forms.BooleanField(required=False)

# views.py
def sendmail(request):
    print(request.method)
    if request.method == "POST":
        print('**********')
        form = ContactForm(request.POST)
        if form.is_valid():
            subject = form.cleaned_data['subject']
            message = form.cleaned_data['message']
            sender = form.cleaned_data['sender']
            cc_myself = form.cleaned_data['cc_myself']

            recipients = ['nin@jianxin.com.cn']
            if cc_myself:
                recipients.append(sender)
            # send_mail()
            return HttpResponse('发送成功')
        else:
            return render(request, 'books/sendmail_manual.html',{'form':form})

    elif request.method == "GET":
        form = ContactForm()
        return render(request, 'books/sendmail_manual.html', {'form': form})

# books/templates/sendmail_manual.html
<form method="post" action="{% url 'books:sendmail' %}">
    {% csrf_token %}
    {{ form.non_field_errors }}
    <div>
        {{ form.subject.errors }}
        <label for="{{ form.subject.id_for_label }}">Email Subject: </label>{{ form.subject }}<br/>
        <div>
        <strong>form.subject.label---></strong>{{ form.subject.label }}<br/>
        <strong>form.subject.label_tag---></strong>{{ form.subject.label_tag }}<br/>
        <strong>form.subject.id_for_label---></strong>{{ form.subject.id_for_label }}<br/>
        <strong>form.subject.value---></strong>{{ form.subject.value }}<br/>
        <strong>form.subject.html_name---></strong>{{ form.subject.html_name }}<br/>
        <strong>form.subject.help_text---></strong>{{ form.subject.help_text }}<br/>
        <strong>form.subject.errors---> </strong>{{ form.subject.errors }}<br/>
        </div>
    </div>
    <div>
        {{ form.message.errors }}
        <label for="{{ form.message.id_for_label }}">Your message: </label>
        {{ form.message }}
    </div>
    <div>
        {{ form.sender.errors }}
        <label for="{{ form.sender.id_for_label }}">Your Email Address: </label>
        {{ form.sender }}
    </div>
    <div>
        {{ form.cc_myself.errors }}
        <label for="{{ form.cc_myself.id_for_label }}">CC yourself?: </label>
        {{ form.cc_myself }}
    </div>
    <div>
        <input type="submit" value="Submit"/>
    </div>
</form>

说明:

  • forms.EmailField(),前端输入字符串必须符合email格式

  • forms.CharField(widget=forms.Textarea),widget用处很大

  • forms.BooleanField(required=False),转换为type='radio',required=False 可选

form和field的一些属性

  • {{ form.non_field_errors }} 对应的是 ModelForm联合验证方法 def clean()

  • {{ form.errors }}

  • {{ field.label }}

  • {{ field.label_tag }}

  • {{ field.id_for_label }}

  • {{ field.value }}

  • {{ field.html }}

  • {{ field.help_text}}

  • {{ field.errors}}

https://docs.djangoproject.com/en/1.11/topics/forms/#looping-over-the-form-s-fields

 

field 手动校验:

 

内置 form field 和widgets:

时常浏览

https://docs.djangoproject.com/en/1.11/ref/forms/fields/

https://docs.djangoproject.com/en/1.11/ref/forms/widgets/

posted on 2017-09-12 14:45  Jonathan1314  阅读(197)  评论(0编辑  收藏  举报