Python学习笔记Day25 - Django_ModelForm

ModelForm

model和form的结合体,比form方便,但是耦合太强,不适合大规模
参考博客

Model + Form => 验证 + 数据库操作

# 利用model.A中的字段,不用重复再写字段

创建ModelForm

from django import forms
from django.forms import widgets as Fwidgets
class UserInfoModelForm(forms.ModelForm):

    is_rmb = Ffields.CharField(widget=Fwidgets.CheckboxInput())     # 创建model以外的标签,用法同form的Field

    class Meta:             # 创建model已有的字段标签
        model = models.UserInfo
        fields = '__all__'

    def clean_username(self):
        old = self.cleaned_data['username']
        return old

./views.py
    obj = XXOOModelForm(request.POST)       # 提交数据
    if obj.is_valid():
        obj = form.save()                   # 默认自动保存多对多数据
    else:
        print(obj.errors['user'][0])            # 获取指定错误信息
        print(obj.errors.as_json())             # 打包为字典的错误信息

./xxx.html
    <p>{{ obj.user }} {{ obj.user.errors }}</p>

    {{ obj.as_p }} {{ obj.user.errors }}           # 一次性以<p>生成所有标签
    {{ obj.as_ul }} {{ obj.user.errors }}          # 一次性以<ul>生成所有标签

    <table>   
        {{ obj.as_table }} {{ obj.user.errors }}   # 一次性以<table>生成所有标签
    </table>

    {{ form.xxoo.label }}                   # label值
    {{ form.xxoo.id_for_label }}            # label的for值,id_xxx
    {{ form.xxoo.label_tag }}               # 自动生成label(包含上述两点)
    {{ form.xxoo.errors }}                  # 错误信息

Meta字段

class Meta:         # 生成HTML标签
    model = models.UserInfo         -> 对应的Model
    fields=None                     -> 字段, '__all__' => 所有字段, ['username','email']
    exclude=None                    -> 排除字段, ['username']
    labels=None                     -> 提示信息, {'username':'用户名'}
    help_texts=None                 -> 帮助提示信息, {'username':'用户名不能以数字开头...'}
    widgets=None                    -> 自定义插件, {'username':F_widgets...}
                                    => 需要从Form里导入widgets并 as ...重命名,以免和字段名重复
    error_messages=None             -> 自定义错误信息, {'username':{'required':'不能为空'},'email':{...}}
                                    => 可整体定义错误信息 {'__all__':{...}}
                                    # ? from django.core.exceptions import NON_FIELD_ERRORS
    field_classes=None              -> 自定义字段类型 (将model中定义的字段类型修改)
                                    => {'email':F_field.URLField}
    localized_fields=None           -> 本地化,如:根据不同时区显示数据, =('birth_date',)
            # 如:
                数据库中,默认UTC时间
                    2016-12-27 04:10:57
                需要在setting中做相应的配置
                    TIME_ZONE = 'Asia/Shanghai'
                    USE_TZ = True
                则显示:
                    2016-12-27 12:10:57

article_modelform = ArticleModelForm(label_suffix='')   -> 修改label后缀

创建或修改数据

.../views.py

obj = XXOOModelForm()                   # 页面显示
模板文件中的使用类似Form

obj = XXOOModelForm(request.POST)       # 提交数据
if obj.is_valid():
    obj = form.save()                   # 默认自动保存多对多数据
    values = obj.cleaned_data           # 获取正确数据
    return ...
else:
    print(obj.errors.as_json())
    return ...

# 拆分为三步
    obj = form.save(commit=False)
    obj.save()      # 保存单表信息
    obj.save_m2m()  # 保存关联的多对多信息

更新和初始化数据

  • 修改数据GET时,传入原始数据

      obj = model.tb.objects.get(id=1)                            # 从model中获取对象
      model_form_obj = XXOOModelForm(instance=obj)                # GET时,将obj对象作为默认值传给modelFrom显示
    
  • 修改完POST时,将数据更新至当前对象,否则将新建数据而不是更新数据

      obj = model.tb.objects.get(id=1)
      model_form_obj = XXOOModelForm(request.POST,instance=obj)   # POST时,将提交的数据更新至obj对象
    

PS: 单纯初始化

model_form_obj = XXOOModelForm(initial={...})

修改样式属性

  • 第一种方法:

      class BookForm(forms.ModelForm):
          class Meta:
              ...
              widgets = {
                  'name': Textarea(attrs={'cols': 80, 'rows': 20}),
                  'description': Textarea(attrs={'cols': 80, 'rows': 20}),
              }
    
  • 第二种重写__init__方法:

      class BookForm(forms.ModelForm):
          class Meta:
              model = Book
          def __init__(self, *args, **kwargs):
              super().__init__(*args, **kwargs)
              self.fields['name'].widget.attrs.update({'class': 'special'})
              self.fields['description'].widget.attrs.update(size='40')
    

验证的执行过程

*UserForm*      >>继承>>  *Form*        >>>>>>>>>>>>>>>>>>>>>>>>>>>>>继承>> *BaseForm*(is_valid...)

*UserModelForm* >>继承>>  *ModelForm*   >>继承>> *BaseModelForm*   >>继承>> *BaseForm*

ModelForm验证的使用方法与Form一样

is_valid -> full_clean -> 钩子 -> 整体错误

字典字段验证

def clean_字段名(self):
    # 可以抛出异常
    # from django.core.exceptions import ValidationError
    return "新值"

用于验证

obj = XXOOModelForm()
obj.is_valid()
obj.errors.as_json()
obj.clean()
obj.cleaned_data

Django ModelChoiceField前台下拉菜单显示object的解决方法

在model中添加如下代码即可,不加的话显示就是object

def __str__(self):
    return self.name

隐藏的modelform标签,而如果该标签为required,提交时浏览器会报错

解决办法:

  1. form表单添加novalidate属性,但会导致所有验证都不能用,不建议

  2. 取消该标签的required

posted @ 2020-07-05 23:36  Jerome12138  阅读(128)  评论(0编辑  收藏  举报