Django表单与模型、后台系统
一、Django表单与模型
表单是搜集用户数据信息的各种表单元素的集合,作用是实现网页上的数据交互,用户在网站输入数据信息,然后提交到网站服务器端进行处理(如数据录入和用户登录、注册等)。
用户表单是Web开发的一项基本功能,Django的表单功能由Form类实现,主要分为两种:django.forms.Form和django.forms.ModelForm。前者是一个基础的表单功能,后者是在前者的基础上结合模型所生成的数据表单。
1、初识表单
传统的表单生成方式是在模板文件中编写HTML代码实现,在HTML语言中,表单由标签实现。表单生成方式如下:
<!DOCTYPE html>
<html>
<body>
<form action="" method="post">
First name:<br>
<input type="text" name="firstname" value="Mickey">
<br>
Last name:<br>
<input type="text" name="lastname" value="Mouse">
<br><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
一个完整的表单主要有4个组成部分:提交地址、请求方式、元素控件和提交按钮。其说明如下:
- 提交地址用于设置用户提交的表单数据应由哪个URL接收和处理,由控件的属性action决定。当用户向服务器提交数据时,若属性action为空,则提交的数据应由当前的URL来接收和处理,否则网页会跳转到属性action所指向的URL地址。
- 请求方式用于设置表单的提交方式,通常是GET请求或POST请求,由控件 的属性method决定。
- 元素控件是供用户输入数据信息的输入框。由HTML的控件实现,其控件属性type用于设置输入框的类型,常用的输入框类型有文本框、下拉框和复选框等。
- 提交按钮供用户提交数据到服务器,该按钮也是由HTML的控件实现的。但该按钮具有一定的特殊性,因此不归纳到元素控件的范围内。
上述的表单实现方式较为简单,但是实际使用时,表单数据会有很多,上述的方式就会有很大的代码量同时也不好维护,所以Django提供了更加完善的表单功能,演示之前,对之前的项目做出席位调整:在MyDjango的index中添加了空白文件form.py,该文件主要用于编写表单的实现功能,文件夹可自行命名;同时在文件夹templates中添加模板文件dataform.html,该文件用于将表单的数据显示到网页上。最后在文件form.py、views.py和data_form.html中分别添加以下代码:
#form.py代码,定义ProductForm表单对象
from django import forms
from .models import *
class ProductForm(forms.Form):
name = forms.CharField(max_length=20, label='名字')
weight = forms.CharField(max_length=50, label='重量')
size = forms.CharField(max_length=50, label='尺寸')
#设置下拉框的值
choices_list = [(i+1, v['type_name'])for i, v in enumerate(Product.objects.values('name'))]
type = forms.ChoiceField(choices=choices_list, label='产品类型')
#views.py代码,将表单ProductForm实例化并将其传递到模板中生成网页内容
from django.shortcuts import render
from .form import *
def index(request):
product = ProductForm()
return render(request, 'data_form.html', locals())
# data_form.html 代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% if product.errors %}
<p>
数据出错啦,错误信息:{{product.errors}}.
</p>
{%else%}
<form action=""method="post">
{% csrf_token%}
<table>
{{product.as_table}}
</table>
<input type="submit"value="提交">
</form>
{%endif%}
</body>
</html>
代码说明:
(1)在form.py中定义表单ProductForm,表单以类的形式表示。在表单中定义了不同类型的类属性,这些属性在表单中称为表单字段,每个表单字段代表HTML里的一个控件,这是表单的基本组成单位。
(2)在views.py中导入form.py所定义的ProductForm类,在视图函数index中对ProductForm实例化生成对象product,再将对象product 传递给模板data_form.html。
(3)模板 data_form.html将对象product以HTML的
效果如下:
2、表单的定义
从上面的例子发现,Django的表单功能主要是通过定义表单类,再由类的实例化生成HTML的表单元素控件,这样可以在模板中减少HTML的硬编码。每个HTML的表单元素控件由表单字段来决定,例如:从表单字段转换HTML元素控件可以发现:
- 字段name的参数label将转换成HTML的标签
- 字段name的forms.CharField类型转换成HTML的控件,标签是一个输入框控件,type="text”代表当前输入框为文本输入框,参数type用于设置输入框的类型。
- 字段name的命名转换成控件的参数name,表单字段的参数max_length将转换成控件的参数required maxlength。
除了上述,Django还提供多种扁担字段,如下:
表单字段除了转换HTML控件之外,还具有一定的数据格式现范,数据格式规范主要由字段类型和字段参数共同实现。每个不同类型的表单字段都有一些自己特殊的参数,但每个表单字段都具有如下的共同参数。
3、表单与模型
我们知道Django的表单分为两种:django.forms.Form和django.forms.ModelForm。前者是一个基础的表单功能,后者是在前者的基础上结合模型所生成的数据表单。数据表单是将模型的字段转换成表单的字段,再从表单的字段生成HTML的元素控件,这是日常开发中常用的表单之一。
演示如下,首先在form.py定义ProductModelForm,该表单继承自父类forms.ModelForm。这里的例子用于理解模型和表单的交互,并不是同一个模型哈。[惊愕]
# 表单和模型
from django import forms
from .models import *
from django.core.exceptions import ValidationError
#数据库表单
class ProductModelForm(forms.ModelForm):
#添加模型外的表单字段
productId = forms.CharField(max_length=20, label='产品序号')
#模型与表单设置
class Meta:
#绑定模型
model = Performer
#fields属性用于设置转换字段,'all'是将全部模型字段转换成表单字段
#fields='all
fields=['id','name','nationality','masterpiece']
#exclude用于禁止模型字段转换表单字段
exclude=[]
#1abe1s设置HTML元素控件的1abe1标签
labels={
'id':'产品编号',
'name':'姓名',
'nationality':'国籍',
'masterpiece':'尺寸',
}
#定义widgets,设置表单字段的CSS样式
widgets={
'name':forms.widgets.TextInput(attrs={'class':'cl'}),
}
#定义字段的类型,一般情况下模型的字段会自动转换成表单字段
field_classes={
'name':forms.CharField
}
#帮助提示信息
help_texts={
'name':''
}
#自定义错误信息
error_messages={
#al1设置全部错误信息
'__all__':{'required':'请输入内容',
'invalid':'请检查输入内容'
},
#设置某个字段的错误信息
'nationality':{'required':'请输入重量数值',
'invalid':'请检查数值是否正确'}
}
#自定义表单字段weight的数据清洗
def clean_weight(self):
#获取字段weight的值
data=self.cleaned_data['nationality']
return data+'g'
上述代码中,表单类ProductModelForm可分为三大部分:添加模型外的表单字段、模型与表单设置和自定义表单字段weight的数据清洗函数,说明如下:
- 添加模型外的表单字段是在模型已有的字段下添加额外的表单字段。
- 模型与表单设置是将模型的字段转换成表单字段,由类Meta的属性实现两者的字段转换。
- 自定义表单字段weight的数据清洗函数只适用于字段weight的数据清洗。
综上所述,模型字段转换成表单字段主要在类Meta中实现。在类Meta中,其属性说明如下:
值得注意的是,一些较为特殊的模型字段在转换表单时会有不同的处理方式。例如模型字段的类型为AutoField,该字段在表单中不存在对应的表单字段;模型字段类型为ForeignKey和Many ToManyField,在表单中对应的表单字段为ModelChoiceField和ModelMultipleChoiceField。
自定义表单字段weight的数据清洗函数是在视图函数中使用cleaned_data方法时,首先判断当前清洗的表单字段是否已定义数据清洗函数。例如上述的clean_weight函数,在清洗表单字段weight的数据时会自动执行该自定义函数。在自定义数据清洗函数时,必须以“clean字段名”的格式作为函数名,而且函数必须有return返回值。如果在函数中设置ValidationError了异常抛出,那么该函数可视为带有数据验证的清洗函数。
二、后台系统
Admin后台系统也称为网站后台管理系统,主要用于对网站前台的信息进行管理,如文字、图片、影音和其他日常使用文件的发布、更新、删除等操作,也包括功能信息的统计和管理,如用户信息、订单信息和访客信息等。简单来说,就是对网站数据库和文件的快速操作和管理系统,以使网页内容能够及时得到更新和调整。
1、走进Admin
当一个网站上线之后,网站管理员是通过网站后台系统对网站进行管理和维护的。Django已内置了强大的Admin后台系统,在创建Django项目的时候,可以从配置文件settings.py中看到项目已默认启用Admin后台系统。在INSTALLEDAPPS中已配置了Django的Admin后台系统,如果网站不需要Admin后台系统,可以将配置信息删除,这样可以减少程序对系统资源的占用。此外,在根目录的urls.py中也可以看到Admin的URL地址信息,我们在浏览器上输入http://127.0.0.1:8000/admin 就能访问Admin后台系统,如下所示。
在访问Admin后台系统时,首先需要输入用户的账号和密码登录才能进入后台管理界面。创建用户的账号和密码之前,必须确保项目的模型在数据库中有相应的数据表。
如果Admin后台系统以英文的形式显示,那么我们还需要在项目的settings.py中设置MIDDLEWARE中间件,将后台内容以中文形式显示。添加的中间件是有先后顺序的,具体设置如下。
完成上述设置后,下一步是创建用户的账号和密码,创建方法由Django的管理工具manage.py完成,在PyCharm的Terminal模式下输入创建指令,代码如下:
python manage.py createsuperuser
然后一步步设置账号名和邮箱以及地址,在创建用户信息时,用户名和邮箱地址可以为空,如果用户名为空会默认使用计算机的用户名,而设置用户密码时,输入的密码不会显示在计算机的屏幕上。完成用户创建后,打开数据表auth_user可看到新增了一条用户信息,如下所示。
然后再登录界面登录就可进入后台管理系统,界面如下:
在Admin后台系统中可以看到,主要功能分为站点管理、认证和授权、用户和组,说明如下:
- 站点管理是整个网站的App管理界面,主要管理Django的App下所定义的模型。
- 认证和授权是Django内置的认证系统,也是项目的一个App。
- 用户和组是认证和授权所定义的模型,分别对应数据表auth_user 和auth_
user groups。
若我们想把已经建立的app index的模型添加在管理系统,只需要在index的admin.py中添加如下代码:
from django.contrib import admin
from .models import *
# Register your models here.
#方法一
#将模型直接注册到admin后台
admin.site.register(Performer)
#方法二:
#自定义ProductAdmin 类并继承 ModelAdmin
#注册方法一,使用Python 装饰器将ProductAdmin 和模型Product绑定并注册到后台
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
#设置显示的字段
list_display = ['id','name', 'type']
#注册方法二
#admin.site.register(Product,ProductAdmin)
上述代码以两种方法将数据表注册到Admin后台系统,方法一是基本的注册方式;方法二是通过类的继承方式实现注册。日常的开发都是采用第二种方法实现的,实现过程如下:
- 自定义ProductAdmin类,使其继承ModelAdmin。ModelAdmin主要设置模型信息如何展现在Admin后台系统中。
- 将ProductAdmin类注册到Admin后台系统中有两种方法,两者都是将模型Product和ProductAdmin类绑定并注册到Admin后台系统。
效果展示:
2、Admin的基本配置
前面,我们将数据表成功展现在站点管理的页面,但对一个不会网站开发的使用者来说,可能无法理解INDEX和Products的含义,而且用英文表示也会影响整个网页的美观。因此,我们需要将INDEX和Products转换成具体的中文内容。将INDEX和Products设置中文显示需要分别使用不同的方法实现,因为INDEX和Products在项目中分别代表不同的意思,前者是一个App的命名,后者是一个App中定义的模型。
首先实现INDEX的中文显示,主要由App的__init.py文件实现,实现代码如下:
#INDEX设置中文,代码编写在App(index)的_init.py文件中
from django.apps import AppConfig
import os
#修改App在Admin后台显示的名称
#default_app_config的值来自apps.py的类名
default_app_config='index.IndexConfig'
#获取当前App的命名
def get_current_app_name(_file):
return os.path.split(os.path.dirname(_file))[-1]
#重写类IndexConfig
class IndexConfig(AppConfig):
name=get_current_app_name(__file__)
verbose_name='网站首页'
当项目启动时,程序会从初始化文件__init获取重写的IndexConfig类,类属性verbosename用于设置INDEX的中文内容。
然后将模型设置中文显示,在models.py中设置类Meta的类属性verbose_name_plural即可实现。值得注意的是,Meta的类属性还有verbose_name,两者都能设置Products的中文内容,但verbose_name是以复数形式表示的,如将Products设置为“演员信息”,verbose_name会显示为“演员信息s”,实现代码如下:
class Performer(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=20)
nationality = models.CharField(max_length=20)
masterpiece = models. CharField(max_length=50)
class Meta:
# 如只设置 verbose_name,在Admin会显示为”产品信息s"
# verbose_name ='演员信息'
verbose_name_plural = '演员信息'
除此之外,我们还可以进一步完善Admin网页标题信息,在App的admin.py文件中编写以下代码:
#修改title和header
admin.site.site_title = 'MyDjango后台管理'
admin.site.site_header = 'MyDjango'
效果如下:
当一个数据表中存储了成千上万的数据,在Admin中查找该表的某条数据信息时,如果不使用一些查找功能,是无法精准地找到需要的数据信息的。为解决这个问题,可以在admin.py中进一步优化ProductAdmin,优化代码如下:
@admin.register(Performer)
class ProductAdmin(admin.ModelAdmin):
#设置显示的字段
list_display = ['id','name', 'nationality','masterpiece']
#注册方法二
#admin.site.register(Product,ProductAdmin)
# 设置可搜索的子段开在Admin后台数据生成搜系框,如有外键,应使用双下画线连接两个模型的字段
search_fields = ['id','name', 'nationality','masterpiece']
# 设置过滤器,在后台数据的右侧生成导航栏,如有外键,应使用双下画线连接两个模型的字段
list_filter=['name', 'nationality','masterpiece']
# 设置排序方式,['id']为升序,降序为[’-id']
ordering = ['id']
# 设置时间选择器,如字段中有时间格式才可以使用
# date hierarchy=Field
# 在添加新数据时,设置可添加数据的字段
fields = ['name', 'nationality','masterpiece']
# 设置可读字段,在修改或新增数据时使其无法设置
readonly_fields=['name']
值得注意的是,如果readonly_fields和fields属性设置了模型的同一个字段,那么在新增数据的时候,该模型字段是无法输入数据的。例如上述设置的字段name,在新增数据时,该字段的值默认为空并且无法输入数据,效果如图。
前面的章节讲述了Admin的基本设置,但实际上每个网站的功能和需求都是各不相同的,这也导致了Admin 后台功能有所差异。因此,通过重写ModelAdmin的方法可以实现Admin的二次开发,满足多方面的开发需求,这部分内容将在后面文章讲解。