一、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中分别添加以下代码:
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='产品类型')
from django.shortcuts import render
from .form import *
def index(request):
product = ProductForm()
return render(request, 'data_form.html', locals())
<!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=['id','name','nationality','masterpiece']
exclude=[]
labels={
'id':'产品编号',
'name':'姓名',
'nationality':'国籍',
'masterpiece':'尺寸',
}
widgets={
'name':forms.widgets.TextInput(attrs={'class':'cl'}),
}
field_classes={
'name':forms.CharField
}
help_texts={
'name':''
}
error_messages={
'__all__':{'required':'请输入内容',
'invalid':'请检查输入内容'
},
'nationality':{'required':'请输入重量数值',
'invalid':'请检查数值是否正确'}
}
def clean_weight(self):
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 *
admin.site.register(Performer)
@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
list_display = ['id','name', 'type']
??上述代码以两种方法将数据表注册到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文件实现,实现代码如下:
from django.apps import AppConfig
import os
default_app_config='index.IndexConfig'
def get_current_app_name(_file):
return os.path.split(os.path.dirname(_file))[-1]
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_plural = '演员信息'
??除此之外,我们还可以进一步完善Admin网页标题信息,在App的admin.py文件中编写以下代码:
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']
search_fields = ['id','name', 'nationality','masterpiece']
list_filter=['name', 'nationality','masterpiece']
ordering = ['id']
fields = ['name', 'nationality','masterpiece']
readonly_fields=['name']
??值得注意的是,如果readonly_fields和fields属性设置了模型的同一个字段,那么在新增数据的时候,该模型字段是无法输入数据的。例如上述设置的字段name,在新增数据时,该字段的值默认为空并且无法输入数据,效果如图。
??前面的章节讲述了Admin的基本设置,但实际上每个网站的功能和需求都是各不相同的,这也导致了Admin 后台功能有所差异。因此,通过重写ModelAdmin的方法可以实现Admin的二次开发,满足多方面的开发需求,这部分内容将在后面文章讲解。
|