一.Django框架之MTV
项目启动后,用户通过浏览器向Web服务器发起请求,Web服务器将请求传递到要处理该请求的Django项目,Django接收用户通过浏览器发起的请求,urls.py文件根据URL地址分发路由,将请求交给views.py中相应的视图;视图处理请求(此时涉及数据存取),并将处理结果与模板结合生成响应数据返回给Web服务器,服务器将数据返回到浏览器,最终呈现给用户。
Django使用MTV架构,该架构由模型(Model)、模板(Template)、视图(View)三部分组成,各部分的职责如下。
- 1. 模型:数据操作层,定义数据模型,封装对数据库层的访问。
- 2. 模板:表现层,负责将页面呈现给用户。
- 3. 视图:业务逻辑层,调用模型和模板,实现业务逻辑。
Django项目的数据模型定义在模型文件models.py中,模板文件存储在templates目录(需手动创建与配置)中,业务逻辑存储在视图文件views.py中。此外Django项目还有一个核心文件urls.py,用于实现路由分发功能。
二.HTML表单
一个典型的HTML表单如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>静态表格</title>
</head>
<body>
<form action="/getdata/" method="post">
<label for="data">请输入数据:</label>
<input id="data" type="text" name="data" value="">
<input type="submit" value="提交">
</form>
</body>
</html>
该表单由静态HTML实现,要直接在浏览器中访问该表单,需将其放在Django项目的static静态资源文件夹中。
1.静态配置内容:
第一步:新建项目文件chapter01,在项目中创建新的应用。
django-admin startproject chapter01
python manage.py app
第二步:在settings.py注册app,配置文件夹templates的路径,以及数据库mysql
#templates路径
'DIRS': [os.path.join(BASE_DIR, 'templates')],
#mysql数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'test',
'HOST':'localhost',
'PORT': 3306,
'USER':'root',
'PASSWORD':'myy040715'
}
}
在settings.py中,默认静态资源URL访问路径配置:
STATIC_URL = '/static/'
第四步:app中创建文件夹:static
第五步:将照片放在static文件夹中
第六步:测试:http:127.0.0.1:8000/static/pic.png
第七步:在static文件夹下创建静态文件(表格.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>静态表格</title>
</head>
<body>
<form action="/getdata/" method="post">
<label for="data">请输入数据:</label>
<input id="data" type="text" name="data" value="">
<input type="submit" value="提交">
</form>
</body>
</html>
测试(http://127.0.0.1:8000/static/表格.html):静态表格
2.共享静态文件
根目录下创建public_statics文件夹(与应用app同级)
在settings.py中配置
STATICFILE_DIRS=[os.path.join(BASE_DIR,'public_statics'),]
3.HTML模板文件
创建静态文件(htmlform.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="/getdata/" method="POST">
{% csrf_token %}
<label for="data">请输入数据:</label>
<input type="data" type="text" name="data" value="{{current_data}}">
<input type="submit" value="提交">
<p>计算得到的值是:{{number}}</p>
</form>
</body>
</html>
定义视图函数(views.py)
from django.shortcuts import render
# Create your views here.
def getdata(request):
data=''
number=''
if 'data' in request.POST:
data=request.POST['data']
number = data * 2
return render(request,'htmlform.html',{'current_data':data,'number':number})
配置根路由(urls.py)
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path('',include('app.urls')),
]
配置子路由:
from django.contrib import admin
from django.urls import path
from app import views
urlpatterns = [
path('getdata/',views.getdata),
]
三.Django表单
模板中的HTML表单中,要改变表单就必须修改模板文件。 Django表单通过扩展django.forms.Form类可在视图中动态生成表单。
1.定义表单类
- 自定义的表单类dataForm继承了django.forms.Form类,它包含一个data字段。
- 字段data的类型为forms.CharField。 表单data字段会被渲染为一个<label>元素和一个<input>元素。
- 表单字段的label参数指定在表单渲染生成的<label>元素中显示的字符串。
定义视图函数(views.py)
from django import forms
class dataForm(forms.Form):
data = forms.CharField(label='请输入数据')
#使用表单类和视图
def useDataForm(request):
if request.method == 'POST':
form = dataForm(request.POST)
msg='数据已提交'
else:
form = dataForm()
msg = '初始表单'
return render(request,'temdataform.html',{'form':form,'msg':msg})
- 在直接使用HTML表单时,视图将数据传递给模板,以便在响应页面中回显数据。
- 在使用Django表单时,视图使用接收到的数据创建表单,先将数据填入表单字段,再将表单对象传递给模板。
创建模板文件(temdataform.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="/dform/" method="POST">
{% csrf_token %}
<table>
{{form}}
</table>
<input type="submit" value="提交">
</form>
{{msg}}
</body>
</html>
配置子路由(urls.py)
path('dform/',views.useDataForm),
2.表单字段渲染方式
- {{ form.as_table }}:表单式样式,默认方式。将字段渲染为包装在表格<tr>元素中的表单元素。
- {{ form.as_p }}:段落样式,将字段渲染为包装在<p>元素中的段落。
- {{ form.as_ul }}:列表样式,将字段渲染为包装在<li>元素中的列表项。
配置视图函数(views.py)
def useDataForm3(request):
return render (request,'temdataform3.html',{'form':dataForm()})
创建模板文件(temdataform3.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
表格样式渲染的结果:
<form action=""method="POST">
{%csrf_token%}
<table>
{{form.as_table}}
</table>
<input type="submit" value="提交">
</form>
<hr>
段落样式渲染的表单
<form action="" method="POST">
{%csrf_token%}
{{form.as_p}}
<input type="submit" value="提交">
</form>
<hr>
列表样式渲染的表单
<form action="" method="post">
{%csrf_token%}
<ul>
{{form.as_ul}}
</ul>
</form>
</body>
</html>
配置子路由(urls.py)
path('dform3/',views.useDataForm3),
3.表单字段类型和参数
表单字段定义包含字段名、字段类型和字段参数3个部分 、
class dataForm(forms.Form):
data = forms.CharField(label='请输入数据') #定义表单字段
data为字段名,字段渲染生成的<label>元素的for属性值为“id_data”,生成的<input>元素的name属性值为“data”、id属性值为“id_data”。CharField为字段类型,label为字段参数。
定义视图函数(views.py)
class dataForm2(forms.Form):
data = forms.CharField(label='请输入数据',)
a = forms.BooleanField(label='a')
sex = forms.ChoiceField(label='sex')
date = forms.DateField(label='date')
def useDataForm4(request):
return render (request,'temdataform4.html',{'form':dataForm2()})
创建模板文件(temdataform4.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="/dform/" method="post">
{%csrf_token%}
<table>
{{form}}
</table>
<input type="submit" value="提交">
</form>
{{msg}}
</body>
</html>
配置子路由(urls.py)
path('dform4',views.useDataForm4),
4.常用表单字段类
(1).required
参数required用于设置当前字段是否为必需字段。
- 默认情况下,所有类型的表单字段的required属性值均为True。如果提供的是None或空字符串,校验数据时会触发ValidationError异常。
- 表单字段的clean()方法用于执行数据清理操作,验证数据的有效性。数据有效时,clean()方法会返回该数据,否则触发ValidationError异常。
#在终端里运行
python manage.py shell
from django import forms
name=forms.CharField()
name.clean('') #报错
name.clean(' ') #报错
name.clean(None) #报错
name.clean(0)
name.clean(True)
name.clean(False)
name.clean(123)
name.clean('as')
(2).label
label参数用于设置表单字段被渲染为HTML <label>元素时的文本内容:
class test(forms.Form):
... name=forms.CharField(label='请输入姓名')
...
>>> print(test())
#在创建表单时,可使用auto_id=False来简化渲染结果
d=test(auto_id=False)
print(d)
(3).label_suffix
label_suffix属性用于设置表单字段被渲染为HTML <label>元素时的文本内容的后缀,默认后缀为英文冒号“:”
>>> class test(forms.Form):
... addr=forms.CharField(label='联系地址',label_suffix='*')
...
>>> print(test())
(4).initial
#initial参数用于设置字段的初始值
>>> class test(forms.Form):
... name=forms.CharField(initial='someone')
...
>>> print(test(auto_id=False))
#也可在创建表单对象时提供初始值:
>>> d=test({'name':'Lining'},auto_id=False)
>>> print(d)
(5).help_text
help_text参数用于设置字段的帮助信息,帮助信息被渲染为<span>元素
class test(forms.Form):
... name=forms.CharField(help_text='姓名包含字母、数字等字符')
...
>>> print(test(auto_id=False))
(5).error_messages
- error_messages用于设置自定义错误信息,它将覆盖默认的错误信息。
- error_messages的参数值为字典对象,其中的每个键值对对应一条校验错误信息
name=forms.CharField(error_messages={'required':'必须提供name字段数据'})
name.clean('11')
(6).disabled
disabled参数被设置为True时,不允许表单字段渲染成的HTML元素与用户交互
class test(forms.Form):
... addr=forms.CharField(label='联系地址',disabled=True)
...
>>> print(test())
5.Form类的字段校验
表单验证即对表单中的数据进行验证,检验表单各个字段的数据是否符合该字段的约束条件。通常,Django根据字段类型执行默认的校验操作。
Django类字段常见验证操作
下面定义一个validate_lt()函数,它在字符串包含小于或大于符号时抛出ValidationError异常。
>>> from django.core.exceptions import ValidationError
>>> def validata_lt(value):
... if"<" in value or ">" in value:
... raise ValidationError("不允许小于号或大于号")
...
>>> str=forms.CharField(validators=[validata_lt]) #定义字段,引用自定义异常函数
>>> str.clean("1<99")
#校验函数内,出现不符合校验标准的情况必须抛出ValidationError异常,异常信息作为校验错误的提示信息
6.Django中的Form模块
request.POST包含了表单采用POST请求方法提交数据,可以使用表单校验传过来的数据是否合法,还能将校验的错误信息保存,还可以判断forms有没有绑定相关的数据。
(1).使用表单数据
- request.POST包含了表单采用POST请求方法提交的数据。
- request.POST中的数据没有被转换为Python类型,也没有经过校验。 表单通过校验时,is_valid()函数返回True。
- 表单中通过校验的数据被包含在cleaned_data字典中。
- 在使用表单数据时,应尽量使用cleaned_data中的数据.
#设置了数据的表单称为绑定表单(is_bound属性为True),没有数据的表单称为未绑定表单(is_bound属性为False)。
>>> class test(forms.Form):
... name=forms.CharField(max_length=50)
... age=forms.IntegerField(max_value=50)
...
>>> d=test() #创建空表单
>>> d.is_bound #结果为False,说明表单未绑定
>>> d=test({}) #绑定空值时,表单也被绑定
>>> d.is_bound #结果为True,说明表单已绑定
>>> d=test({'name':'mike','age':20}) #绑定具体数据
>>> d.is_bound
(2).使用Form校验数据
调用表单is_valid()方法时会执行数据校验,当所有字段数据均合法时,方法返回True,否则返回False。
#打开python manage.py shell的时候,都要导入表单。
>>> from django import forms
class test(forms.Form):
... age=forms.IntegerField(max_value=35)
... name=forms.CharField(max_length=20)
...
>>> d=test({'name':'zhangsan','age':20}) #绑定具体数值
>>> d.is_valid() #字段数据符合form标单参数要求,通过校验
>>> d=test({'name':'xiaoming','age':36})
>>> d.is_valid()
执行校验时,Django为表单对象创建cleaned_data属性。 通过校验的数据是“干净的”,被保存在表单的cleaned_data属性中。 cleaned_data属性只能在执行校验之后访问,否则会触AttributeError异常。
>>> d=test({'name':'xiaoming','age':20})
>>> d.cleaned_data #触发异常
>>> d.is_valid()
True
>>> d.cleaned_data
{'age': 20, 'name': 'xiaoming'}
>>>
如果有数据没有通过校验,is_valid()方法返回Flase,cleaned_data属性中保存了已经通过校验的字段数据,error属性保存未通过校验的字段的错误信息。
>>> d=test({'name':'zhangsan','age':50})
>>> d.is_valid()
>>> d.cleaned_data
- From.errors:它是一个类属性,保存的是校验错误信息。
- errors返回一个字典对象,其中的每个键值对中的键是字段名,值是一个列表对象,列表对象包含错误信息字符串。可以调用as_json()或get_json_data()方法返回包含JSON格式的错误信息。
>>> d.errors.as_json()
>>> d.errors.get_json_data()
(3).使用FRom表单输出
Form对象的另一个作用是将自身转为HTML。为此,我们只需要简单的使用print()方法可以看到From对象的HTML输出。
class test(forms.Form):
... age=forms.IntegerField(max_value=35)
... name=forms.CharField(max_length=20)
...
>>> print(test())
如果表单绑定了数据,则HTML输出包含数据的HTML文本。
d=test({'name':'zhangsan','age':50})
>>> print(d)
7.手动处理表单字段
手动处理表单字段时可将每个表单字段视为表单属性,通过{{form.name_of_field}}的形式访问。Django允许在表单模板中自定义表单字段的渲染效果。在模板中,用{{form.字段名}}格式来访问表单字段。在表单模板中,也可用{%for%}循环来遍历表单字段。表单字段的常用属性如下。
- {{ form.字段名.label }}:字段的label文本,例如,“姓名”。
- {{ form.字段名.label_tag }}:封装在HTML <label>元素中的label文本,包含表单的 label_suffix。
- {{ form.字段名.value }}:字段值。
- {{ form.字段名.help_text }}:字段的帮助文本。
- {{ form.字段名.errors }}:字段未通过验证时的错误信息。
- {{ form.字段名.field }}:表单字段的 BoundField实例对象,用于访问字段属性。例如, {{ form.name.field.max_length }} 。
相比较Django对表单字段的自动解析,手动处理更加灵活,开发者可以有选择的处理字段,也可以调整字段顺序。下面定义成绩表单的例子
定义视图函数(views.py)
class test(forms.Form):
name=forms.CharField(max_length=50,label='姓名')
age=forms.IntegerField(max_value=50,min_value=15,label="年龄",help_text='年龄小于15且不大于50')
def useTest(request):
if request.method == 'POST':
form = test(request.POST)
else:
form = test()
return render(request, 'temtest.html', {'form': form})
创建模板文件(temtest.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="/diyfield/" method="POST">
{% csrf_token %}
<div>{{form.name.label}}={{form.name}}</div>
<div>{{form.age.label}}={{form.age}}{{form.age.help_text}}</div>
<input type="submit" value="提交">
</form>
</body>
</html>
配置子路由:
path('diyfield/',views.useTest),
8.遍历表单字段
在表单模板中,若每个表单字段使用相同的HTML,也可用{%for%}循环来遍历表单字段。
在templates里面创建模板文件(temtestfor.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h3>遍历表单字段</h3>
<form action="/diyfor/" method="POST">
{%csrf_token%}
{%for field in form%}
<p>
{{field.error}}
<b>{{field.label_tag}}</b>
{{field}}
{%if field.help_text%}
<I>{{field.help_text|safe}}</I>
{%endif%}
</p>
{%endfor%}
</form>
<input type="submit" value="提交">
</body>
</html>
定义视图函数(views.py)
def useTestFor(request):
return render (request,'temtestfor.html',{'form':test()})
配置子路由:
path('diyfor/',views.useTestFor),
四.表单集
表单集是表单对象的集合,用于处理多个表单。利用表单集,用户可以同时提交一组表单,在数据库中添加多条记录。
1.创建表单集
可调用django.forms模块提供的formset_factory()工厂类方法创建表单集类,定义视图(views.py)
#创建表单集
class GoodForm(forms.Form):
name = forms.CharField(label='商品')
price = forms.DecimalField(label='价格')
stock = forms.IntegerField(label='库存')
sales = forms.IntegerField(label='销量')
from django.forms import formset_factory
from django.shortcuts import render
def useFormset(request):
classTestFormset = formset_factory(GoodForm, extra=2)
if request.method == 'POST':
formset = classTestFormset(request.POST)
else:
formset = classTestFormset()
return render(request, 'temformset.html', {'formset': formset})
创建模板文件(temformset.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>商品表单集合</title>
</head>
<body>
<h1>商品表单集合</h1>
<form action="" method="POST">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset.forms %}
{{ form.as_p }}
{% endfor %}
<input type="submit" value="提交">
</form>
</body>
</html>
配置子路由(app里面urls.py)
path('formset/',views.useFormset),
表单集中的表单分为空表单和非空表单,表单集中空表单的数量默认为1。在页面中查看渲染得到的HTML代码可以发现,代码输出结果中只有一个空表单,这是因为表单集默认只显示一个表单,另外表单集中的表单尚未绑定数据。
如以下可知:extra可以控制表单集中空表单的数量,默认值为1,
设置表单集的初始数据(initial)
像表单一样,以上代码使用initial参数为表单集设置了初始值。由于initial参数接收的字典中只有一个元素, 所以表单集中包含 了一个绑定了初始值的表单和两个空表单。
限制表单的最大数量
利用参数max_num可以控制表单集中表的表单数量。max_num设置为None,那么表单最多包含1000张表单。
五.根据模型创建表单
- 模型表单指绑定到模型的表单。自定义的模型表单需扩展django.forms模块提供的ModelForm类。
- 模型表单基本操作包括定义模型、定义模型表单以及使用模型表单为数据库添加和修改数据。
定义模型(models.py):
from django.db import models
class person(models.Model):
name=models.CharField(max_length=8)
age=models.SmallIntegerField()
生成迁移文件,执行数据的迁移
python manage.py makemigrations
python manage.py migrate
模型表单有两个特点:
- 必须继承django.forms.ModelForm类。
- 提供子类Meta。在Meta的model字段中绑定模型,在fields字段中设置在表单中使用的模型字段。
- 可以使用特殊值“__all__”表示使用模型全部字段,示例代码如下。 fields = '__all__'
- 也可使用exclude属性来排除不使用的字段,示例代码如下。 exclude = ['age']
定义视图函数(views.py):
#模型表单
from .models import person
from django.forms import ModelForm
class personForm(ModelForm):
class Meta:
model = person
fields = '__all__'
def usePersonForm(request):
if request.method == 'POST':
mform = personForm(request.POST)
if mform.is_valid():
ps=person.objects.filter(name=request.POST['name'])
if ps.count()==0:
mform.save()
msg='数据已保存!'
else:
msg='数据库已存在相同姓名的数据,请勿重复提交!'
else:
msg='表单数据有错'
else:
mform = personForm()
msg="请输入数据添加新纪录"
return render(request,'temmodelform.html',{'mform':mform,'msg':msg})
视图在使用POST请求时,视图通过request.POST 获得客户端提交的数据。将requestPOST作为参数初始化表单,执行表单验证操作,可以检查数据是否有效。在数据有效时,用客户端提交的书名作为条件执行查询。当数据库中不存在相同姓名时,执行表单保存操作,将数据写入数据库。
创建模板文件(temmodelform.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="/mform/" method="POST">
{%csrf_token%}
<table>{{mform}}</table>
<input type="submit" value="提交">
</form>
<hr>
{{msg}}
</body>
</html>
配置子路由(urls.py)
path('mform/',views.usePersonForm),
六.自定义模型表单字段
通常情况下,模型表单字段与模型字段保持一致。 Django允许在模型表单中覆盖模型字段定义
定义模型(views.py)
#自定义模型表单字段
from django.forms import ValidationError
def validate_age(value):
if int(value) < 20:
raise ValidationError('年龄不能小于20!',code='min_value')
elif int(value) >50:
raise ValidationError('年龄不能大于50!',code='max_value')
class personFormDIY(ModelForm):
#重定义age字段
age=forms.CharField(validators=[validate_age],label='年龄',\
widget=forms.NumberInput(),\
help_text= '年龄为[20,50]以内的整数')
class Meta:
model=person
fields = ['name','age']
labels = {'name':'姓名'}
help_texts ={'name':'姓名为中英文字符串',}
widgets = {'name' : forms.Textarea(attrs={'cols':30,'rows':2}),}
def usePersonFormDIY(request):
if request.method == 'POST':
mform = personFormDIY(request.POST)
if mform.is_valid():
ps=person.objects.filter(name=request.POST['name'])
if ps.count()==0:
mform.save()
msg='数据已保存!'
else:
msg='数据库已存在相同姓名的数据,请勿重复提交!'
else:
msg='表单数据有错'
else:
mform = personForm()
msg="请输入数据添加新纪录"
return render(request,'temmodelformdiy.html',{'mform':mform,'msg':msg})
创建模板文件(temmodelformdiy.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="/mdiy/" method="POST">
{%csrf_token%}
<table>{{mform.as_p}}</table>
<input type="submit" value="提交">
</form>
<hr>
{{msg}}
</body>
</html>
配置子路由:
path('mdiy/',views.usePersonFormDIY)
七.表单样式优化
1.资源
资源指应用于表单的CSS和JavaScript文件。
当定义表单或小部件时,可以在Media子类中为其定义资源。在渲染表单时,Django会将资源文件包含到HTML中。
2.小部件资源
通过扩展小部件定义表单资源的基本格式如下。 class 自定义小部件类名称(forms.内置小部件类名称):
class Media:
css={'设备类型': ('CSS资源文件URL',……),……}
js= ('JavaScript资源文件URL',……)
Media子类的css属性用于设置CSS资源。css属性中的键设置CSS资源中的样式单适用的设备类型 资源文件的URL可以使用相对路径或绝对路径。CSS和JavaScript资源文件属于静态资源,通常将其放在项目的static文件夹中
可用的类型名称如下。
- all:默认。适用于所有设备。
- aural:语音合成器。
- braille:盲文反馈装置。
- handheld:手持设备。
- projection:投影仪。
- print:打印预览模式或打印页面。
- screen:计算机屏幕。
- tty:电传打字机以及类似的使用等宽字符网格的设备。
- tv:电视机类型设备。
以图6-17的自定义的模型表单bookformly为例,通过css静态文件优化表单样式
第一步:在项目同名文件夹下创建static文件夹,将css样式单文件diyform.css放入static文件夹内
.helptext{
color:cadetblue;
font-size:12px;
}
.errorlist{
color:red;
font-size: 12px;
}
p{
color: darkgoldenrod;
font-size: 18px;
}
body{
background: url(./pic1.jpg) no-repeat center center fixed;
background-size: cover;
padding-top: 20px;
}
form {
width: 543px;
height: 300px;
margin: 0 auto;
padding: 20px;
border: 1px solid rgba(0,0,0,0.2);
border-radius: 5px;
background: rgba(0,0,0,0.5);
overflow: hidden;
}
input{
width: 96px;
height: 28px;
border: 1px solid rgba(255,255,255,0.4);
border-radius: 4px;
display: inline-block;
font-size: 16px;
color: #fff;
background: rgba(255,255,255,0.4) no-repeat 16px 16px;
margin-bottom: 10px;
padding-left: 25px;
padding-right: 20px;
}
修改temmodelformdiy.html,添加{{bform.media}}变量,以及css的链接路径
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="../static/diyform.css">
</head>
<body>
{{bform.media}}
<form action="/mdiy/" method="POST">
{%csrf_token%}
<table>{{mform.as_p}}</table>
<input type="submit" value="提交">
</form>
<hr>
{{msg}}
</body>
</html>