【Django】教程-1-安装+创建项目+目录结构介绍
【Django】教程-2-前端-目录结构介绍
【Django】教程-3-数据库相关介绍
【Django】教程-4-一个增删改查的Demo
11. ModelForm
11.1 models.py
python
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
python
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
python
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
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
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
python
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
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
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格式校验
python
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}
python# 添加 - 不允许重名,去数据库查询,校验! 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