【Django】Form 与 ModelForm (积累总结中...)

前言

  在学习 Django Form 和 ModelForm 之前,先实践下基础 Django 表单 | 菜鸟教程。我在实践时遇到了编码问题并提供了如下解决方案:【Python】’ascii’ codec can’t decode byte 0xe4 in position 0: ordinal not in range(128)

  如果我们手动将输入之后的数据在 views 中都获取到再传递到网页,这样是可行的,但是很不方便,所以 Django 提供了更简单易用的 forms 来解决验证等这一系列的问题。

Form Objects

Form对象封装了一系列Field和验证规则,Form类都必须直接或间接继承自django.forms.Form,定义Form有两种方式:

方式一:直接继承Form

from django import forms

class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100,label='主题')
    message = form.CharField(widget=forms.TextArea)
    sender = form.EmailField()
    cc_myself = forms.BooleanField(required=False)

Field:Form对象中的一个字段,如:EmailField表示email字段,如果这个字段不是有效的email格式,就会产生错误。

数据的层次验证

  Django Form提供了许多钩子供开发者做不同层次的验证,在Form.full_clean()方法中主要包括了三个层次的验证,并且这三个验证依次进行:

  • Form._clean_fields() 字段层次验证
  • Form._clean_form() 表单层次验证
  • Form._post_clean() ModelForm的额外验证

form类的运行顺序是init,clean,validte,save
其中clean和validate会在form.is_valid()方法中被先后调用。

# 获取文章详细信息,包含一个CommentForm表单
def detail(req, article_id):
    if req.method == 'POST':
        form = CommentForm(req.POST)
        if form.is_valid():
            name = form.cleaned_data['name']
            address = form.cleaned_data['address']
            email = form.cleaned_data['email']
            context = form.cleaned_data['context']
            article = Article.objects.get(pk=article_id)
            comment = Comment(article=article, name=name, address=address, email=email, context=context)
            comment.save()
            return HttpResponseRedirect('blog/detail.html')

cleaned_data 就是读取表单返回的值,返回类型为字典dict型。
cleaned_data[‘email’] 读取name为 ‘email’的表单提交值,并赋予 email变量。
cleaned_data中对应的值都必须按照model中定义的字段类型取值,否则校验不通过或保存时报错。


方式二:结合Model,继承django.forms.ModelForm

在Form的基础上,Django还提供了一种ModelForm。如果你的FORM表单十分贴近数据Model,那么可以用ModelForm来节省大量代码。

Model + Form (之前的操作)

models.py

class UserType(models.Model):
    caption = models.CharField(max_length=32)

class UserInfo(models.Model):
    username = models.CharField(max_length=32)
    email = models.EmailField()
    user_type = models.ForeignKey(to='UserType',to_field='id')

forms.py

from django import forms
from django.forms import fields

class UserInfoForm(forms.Form):
    # username = models.CharField(max_length=32)    <-- models
    username = fields.CharField(max_length=32)
    # email = models.EmailField()    <-- models
    email = fields.EmailField()
    # user_type = models.ForeignKey(to='UserType',to_field='id')    <-- models
    user_type = fields.ChoiceField(
        choices=models.UserType.objects.values_list('id','caption')
    )

    # 下面的操作是让数据在网页上实时更新。
    def __init__(self, *args, **kwargs):
        super(UserInfoForm,self).__init__(*args, **kwargs)
        self.fields['user_type'].choices = models.UserType.objects.values_list('id','caption')

ModelForm 基本操作

使用情景:如果我们在models里设计数据库时,已经设计好了一个类(就是数据库的表)之后想复用这个类的信息来作为表单的模型

forms.py

from django.forms import ModelForm

class UserInfoModelForm(forms.ModelForm):

    class Meta:
        model = models.UserInfo    # 与models建立了依赖关系
        fields = "__all__"

views.py

def index(request):
    if request.method == "GET":
        obj = UserInfoModelForm()
        return render(request,"index.html",{'obj':obj})
    elif request.method == "POST":
        obj = UserInfoModelForm(request.POST)
        print(obj.is_valid())  # 这是方法,别忘记了加括号
        print(obj.cleaned_data)
        print(obj.errors)
        return render(request,"index.html",{'obj':obj})

自定制字段名

如何定义http上定义的字段呢,自定义写成中文的?之前的用法是在Form里写上label。Model Form定义要用verbose_name

models.py

class UserInfo(models.Model):
    username = models.CharField(max_length=32, verbose_name='用户')
    email = models.EmailField(verbose_name='邮箱')
    user_type = models.ForeignKey(to='UserType',to_field='id', verbose_name='类型')

如果不在model里定义,在modelForm里实现,利用labels

class UserInfoModelForm(forms.ModelForm):

    class Meta:
        model = models.UserInfo
        fields = "__all__"
        labels = {
            'username':'用户名',
            'email':'邮箱',
        }

Form验证:
UserInfoForm -> Form -> BaseForm( 包含is_valid等方法)

ModelForm验证:
UserInfoModelForm -> ModelForm -> BaseModelForm -> BaseForm

ModelForm因为model和form耦合太密切,所以一般写小程序用它。

你可能感兴趣的:(Django)