Django-Form组件-forms.ModelForm

froms.ModelForm

具有models操作数据库字段的功能,还具有Form的功能。较Form组件而言,根据model自动生成Form。

使用注册的案例进行初步认识

# 使用ModelForm创建Form模板

from django import forms
class RegForm(forms.ModelForm):
    re_password = forms.CharField(min_length=6,
                                  widget=forms.PasswordInput(attrs={'placeholder': '确认密码', 'autocomplete': 'off'}),
                                  label='确认密码', )

    class Meta:
        model = models.UserProfile
        fields = '__all__'
        ecclude = ['is_active', 'memo']

        min_lengths = {'password': 6}
        
		# 定义字段的widgets属性
        widgets = {
            'username': forms.EmailInput(attrs={'placeholder': '用户名', 'autocomplete': 'off'}),
            'password': forms.PasswordInput(attrs={'placeholder': '密码', 'autocomplete': 'off'}),
            'name': forms.TextInput(attrs={'placeholder': '姓名', 'autocomplete': 'off'}),
            'mobile': forms.TextInput(attrs={'placeholder': '手机号', 'autocomplete': 'off'}),
        }
		
		# 定义每一个字段的labels属性
        labels = {
            'username': '用户名',
            'password': '密码',
            'name': '姓名',
            'mobile': '手机号',
            'department': '部门'
        }
	# 可以使用局部钩子
    def clean_mobile(self):
        phone = self.cleaned_data.get('mobile')
        ret = re.match(r"^1[35678]\d{9}$", phone)
        if ret:
            return phone
        else:
            raise ValidationError('手机格式不正确')

    def clean_username(self):
        user = self.cleaned_data.get('username')
        obj = models.UserProfile.objects.get(username=user)
        if obj:
            raise ValidationError('该用户已存在')
        return user
        
	# 可以定义全局钩子
    def clean(self):
        self._validate_unique = True  # 去数据库检验唯一性
        password = self.cleaned_data.get('password')
        re_password = self.cleaned_data.get('re_password')
        if password == re_password:
            md5 = hashlib.md5()
            md5.update(password.encode('utf-8'))
            self.cleaned_data['password'] = md5.hexdigest()
            return self.cleaned_data
        self.add_error('re_password', '两次密码不一致')  # 将全局的错误信息添加到字段错误列表中
        raise ValidationError('两次密码不一致')

在views视图函数中进行实例化

def reg(request):
    form_obj = RegForm()
    if request.method == 'POST':
        form_obj = RegForm(request.POST)
        if form_obj.is_valid():   
            form_obj.save()
            return redirect('app01:login')
    return render(request, 'logon.html', {'form_obj': form_obj})

在htm中进行展示

<form action="" method="post">
    {% csrf_token %}
    <div>{# 注册账户 #}
        {{ form_obj.username }}  {{ form_obj.username.errors.0 }}
    </div>
    <div>{# 注册密码 #}
        {{ form_obj.password }}  {{ form_obj.password.errors.0 }}
    </div>
    <div>{# 密码确认 #}
        {{ form_obj.re_password }}  {{ form_obj.re_password.errors.0 }}
    </div>
    <div>{# 真实姓名 #}
        {{ form_obj.name }}  {{ form_obj.name.errors.0 }}
    </div>
    <div>{# 注册部门 #}
        {{ form_obj.department }}  {{ form_obj.department.errors.0 }}
    </div>
    <div>{# 注册手机号 #}
        {{ form_obj.mobile }}  {{ form_obj.mobile.errors.0 }}
    </div>
    <div>
        {{ error }}
    </div>
    <button id="submit">Sign on</button>
</form>

知识点-class Meta

class Meta是一个内部类,作用是定义Form模型的特殊性质

class Meta中常用的参数有:

model = models.UserProfile  # 根据一个具体的model表进行form的创建
fields = "__all__"  # 字段,如果是__all__,就是表示列出所有的字段
exclude = None  # 排除的字段
labels = None  # 提示信息
help_texts = None  # 帮助提示信息
widgets = None  # 自定义插件
error_messages = None  # 自定义错误信息
field_classes=None   # 自定义字段类 (也可以自定义字段)

知识点-验证和其他

# views中进行写入验证
form_obj.is_valid()  # 数据库保存数据之前,判断该条记录能否写入

# vies中进行保存
form_obj.save()

# 可以重写全局钩子和局部钩子

# 全局钩子中
self._validate_unique = True  # 去数据库检验进行unique判断,不设置时会有唯一性异常

数据添加和修改中的应用

路由

url(r'^customer_add/', views.customer_operate,name='customer_add'),
url(r'^customer_edit/(\d+)/', views.customer_operate,name='customer_edit'),

视图函数

def customer_operate(request, pk=None):
    obj = models.Customer.objects.filter(pk=pk).first()
    form_obj = OperateForm(instance=obj)
    if request.method == 'POST':
        form_obj = OperateForm(request.POST, instance=obj)
        if form_obj.is_valid():
            form_obj.save()  # save
            next = request.GET.get('next')
            if next:
                return redirect(next)
            return redirect('app01:mine_customer')
    title = '编辑客户信息' if pk else '添加用户信息'
    return render(request, 'customeroperate.html', {'form_obj': form_obj, 'title': title})

ModelForm

class BaseForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 自定义操作,循环添加class操作,当遇到MultiSelectFormField或者forms.BooleanField框时,不加class类
        for name, field in self.fields.items():
            # if name == 'course'  # 可以直接判断字段名
            if isinstance(field, (MultiSelectFormField, forms.BooleanField)):
                # 判断字段类型是MultiSelectFormField, forms.BooleanField还可以根据需求继续添加到元组中,让他们的格式不接受form-control的样式
                continue
            # 方式一:
            field.widget.attrs['class'] = 'form-control'
            # 方式二:
            # field.widget.attrs.update({'class': 'form-control'})


# 新增和编辑客户form组件
class OperateForm(BaseForm):

    class Meta:
        model = models.Customer
        fields = '__all__'

html中

<form class="form-horizontal" action="" method="post" novalidate >
      {% csrf_token %}
      {% for customer in form_obj %}

     <div class="form-group {% if customer.errors %} has-error {% endif %}">
           <label for="{{customer.id_for_label}}"
                           class="col-sm-3 control-label {% if not customer.field.required %} not_required {% endif %}">
                            {{customer.label}}</label>
          <div class="col-sm-4">
                        {{ customer }}
                    </div>
                    <p class="col-sm-4"><span>{{ customer.errors.0 }}</span></p>

           </div>
                {% endfor %

           <div class="form-group">
                    <div class="col-sm-offset-2 col-sm-10">
                        <button type="submit" class="btn btn-primary">保存</button>
                    </div>
                </div>
            </form>
posted @ 2019-10-07 11:39  Aries-X  阅读(342)  评论(0编辑  收藏  举报