当前位置: 首页 > news >正文

【Django】教程-5-ModelForm增删改查+规则校验【正则+钩子函数】

【Django】教程-1-安装+创建项目+目录结构介绍
【Django】教程-2-前端-目录结构介绍
【Django】教程-3-数据库相关介绍
【Django】教程-4-一个增删改查的Demo

11. ModelForm

  • 11.1 models.py

from django.utils import timezone
from django.db import models

# 数据库,表对应关系
class Department(models.Model):
    """部门表"""
    title = models.CharField(verbose_name="部门名称", max_length=32)
    create_time = models.DateTimeField(verbose_name="创建时间", default=timezone.now)
    # 数据状态
    status_choices = (
        (1, "已删除"),
        (0, "可用"),
    )
    status = models.SmallIntegerField(verbose_name="状态", choices=status_choices, default=0)

    # 重写toString方法
    def __str__(self):
        return self.title


class UserInfo(models.Model):
    '''用户表'''

    name = models.CharField(verbose_name="姓名", max_length=32)
    password = models.CharField(verbose_name="密码", max_length=64)
    age = models.IntegerField(verbose_name="年龄")
    create_time = models.DateTimeField(verbose_name="创建时间", default=timezone.now)
    depart = models.ForeignKey(verbose_name="部门", to="Department", to_field="id", null=True, blank=True,
                               on_delete=models.SET_NULL)

    # 在django中做的约束
    gender_choices = (
        (1, "男"),
        (2, "女"),
    )
    gender = models.SmallIntegerField(verbose_name="性别", choices=gender_choices, default=1)
    # 数据状态
    status_choices = (
        (1, "已删除"),
        (0, "可用"),
    )
    status = models.SmallIntegerField(verbose_name="数据状态", choices=status_choices, default=0)

  • 11.1 forms.py

from django import forms
from .models import Department, UserInfo


class DepartmentForm(forms.ModelForm):
    class Meta:
        model = Department
        fields = "__all__"


class UserModelForm(forms.ModelForm):
    name = forms.CharField(min_length=8, label="用户名")
    class Meta:
        model = UserInfo
        # fields = ['name', 'password', 'age', 'gender']
        fields = "__all__"
        # 排除哪个字段
        # exclude = ['status']
        
	# 样式重写 
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        for name, field in self.fields.items():
            if name == "status":
                continue
            field.widget.attrs = {"class": "form-control", "placeholder": field.label}

  • 11.1 urls.py

from django.urls import path
from appTang import views

# 映射关系,视图--->函数
urlpatterns = [
    path('user/modelform/add', views.user_modelform_add),
    path('user/modelform/edit/<int:nid>/', views.user_modelform_edit),

]
  • 11.1 user_model_add.html

{% extends 'layout.html' %}

{% block title %}
    添加用户
{% endblock %}

{% block content %}
    <div>
        <div class="container">
            <div class="panel panel-default">
                <div class="panel-heading">
                    <h3 class="panel-title">
                        <span class="glyphicon glyphicon-tag" aria-hidden="true">
                            添加用户</span>
                    </h3>
                </div>

                <div class="panel panel-body">
{#                novalidate, 关掉浏览器的校验#}
                    <form method="post" novalidate>

                        {% csrf_token %}

                        {% for u in user %}
                            <div class="form-group">
                                <label>{{ u.label }}:</label>
                                {{ u }}
                                <span style="color: red">{{ u.errors.0 }}</span>
                            </div>
                        {% endfor %}


                        <button type="submit" class="btn btn-primary">保存</button>
                    </form>
                </div>
            </div>
        </div>
    </div>

{% endblock %}
  • 11.1 user_model_edit.html

{% extends 'layout.html' %}
{% block title %}
    编辑用户
{% endblock %}

{% block content %}
    <div class="container">
            <div class="panel panel-default">
                <div class="panel-heading">
                    <h3 class="panel-title">
                        <span class="glyphicon glyphicon-tag" aria-hidden="true">
                            编辑用户</span>
                    </h3>
                </div>

                <div class="panel panel-body">
                    <form method="post" novalidate>
                        {% csrf_token %}
                        {% for u in user %}
                            <div class="form-group">
                                <label>{{ u.label }}:</label>
                                {{ u }}
                                <span style="color: red">{{ u.errors.0 }}</span>
                            </div>
                        {% endfor %}


                        <button type="submit" class="btn btn-primary">保存</button>
                    </form>
                </div>
            </div>
        </div>
{% endblock %}
  • 11.1 views.py

from django.shortcuts import render, HttpResponse, redirect

from appTang import models
from appTang.forms import DepartmentForm, UserModelForm
from appTang.models import UserInfo, Department


# 用户列表
def user_list(req):
    """用户展示"""
    # select * from userinfo order by name asc; -name 倒序
    user_list = UserInfo.objects.all().order_by("-name")
    return render(req, 'user/user_list.html', {"user_list": user_list})

def user_modelform_add(req):
    """ modelform 方式添加用户"""
    if req.method == 'GET':
        user = UserModelForm()
        return render(req, 'user/user_model_add.html', {"user": user})
    # 用户post提交,数据校验
    user = UserModelForm(data=req.POST)
    if user.is_valid():
        print(user.changed_data)
        user.save()
        return redirect("/user/list")
    # 校验失败, 在页面上展示错误信息
    return render(req, 'user/user_model_add.html', {"user": user})


def user_modelform_edit(req, nid):
    """ 用户编辑"""
    if req.method == 'GET':
        # 根据id获取要编辑,那行数据
        row_obj = models.UserInfo.objects.filter(id=nid).first()
        user = UserModelForm(instance=row_obj)
        return render(req, "user/user_model_edit.html", {"user": user})
    # 表单提交, 需要先查询到,然后实例化进去
    row_obj = models.UserInfo.objects.filter(id=nid).first()
    user = UserModelForm(data=req.POST, instance=row_obj)
    # 数据校验通过
    if user.is_valid():
        # 默认用户保存,用户输入的所有数据
        # 给数据增加其他的, 需要保存的值, user.instance.字段名 = 值
        user.save()
        return redirect("/user/list")
    # 否则
    return render(req, "user/user_model_edit.html", {"user": user})
  • 11.1 user_list.html

{% extends 'layout.html' %}

{% block content %}

    <div>
        <div class="container">
            <div style="margin-bottom: 10px">
                <a class="btn btn-success" href="/user/modelform/add">
                    <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
                    ModelForm新建用户</a>
            </div>
            <div class="panel panel-default">
                <div class="panel-heading"><span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>用户列表
                </div>

                <table class="table table-bordered">
                    <thead>
                    <tr>
                        <th>#</th>
                        <th>姓名</th>
                        <th>密码</th>
                        <th>年龄</th>
                        <th>部门</th>
                        <th>创建时间</th>
                        <th>性别</th>
                        <th>状态</th>
                        <th>操作</th>
                    </tr>
                    </thead>
                    <tbody>
                    {% for i in user_list %}
                        <tr>
                            <td>{{ i.id }}</td>
                            <td>{{ i.name }}</td>
                            <td>{{ i.password }}</td>
                            <td>{{ i.age }}</td>
                            <td>
                                {% if i.depart %}
                                    {{ i.depart.title }}
                                {% endif %}

                            </td>
                            <td>{{ i.create_time|date:"Y-m-d H:i:s" }}</td>
                            <td>{{ i.get_gender_display }}</td>
                            <td>{{ i.get_status_display }}</td>
                            <td>
                                <a class="btn btn-primary btn-xs" href="/user/modelform/edit/{{ i.id }}">MF编辑</a>
                                <a class="btn btn-danger  btn-xs" href="/user/del?nid={{ i.id }}">删除</a>
                            </td>
                        </tr>
                    {% endfor %}
                    </tbody>
                </table>
            </div>

        </div>


    </div>


{% endblock %}
  • 11.1 layout.html

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}{% endblock %}</title>
    <link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.css' %}"/>
    <style>
        .navbar {
            border-radius: 0;
        }
    </style>

</head>
<body>

<nav class="navbar navbar-default">
    <div class="container-fluid">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                    data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="#">系统</a>
        </div>


        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
            <ul class="nav navbar-nav">
                <li><a href="/user/list">用户管理</a></li>
                <li><a href="/department/list">部门管理</a></li>
            </ul>
            <form class="navbar-form navbar-left">
                <div class="form-group">
                    <input type="text" class="form-control" placeholder="查询">
                </div>
                <button type="submit" class="btn btn-default">查询</button>
            </form>
            <ul class="nav navbar-nav navbar-right">
                <li><a href="#">Link</a></li>
                <li class="dropdown">
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
                       aria-expanded="false">Dropdown <span class="caret"></span></a>
                    <ul class="dropdown-menu">
                        <li><a href="#">Action</a></li>
                        <li><a href="#">Another action</a></li>
                        <li><a href="#">Something else here</a></li>
                        <li role="separator" class="divider"></li>
                        <li><a href="#">Separated link</a></li>
                    </ul>
                </li>
            </ul>
        </div>
    </div>
</nav>


<div>
    {% block content %}{% endblock %}
</div>

<script src="{ % static 'js/jquery-3.7.1.js %'}"></script>
<script src="{ % static 'plugins/bootstrap-3.4.1/js/bootstrap.js %'}"></script>

</body>
</html>

11.2 forms.py格式校验

from django import forms
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
from .models import Department, UserInfo

class DepartmentForm(forms.ModelForm):
    class Meta:
        model = Department
        fields = "__all__"

# 添加的 ModelForm
class UserModelForm(forms.ModelForm):
    name = forms.CharField(min_length=2, label="用户名")
    # 定义密码正则表达式和验证器
    password_regex = r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]+$'
    password_validator = RegexValidator( regex=password_regex,
        message="密码必须包含至少一个小写字母、一个大写字母、一个数字和一个特殊字符。")
    password = forms.CharField(label="密码", validators=[password_validator],widget=forms.PasswordInput)

    class Meta:
        model = UserInfo
        # fields = ['name', 'password', 'age', 'gender']
        fields = "__all__"
        # 排除哪个字段
        # exclude = ['status']
        # widgets = {"name": forms.TextInput(attrs={"class": "form-control"}),
        #            "password": forms.PasswordInput(attrs={"class": "form-control"})}

    # 验证方式2 : 定义钩子方法, clean_字段名(self)
    def clean_age(self):

        txt_age = self.cleaned_data["age"]
        if txt_age<=18:
            #验证不通过
            raise ValidationError("未成年不允许!")
        # 验证通过
        return txt_age
    # 不允许重名,去数据库查询,校验!
    def clean_name(self):
        txt_name = self.cleaned_data["name"]
        if models.UserInfo.objects.filter(name=txt_name).exists():
            raise ValidationError("---重名了!---")
        # 验证通过
        return txt_name

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        for name, field in self.fields.items():
            if name == "status":
                continue
            field.widget.attrs = {"class": "form-control", "placeholder": field.label}
# 编辑的 ModelForm
class UserModelEditForm(forms.ModelForm):
    # 定义name不可编辑 
    name = forms.CharField(disabled=True, label="用户名")
    password_regex = r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]+$'
    password_validator = RegexValidator(regex=password_regex,
        message="密码必须包含至少一个小写字母、一个大写字母、一个数字和一个特殊字符。")
    password = forms.CharField(label="密码",validators=[password_validator],widget=forms.PasswordInput)

    class Meta:
        model = UserInfo
        fields = "__all__"
        # 排除哪个字段
        exclude = ['status']

    def clean_age(self):
        txt_age = self.cleaned_data["age"]
        if txt_age<=18:
            raise ValidationError("未成年不允许!")
        return txt_age

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        for name, field in self.fields.items():
            if name == "status":
                continue
            if name == "depart":
                # 过滤掉 status=1 的数据
                self.fields['depart'].queryset = Department.objects.exclude(status=1)
                # 设置默认选项的标签为 请选择
                self.fields['depart'].empty_label = "请选择"
            field.widget.attrs = {"class": "form-control", "placeholder": field.label}

# 添加  - 不允许重名,去数据库查询,校验!
    def clean_name(self):
        txt_name = self.cleaned_data["name"]
        if models.UserInfo.objects.filter(name=txt_name).exists():
            raise ValidationError("---重名了!---")
        # 验证通过
        return txt_name
# 编辑 - 排除自己,校验    
    def clean_name(self):
       # print(self.instance.pk)
        txt_name = self.cleaned_data["name"]
        if models.UserInfo.objects.exclude(id=self.instance.pk).filter(name=txt_name).exists():
            raise ValidationError("---重名了!---")
        # 验证通过
        return txt_name

相关文章:

  • 数据库表省市区分析
  • Kubernetes可视化面板——KubePi(Kubernetes Visualization Panel - kubepi)
  • Android BottomNavigationView 完全自定义指南:图标、文字颜色与选中状态
  • Outlook客户端无法连接到服务器,添加账户显示“无网络连接,请检查你的网络设置,然后重试。[2603]”
  • 优秀的 React 入门开源项目推荐
  • Redis 源码硬核解析系列专题 - 结语:从源码看Redis的设计哲学
  • Meta Llama 3:开启大语言模型新纪元
  • 美股恐惧贪婪指数监控
  • Kafka 实战指南:原理剖析与高并发场景设计模式
  • Python Cookbook-4.17 字典的并集与交集
  • 翻译: 人工智能如何让世界变得更美好一
  • 【Easylive】项目常见问题解答(自用持续更新中......)
  • 量子退火实用案例(1):量子退火求解化学中的分子吸附问题,10小时缩短为15分
  • 周总结aa
  • 多段圆弧拟合离散点实现切线连续
  • 【Vue2插槽】
  • PDF解析黑科技:从OCR-Free到多模态大模型的进化之旅
  • 43、接口请求需要时间,导致页面初始加载时会出现空白,影响用户体验
  • Python实现音频数字水印方法
  • Python人工智能大模型入门教程:从零构建高性能预测模型
  • 网站开发需要哪些文档/seo排名优化公司价格
  • flashfxp 网站/网上怎么推广产品
  • 做logo有哪些网站/重庆网络seo
  • 牛商网做网站的思路/seo关键词使用
  • 深圳网站定制公司/百度seo和谷歌seo有什么区别
  • 怎么做弹幕网站/营销网站建设选择原则