号外号外,基于Pycharm的Django学习,项目实战来啦!
项目开发流程
实战之前,我们先来结合前面学习的知识,捋一捋整个项目开发的流程:
- 新建项目
- 创建app并注册
- 设计表结构
- 在MYSQL生成表
- 静态文件管理
- 代码编写
- 测试
项目准备工作
上述1-5,其实我们在之前就已经接触过了,所以在这个项目实战中,就当作是准备工作,大家先提前完成,有不懂的也可以看我之前写的博客。
第一步:新建项目
 
第二步:创建app并注册
 

第三步:设计表结构
from django.db import models
# Create your models here.
class Department(models.Model):
"""部门表"""
# verbose_name注解 相当于给我们程序员自己看代码时的字段含义提示
title = models.CharField(verbose_name="部门", max_length=32)
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="年龄")
# max_digits表示最大位数 decimal_places表示小数位数 default表示默认值
account = models.DecimalField(verbose_name="账户", max_digits=10, decimal_places=2, default=0)
create_time = models.DateTimeField(verbose_name="入职时间")
# 存入外键 表示员工所属部门ID 节省存储字节数 需要加入约束 即只能是部门表中已经存在的id 并且需要设置当部门表被删除 其为级联删除或者可以置空
# 存入名称 表示员工所属部门名称 主要用于优化检索速度
# to表示和哪张表连接 to_field表示和哪个字段连接 on_delete表示部门表删除时员工表做出的操作
depart = models.ForeignKey(to="Department", to_field="id", on_delete=models.CASCADE)
# Django约束 由于性别只有男和女 所以可以通过choices选择哪一些
gender_choices = (
(1, "男"),
(2, "女")
)
gender = models.SmallIntegerField(verbose_name="性别", choices=gender_choices)
第四步:在MYSQL生成表
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
# 数据库名字
'NAME':'写自己的名字',
# 用户名
'USER': 'root',
# 密码
'PASSWORD': '写自己的密码',
# 主机
'HOST': 'localhost',
# 端口
'PORT': '3306',
}
}
python manage.py makemigrations
python manage.py migrate
 
第五步:静态文件管理
 
项目部门管理
UI设计
先看一下页面大致UI设计:

depart_list
于是开始编写页面:
 
页面整体布局采用的是bootstrap框架,上面的是一个导航条,下面的是一个面板加表格的结构,先使用的静态数据进行测试页面。
大部分需要实现跳转的,哪怕长得再像按钮,其实都是一个a标签,然后设置class为btn属性。
{% load static %}
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<!--rel="stylesheet"不能缺少 否则显示不出来样式 rel属性就是指明你链进来的对象是个什么东西 stylesheet表示是样式表-->
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
<style>
.navbar{
border-radius:0;
}
</style>
</head>
<body>
<nav class="navbar navbar-default">
<div class="container">
<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="/depart/list/">部门管理</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">登录</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="true"><span
class="glyphicon glyphicon-user"></span>
个人信息<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#"><span
class="glyphicon glyphicon-tree-conifer"></span>
昵称:王晓曼</a>
</li>
<li role="separator" class="divider"></li>
<li><a href="#"><span
class="glyphicon glyphicon-music"></span>
个性签名:关关难过关关过,前路漫漫亦灿灿。</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<div>
<div class="container">
<div style="margin-bottom:20px">
<!--span后一个换行使得字体图标和文字有一点空隙-->
<a class="btn btn-primary" href="#"><span class="glyphicon glyphicon-plus-sign"></span>
新建部门</a>
</div>
<!--面板+表格-->
<div>
<div class="panel panel-default">
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list"></span>
部门列表
</div>
<!--可以直接在浏览器中选中元素 copy element-->
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>名称</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">1</th>
<td>销售部</td>
<td>
<a class="btn btn-success btn-xs">编辑</a>
<a class="btn btn-danger btn-xs">删除</a>
</td>
</tr>
<tr>
<th scope="row">2</th>
<td>技术部</td>
<td>
<a class="btn btn-success btn-xs">编辑</a>
<a class="btn btn-danger btn-xs">删除</a>
</td>
</tr>
<tr>
<th scope="row">3</th>
<td>广告部</td>
<td>
<a class="btn btn-success btn-xs">编辑</a>
<a class="btn btn-danger btn-xs">删除</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<script src="{% static 'js/jquery.min.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
</body>
</html>
 下面将静态数据换成从数据库进行获取的数据。
{% load static %}
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<!--rel="stylesheet"不能缺少 否则显示不出来样式 rel属性就是指明你链进来的对象是个什么东西 stylesheet表示是样式表-->
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
<style>
.navbar{
border-radius:0;
}
</style>
</head>
<body>
<nav class="navbar navbar-default">
<div class="container">
<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="/depart/list/">部门管理</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">登录</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="true"><span
class="glyphicon glyphicon-user"></span>
个人信息<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#"><span
class="glyphicon glyphicon-tree-conifer"></span>
昵称:王晓曼</a>
</li>
<li role="separator" class="divider"></li>
<li><a href="#"><span
class="glyphicon glyphicon-music"></span>
个性签名:关关难过关关过,前路漫漫亦灿灿。</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<div>
<div class="container">
<div style="margin-bottom:20px">
<!--span后一个换行使得字体图标和文字有一点空隙-->
<a class="btn btn-primary" href="#"><span class="glyphicon glyphicon-plus-sign"></span>
新建部门</a>
</div>
<!--面板+表格-->
<div>
<div class="panel panel-default">
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list"></span>
部门列表
</div>
<!--可以直接在浏览器中选中元素 copy element-->
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>名称</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for data in data_list %}
<tr>
<th scope="row">{{data.id}}</th>
<td>{{data.title}}</td>
<td>
<a class="btn btn-success btn-xs">编辑</a>
<a class="btn btn-danger btn-xs">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
<script src="{% static 'js/jquery.min.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
</body>
</html>
效果和上述一样,只不过这里的数据是从数据库来的,更加符合开发。

模板继承
我们在访问一个网站,比如淘宝、京东时,我们会发现,其实每次实现页面跳转的时候,它的每一个页面的导航条都是相同的,那如果每一个页面都写同样的内容,你会不会觉得很繁琐啊,那么怎么办呢?
模板继承!
导航条:layout.html
{% load static %}
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<!--rel="stylesheet"不能缺少 否则显示不出来样式 rel属性就是指明你链进来的对象是个什么东西 stylesheet表示是样式表-->
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
<style>
.navbar{
border-radius:0;
}
</style>
</head>
<body>
<nav class="navbar navbar-default">
<div class="container">
<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="/depart/list/">部门管理</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">登录</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="true"><span
class="glyphicon glyphicon-user"></span>
个人信息<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#"><span
class="glyphicon glyphicon-tree-conifer"></span>
昵称:王晓曼</a>
</li>
<li role="separator" class="divider"></li>
<li><a href="#"><span
class="glyphicon glyphicon-music"></span>
个性签名:关关难过关关过,前路漫漫亦灿灿。</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<div>
<!--设置居中-->
<div class="container">
{% block content %}{% endblock %}
</div>
</div>
<script src="{% static 'js/jquery.min.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
</body>
</html>
添加页面:depart_add.html
{% extends 'layout.html' %}
{% block content %}
<!--添加该页面内容-->
{% endblock %}
这样就可以了,当然,如果对其有多处改动,那也可以多加几个下面部分:
{% block 名称 %}
<!--添加该页面内容-->
{% endblock %}
测试结果如下:

depart_add
模板继承测试成功后,下面开始正式编写depart_add页面的编写了。
添加页面的主体是面板加表单设计。
 
{% extends 'layout.html' %}
{% block content %}
<!--添加该页面内容-->
<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="title">
</div>
<button type="submit" class="btn btn-primary">提交</button>
</form>
</div>
</div>
{% endblock %}
 基础样式出来了后,我们就需要继续实现页面跳转。
def depart_add(request):
# 如果是get请求
if request.method == "GET":
return render(request, "depart_add.html")
# 如果是post请求 获取用户提交的数据
title = request.POST.get("title")
# 将数据加入到数据库 (此处默认数据都是合法的 后面用Form和ModelForm实现)
models.Department.objects.create(title=title)
# 重定向到用户列表
return redirect("/depart/list/")
有没有发现把我们前面学习的东西都用起来了?  
depart_delete
是不是很有成就感呢?下面来写一个删除吧,和上一篇案例中的删除大同小异奥!
首先要在depart_list中找到删除对应的位置,然后实现url跳转。

def depart_delete(request):
# 获取需要删除的id
nid = request.GET.get("nid")
# 在数据库删除对应内容
models.Department.objects.filter(id=nid).delete()
# 重新返回列表展示页面
return redirect("/depart/list/")


此处相当于更改为跳转到url为/depart/delete的位置,并且将用户id传递过来,在urls.py文件中的url - 视图函数对应中,可以知道其对应会执行depart_delete函数,于是获取参数、删除内容后,重定向到展示页面,整个流程一气呵成。
depart_edit
编辑页面,我们想想它长什么样子,其和我们新建部门页面应该差不多,但是差别在于,编辑的时候,你点进去的时候,部门的默认值是原来需要编辑的内容。
有了id有了一切,传id。
 
def depart_edit(request, nid):
# 根据nid获取数据
edit_data = models.Department.objects.filter(id=nid).first()
return render(request, "depart_edit.html", {"edit_data": edit_data})

{% extends 'layout.html' %}
{% block content %}
<!--添加该页面内容-->
<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="title" value="{{edit_data.title}}">
</div>
<button type="submit" class="btn btn-primary">提交</button>
</form>
</div>
</div>
{% endblock %}
   再来完善一下页面跳转。
def depart_edit(request, nid):
# 如果是get请求
if request.method == "GET":
# 根据nid获取数据
edit_data = models.Department.objects.filter(id=nid).first()
return render(request, "depart_edit.html", {"edit_data": edit_data})
# 获取用户更新的title
title = request.POST.get("title")
# 对数据库中进行修改
models.Department.objects.filter(id=nid).update(title=title)
# 重定向为部门列表
return redirect("/depart/list/")
  一直没看数据库,这里一起看一下吧~
 
记得刷新!空白部分,右键刷新!
项目用户管理
部门管理差不多了,下面来看用户管理吧!
用户管理可不一般,也就是字段多了点,那么在获取内容的时候也有很多小细节需要注意奥!
user_list
首先我们需要为数据库准备一些数据:

def user_orm(request):
# 虽然在models.py中其为depart,但是实际上是depart_id,在操作的时候注意
models.UserInfo.objects.create(name="王晓曼", password="123520", age=20, account=99999, create_time="2022-09-01",
depart_id=1, gender=2)
models.UserInfo.objects.create(name="王尚春", password="666666", age=49, account=199999, create_time="2000-01-01",
depart_id=2, gender=1)
models.UserInfo.objects.create(name="彭艳", password="111111", age=48, account=299999, create_time="2001-01-01",
depart_id=3, gender=2)
models.UserInfo.objects.create(name="王梦迪", password="131420", age=28, account=399999, create_time="2015-06-14",
depart_id=6, gender=2)
models.UserInfo.objects.create(name="黄伟", password="888888", age=33, account=499999, create_time="2012-12-31",
depart_id=7, gender=1)
return HttpResponse("成功")
然后在导航条里加上用户管理这一个标签。
 用户列表,其实和部门列表差不多,只是字段可能不一样,先仿着部门列表写。
{% extends 'layout.html' %}
{% block content %}
<!--添加该页面内容-->
<div style="margin-bottom:20px">
<!--span后一个换行使得字体图标和文字有一点空隙-->
<a class="btn btn-primary" href="/user/add/"><span class="glyphicon glyphicon-plus-sign"></span>
新建用户</a>
</div>
<!--面板+表格-->
<div>
<div class="panel panel-default">
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list"></span>
用户列表
</div>
<!--可以直接在浏览器中选中元素 copy element-->
<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 data in data_list %}
<tr>
<th scope="row">{{data.id}}</th>
<td>{{data.name}}</td>
<td>{{data.password}}</td>
<td>{{data.age}}</td>
<td>{{data.account}}</td>
<td>{{data.create_time}}</td>
<td>{{data.depart}}</td>
<td>{{data.gender}}</td>
<td>
<a class="btn btn-success btn-xs" href="#">编辑</a>
<a class="btn btn-danger btn-xs" href="#">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
{% endblock %}
测试效果如下:

但是这样的效果肯定不好,所以我们需要在后端调整。
def user_list(request):
data_list = models.UserInfo.objects.all()
# 由于数据比较复杂 所以需要在后端进行调试数据格式 当然有可能前后端数据格式调整代码会不同 也会有局部更改
for data in data_list:
print(data.create_time.strftime("%Y-%m-%d"))
return render(request, "user_list.html", {"data_list": data_list})
 但是我们发现性别不是我们想要的展示数据,于是我们想起在定义表的时候,有一个gender_choices这个变量,那么怎么将数据展示成我们想要的呢?
def user_list(request):
data_list = models.UserInfo.objects.all()
# 由于数据比较复杂 所以需要在后端进行调试数据格式 当然有可能前后端数据格式调整代码会不同 也会有局部更改
for data in data_list:
# strftime("%Y-%m-%d")是后端将datetime类型转换为字符串形式
print(data.create_time.strftime("%Y-%m-%d"))
# 将元组套元组的类型 转换成 对应的字段
print(data.get_gender_display())
return render(request, "user_list.html", {"data_list": data_list})

那么depart_id怎么展示成对应的部门名称呢?
def user_list(request):
data_list = models.UserInfo.objects.all()
# 由于数据比较复杂 所以需要在后端进行调试数据格式 当然有可能前后端数据格式调整代码会不同 也会有局部更改
for data in data_list:
# strftime("%Y-%m-%d")是后端将datetime类型转换为字符串形式
print(data.create_time.strftime("%Y-%m-%d"))
# 将元组套元组的类型 转换成 对应的字段
print(data.get_gender_display())
# 拿取部门id对应的部门名称 我们知道在定义表的时候 定义的是depart 但是数据库给我们存的是depart_id 那么depart其实对应的是表的那一行的对象
print(data.depart.title)
return render(request, "user_list.html", {"data_list": data_list})
 在后端测试好了后,移植到前端了。
  是不是感觉很好呢?
user_add
其实添加用户和新建部门是一样的原理,但是可能字段会更多一点。

{% extends 'layout.html' %}
{% block content %}
<!--添加该页面内容-->
<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="name">
</div>
<div class="form-group">
<label>密码</label>
<input type="text" class="form-control" placeholder="密码" name="password">
</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="account">
</div>
<div class="form-group">
<label>入职时间</label>
<input type="text" class="form-control" placeholder="入职时间" name="create_time">
</div>
<div class="form-group">
<label>部门</label>
<select class="form-control" name="depart">
{% for data in depart_list %}
<option value="{{data.id}}">{{data.title}}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label>性别</label>
<select class="form-control" name="gender">
{% for item in gender_choices %}
<option value="{{item.0}}">{{item.1}}</option>
{% endfor %}
</select>
</div>
<button type="submit" class="btn btn-primary">提交</button>
</form>
</div>
</div>
{% endblock %}
def user_add(request):
# 拿到性别元组 和 部门信息
gender_choices = models.UserInfo.gender_choices
depart_list = models.Department.objects.all()
# 如果是get请求
if request.method == "GET":
return render(request, "user_add.html", {"gender_choices": gender_choices, "depart_list": depart_list})
# 如果是post请求 获取用户提交的数据
name = request.POST.get("name")
password = request.POST.get("password")
age = request.POST.get("age")
account = request.POST.get("account")
create_time = request.POST.get("create_time")
depart = request.POST.get("depart")
gender = request.POST.get("gender")
# 将数据加入到数据库 (此处默认数据都是合法的 后面用Form和ModelForm实现)
models.UserInfo.objects.create(name=name, password=password, age=age, account=account, create_time=create_time,
depart_id=depart, gender=gender)
# 重定向到用户列表
return redirect("/user/list/")
  
Form和ModelForm
有没有觉得如果字段很多的话,这也太复杂了吧!

没关系,Django给我们提供了Form和ModelForm奥,一起先来看看他们的基本用法吧!
Form

ModelForm
 当然也支持自定义字段和Model字段一起! 
user_add(ModelForm)
为了区分,我们首先在用户列表中,新增加一个按钮。
  views.py中增加如下:
from django import forms
class UserModelForm(forms.ModelForm):
class Meta:
model = models.UserInfo
fields = ["name", "password", "age"]
def user_model_form_add(request):
form = UserModelForm()
return render(request, "user_model_form_add.html", {"form": form})
 先测试基本数据(不考虑样式):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post">
{% csrf_token %}
<!--form.字段.label表示对应的中文名-->
{{form.name.label}}:{{form.name}}
{{form.password.label}}:{{form.password}}
{{form.age.label}}:{{form.age}}
</form>
</body>
</html>
 对form进行循环:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post">
{% csrf_token %}
<!--form.字段.label表示对应的中文名-->
<!--{{form.name.label}}:{{form.name}}
{{form.password.label}}:{{form.password}}
{{form.age.label}}:{{form.age}}-->
{% for field in form %}
{{field.label}}:{{field}}
{% endfor %}
</form>
</body>
</html>
 剩下的字段都加上,看一下效果:
  
有没有发现其他的很方便,但是depart怎么肥四?!
首先我们没有写verbose_name,所以直接把字段名写出来了。
其次这个为对象,所以直接输出了对象。
 搞定!  现在集成到bootstrap中!
{% extends 'layout.html' %}
{% block content %}
<!--添加该页面内容-->
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">新建ModelForm用户</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>
{% endblock %}
 但是长得有点丑啊!
  把所有的都加上:
from django import forms
class UserModelForm(forms.ModelForm):
class Meta:
model = models.UserInfo
fields = ["name", "password", "age", "account", "create_time", "depart", "gender"]
# 插件
# widgets = {
# "name": forms.TextInput(attrs={"class": "form-control"})
# }
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for name, field in self.fields.items():
field.widget.attrs = {"class": "form-control", "placeholder": field.label}
def user_model_form_add(request):
form = UserModelForm()
return render(request, "user_model_form_add.html", {"form": form})
 完善POST后的相关处理:
def user_model_form_add(request):
if request.method == "GET":
form = UserModelForm()
return render(request, "user_model_form_add.html", {"form": form})
# 用Post提交的数据 进行数据校验
form = UserModelForm(data=request.POST)
if form.is_valid():
# 如果数据合法 保存到数据库
print(form.cleaned_data)
form.save()
return redirect("/user/list/")
else:
print(form.errors)
return render(request, "user_model_form_add.html", {"form": form})
 怎么将提示变成中文呢?

LANGUAGE_CODE = 'zh-hans'
  如果对于姓名字段,添加一些限制呢?
  正确的添加: 
总而言之:ModelForm针对操作数据库某个表,其他还是Form。
user_edit
  
def user_edit(request, nid):
if request.method == "GET":
# 根据id去数据库获取编辑的那一行
row_object = models.UserInfo.objects.filter(id=nid).first()
form = UserModelForm(instance=row_object)
return render(request, "user_edit.html", {"form": form})
# 完成编辑后保存到当前对象中 而不是新增一个用户 (该行可放在最上面)
row_object = models.UserInfo.objects.filter(id=nid).first()
# 用Post提交的数据 进行数据校验
form = UserModelForm(data=request.POST, instance=row_object)
if form.is_valid():
# 如果数据合法 保存到数据库
print(form.cleaned_data)
# 默认保存的是用户输入的所有数据 如果想要再保存用户输入的额外的值
# form.instance.字段名=值
form.save()
return redirect("/user/list/")
else:
print(form.errors)
return render(request, "user_edit.html", {"form": form})
页面就和用户添加的页面差不多,只需要修改标题。
{% extends 'layout.html' %}
{% block content %}
<!--添加该页面内容-->
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">编辑用户</h3>
</div>
<div class="panel-body">
<form method="post" novalidate>
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label>{{field.label}}</label>
{{field}}
<span style="color:red;">{{field.errors.0}}</span>
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">提交</button>
</form>
</div>
</div>
{% endblock %}

user_delete
  叮咚,完成!
|