Django入门 ----表单的使用

文章目录

    • 1. 表单类
      • 1. 自定义表单
      • 2. 自定义字段错误信息
      • 3. 设置 widget 美化表单
    • 2. 表单实例化与初始化
    • 3. 模板中使用表单
    • 4. 函数视图中使用表单
    • 5. 类视图中使用表单
    • 6. 表单的验证
    • 7. Formset的使用

  • 在app目录下新建 forms.py,用于自定义表单
  • 表单Form类的作用是把用户输入的数据转化成Python对象格式,便于增删改查操作

1. 表单类

  • Django提供了两种自定义表单的方式:继承Form类ModelForm类

1. 自定义表单

  • 继承 Form 类,需要自定义表单中的字段
  • 继承 ModelForm 类,依据之前定义好Django模型字段来自动生成表单
# app/forms.py
# 表单
from django import forms
from .models import Contact

# 1. 继承 Form
class ContactForm1(forms.Form):
    name = forms.CharField(label="Your Name", max_length=255)
    email = forms.EmailField(label="Email address")
    # 模型里用 verbose_name 来给字段添加一个别名, 
    # 而表单用的是 label


# 2. 继承 ModelForm
class ContactForm2(forms.ModelForm):
    
    class Meta:
        model = Contact
        fields = ('name', 'email',)
        # fields = '__all__'
        # 一次性添加全部模型字段

2. 自定义字段错误信息

  • 对于继承 Form类 的表单,可以针对每个字段自定义验证错误信息
from django import forms

class LoginForm(forms.Form):  
    username = forms.CharField(
        required=True,
        max_length=20,
        min_length=6,
        error_messages={
     
            'required': '用户名不能为空',
            'max_length': '用户名长度不得超过20个字符',
            'min_length': '用户名长度不得少于6个字符',
        }
    )

  • 对于继承 ModelForm类 的表单, 可以在Meta选项下来自定义错误信息
from django.forms import ModelForm, Textarea
from myapp.models import Author

class AuthorForm(ModelForm):
    class Meta:
        model = Author
        fields = ('name', 'title', 'birth_date')
        widgets = {
     
            'name': Textarea(attrs={
     'cols': 80, 'rows': 20}),  # 关键是这一行
        }
        labels = {
     
            'name': 'Author',
        }
        help_texts = {
     
            'name': 'Some useful help text.',
        }
        error_messages = {
     
            'name': {
     
                'max_length': "This writer's name is too long.",
            },
        }

3. 设置 widget 美化表单

  • widget 可以指定控件css属性
from django import forms

class ContactForm(forms.Form):
    name = forms.CharField(
        max_length=255,
		# 指定了输入控件为 Textarea 和样式css
        widget=forms.Textarea(
            attrs={
     'class': 'custom'},
        ),
    )


BIRTH_YEAR_CHOICES = ('1980', '1981', '1982')
COLORS_CHOICES = (
    ('blue', 'Blue'),
    ('green', 'Green'),
    ('black', 'Black'),
)

class SimpleForm(forms.Form):
	# 对年份使用了 SelectDateWidget
    birth_year = forms.DateField(
        widget=forms.SelectDateWidget(years=list(BIRTH_YEAR_CHOICES))
    )
    
    # 颜色使用复选框 CheckboxSelectMultiple
    favorite_colors = forms.MultipleChoiceField(
        required=False,
        widget=forms.CheckboxSelectMultiple,
        choices=list(COLORS_CHOICES),
    )

2. 表单实例化与初始化

# 1. 空表单,无数据,通过 {
     { form }}在模板中渲染
form = ContactForm()


# 2. 带初始值的表单,initial() 或 default_data()
# initial方法初始化
form = ContactForm(
    initial={
     
        'name': 'First and Last Name',
    },)

# default_data默认值
default_data = {
     'name': 'John', 'email': '[email protected]', }
form = ContactForm(default_data)


# 3. 用户提交的数据与表单结合,并对新表单数据校验,即先结合后校验
form = ContactForm(data=request.POST, files=request.FILES)


# 4. 给表单提供现有对象实例的数据来编辑修改
# 该方法仅适用于由模型创建的ModelForm
contact = Contact.objects.get(id=1)
form =  ContactForm(instance = contact, data=request.POST)

3. 模板中使用表单

  • 表单以form变量传递给模板,在模板文件中我们可以通过{ { form.as_p }}, { { form.as_li }}, { { form.as_table }} 的方式渲染表单
{
     % block content %}
<div class="form-wrapper">
   <form method="post" action="" enctype="multipart/form-data">
      {
     % csrf_token %}
      {
     % 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 %}
      <div class="button-wrapper submit">
         <input type="submit" value="Submit" />
      </div>
   </form>
</div>
{
     % endblock %} 

4. 函数视图中使用表单

  • 设计一个表单让用户完成注册
  • 在app目录下新建forms.py, 然后创建一个RegistrationForm
from django import forms
from django.contrib.auth.models import User

class RegistrationForm(forms.Form):
    username = forms.CharField(label='Username', max_length=50)
    email = forms.EmailField(label='Email',)
    password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Password Confirmation', widget=forms.PasswordInput)
  • 在函数视图views.py中使用表单,并将其向指定模板传递
from django.shortcuts import render, get_object_or_404
from django.contrib.auth.models import User
from .forms import RegistrationForm
from django.http import HttpResponseRedirect

def register(request):
    if request.method == 'POST':
        # 将用户POST提交数据与表单结合,准备验证
        form = RegistrationForm(request.POST) 
        
        if form.is_valid():
			# 使用 ModelForm 创建的话,直接通过 form.save() 将验证后表单数据存入数据库
		# if form.is_valid():
    		# form.save()

        	# 使用自定义的表单,需要显示地通过 form.cleaned_data 获取验证后的数据,然后手动地存入数据库
            username = form.cleaned_data['username']
            email = form.cleaned_data['email']
            password = form.cleaned_data['password2']
            
            # 使用内置User自带create_user方法创建用户,不需要使用save()
            # 如果直接使用objects.create()方法后需要使用save()
            user = User.objects.create_user(username=username, password=password, email=email)
            
            return HttpResponseRedirect("/accounts/login/")
    else:
        form = RegistrationForm()

    return render(request, 'users/registration.html', {
     'form': form})

5. 类视图中使用表单

from django.views.generic.edit import CreateView
from .models import Article
from .forms import ArticleForm

# 方式一: 通过 model和fields 定义表单
class ArticleCreateView(CreateView):
    model = Article
    fields = ['title', 'body']
    template_name = 'blog/article_form.html'

# 方式二:使用 form_class
class ArticleCreateView(CreateView):
    model = Article
    form_class = ArticleForm
    template_name = 'blog/article_form.html'

6. 表单的验证

  • 每个forms类可以通过自定义 clean() 方法进行表单验证
  • 可以自定义 clean_字段名() 方法只对某些字段进行验证
  • 如果数据有效 form.is_valid() == True,则会将数据存储在cleaned_data 字典
from django import forms
from django.contrib.auth.models import User
import re

def email_check(email):
    pattern = re.compile(r"\"?([-a-zA-Z0-9.`?{}]+@\w+\.\w+)\"?")
    return re.match(pattern, email)

class RegistrationForm(forms.Form):
    username = forms.CharField(label='Username', max_length=50)
    email = forms.EmailField(label='Email',)
    password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Password Confirmation', widget=forms.PasswordInput)

    # 自定义验证方法
    def clean_username(self):
        username = self.cleaned_data.get('username')

        if len(username) < 6:
            raise forms.ValidationError("Your username must be at least 6 characters long.")
        elif len(username) > 50:
            raise forms.ValidationError("Your username is too long.")
        else:
            user = User.objects.filter(username__exact=username).first()
            if user.exists():
                raise forms.ValidationError("Your username already exists.")

        return username

    def clean_email(self):
        email = self.cleaned_data.get('email')

        if email_check(email):
            filter_result = User.objects.filter(email__exact=email)
            if len(filter_result) > 0:
                raise forms.ValidationError("Your email already exists.")
        else:
            raise forms.ValidationError("Please enter a valid email.")

        return email

    def clean_password1(self):
        password1 = self.cleaned_data.get('password1')

        if len(password1) < 6:
            raise forms.ValidationError("Your password is too short.")
        elif len(password1) > 20:
            raise forms.ValidationError("Your password is too long.")

        return password1

    def clean_password2(self):
        password1 = self.cleaned_data.get('password1')
        password2 = self.cleaned_data.get('password2')

        if password1 and password2 and password1 != password2:
            raise forms.ValidationError("Password mismatch. Please enter again.")

        return password2

7. Formset的使用

  • 1个页面上使用多个表单,可以创建一个Formset,表单的集合
from django import forms

class BookForm(forms.Form):
    name = forms.CharField(max_length=100)
    title = forms.CharField()
    pub_date = forms.DateField(required=False)

# forms.py - build a formset of books
from django.forms import formset_factory
from .forms import BookForm

# extra: 额外的空表单数量
# max_num: 包含表单数量(不含空表单)
BookFormSet = formset_factory(BookForm, extra=2, max_num=1)
  • 在视图文件views.py,像使用form一样使用formset
# views.py - formsets example.
from .forms import BookFormSet
from django.shortcuts import render

def manage_books(request):
    if request.method == 'POST':
        formset = BookFormSet(request.POST, request.FILES)
        if formset.is_valid():
            # do something with the formset.cleaned_data
            pass
    else:
        formset = BookFormSet()
    return render(request, 'manage_books.html', {
     'formset': formset})
  • 模板中使用 formset
<form action=.” method=POST>
{
     {
      formset }}
</form>

你可能感兴趣的:(Django,Python,django,python)