原始思路实现添加用户功能的缺点:
1)用户提交的数据没有校验
2)如果用户输入的数据有错误,没有错误提示
3)前端页面上的每一个字段都需要我们重新写一次
4)关联的数据需要手动取获取并循环展示在页面
在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>
上面的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})