Django 之 ModelForm注意点:

作用:

ModelForm,即可用于数据库操作(部分),也可用于用户请求的验证(部分)!

Models.py

class PrettyNum(models.Model):
    """ 靓号表 """
    mobile = models.CharField(max_length=11, verbose_name='手机号')
    # 允许为空 null=True, blank=True
    price = models.IntegerField(verbose_name='价格', default=0, null=True, blank=True)
    level_choices = (
        (1, '一级'),
        (2, '二级'),
        (3, '三级'),
        (4, '四级'),
    )
    level = models.SmallIntegerField(choices=level_choices, default=1,
                                     verbose_name='级别')
    status_choices = (
        (1, '末占用'),
        (2, '已占用')
    )
    status = models.SmallIntegerField(choices=status_choices, default=1,
                                      verbose_name='状态')

定义 ModelForm 类

views.py

""" 定义ModelForm类 """

# 导入forms
from django import forms

# 从验证器导入正则表达式验证器
from django.core.validators import RegexValidator
# 钩子方法
from django.core.validators import ValidationError
# 正则
import re


class PrettyNumModelForm(forms.ModelForm):
    """ 验证方法一:"""
    # 需要重新定义校验的字段,
    # mobile = forms.CharField(
    #     # 重写 label
    #     label='手机号',
    #     # 正则表达式匹配
    #     # 验证手机号: 第一位以1做开头,第二位取[3-9],接9个数字 (正则表达式, 提示信息)
    #     validators=[RegexValidator(r'^1[3-9]\d{9}$', '号码格式错误')],
    # )0
    price = forms.IntegerField(
        label='建议价格',
        # forms.HiddenInput()  隐藏输入框
        # widget=forms.HiddenInput(),
    )

    class Meta:
        # 定义对哪张表,哪些字段
        # 定义 元类 class meta, 获取 models.PrettyNum 类(表)的字段
        model = models.PrettyNum
        # 需要的字段
        fields = '__all__'  # 全部字段
        # fields = ['mobile', 'price', 'level', 'status']  #选择部分字段
        # exclude = ['level']     # 排除某个字段

    # 该方法是通过修改内部代码,对样式进行修改,样式的值可根据需求随意修改
    # 重新定义 init 方法
    def __init__(self, *args, **kwargs):
        # 重新定义 它 父类的 init 方法
        super().__init__(*args, **kwargs)
        # 循环ModelForm中的所有字段,给每个字段增加插件设置
        for name, field in self.fields.items():
            print(name, field)
            # 判断,给某个字段不加插件
            # if name == 'password':
            #     continue
            # 字段的插件
            field.widget.attrs = {
                "class": "form-control",
                # "placeholder": field.label,
            }

    """ 验证方法二:钩子方法 """
    def clean_mobile(self):
        # 用户传入的数据mobile
        txt_mobile = self.cleaned_data['mobile']
        print('用户传入的数据mobile:', txt_mobile)
        # 多条件判断
        # 条件一:判断是否存在,返回True、False
        flag = models.PrettyNum.objects.filter(mobile=txt_mobile).exists()
        if flag:  # 如果是True 验证不通过,抛出错误信息
            raise ValidationError('号码已经存在')

        # 条件二:判断格式  利用正则
        pattern = r'^1[3-9]\d{9}$'
        # 正则匹配,返回 返回True、False
        match = re.match(pattern, txt_mobile)
        print('match:', match)
        if not match:   # 布尔值取反, not True = False, 将成功执行转变成失败执行
            raise ValidationError('格式错误')
        return txt_mobile




def num_add(request):
    """ 增加靓号 """
    if request.method == 'GET':
        print("请求方式是:", request.method)
        # form实例化, 自动生成html表单
        form = PrettyNumModelForm()
        print(form)
        context = {
            'form': form
        }
        return render(request, 'num_add.html', context=context)
    else:
        print("请求方式是:", request.method)

        # form对象实例化,得到提交的所有字段,
        # data=request.POST 当参数传入, 包含每个字段的值
        form = PrettyNumModelForm(data=request.POST)
        # is_valid() 验证数据
        if form.is_valid():
            # cleaned_data 验证通过的数据
            print(form.cleaned_data)
            # 保存 类似 models.PrettyNum.objects.create(xxx=xxx)
            form.save()
            return redirect('/prettynum/list/')
        else:
            # 没有通过验证的数据
            print(form.errors)

            context = {
                'form': form
            }
            # 再传回到html, 遍历后,还包含了 errors 信息
            return render(request, 'num_add.html',
                          context=context)

num_add.html

{% extends 'layout.html' %}

{% block content %}

    <div class="container">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title">新增靓号</h3>
            </div>
            <div class="panel-body">
                {#  同行显示  <form class="form-inline">#}
                {#    novalidate  关掉浏览器校验#}
                <form method="post" novalidate >
                    {% csrf_token %}
                    {#    form 是 views传过来的对象,也是ModelForm自动生成的html内容#}
                    {% for field in form %}

                        <div class="form-group">
                            {#        field  是循环后得到的每一个字段的 input框#}
                            {#        filed.label 就是 字段的 verbose_name#}
                            <label>{{ field.label }}:</label>
                            {#    <input type="text" ....................>#}
                            {{ field }}
                            {#    错误信息#}
                        <span style="color: red">{{ field.errors }}</span>
                        </div>

                    {% endfor %}

                    <button type="reset" class="btn btn-primary btn-sm">
                        <span class="glyphicon glyphicon-remove-circle" aria-hidden="true"></span>
                        Reset
                    </button>
                    <button type="submit" class="btn btn-primary btn-sm">
                        <span class="glyphicon glyphicon-ok-circle" aria-hidden="true"></span>
                        Submit
                    </button>

                </form>
            </div>
        </div>
    </div>

{% endblock %}

修改号码:

新建修改靓号的 ModelForm

钩子方法验证数据

# 修改靓号的 ModelForm
class PrettyNumEditModelForm(forms.ModelForm):
    # 重新定义字段
    # mobile 只显示,不让修改  disabled=True
    # mobile = forms.CharField(disabled=True, label='手机号')

    class Meta:
        model = models.PrettyNum
        # 定义需要显示和修改的字段
        fields = ['mobile', 'price', 'level', 'status']
        # widgets = {
        #     'mobile': forms.TextInput(attrs={'class': 'form-control'}),
        #     'price': forms.TextInput(attrs={'class': 'form-control'}),
        #     'level': forms.Select(attrs={'class': 'form-control'}),
        #     'status': forms.Select(attrs={'class': 'form-control'})
        #
        # }

        # 该方法是通过修改内部代码,对样式进行修改,样式的值可根据需求随意修改
        # 重新定义 init 方法
        def __init__(self, *args, **kwargs):
            # 重新定义 它 父类的 init 方法
            super().__init__(*args, **kwargs)
            # 循环ModelForm中的所有字段,给每个字段增加插件设置
            for name, field in self.fields.items():
                print(name, field)
                # 判断,给某个字段不加插件
                # if name == 'password':
                #     continue
                # 字段的插件
                field.widget.attrs = {
                    "class": "form-control",
                    # "placeholder": field.label,
                }



    # 定义钩子方法,
    def clean_mobile(self):
        # 条件一:除了当前id后,号码不能重复
        # pk 拿到主键当前id:  self.instance.pk
        primary = self.instance.pk
        print("主键id:", primary)

        # 用户传入的数据mobile
        txt_mobile = self.cleaned_data['mobile']
        # exclude 排除了当前id后,号码不能重复
        flag = models.PrettyNum.objects.exclude(id=primary).filter(mobile=txt_mobile).exists()
        if flag:  # 如果是True 验证不通过,抛出错误信息
            raise ValidationError('号码已经存在')

        # 条件二:判断格式  利用正则
        pattern = r'^1[3-9]\d{9}$'
        # 正则匹配,返回 返回True、False
        match = re.match(pattern, txt_mobile)
        print('match:', match)
        if not match:  # 布尔值取反, not True = False, 将成功执行转变成失败执行
            raise ValidationError('格式错误')
        return txt_mobile

修改号码的函数

def num_edit(request, nid):     # 从urls里传入nid
    """ 编辑靓号 """
    if request.method == 'GET':
        print("请求方式是:", request.method)
        # 根据 id 拿到现有数据
        row_data = models.PrettyNum.objects.get(id=nid)
        print(row_data, type(row_data))
        # form实例化, 自动生成html表单,
        # instance=row_data 将现有结果带入参数传入
        form = PrettyNumEditModelForm(instance=row_data)
        context = {
            'form': form
        }

        return render(request, 'num_edit.html',
                      context=context)
    # post 请求提交数据
    else:
        print("请求方式是:", request.method)
        # 得到提交的数据
        row_data = models.PrettyNum.objects.get(id=nid)
        # form对象实例化,得到提交的所有字段,
        # data=request.POST 当参数传入, 包含每个字段的值
        # instance=row_data 将现有结果带入参数传入,如果不传入就是新增
        form = PrettyNumEditModelForm(data=request.POST, instance=row_data)
        # 进行数据校验
        if form.is_valid():
            print(form.cleaned_data)
            form.save()
            return redirect('/prettynum/list/')
        else:
            print(form.errors)
            context = {
                'form': form
            }
            return render(request, 'num_edit.html',
                          context=context)

num_edit.html

{% extends 'layout.html' %}

{% block content %}

    <div class="container">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title">编辑靓号</h3>
            </div>
            <div class="panel-body">
                {#  同行显示  <form class="form-inline">#}
                {#    novalidate  关掉浏览器校验#}
                <form method="post" novalidate >
                    {% csrf_token %}
                    {#    form 是 views传过来的对象,也是ModelForm自动生成的html内容#}
                    {% for field in form %}

                        <div class="form-group">
                            {#        field  是循环后得到的每一个字段的 input框#}
                            {#        filed.label 就是 字段的 verbose_name#}
                            <label>{{ field.label }}:</label>
                            {#    <input type="text" ....................>#}
                            {{ field }}
                            {#    错误信息#}
                        <span style="color: red">{{ field.errors }}</span>
                        </div>

                    {% endfor %}

                    <button type="reset" class="btn btn-primary btn-sm">
                        <span class="glyphicon glyphicon-remove-circle" aria-hidden="true"></span>
                        Reset
                    </button>
                    <button type="submit" class="btn btn-primary btn-sm">
                        <span class="glyphicon glyphicon-ok-circle" aria-hidden="true"></span>
                        Submit
                    </button>

                </form>
            </div>
        </div>
    </div>

{% endblock %}

搜索靓号:

扩展语法:

# 多条件
models.PrettyNum.objects.filter(mobile=1999999999, id=123)

# 也支持字典  增加 两个** 支持字典 空字典是获取所有
data_dict = {'mobile': '1999999999', 'id' = 123}
models.PrettyNum.objects.filter(**data)

models.PrettyNum.objects.filter(id=12)       # 等于12
models.PrettyNum.objects.filter(id__gt=12)   # 大于12
models.PrettyNum.objects.filter(id__gte=12)  # 大于等于12
models.PrettyNum.objects.filter(id__lt=12)   # 小于12
models.PrettyNum.objects.filter(id__lte=12)  # 小于等于12
data_dict = {"id__lte":12}
models.PrettyNum.objects.filter(**data_dict)

models.PrettyNum.objects.filter(mobile="999")               # 等于
models.PrettyNum.objects.filter(mobile__startswith="1999")  # 筛选出以1999开头
models.PrettyNum.objects.filter(mobile__endswith="999")     # 筛选出以999结尾
models.PrettyNum.objects.filter(mobile__contains="999")     # 筛选出包含999
data_dict = {"mobile__contains":"999"}
models.PrettyNum.objects.filter(**data_dict)

搜索

views.py

# views.py

def num_list(request):

    """ 搜索 """
    # q1 = models.PrettyNum.objects.filter(mobile=18981889158, id=5)
    # print(q1)   # <QuerySet [<PrettyNum: PrettyNum object (5)>]>
    #
    #
    # # 支持字典 空字典是获取所有
    # data_dict = {'mobile': '18180955800', 'id': 10}
    # q2 = models.PrettyNum.objects.filter(**data_dict)
    # print(q2)   # <QuerySet [<PrettyNum: PrettyNum object (5)>]>

    """号码列表"""
    if request.method == 'GET':
        print('访问方式是 GET ')

        """ 搜索 """
        # 先定义一个空字典
        data_dict = {}
        # 通过浏览器url传值
        # q有值,就拿q; 没值,就拿空字符串
        search_data = request.GET.get('q', "")
        if search_data:  # 不为空时,为字典增加key和value
            data_dict['mobile__contains'] = search_data
        # 如果value是空,空字典就是获取所有
        res = models.PrettyNum.objects.filter(**data_dict)
        print("搜索结果:", res)
        # order_by(排序字段) , 默认是升序,  - 减号表示降序
        # 搜索 filter(**data_dict),空字典就是获取所有
        queryset = models.PrettyNum.objects.filter(**data_dict).order_by('-id')
        print(queryset)
        for obj in queryset:
            print(obj.id, obj.mobile, obj.price,
                  # level 和 status 有 choices 选择字段, 显示选择字段
                  obj.get_level_display(), obj.get_status_display())
        context = {
            'queryset': queryset,
            'count': queryset.count(),
            # 搜索的字符串再传回html 显示
            'search_data': search_data,

        }
        return render(request, 'num_list.html',
                      context=context)

num_list.html

{% extends 'layout.html' %}

{% block content %}

    <div class="container">
        <div style="margin-bottom: 5px" class="clearfix">
            <a href="/prettynum/add/" class="btn btn-success">
                <span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
                添加靓号
            </a>

            <div style="float: right; width: 300px">
                {#    get方式传递出现在地址栏#}
                <form method="get">
                    <div class="input-group">
                    {#    value="{{ search_data }} 将输入的搜索值显示出来#}
                        <input type="text" name="q" class="form-control" placeholder="Search for..." value="{{ search_data }}">
                        <span class="input-group-btn">
                        <button class="btn btn-default" type="submit">
                            <span class="glyphicon glyphicon-search" aria-hidden="true">Search</span>
                        </button>
                        </span>
                    </div>
                </form>

            </div>

        </div>


        <div class="panel panel-default">
            <!-- Default panel contents -->
            <div class="panel-heading">
                <span class="glyphicon glyphicon-list" aria-hidden="true"></span>
                靓号列表
            </div>

            <!-- Table -->
            <table class="table table-hover">
                <thead>
                <tr>
                    <th>ID</th>
                    <th>号 码</th>
                    <th>价 格</th>
                    <th>级 别</th>
                    <th>状 态</th>
                    <th>操 作</th>
                </tr>
                </thead>
                <tbody>
                {% for obj in queryset %}
                    <tr>
                        <th>{{ obj.id }}</th>
                        <td>{{ obj.mobile }}</td>
                        <td>{{ obj.price }}</td>
                        {#    level 和 status 有 choices 选择字段, 显示选择字段#}
                        <td>{{ obj.get_level_display }}</td>
                        <td>{{ obj.get_status_display }}</td>
                        <td>
                            <a href="/prettynum/{{ obj.id }}/edit/" class="btn btn-primary btn-xs">
                                <span class="glyphicon glyphicon-edit" aria-hidden="true"></span>
                                Edit
                            </a>
                            <a href="/prettynum/{{ obj.id }}/delete/" class="btn btn-danger btn-xs">
                                <span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
                                Delete
                            </a>
                        </td>
                    </tr>
                {% endfor %}
                </tbody>
            </table>

        </div>
        <div><span style="float: right">合计:{{ count }}</span></div>
    </div>

{% endblock %}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值