Django 第八章 表单与模型

表单是搜集用户数据信息的各种表单元素的合集,其作用是实现网页上的数据交互,比如用户在网站输入数据信息,然后提交到网站服务器进行处理(如数据录入和用户登陆注册),分为django.forms.Form:基础的表单功能,django.forms.ModelForm:在基础上结合模型所生成的数据表单。

1.传统表单在模板文件中编写HTML标签实现

完整的表单包括:

  • 提交地址:(form标签的action属性)用于设置用户提交的表单数据应有哪个路由接收和处理。当用户向服务器提交数据时,若属性action为空,则提交的数据应当由当前的路由接受和处理,否则网页会跳转到属性action所指向的路由地址。
  • 请求方式:设置表单的提交方式,通常是GET请求或POST请求,由form标签的method决定。
  • 元素控件:供用户输入数据信息的输入框,由HTML的控件实现,控件属性type用于设置输入框的类型,常用的输入框有文本框、下拉框、复选框。
  • 提交按钮:供用户提交数据到服务器,该按钮由HTML的控件实现。但该按钮具有一定的特殊性,因此不归纳到元素控件的范围内。

2.视图里使用Form和ModelForm

1. 在models.py中创建数据库模型
from django.db import models

# Create your models here.
class PersonInfo(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=20)
    age = models.IntegerField()

    def __str__(self):
        return self.name
    class Meta:
        verbose_name = '人员信息'

class Vocation(models.Model):
    id = models.AutoField(primary_key=True)
    job = models.CharField(max_length=20)
    title = models.CharField(max_length=20)
    payment = models.IntegerField(null=True, blank=True)
    person = models.ForeignKey(PersonInfo, on_delete=models.CASCADE)

    def __str__(self):
        return str(self.id)
    class Meta:
        verbose_name = '职业信息'

2.迁移数据库
3.创建表单form.py
from django import forms
from .models import *
class PersonInfoForm(forms.ModelForm):
    class Meta:
        model = PersonInfo
        fields = '__all__'
    
class VocationForm(forms.ModelForm):
    class Meta:
        model = Vocation
        fields = '__all__'
        labels = {
            'job': '职位',
            'title': '职称',
            'payment': '薪资',
            'person': '姓名'
        }
        error_messages = {
            '__all__': {'required': '请输入内容',
                        'invalid': '请检查输入内容'},
        }
    # 自定义表单字段payment的数据清洗
    def clean_payment(self):
        data = self.cleaned_data['payment'] + 10
        return data


4.views.py中添加交互信息
from django.shortcuts import render
from django.http import HttpResponse
from .form import *
from .models import *
def index(request):
    # GET请求
    if request.method == 'GET':
        id = request.GET.get('id', '')
        if id:
            i = Vocation.objects.filter(id=id).first()
            # 将参数i传入表单VocationForm执行实例化
            v = VocationForm(instance=i, prefix='vv')
        else:
            v = VocationForm(prefix='vv')
        return render(request, 'index.html', locals())
    # POST请求
    else:
        # 由于在GET请求设置了参数prefix
        # 实例化时设置参数prefix,否则无法获取POST的数据
        v = VocationForm(data=request.POST, prefix='vv')
        # is_valid()会使字段payment自增加10
        if v.is_valid():
            # 根据请求参数id查询模型数据是否存在
            id = request.GET.get('id')
            result = Vocation.objects.filter(id=id)
            # 数据不存在,则新增数据
            if not result:
                # 数据保存方法一
                # 直接将数据保存到数据库
                # v.save()
                # 数据保存方法二
                # 将save的参数commit=False
                # 生成数据库对象v1,修改v1的属性值并保存
                v1 = v.save(commit=False)
                v1.title = '初级' + v1.title
                v1.save()
                # 数据保存方法三
                # save_m2m()方法用于保存ManyToMany的数据模型
                # v.save_m2m()
                return HttpResponse('新增成功')
            # 数据存在,则修改数据
            else:
                d = v.cleaned_data
                d['title'] = '中级' + d['title']
                result.update(**d)
                return HttpResponse('修改成功')
        else:
            # 获取错误信息,并以json格式输出
            error_msg = v.errors.as_json()
            print(error_msg)
            return render(request, 'index.html', locals())
5.index.html中写显示页面

```bash
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {% if v.errors %}
        <p>
            数据出错啦,错误信息:{{ v.errors }}
        </p>
    {% else %}
        <form action="" method="post">
        {% csrf_token %}
            <table>
                {{ v.as_table }}
            </table>
            <input type="submit" value="提交">
        </form>
    {% endif %}
</body>
</html>

表单类Form和模型实现数据交互需要注意以下事项:

  • 表单字段最好与模型字段相同,否则两者在进行数据交互时,必须将两者的字段进行转化。
  • 使用同一个表单并且需要多次实例化表单时,除了参数initial和data的数据不同之外,其他参数设置必须相同,否则无法接受上一个表单对象所传递的数据信息。
  • 参数initial是表单实例化的初始数据,它只适用于模型数据传递给表单,再由表单显示在网页上;参数data是在表单实例化之后,再将数据传递给实例化对象,只适用于表单接收HTTP请求的请求参数。
  • 参数prefix设置表单的控件属性name和id的值,若在一个网页里使用同一个表单生成多个不同的网页表单,参数prefix可分区每个网页表单,则在接收或设置某个表单数据时不会与其他表单数据混淆。
    模型表单ModelForm实现数据保存只有save()和save_m2m()两种方法。使用save()保存数据时,参数commit的值会影响数据的保存方式。如果参数commit为True,就直接将表单保存到数据库;如果参数commit为False,就会生成一个数据库对象,然后可以对该对象进行增、删、改、查等数据操作,再将修改后的数据保存到数据库。
    save()只适合将数据保存在非多对多关系的数据表中,save_m2m()只适合将数据保存在多对多关系的数据表中。

你可能感兴趣的:(Django学习,django)