原始思路实现添加用户功能的缺点:
1)用户提交的数据没有校验
2)如果用户输入的数据有错误,没有错误提示
3)前端页面上的每一个字段都需要我们重新写一次
4)关联的数据需要手动取获取并循环展示在页面
1、Form
在views.py中:
# MyForm中继承的Form是Django自带的
class MyForm(forms):
# widget=forms.Input表示可以在HTML页面中可以显示成input框
user = forms.CharField(widget=forms.Input)
pwd = forms.CharField(widget=forms.Input)
email = forms.CharField(widget=forms.Input)
def user_add():
if method.request == "GET":
form = MyForm() # 实例化一个MyForm对象
return render(request, "user_add.html", {"form": form})
前端user_add.html中:
<form method="post" action="/user/add/">
{{ form.user }}
{{ form.pwd }}
{{ form.email }}
</form>
上面代码相当于如下代码,两者比较,明显上面使用了form的代码更加简洁
<form method="post" action="/user/add/">
<input type="text" class="form-control" placeholder="请输入用户名称" name="user">
<input type="text" class="form-control" placeholder="请输入密码" name="pwd">
<input type="text" class="form-control" placeholder="请输入邮箱" name="email">
</form>
还有一种比上面更简洁的写法,直接用for循环遍历form
<form method="post" action="/user/add/">
{% for field in form %}
{{ field }}
{% endfor %}
</form>
2、ModelForm(对某些数据库的表做增删改查,推荐用ModelForm)
1)使用ModelForm增加用户
上面的views.py的方法其实也有很麻烦的地方,就是如果我要用字段的话,那我就要在MyForm这个类中把所要用的字段都手动写一遍,如果字段很多的话,就比较麻烦,有没有更加简单的办法呢?
答案是有的,注意看MyForm里面的字段是不是和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.DateField(verbose_name="入职时间")
gender_choices = (
(1, "男"),
(2, "女")
)
# gender = models.SmallIntegerField(verbose_name="性别", choices=gender_choices)
gender = models.SmallIntegerField(verbose_name="性别", choices=gender_choices)
depart = models.ForeignKey(verbose_name="部门", to="Department", to_field="id",
null=True, blank=True, on_delete=models.SET_NULL)
其实,它们之间的内部之间是有关联的,我们如果使用ModelForm的话,可以这样写:
views.py中:
from django import forms
# 注意:如果要用ModelForm,则前面必须写这个类
class MyModelForm(forms.ModelForm):
class Meta:
model = models.UserInfo
# 这里fields这个列表就把models.py中的UserInfo表中的字段关联到了ModelForm这里
fields = ["name", "password", "age", "account", "create_time", "gender", "depart"]
def user_add():
if method.request == "GET":
form = MyModelForm() # 实例化一个MyModelForm对象
return render(request, "user_add.html", {"form": form})
同时,ModelForm中的fields列表里的字段不仅可以是数据库的字段,也可以是我们自定义的字段,而新字段相当于新加字段到表中。如下所示:
from django import forms
class MyModelForm(forms.ModelForm):
xxx = forms.CharField("...")
class Meta:
model = UserInfo
fields = ["name", "password", "age", "account", "create_time", "gender", "depart", "xxx"]
def user_add():
if method.request == "GET":
form = MyModelForm() # 实例化一个MyModelForm对象
return render(request, "user_add.html", {"form": form})
实操:
views.py中:
from django import forms
class UserModelForm(forms.ModelForm):
class Meta:
model = models.UserInfo
fields = ["name", "password", "age", "account", "create_time", "gender", "depart"]
def user_model_form_add():
if method.request == "GET":
form = UserModelForm() # 实例化一个MyModelForm对象
return render(request, "user_model_form_add.html", {"form": form})
user_model_form_add.html中:
<form method="post" action="/user/model/form/add/">
{% csrf_token %}
{% for field in form %}
{{ field.label }} : {{ field }}
{% endfor %}
</form>
运行后页面显示如下:
那么问题来了,为什么部门这块显示的不是部门名称,而是一个个Department类的对象呢?
首先,我们来分析一下models.py中的代码:
from django.db import models
class Department(models.Model):
"""部门表"""
# title是部门的名字,eg.title=招标部
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="年龄")
account = models.DecimalField(verbose_name="工资", max_digits=10, decimal_places=2, default=0)
create_time = models.DateField(verbose_name="入职时间")
gender_choices = (
(1, "男"),
(2, "女")
)
gender = models.SmallIntegerField(verbose_name="性别", choices=gender_choices)
depart = models.ForeignKey(verbose_name="部门", to="Department", to_field="id",
null=True, blank=True, on_delete=models.SET_NULL)
从上面代码中可以看出,models.py中的depart变量其实是从Department表中取到的一连串对象,前端页面显示的正是这一个个Department类的实例化对象。可是我们要让前端页面显示具体的部门名称,所以这里要引入一个知识点:
当我们定义一个类,并且实例化一个该类的对象时,我们可以在类中定义一个__str()__,这样当我们打印这个对象时,输出的就是__str()__中return的值,比如:而这个页面的问题,也可以用这种方法,也就是在Department表中定义一个__str()__方法,return的就是self.title。代码如下:
class Department(models.Model):
"""部门表"""
# title是部门的名字,eg.title=招标部
title = models.CharField(verbose_name="标题", max_length=32)
def __str__(self):
return self.title
上面的问题解决了,接下来,我们需要给这些输入框增加样式。具体怎么做呢?
前端user_model_form_add.html中:
{% extends 'layout.html' %}
{% load static %}
{% block css %}
<link rel="stylesheet" href="{% static 'plugins/bootstrap-datepicker/css/bootstrap-datepicker.min.css' %}">
{% endblock %}
{% 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" action="/user/model/form/add/" novalidate>
{% csrf_token %}
{% for field in form %}
{# 框外文字: 框内文字#}
<div>{{ field.label }}: {{ field }}</div>
<span style="color: red">{{ field.errors.0 }}</span>
{% endfor %}
<button type="submit" class="btn btn-primary">保 存</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
上面的代码中,样式唯一缺的就是form-control,我们要想办法把这个样式加上。具体时在views.py中通过widgets来加:
from django import forms
class UserModelForm(forms.ModelForm):
class Meta:
model = models.UserInfo
fields = ["name", "password", "age", "account", "create_time", "gender", "depart"]
widgets = {
"name": TextInput(attrs={"class": "form-control"}),
"password": PasswordInput(attrs={"class": "form-control"})
}
def user_model_form_add():
if method.request == "GET":
form = UserModelForm() # 实例化一个MyModelForm对象
return render(request, "user_model_form_add.html", {"form": form})
页面如下:
这种方法虽然可以,但是当字段比较多的时候,像这样一个一个的写就会比较麻烦。在我们真正做开发的时候,肯定不会像这样一个一个的写,我们通常这样写:
from django import forms
class UserModelForm(forms.ModelForm):
class Meta:
model = models.UserInfo
fields = ["name", "password", "age", "account", "create_time", "gender", "depart"]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环找到所有插件,添加class="form-control"样式
for name, field in self.fields.items():
field.widget.attrs = {"class": "form-control", "place-holder": field.label}
def user_model_form_add():
if method.request == "GET":
form = UserModelForm() # 实例化一个MyModelForm对象
return render(request, "user_model_form_add.html", {"form": form})
如果我想让某个字段(比如age)不加样式,可以循环中判断:if name == "age": continue
那么如何对用户输入的数据进行校验呢?
from django import forms
class UserModelForm(forms.ModelForm):
class Meta:
model = models.UserInfo
fields = ["name", "password", "age", "account", "create_time", "gender", "depart"]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环找到所有插件,添加class="form-control"样式
for name, field in self.fields.items():
field.widget.attrs = {"class": "form-control", "place-holder": field.label}
def user_model_form_add():
if method.request == "GET":
form = UserModelForm() # 实例化一个MyModelForm对象
return render(request, "user_model_form_add.html", {"form": form})
elif method.request == "POST":
form = UserModelForm(data=request.POST)
# 如果校验成功,可以获取到form.cleaned_data,返回一个字典
# 如果数据合法,我们将这个新增的用户数据保存到数据库,这里注意:我们不再需要用ORM语句了(虽然用也可以),因为ModelForm知道我们获取用户数据可能会将其保存进数据库,所以我们直接调用form.save()就可以了,数据会直接保存到UserInfo这个表中,因为在上面的ModelForm中我们定义了model = models.UserInfo
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})
前端页面通过field.errors.0来显示错误信息,field.errors是一个列表,我们只要显示这个列表的第0个元素就行。
{% extends 'layout.html' %}
{% load static %}
{% block css %}
<link rel="stylesheet" href="{% static 'plugins/bootstrap-datepicker/css/bootstrap-datepicker.min.css' %}">
{% endblock %}
{% 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" action="/user/model/form/add/" novalidate>
{% csrf_token %}
{% for field in form %}
{# 框外文字: 框内文字#}
<div>{{ field.label }}: {{ field }}</div>
<span style="color: red">{{ field.errors.0 }}</span>
{% endfor %}
<button type="submit" class="btn btn-primary">保 存</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
以上的代码只能校验输入内容是否为空,那比如,我想规定姓名的长度必须大于3,那么我们需要在ModelForm的类中额外规定一下:name = forms.CharField(min_length=3, label="姓名")
from django import forms
class UserModelForm(forms.ModelForm):
name = forms.CharField(min_length=3, label="姓名")
class Meta:
model = models.UserInfo
fields = ["name", "password", "age", "account", "create_time", "gender", "depart"]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环找到所有插件,添加class="form-control"样式
for name, field in self.fields.items():
field.widget.attrs = {"class": "form-control", "place-holder": field.label}
def user_model_form_add():
if method.request == "GET":
form = UserModelForm() # 实例化一个MyModelForm对象
return render(request, "user_model_form_add.html", {"form": form})
elif method.request == "POST":
form = UserModelForm(data=request.POST)
# 如果校验成功,可以获取到form.cleaned_data,返回一个字典
# 如果数据合法,我们将这个新增的用户数据保存到数据库,这里注意:我们不再需要用ORM语句了(虽然用也可以),因为ModelForm知道我们获取用户数据可能会将其保存进数据库,所以我们直接调用form.save()就可以了,数据会直接保存到UserInfo这个表中,因为在上面的ModelForm中我们定义了model = models.UserInfo
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})
2)使用ModelForm编辑用户信息
{% 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" novalidate>
{% csrf_token %}
{% for field in form %}
<div>{{ field.label }}: {{ field }}</div>
<span style="color: red">{{ field.errors.0 }}</span>
{% endfor %}
<button type="submit" class="btn btn-primary">保 存</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
def user_edit(request, nid):
"""编辑用户"""
# 根据ID获取到需要编辑的那一行的数据(对象)
row_object = models.UserInfo.objects.filter(id=nid).first()
if request.method == 'GET':
# 在ModelForm中写instance=row_object,则Django会默认将该对象中的每一个值写在输入框中
form = UserModelForm(instance=row_object)
return render(request, 'user_edit.html', {"form": form})
# 把用户post的数据更新到row_object这一行,并赋值给form
elif request.method == "POST":
form = UserModelForm(data=request.POST, instance=row_object)
if form.is_valid():
form.save()
return redirect('/user/list/')
else:
return render(request, 'user_edit.html', {"form": form})