zoukankan      html  css  js  c++  java
  • Django11-ModelForm

    一、定义ModelForm类

    # 创建部门表单校验

    class DepartmentForm(forms.ModelForm): 
        class Meta:
            model = models.Department    #关联到Models中的表名Department
            fields = '__all__'      #获取Department表中的所有对象,也可以写成列表['depName','depDes'],指定要获取的对象,而且是有顺序的
            labels = {
                'depName': '部门名称',
                'depDes': '职责描述',
            }
            widgets = {         #设置插件,type类型和类名等属性 
                'depName': forms.TextInput(attrs={'class': 'form-control','placeholder':'请输入部门名称'}),
                'depDes': forms.TextInput(attrs={'class': 'form-control','placeholder':'请输入部门职责描述'}),
            }

    class Meta:下常用参数:

    model = models.Department    # 对应的Model中的类
    fields = "__all__"            # 字段,如果是__all__,就是表示列出所有的字段,也可以写成列表['title','price'],指定要获取的对象
    exclude = None             # 排除的字段
    labels = None                # 提示信息
    help_texts = None              # 帮助提示信息
    widgets = None             # 自定义插件,form组件里是widget,ModelForm组件里是widgets
    error_messages = None         # 自定义错误信息

    其中label属性可以不在ModelForm这里面写,也可以在models.py中的Depart表中各个对象定义verbose_name属性值,用于非ForeignKey对象,
    推荐这种写法,在Admin系统中也可以显示这里定义的verbose_name值

    class Depart(models.Model):
        depName = models.TextField(max_length=32, verbose_name='部门名称')
        depDes = models.TextField(max_length=64, black=True, null=True, verbose_name='职责描述')

    二、批量添加样式

    可通过重写ModelForm类的init方法来实现。

    # 创建部门表单校验

    class DepartmentForm(forms.ModelForm):
        depName = forms.TextField(validators=[],)   #如果depName字段存在,就代表重写这个字段
        count = forms.TextField(validators=[],)     #如果count字段不存在,就代表新增这个字段,models文件中不存在这个字段
        class Meta:
            model = models.Department   #model和fields都是固定写法,不能写
            fields = '__all__'
            labels = {
                'depName': '部门名称',
                'depDes': '职责描述',
            }
            widgets = {
                'depName': forms.TextInput(attrs={'placeholder':'请输入部门名称'}),
                'depDes': forms.TextInput(attrs={'placeholder':'请输入部门职责描述'}),
                 'purchase_date': forms.widgets.DateInput(attrs={'type': 'date'}),
                     'expiration_date': forms.widgets.DateInput(attrs={'type': 'date'}),
    
            }
            error_messages = {      #这里的error_messages只能写默认存在的校验字段
                'depName':{
                    'required':'不能为空'
                }
            }
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            for field in self.fields.values():
                field.widget.attrs.update({'class': 'form-control'})
    
    
    class DepartAdd(View):
        def get(self, request):
            form_obj = DepartmentForm()
            return render(request, 'departadd.html', {'form_obj': form_obj})
        
        def post(self, request):
            form_obj = DepartmentForm(request.POST)
            print(form_obj)
            if form_obj.is_valid():
                # models.Department.objects.create(**form_obj.cleaned_data)
                form_obj.save()        #直接save()方法就可以保存     
                return redirect(reverse('departList'))

    三、部门添加、修改例子(FVB版)

    部门添加

    def depart_add(request):
        form_obj = departForm.DepartForm()
        if request.method == 'POST':
            form_obj = departForm.DepartForm(request.POST)
            if form_obj.is_valid():
                form_obj.save()
                return redirect(reverse('depart_list'))
        return render(request, 'depart/depart_add.html', {'form_obj': form_obj})

    部门修改

    def depart_edit(request, pk):
        form_edit = models.Depart.objects.filter(pk=pk).first()
        form_obj = departForm.DepartForm(instance=form_edit)
        if request.method == 'POST':
            form_obj = departForm.DepartForm(request.POST, instance=form_edit)   #这里要将当前对象作为一个实例传给ModelForm  
            # 如果没有修改,则不需要校验
            depart_name_new = request.POST.get('depart_name', None)
            if form_edit.depart_name == depart_name_new:
                # 部门描述不需要校验,直接更新保存
                form_edit.depart_desc = request.POST.get('depart_desc', None)
                form_edit.save()
                return redirect(reverse('depart_list'))
            # 如果修改了值,就调用DepartForm校验,注意用instance表示将当前对象传给Modelform校验,模板中字段仍然可以自动生成
            elif form_obj.is_valid():
                form_obj.save()
                return redirect(reverse('depart_list'))
        return render(request, 'depart/depart_edit.html', {'form_edit': form_edit, 'form_obj': form_obj})

    前端页面

    展示页面depart_list.html

    <table class="form-horizontal table table-bordered" style="margin-top: 10px">
        <thead>
        <tr>
            <th>ID</th>
            <th>用户名称</th>
            <th>密码</th>
            <th>所属部门</th>
            <th>操作</th>
        </tr>
        </thead>
        <tbody>
        {% for user in user_all %}
            <tr>
            <td>{{ forloop.counter }}</td>
            <td>{{ user.username }}</td>
            <td>{{ user.pwd }}</td>
    {#        <td>{{ user.depart.depart_name}}</td>#}  #这里可以通过depart外键.depart_name来获取部门名称进行前端页面显示
             <td>{{ user.depart }}</td>                         #也可以通过在models.py中给Depart类写__str__方法,这里就不需要用点方法了
            <td>
                <a href="{% url 'user_edit' user.pk %}"><i class="fa fa-edit fa-2x"></i></a>&nbsp;&nbsp;&nbsp;&nbsp;
                <a class="del" del_obj="user" del_id="{{ user.pk }}"><i class="fa fa-trash-o fa-2x" style="cursor: pointer;"></i></a>
            </td>
            </tr>
        {% endfor %}
        </tbody>
    </table>

    修改页面depart_edit.html

    <form action="" method="post" class="form-horizontal">
        {% csrf_token %}
        <div class="form-group {% if form_obj.depName.errors %}has-error{% endif %}">
            <label for="{{ form_obj.depName.id_for_label }}" class="col-lg-2 control-label">{{ form_obj.depName.label }}</label>
            <div class="col-lg-6">
                {{ form_obj.depName}}
            </div>
            <span class="help-block">{{ form_obj.errors.0 }}</span>
        </div>
    
    bootstrape样式中使用has-error和help-block类渲染错误提示效果

    models.py

    from django.db import models
    
    # Create your models here.
    class Depart(models.Model):
        depart_name = models.CharField(max_length=32, verbose_name='部门名称')
        depart_desc = models.CharField(max_length=64, verbose_name='部门描述')
        
            #通过写__str__方法,前端直接调用depart对象时就可以直接获取到depart_name的值了
        def __str__(self):
            return self.depart_name
    
    class User(models.Model):
        username = models.CharField(max_length=32, verbose_name='用户名')
        pwd = models.CharField(max_length=32, verbose_name='密码')
        depart = models.ForeignKey(to='Depart', verbose_name='所属部门')

    四、代码合并

    1、depart_all.html模板代码合并

    未合并写法,写了多个form-group,重复

    <form action="" method="post" class="form-horizontal" novalidate>
        {% csrf_token %}
        <div class="form-group {% if form_obj.depart_name.errors %}has-error{% endif %}">
            <label for="{{ form_obj.depart_name.id_for_label }}" class="col-lg-2 control-label">
                {{ form_obj.depart_name.label }}
            </label>
            <div class="col-lg-6">
                {{ form_obj.depart_name }}
                <span class="help-block">{{ form_obj.depart_name.errors.0 }}</span>
            </div>
        </div>
    
        <div class="form-group {% if form_obj.depart_desc.errors %}has-error{% endif %}">
            <label for="{{ form_obj.depart_desc.id_for_label}}" class="col-lg-2 control-label ">
                {{ form_obj.depart_desc.label }}
            </label>
            <div class="col-lg-6">
                {{ form_obj.depart_desc }}
                <span class="help-block">{{ form_obj.depart_desc.errors.0 }}</span>
            </div>
        </div>
    
        <div class="form-group">
            <div class="col-lg-10 col-lg-offset-2">
                <button class="btn btn-primary">提交</button>
            </div>
        </div>
    </form>
    View Code

    合并写法

    <form action="" method="post" class="form-horizontal" novalidate>
        {% csrf_token %}
    
        {#需要渲染多个form-group, 可以使用for循环避免重新编写,将form_obj.depart_name和form_obj.depart_desc改成field即可#}
        {% for field in form_obj %}
        <div class="form-group {% if field.errors %}has-error{% endif %}">
            <label for="{{ field.id_for_label }}" class="col-lg-2 control-label">
                {{ field.label }}
            </label>
            <div class="col-lg-6">
                {{ field }}
                <span class="help-block">{{ field.errors.0 }}</span>
            </div>
        </div>
        {% endfor %}
    
        <div class="form-group">
            <div class="col-lg-10 col-lg-offset-2">
                <button class="btn btn-primary">提交</button>
            </div>
        </div>
    </form>
    View Code

    2、views.py视图代码合并

    未合并写法

    urls.py
    url(r'^user/add/$', user.user_add, name='user_add'),
    url(r'^user/edit/(d+)/$', user.user_edit, name='user_edit'),
    
    views.py
    #用户添加函数
    def user_add(request):
        form_obj = userForm.UserForm()
        if request.method == 'POST':
            form_obj = userForm.UserForm(request.POST)
            if form_obj.is_valid():
                form_obj.save()
                return redirect(reverse('user_list'))
        return render(request, 'user/user_add.html', {'form_obj': form_obj})
    
    #用户编辑函数
    def user_edit(request, pk):
        obj = models.User.objects.filter(pk=pk).first()
        form_obj = userForm.UserForm(instance=obj)
        if request.method == 'POST':
            form_obj = userForm.UserForm(request.POST, instance=obj)
            # 如果未修改原值,则不校验
            if request.POST.get('username', None) == obj.username:
                obj.pwd = request.POST.get('pwd', None)
                obj.gender = request.POST.get('gender', None)
                # depart不能直接保存为request.POST.get('depart',None),因为depart是一个外键,需要保存Depart的一个实例
                obj.depart = models.Depart.objects.filter(pk=request.POST.get('depart', None)).first()
                obj.save()
                # 这里先创建用户的时候校验密码不能为空,但是修改用户时没有校验密码是否为空
                return redirect(reverse('user_list'))
            # 修改了原值,则进行校验
            elif form_obj.is_valid():
                form_obj.save()
                return redirect(reverse('user_list'))
        return render(request, 'user/user_edit.html', {'form_obj': form_obj})
    View Code

    将用户添加函数和用户编辑函数合并编写

    将urls中函数方法统一写成user_change,在views中只需要写一个user_change函数包含用户添加和编辑功能。
    
    urls.py
    url(r'^user/add/$', user.user_change, name='user_add'),
    url(r'^user/edit/(d+)/$', user.user_change, name='user_edit'),
    
    views.py
    由于用户添加和编辑函数逻辑相似,可以合并编写
    区别就是编辑函数需要传入pk值,而添加函数不需要传入pk值,所以设置pk=None默认为空
    其他代码基本相同
    
    def user_change(request, pk=None):
            #如果是添加方法,则obj为空
        obj = models.User.objects.filter(pk=pk).first()
        form_obj = userForm.UserForm(instance=obj)
        if request.method == 'POST':
            form_obj = userForm.UserForm(request.POST, instance=obj)
            if obj:
                # 如果未修改username原值,则不校验
                if request.POST.get('username', None) == obj.username:
                    obj.pwd = Md5(request.POST.get('pwd', None)).md5
                    obj.gender = request.POST.get('gender', None)
                    # depart不能直接保存为request.POST.get('depart',None),因为depart是一个外键,需要保存Depart的一个实例
                    obj.depart = models.Depart.objects.filter(pk=request.POST.get('depart', None)).first()
                    obj.save()
                    # 这里先创建用户的时候校验密码不能为空,但是修改用户时没有校验密码是否为空
                    return redirect(reverse('user_list'))
            # 修改了原值,则进行校验
            elif form_obj.is_valid():
                form_obj.save()
                return redirect(reverse('user_list'))
        return render(request, 'user/user_edit.html', {'form_obj': form_obj})
    View Code
  • 相关阅读:
    tudou(土豆)、youku(优酷)API(有相应的dll [C#])
    创新工场2012笔试编程捕鱼和分鱼
    区别Web文本框和HTML文本框的RandOnly、Disabled
    DataRow[]、List<DataRow>无法绑定到GridView的问题解决!
    1、NHibernate入门
    Verilog HDL 学习笔记2blocking and nonblocking assignment
    Verilog HDL 学习笔记1data type
    2006.08.21网摘
    推荐十一个很酷的实用网站
    类 ObjectOutputStream的writeObject()方法的中英文对照
  • 原文地址:https://www.cnblogs.com/dxnui119/p/10757572.html
Copyright © 2011-2022 走看看