zoukankan      html  css  js  c++  java
  • ModelForm解密

     一、复用model表和字段

     models.py文件

    class User(models.Model):
        username = models.CharField(max_length=32)
        email = models.EmailField(max_length=32)
        #指定关系一对多,指定哪张表,指定哪个字段
        user_type = models.ForeignKey(to='UserType',to_field='id')
    
        class Meta:
            unique_together = (('username','email'))
    

      

    forms.py文件

    class UserModelForm(forms.ModelForm):
        class Meta:
            model = models.User
            fields = "__all__"
    

     

    model指定哪个model类

    fields = "__all__",指定展示所有列,也可以选定或排除对应的列

    fields = ['username','email']   # 显示指定列
    exclude = ['username']          # 排除指定列
    

      

    views.py文件

    def mf(request):
        if request.method == 'GET':
            obj = UserModelForm()
            new_obj = models.User.objects.all()
            return render(request,'index.html',{'obj':obj,'new_obj':new_obj})
        elif request.method == 'POST':
            obj = UserModelForm(request.POST)
            if obj.is_valid():
                obj.save()
            return render(request,'index.html',{'obj':obj})
    

      form里面有is_validcleaned_dataerrors

     

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <form action="/index/" method="POST">
            {% csrf_token %}
    
            {{ obj.as_p }}
            <input type="submit" value="提交">
        </form>
    
    
     <table>
           <th>
               <tr>用户名</tr>
               <tr>邮箱</tr>
               <tr>角色</tr>
           </th>
           {% for obj in new_obj %}
           <tr>
               <td>{{ obj.username }}</td>
               <td>{{ obj.email }}</td>
               <td>{{ obj.user_type.caption }}</td>
           </tr>
            {% endfor %}
       </table>
    </body>
    </html>
    

      

    二、实施

    1、Meta和操作

      a.  class Meta:
                model,                           # 对应Model的
                fields=None,                     # form里面展示的字段
                exclude=None,                    # form从models排除的字段
                labels=None,                     # 提示信息
                help_texts=None,                 # 帮助提示信息
                widgets=None,                    # 自定义插件
                error_messages=None,             # 自定义错误信息(整体错误信息from django.core.exceptions import NON_FIELD_ERRORS)
                field_classes=None               # 自定义字段类 (也可以自定义字段)
                localized_fields=('birth_date',) # 本地化,如:根据不同时区显示数据
                如:
                    数据库中
                        2016-12-27 04:10:57
                    setting中的配置
                        TIME_ZONE = 'Asia/Shanghai'
                        USE_TZ = True
                    则显示:
                        2016-12-27 12:10:57
        b. 验证执行过程
            is_valid -> full_clean -> 钩子 -> 整体错误
    
        c. 字典字段验证
            def clean_字段名(self):
                # 可以抛出异常
                # from django.core.exceptions import ValidationError
                return "新值"
        d. 用于验证
            model_form_obj = XXOOModelForm()
            model_form_obj.is_valid()
            model_form_obj.errors.as_json()
            model_form_obj.clean()
            model_form_obj.cleaned_data
        e. 用于创建
            model_form_obj = XXOOModelForm(request.POST)
            #### 页面显示,并提交 #####
            # 默认保存多对多
                obj = form.save(commit=True)
            # 不做任何操作,内部定义 save_m2m(用于保存多对多)
                obj = form.save(commit=False)
                obj.save()      # 保存单表信息
                obj.save_m2m()  # 保存关联多对多信息
    
        f. 用于更新和初始化,指定instance为更新记录
            obj = model.tb.objects.get(id=1)
            model_form_obj = XXOOModelForm(request.POST,instance=obj)
            ...
    
            PS: 单纯初始化
                model_form_obj = XXOOModelForm(initial={...})
    

     

    2、范例  

    注意:导入模块名(fields、widgets)和字段名重复,所以导入时要起个别名。

    from django import forms
    from django.forms import fields as Ffields
    from django.forms import widgets as Fwidgets
    class UserInfoModelForm(forms.ModelForm): is_rmb = Ffields.CharField(widget=Fwidgets.CheckboxInput()) class Meta: model = models.UserInfo fields = '__all__' # fields = ['username','email'] # exclude = ['username'] labels = { 'username': '用户名', 'email': '邮箱', } help_texts = { 'username': '...' } widgets = { 'username': Fwidgets.Textarea(attrs={'class': 'c1'}) } error_messages = { '__all__':{ # 整体错误信息 }, 'email': { 'required': '邮箱不能为空', 'invalid': '邮箱格式错误..', } } field_classes = { # 定义字段的类是什么 # 'email': Ffields.URLField # 这里只能填类,加上括号就是对象了。 } # localized_fields=('ctime',) # 哪些字段做本地化

      

     

    三、数据库操作

    1、创建数据save

    如果数据验证是ok的,那么save,就直接在数据库中创建完数据了

     if obj.is_valid():
         obj.save()      # 创建数据
    

      

    在如下一对多、多对多关系中:

    class UserType(models.Model):
        caption = models.CharField(max_length=32)
    
    class UserGroup(models.Model):
        name = 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')
        u2g = models.ManyToManyField(UserGroup)
    

      这样的话,执行上面的obj.save()会在UserInfo表和多对多关系表里都增加数据。

    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)
            if obj.is_valid():
                obj.save()  # 等价以下三句,默认commit=True
                # instance = obj.save(commit=False)
                # instance.save()
                # obj.save_m2m()
            return render(request,'index.html',{'obj': obj})
    

      

    save()函数做了如下操作:

    def save(self, commit=True):
        """"""
        if commit:
            self.instance.save()    # 指的当前model对象
            self._save_m2m()        # 指:保存m2m对象
        else:
            self.save_m2m = self._save_m2m
        return self.instance    # model 类的对象
        """"""
    

      

    所以instance = obj.save(False)时,什么都不会操作。

    if obj.is_valid():
        instance = obj.save(commit=False)
        instance.save()     # 当前对象表数据创建
        obj.save_m2m()      # 多对多表数据创建
        # 上面这三句完成的是和上面 obj.save 一样的操作。拆开就可以自定制操作了
    

      

     

    2、修改数据

    修改表数据是,记得把instance信息也传进去,不然是新建数据,而不是对某行数据进行修改。

    views.py

    def user_list(request):
        li = models.UserInfo.objects.all().select_related('user_type')  # 这里只能是外键,多对多字段也不可以
        return render(request,'user_list.html',{'li': li})
    
    def user_edit(request, nid):
        # 获取当前id对象的用户信息
        # 显示用户已经存在数据
        if request.method == "GET":
            user_obj = models.UserInfo.objects.filter(id=nid).first()
            mf = UserInfoModelForm(instance=user_obj)   # 把默认数据传递进去,回显数据
            return render(request,'user_edit.html',{'mf': mf, 'nid': nid})
        elif request.method == 'POST':
            # 数据修改的信息,给数据库的哪一行做修改?
            user_obj = models.UserInfo.objects.filter(id=nid).first()
            mf = UserInfoModelForm(request.POST,instance=user_obj)  # 指定修改哪条记录
            if mf.is_valid():
                mf.save()
            else:
                print(mf.errors.as_json())
            return render(request,'user_edit.html',{'mf': mf, 'nid': nid})
    

     

    user_list.html

    <body>
        <ul>
            {% for row in li %}
                <li>{{ row.username }} - {{ row.user_type.caption }} - <a href="/edit-{{ row.id }}/">编辑</a></li>
            {% endfor %}
        </ul>
    </body>
    

      

    user_edit.html

    <body>
        <form method="POST" action="/edit-{{ nid }}/">
            {% csrf_token %}
        {{ mf.as_p }}
            <input type="submit" value="提交" />
        </form>
    </body>
    

      

    五、继承关系

    1、继承

    UserModelForm==>ModelForm==>BaseModelForm==>BaseForm
                 UserInfoForm==>Form==>BaseForm

    2、方法

    1、ModelForm方法
    class ModelForm(six.with_metaclass(ModelFormMetaclass, BaseModelForm)):
    pass
     
    2、BaseModelForm方法

     


    3、BaseForm方法

     

     

    六、总结

    ModelForm适用于较小的工程中,耦合度较高,而当工程一旦变得很大时,Model和Form就需要分开,耦合度就会变低,更加灵活定制。

  • 相关阅读:
    BZOJ 1449: [JSOI2009]球队收益 最小费用最大流 网络流
    HDU 4348 To the moon 主席树 在线更新
    省选模拟赛20180416
    线性基总结
    Write-up-Bulldog2
    [Write-up]BSides-Vancouver
    Write-up-Bob_v1.0.1
    Genymotion设置代理至BurpSuite和Charles
    PE之RVA转FOA
    django的序列化
  • 原文地址:https://www.cnblogs.com/skyflask/p/9807030.html
Copyright © 2011-2022 走看看