Bootstrap

Django 03 :员工管理【 模板继承 + Form + ModelForm】


上一篇: Django 02 :部门管理 【面板设计(Bootstrap)+部门的增删改查(Django+MySQL)】_.末明.的博客-CSDN博客

1、模板的继承

上一篇文章中我们发现,我们每创建一个新页面(HTML文件),都要重复的去做引入静态文件、导航条等操作,下面提供一个更简单的方式:模板继承

  • 部门列表
  • 添加部门
  • 编辑部门

定义母版:layout.html

母版包含内容:

  • 静态文件的引入
  • 导航条
  • 子版部分

如下,我们规定好母版的内容,此时子板只需要填写{% block content %}{% endblock %}的内容就ok了

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


{# 子板部分 #}
<div>
    {% block content %}{% endblock %}
</div>

<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.4.1/js/bootstrap.min.js' %}"></script>
</body>
</html>

子模板:

{% extends 'layout.html' %}

{% block content %}
    {# 子板的内容 #}
{% endblock %}

当然,我们还可以在模板中多添加点block,如下,我们新增了css、js

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="{% static 'plugin...min.css' %}">
    {% block css %}{% endblock %}
</head>
<body>
    <div>
        {% block content %}{% endblock %}
    </div>
    <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
    {% block js %}{% endblock %}
</body>
</html>

继承母版:

{% extends 'layout.html' %}

{% block css %}
	<link rel="stylesheet" href="{% static 'pluxxx.css' %}">
	<style>
		...
	</style>
{% endblock %}


{% block content %}
    <h1>首页</h1>
{% endblock %}


{% block js %}
	<script src="{% static 'js/jqxxxin.js' %}"></script>
{% endblock %}

这样我们就可以重构一下之前的前端代码:

请添加图片描述

2、用户管理

urls.py

path('user/list/', views.user_list),

views.py

def user_list(request):
    """用户管理"""
    return render(request, 'user_list.html')

user_list.html

直接copydepart_list.html,修改一下文字部分即可

{% extends 'layout.html' %}

{% block content %}
    {# 用户列表 #}
    <div class="container">
        <div style="margin-bottom: 10px">
            <a class="btn btn-success" href="/depart/add/" >
                {# 可以添加一个 target="_blank" : 使页面在新页面打开,如果不设置,会在原页面打开(这里我们还是在当前页面打开) #}
                <span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
                新建用户
            </a>
            {#新建一个 depart_add.html , 用来写新建部门界面#}
        </div>
        <div class="panel panel-default">
            <!-- Default panel contents -->
            <div class="panel-heading">
                <span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
                用户列表
            </div>

            <!-- 表格部分 -->
            <table class="table table-bordered">
                <thead>
                <tr>
                    <th>ID</th>
                    <th>名称</th>
                    <th>操作</th>
                </tr>
                </thead>
                <tbody>
                    <tr>
                        <th>123</th>
                        <td>321</td>
                        <td>
                            <a class="btn btn-primary btn-xs" href="#">编辑</a>
                            <a class="btn btn-danger btn-xs" href="#">删除</a>
                        </td>
                    </tr>

{#                {% for obj in queryset %}#}
{#                    <tr>#}
{#                        <th>{{ obj.id }}</th>#}
{#                        <td>{{ obj.title }}</td>#}
{#                        <td>#}
{#                            <a class="btn btn-primary btn-xs" href="/depart/{{ obj.id }}/edit/">编辑</a>#}
                            {# btn ==> 添加btn的按钮#}
                            {# btn-primary ==> 蓝色按钮(按钮的样式)#}
                            {# btn-xs ==> 	这会让按钮看起来特别小(按钮大小)#}
{#                            <a class="btn btn-danger btn-xs" href="/depart/detele/?nid={{ obj.id }}">删除</a>#}
{#                        </td>#}
{#                    </tr>#}
{#                {% endfor %}#}
                </tbody>
            </table>
        </div>
    </div>
{% endblock %}

效果展示:

在这里插入图片描述

导航栏的跳转效果

任务:点击导航栏的“用户管理”,即可跳转到用户管理界面

修改导航栏

layout.html

<ul class="nav navbar-nav">
                <li><a href="/depart/list/">部门管理</a></li>
                <li><a href="/user/list/">用户管理</a></li>
                <li><a href="#">Link</a></li>
            </ul>

这样就完成了跳转功能

用户管理表格设计

user_list.html

<!-- 表格部分 -->
            <table class="table table-bordered">
                <thead>
                <tr>
                    <th>ID</th>
                    <th>姓名</th>
                    <th>密码</th>
                    <th>年龄</th>
                    <th>余额</th>
                    <th>入职时间</th>
                    <th>性别</th>
                    <th>所属部门</th>
                    <th>操作</th>
                </tr>
                </thead>
                <tbody>
                    <tr>
                        <th>123</th>
                        <td>321</td>
                        <td>321</td>
                        <td>321</td>
                        <td>321</td>
                        <td>321</td>
                        <td>321</td>
                        <td>321</td>
                        <td>
                            <a class="btn btn-primary btn-xs" href="#">编辑</a>
                            <a class="btn btn-danger btn-xs" href="#">删除</a>
                        </td>
                    </tr>

效果展示:

在这里插入图片描述

向表格添加用户数据

回顾一下我们之前设计的用户管理表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1nzjvPUn-1645714937055)(C:\Users\pc\AppData\Roaming\Typora\typora-user-images\image-20220223200244874.png)]

写点sql语句,添加用户:

insert into app01_userinfo(name,password,age,account,create_time,gender,depart_id) values("韩超","666",23,100.68,"2020-01-11",2,1);

insert into app01_userinfo(name,password,age,account,create_time,gender,depart_id) values("刘东","123",23,100.68,"2010-11-11",1,1);

insert into app01_userinfo(name,password,age,account,create_time,gender,depart_id) values("朱虎飞","999",33,9900.68,"2021-05-11",1,1);

问题:

mysql> insert into app01_userinfo(name,password,age,account,create_time,gender,depart_id) values("刘东","123",23,100.68,"2010-11-11",1,4);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`employee`.`app01_userinfo`, CONSTRAINT `app01_userinfo_depart_id_e22e0907_fk_app01_department_id` FOREIGN KEY (`depart_id`) REFERENCES `app01_department` (`id`))

输入第二个数据报错:我们收到错误"无法添加或更新子行:外键"
约束失败"。

原因:在插入含有外键的表中,若要插入外键为空时,直接insert则会报错,注意他最后一个参数是【4】,我们定义的【1】是【男】、【2】是【女】,【4】在范围之外

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s0MZPj7o-1645714937056)(C:\Users\pc\AppData\Roaming\Typora\typora-user-images\image-20220223205100423.png)]

我们修改一下views.py看一下效果:

def user_list(request):
    """用户管理"""

    # 获取所有的用户列表
    queryset = models.UserInfo.objects.all()
    for obj in queryset:
        print(obj.id, obj.name, obj.accoun, obj.create_time.strftime("%Y-%m-%d"), type(obj.create_time))

    return render(request, 'user_list.html')

PS:关于入职时间
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2kV9HCmG-1645714937056)(C:\Users\pc\AppData\Roaming\Typora\typora-user-images\image-20220223210307219.png)]

效果展示:

运行django项目,跳转到http://127.0.0.1:8000/user/list/

Django version 3.2.6, using settings 'employeemanage.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
6 韩超 100.68 2020-01-11 <class 'datetime.datetime'>
7 刘东 100.68 2010-11-11 <class 'datetime.datetime'>
8 朱虎飞 9900.68 2021-05-11 <class 'datetime.datetime'>

如何获取关联的数据呢?

def user_list(request):
    """用户管理"""

    # 获取所有的用户列表
    queryset = models.UserInfo.objects.all()
    for obj in queryset:
        print(obj.id, obj.name, obj.account, obj.create_time.strftime("%Y-%m-%d"), type(obj.create_time))

        # 想要获取关联的数据
        # 方式一: 传统方法,根据id获取关联的数据
        temp = models.Department.objects.filter(id=obj.depart_id).first()
        print(temp.title)
        # 方式二: Django的方法(注意区别obj.depart_id与obj.depart.title)
        print(obj.depart_id)  # 获取数据库中存储的那个字段值
        print(obj.depart.title)  # 根据id自动去关联的表中获取哪一行数据depart对象
    return render(request, 'user_list.html')

效果展示:

6 韩超 100.68 2020-01-11 <class 'datetime.datetime'>
IT部门
1
IT部门
7 刘东 100.68 2010-11-11 <class 'datetime.datetime'>
IT部门
1
IT部门
8 朱虎飞 9900.68 2021-05-11 <class 'datetime.datetime'>
IT部门
1
IT部门

然后就是把数据库的数据传到前端了

user_list.html

<!-- 表格部分 -->
            <table class="table table-bordered">
                <thead>
                <tr>
                    <th>ID</th>
                    <th>姓名</th>
                    <th>密码</th>
                    <th>年龄</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.name }}</td>
                        <td>{{ obj.password }}</td>
                        <td>{{ obj.age }}</td>
                        <td>{{ obj.account }}</td>
                        {# 模板语法是不能加括号的,需要加括号时,他会自动帮你加上 #}
                        {# <td>{{ obj.create_time.strftime("%Y-%m-%d") }}</td>#}
                        {# <td>{{ obj.get_gender_display() }}</td>#}
                        <td>{{ obj.create_time|date:"Y-m-d"}}</td>
                        <td>{{ obj.get_gender_display }}</td>
                        <td>{{ obj.depart.title }}</td>
                        <td>
                            <a class="btn btn-primary btn-xs" href="#">编辑</a>
                            <a class="btn btn-danger btn-xs" href="#">删除</a>
                        </td>
                    </tr>
                {% endfor %}
                </tbody>
            </table>

注意区别Python语法与模板语法:

{# 模板语法是不能加括号的,需要加括号时,他会自动帮你加上 #}
{# <td>{{ obj.create_time.strftime("%Y-%m-%d") }}</td>#}
{# <td>{{ obj.get_gender_display() }}</td>#}
<td>{{ obj.create_time|date:"Y-m-d"}}</td>
<td>{{ obj.get_gender_display }}</td>
<td>{{ obj.depart.title }}</td>

可能遇到的问题:

Exception Type:	TemplateSyntaxError
Exception Value:	
Could not parse the remainder: ': "Y-m-d"' from 'obj.create_time|date: "Y-m-d"'

原因:

<td>{{ obj.create_time|date:"Y-m-d"}}</td>对于"Y-m-d",其前面一个空格都不能有,否则就会报上述错误,格式要求很严格

前端效果展示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hVgqapjH-1645714937056)(C:\Users\pc\AppData\Roaming\Typora\typora-user-images\image-20220223224500635.png)]

3、新建用户(原始方法)

三种方式

  • 原始方法思路:麻烦

  • Django组件

    • Form组件(简便)
    • ModelForm组件(最简便)

我们首先体验一下用原始的方式实现新增用户,下一节中再使用Django组件

基础效果

  • (1)user_list.html

修改href

<a class="btn btn-success" href="/user/add/">
                {# 可以添加一个 target="_blank" : 使页面在新页面打开,如果不设置,会在原页面打开(这里我们还是在当前页面打开) #}
                <span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
                新建用户
            </a>
  • (2)urls.py
path('user/add/', views.user_add),
  • (3)user_add.html

    复用depart_add.html的代码,并新增几个输入框用来填写用户的各种信息(很繁琐,不断的去做重复的共工作建立输入框)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RmHTwrnM-1645714937057)(C:\Users\pc\AppData\Roaming\Typora\typora-user-images\image-20220224135718717.png)]

特别是“性别”和“部门”俩属性,需要特殊处理,我们输入值只能是已有的选项

{% extends 'layout.html' %}

{% block content %}
    {# 新建用户部分 #}
    <div>
    <div class="container">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title"> 新建用户 </h3>
            </div>
            <div class="panel-body">
                <form method="post">
                    {% csrf_token%}
                    <div class="form-group">
                        <label>姓名</label>
                        <input type="text" class="form-control" placeholder="姓名" >
                    </div>

                    <div class="form-group">
                        <label>密码</label>
                        <input type="text" class="form-control" placeholder="密码">
                    </div>

                    <div class="form-group">
                        <label>年龄</label>
                        <input type="text" class="form-control" placeholder="年龄">
                    </div>

                    <div class="form-group">
                        <label>余额</label>
                        <input type="text" class="form-control" placeholder="余额">
                    </div>

                    <div class="form-group">
                        <label>入职时间</label>
                        <input type="text" class="form-control" placeholder="入职时间">
                    </div>

                    <div class="form-group">
                        <label>性别</label>
                        {#<input type="text" class="form-control" placeholder="性别">#}
                        <select class="form-control">
                            <option value="1"></option>
                            <option value="2"></option>
                        </select>
                    </div>

                    <div class="form-group">
                        <label>部门</label>
                        {# <input type="text" class="form-control" placeholder="部门"> #}
                        <select class="form-control">
                            <option value="1">IT部门</option>
                            <option value="2">媒体企划</option>
                        </select>
                    </div>

                    <button type="submit" class="btn btn-primary">提交</button>
                </form>
            </div>
        </div>
    </div>
</div>

{% endblock %}

效果展示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O1ICOY4w-1645714937057)(C:\Users\pc\AppData\Roaming\Typora\typora-user-images\image-20220224140548416.png)]

优化

前面,对于“部门”我们是写死的,这样很不好,部门数量太多、部门关联的ID变化、新增部门等等情况都会引来麻烦

  • views.py
def user_add(request):
    """添加用户"""

    # 拿到部门信息,传到前端
    context = {
        'gender_choice' : models.UserInfo.gender_choices,
        'depart_list' : models.Department.objects.all(),
    }

    return render(request, "user_add.html", context)
  • user_add.html
<div class="form-group">
                        <label>部门</label>
                        {# <input type="text" class="form-control" placeholder="部门"> #}
                        <select class="form-control">
                            {# <option value="1">IT部门</option>#}
                            {# <option value="2">媒体企划</option>#}
                            {# value 的值必须与数据库相对应 #}
                            {% for item in depart_list %}
                                <option value="{{ item.id }}">{{ item.title }}</option>
                            {% endfor %}
                        </select>
                    </div>

完成提交(数据库)

老样子

  • (1)对前端各个信息一个一个获取
  • (2)后端( views.py / user_add() )中接收前端提交的数据(POST)
  • (3)传入数据库
  • (4)返回用户列表界面
  • (1)对前端各个信息一个一个获取

在最后加【name】属性

<div class="form-group">
                        <label>姓名</label>
                        <input type="text" class="form-control" placeholder="姓名" name="user"/>
                    </div>

                    <div class="form-group">
                        <label>密码</label>
                        <input type="text" class="form-control" placeholder="密码" name="pwd"/>
                    </div>

                    <div class="form-group">
                        <label>年龄</label>
                        <input type="text" class="form-control" placeholder="年龄" name="age"/>
                    </div>

                    <div class="form-group">
                        <label>余额</label>
                        <input type="text" class="form-control" placeholder="余额" name="ac"/>
                    </div>


                    <div class="form-group">
                        <label>入职时间</label>
                        <input type="text" class="form-control" placeholder="入职时间" name="ctime"/>
                    </div>
  • (2)后端( views.py / user_add() )中接收前端提交的数据(POST)

将用户的一堆属性一个一个获取

# 获取用户提交的数据
user = request.POST.get('user')
pwd = request.POST.get('pwd')
age = request.POST.get('age')
account = request.POST.get('ac')
ctime = request.POST.get('ctime')
gender = request.POST.get('gd')
depart_id = request.POST.get('dp')
  • (3)传入数据库
# 添加到数据库中
models.UserInfo.objects.create(name=user, password=pwd, age=age,
                               account=account, create_time=ctime,
                               gender=gender, depart_id=depart_id)
  • (4)返回用户列表界面
# return render(request, "user_add.html", context)
return redirect("/user/list/")

user_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 method="post">
                    {% csrf_token %}

                    <div class="form-group">
                        <label>姓名</label>
                        <input type="text" class="form-control" placeholder="姓名" name="user"/>
                    </div>

                    <div class="form-group">
                        <label>密码</label>
                        <input type="text" class="form-control" placeholder="密码" name="pwd"/>
                    </div>

                    <div class="form-group">
                        <label>年龄</label>
                        <input type="text" class="form-control" placeholder="年龄" name="age"/>
                    </div>

                    <div class="form-group">
                        <label>余额</label>
                        <input type="text" class="form-control" placeholder="余额" name="ac"/>
                    </div>


                    <div class="form-group">
                        <label>入职时间</label>
                        <input type="text" class="form-control" placeholder="入职时间" name="ctime"/>
                    </div>

                    <div class="form-group">
                        <label>性别</label>
                        <select class="form-control" name="gd">
                            {% for item in gender_choices %}
                                <option value="{{ item.0 }}">{{ item.1 }}</option>
                            {% endfor %}
                        </select>
                    </div>

                    <div class="form-group">
                        <label>部门</label>
                        <select class="form-control" name="dp">
                            {% for item in depart_list %}
                                <option value="{{ item.id }}">{{ item.title }}</option>
                            {% endfor %}
                        </select>
                    </div>

                    <button type="submit" class="btn btn-primary">提 交</button>
                </form>
            </div>
        </div>
    </div>
{% endblock %}

views.py

def user_add(request):
	"""添加用户(原始方式)"""

    # 拿到部门信息,传到前端
    if request.method == "GET":
        context = {
            'gender_choices': models.UserInfo.gender_choices,
            "depart_list": models.Department.objects.all()
        }
        return render(request, 'user_add.html', context)

    # 获取用户提交的数据
    user = request.POST.get('user')
    pwd = request.POST.get('pwd')
    age = request.POST.get('age')
    account = request.POST.get('ac')
    ctime = request.POST.get('ctime')
    gender = request.POST.get('gd')
    depart_id = request.POST.get('dp')

    # 添加到数据库中
    models.UserInfo.objects.create(name=user, password=pwd, age=age,
                                   account=account, create_time=ctime,
                                   gender=gender, depart_id=depart_id)

    # 返回到用户列表页面
    return redirect("/user/list/")

4、Django组件:Form 和 ModelForm

我们刚了解了用原始方式实现“新建用户”,我们先回顾一下

新建用户:

  • 原始方式理思路:许多情况下会很麻烦

    - 用户提交数据没有校验。
    - 错误,页面上应该有错误提示(例:用户民未填写)。
    - 页面上,没一个字段都需要我们重新写一遍。数据多了简直爆炸
    - 关联的数据,手动去获取并展示循环展示在页面。 
    

    上面四个问题怎么解决呢?

  • Django组件

    • Form组件(简便,可以解决前三个问题)
    • ModelForm组件(最简便)

4.1、初识Form

我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来。

与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不正确。如果用户输入的内容有错误就需要在页面上相应的位置显示对应的错误信息.。

Django form组件就实现了上面所述的功能。

总结一下,其实form组件的主要功能如下:

  • 生成页面可用的HTML标签
  • 对用户提交的数据进行校验
  • 保留上次输入内容
1、views.py
class MyForm(Form):  # django.Form
    user = forms.CharField(widget=forms.Input)
    pwd = form.CharFiled(widget=forms.Input)
    email = form.CharFiled(widget=forms.Input)
    account = form.CharFiled(widget=forms.Input)
    create_time = form.CharFiled(widget=forms.Input)
    depart = form.CharFiled(widget=forms.Input)
    gender = form.CharFiled(widget=forms.Input)


def user_add(request):
    if request.method == "GET":
        form = MyForm()
        return render(request, 'user_add.html',{"form":form})
2、user_add.html

以往要写一堆input,一个input还要一堆参数,现在利用Form:

<form method="post">
    {{ form.user }}
    {{ form.pwd }}
    {{ form.email }}
    <!-- <input type="text"  placeholder="姓名" name="user" /> -->
</form>

其实,还能再简便一点,写个循环(循环form中所有的字段):

<form method="post">
    {% for field in form%}
    	{{ field }}
    {% endfor %}
</form>

对比采用原始方法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y06jGab6-1645714937058)(C:\Users\pc\AppData\Roaming\Typora\typora-user-images\image-20220224161845438.png)]

但这样class MyForm(Form)中的内容还是太繁琐了,一个属性一个属性的去定义

细心的同学可能想到,我们在models.py中已经干过这些事情了

4.2、ModelForm(推荐)

0、models.py
class UserInfo(models.Model):
    """ 员工表 """
    name = models.CharField(verbose_name="姓名", max_length=16)
    password = models.CharField(verbose_name="密码", max_length=64)
    age = models.IntegerField(verbose_name="年龄")
    account = models.DecimalField(verbose_name="账户余额", max_digits=10, decimal_places=2, default=0)
    create_time = models.DateTimeField(verbose_name="入职时间")
    depart = models.ForeignKey(to="Department", to_field="id", on_delete=models.CASCADE)
    gender_choices = (
        (1, "男"),
        (2, "女"),
    )
    gender = models.SmallIntegerField(verbose_name="性别", choices=gender_choices)
1、views.py
class MyForm(ModelForm): 
    xx = form.CharField*("...")  # ModelForm不仅支持数据库中支持的字段,我们也可以另外自定义
    class Meta:
        model = UserInfo
        fields = ["name","password","age","xx"]


def user_add(request):
    if request.method == "GET":
        form = MyForm()
        return render(request, 'user_add.html',{"form":form})
2、user_add.html
<form method="post">
    {% for field in form%}
    	{{ field }}
    {% endfor %}
    <!-- <input type="text"  placeholder="姓名" name="user" /> -->
</form>
<form method="post">
    {{ form.user }}
    {{ form.pwd }}
    {{ form.email }}
    <!-- <input type="text"  placeholder="姓名" name="user" /> -->
</form>

5、新建用户(ModelForm)

补充知识:

class Foo(object):

    def __str__(self):
        return "Hello World"


obj = Foo()
print(obj)  # 输出对象时,如果想要定制显示的内容,可以借助“__str__”

Hello World

进程已结束,退出代码为 0
  • views.py
from django.forms import ModelForm

"""新建用户(ModelForm版本)"""


class MyForm(ModelForm):
    # xx = form.CharField*("...")  # ModelForm不仅支持数据库中支持的字段,我们也可以另外自定义
    class Meta:
        model = models.UserInfo
        # fields = ["name", "password", "age", "xx"]
        fields = ["name", "password", "age", 'account', 'create_time', "gender", "depart"]

        # 我们可以使用下面的方法去获取各个属性,但有个更方便的方法:重定义_init__
        # widgets = {
        #     "name": forms.TextInput(attrs={"class": "form-control"}),
        #     "password": forms.PasswordInput(attrs={"class": "form-control"}),
        #     "age": forms.TextInput(attrs={"class": "form-control"}),
        # }

    # 重定义_init__
    # 在前端中,我们使用ModelForm的组件中,前端失去了 class="form-control" 效果,我们可以通过Django控制插件
    # 循环找到所有的插件,添加了class="form-control"
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for name, field in self.fields.items():
            # 如果你不想要某一个属性不使用 class="form-control" 这个效果,如 : password
            # if name == "password":
            #     continue
            field.widget.attrs = {"class": "form-control", "placeholder": field.label}


def user_add(request):
    form = MyForm()
    return render(request, 'user_add.html', {"form": form})
  • user_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 method="post">
                    {% csrf_token %}

                    {% for field in form %}
                        <div class="form-group">
                            <label>{{ field.label }}</label>
                            {{ field }}
                        </div>
                    {% endfor %}

                    <button type="submit" class="btn btn-primary">提 交</button>
                </form>
            </div>
        </div>
    </div>

{% endblock %}

问题:

在这里插入图片描述

原因:
Department object(1)是 models.py 中 Department 的对象

让他正常显示部门名称,解决方法就是本节开头说的,利用__str__魔法函数

models.py

    def __str__(self):
        return self.title
depart = models.ForeignKey(verbose_name="部门", to="Department", to_field="id", on_delete=models.CASCADE)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sL9aki5B-1645714937058)(C:\Users\pc\AppData\Roaming\Typora\typora-user-images\image-20220224191835012.png)]

效果展示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8gJskpGh-1645714937059)(C:\Users\pc\AppData\Roaming\Typora\typora-user-images\image-20220224191940798.png)]

将数据储存至数据库:

def user_add(request):
    if request.method == "GET":
        form = MyForm()
        return render(request, 'user_add.html', {"form": form})

    # 用户POST提交数据,数据效验(不能为空)
    # 如果数据合法,提交到数据库
    form = MyForm(data=request.POST)
    if form.is_valid():
        print(form.cleaned_data)
        # 将数据存储至数据库
        # 方法一:老套路
        # models.UserInfo.objects.create(...)
        # 方法二:ModelForm
        form.save()
        return redirect("/user/list/")
    else:
        print(form.errors)

效果展示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LxbDHvAp-1645714937059)(C:\Users\pc\AppData\Roaming\Typora\typora-user-images\image-20220224192057445.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Uabon78t-1645714937060)(C:\Users\pc\AppData\Roaming\Typora\typora-user-images\image-20220224192106025.png)]

错误提示

  • user_add.html

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VOjoOmFy-1645714937060)(C:\Users\pc\AppData\Roaming\Typora\typora-user-images\image-20220224220829674.png)]

{% 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 method="post" novalidate> {# novalidate : 关闭浏览器帮我们做的校验,用自己的 #}
                    {% csrf_token %}

                    {% for field in form %}
                        <div class="form-group">
                            <label>{{ field.label }}</label>
                            {{ field }}
                            <span style="color: red;">{{ field.errors.0 }}</span> {# 错误信息可能有很多,我们只显示第0个就好了 #}
                        </div>
                    {% endfor %}

                    <button type="submit" class="btn btn-primary">提 交</button>
                </form>
            </div>
        </div>
    </div>

{% endblock %}

  • views.py
def user_add(request):
    if request.method == "GET":
        form = MyForm()
        return render(request, 'user_add.html', {"form": form})

    # 用户POST提交数据,数据效验(不能为空)
    # 如果数据合法,提交到数据库
    form = MyForm(data=request.POST)
    if form.is_valid():
        print(form.cleaned_data)
        # 将数据存储至数据库
        # 方法一:老套路
        # models.UserInfo.objects.create(...)
        # 方法二:ModelForm
        form.save()
        return redirect("/user/list/")
    # else:
    #     print(form.errors)

    return render(request, 'user_add.html', {"form": form})

把多余的注释都去掉

def user_add(request):
    if request.method == "GET":
        form = MyForm()
        return render(request, 'user_add.html', {"form": form})

    form = MyForm(data=request.POST)
    if form.is_valid():
        form.save()
        return redirect("/user/list/")
        
    return render(request, 'user_add.html', {"form": form})
  • 效果展示:
    提交空数据(这里的错误提示都是ModelForm帮我们默认做好的)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VNS2EIJ6-1645714937060)(C:\Users\pc\AppData\Roaming\Typora\typora-user-images\image-20220224221213843.png)]

我们可以自己自定义一下:

比如,名字限制在三位以内

  • views.py / MyForm
class MyForm(forms.ModelForm):
    name = forms.CharField(min_length=3, label="用户名")

报错改为中文:

  • settings.py
# LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'zh-hans'
  • 效果展示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G1SmJlQP-1645714937061)(C:\Users\pc\AppData\Roaming\Typora\typora-user-images\image-20220224224103529.png)]

;