玩转Django2.0---Django笔记建站基础七(表单与模型)
第七章 表单与模型
表单是搜集用户数据信息的各种表单元素的集合,作用是实现网页上的数据交互,用户在网站输入信息,然后提交到网站服务器端进行处理(如数据录入和用户登录、注册等)。
用户表单是web开发的一项基本功能,Django的表单功能有Form类实现,主要分为两种:django.forms.Form和django.forms.ModelForm。前者是一个基础的表单功能,后者是在前者的基础上结合模型所生成的数据表单。
7.1 初识表单
传统的表单生成方式是在模板文件总编写HTML代码实现,在HTML语言中,表单由<form>标签实现。表单生成方式如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>表单</title>
</head>
<body>
#表单
<form action="" method="post">
First name:<br>
<input type="text" name="firstname" value="Mickey">
<br>
Last name:<br>
<input type="submit" value="Submit">
#表单
</form>
</body>
</html>
一个完整的表单主要有4个组成部分:提交地址、请求方式、元素控件和提交按钮。其说明如下:
1、提交地址用于设置用户提交的表单数据应有那个URL接收和处理,由控件<form>的属性action决定。当用户向服务器提交数据时,若属性action为空,则提交的数据应有当前的URL来接收和处理,否则网页会跳转到属性action所指向的URL地址。
2、请求方式用于设置表单的提交方式,通常是GET请求或POST请求,由控件<form>的属性method决定。
3、元素控件是供用户输入数据信息的输入框。由HTML的<input>控件实现,其控件属性type用于设置输入框的类型,常用的输入框类型有文本框、下拉框和复选框等。
4、提交按钮供用户数据到服务器,该按钮也是由HTML的<input>控件实现的。但该按钮具有一定的特殊性,因此不归纳到元素控件的范围内。
在模板文件中,直接编写表单是一种较为简单的实现方式,如果表单元素较多,会在无形之中增加模板的代码量,这样对日后的维护和更新造成极大的不便。为了简化表单的实现过程和提高表单的灵活性,Django提供了完善的表单功能。下面是对MyDjango的目录调整:
在MyDjango的index中添加了空白文件form.py,该文件主要用于编写表单的实现功能,文件夹可自行命名;同时在文件夹templates中添加模板文件data_form.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(Type.objects.values('type_name'))]
type = forms.ChoiceField(choices=choices_list, label='产品类型') #views.py代码,将表单ProductForm实例化并将其传递到模板中生成网页内容
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>
</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>
上述代码演示了Django内置表单功能的使用方法,主要由form.py、views.py和data_form.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的<table>的形式展现在网页上:
7.2 表单的定义
以上面的例子为例,Django的表单功能主要是通过定义表单类,再由类的实例化生成HTML的表单元素控件,这样可以在模板中减少HTML的硬编码。每个HTML的表单元素控件由表单字段来决定,代码如下:
#表单类ProductForm的表单字段name
name = forms.CharField(max_length=20, label='名字',) #表单字段name所生成的HTML元素控件
<tr>
<th><label for="id_name">名字:</label></th>
<td><input type="text" name="name" id="id_name" required maxlength=""></td>
</tr>
从表单字段转换HTML元素控件可以发现:
1、字段name的参数label转换成HTML的标签<label>
2、字段name的forms.pyCharField类型转换成HTML的<input type="text">控件,标签<input>是一个输入框控件,type="text"代表当前输入框为文本输入框,参数type用于设置输入框的类型。
3、字段name的命名转换成<input>控件的参数name,表单字段的参数max_length将转换成<input>控件的参数required maxlength。
除了上述表单字段外,Django还提供多种内置的表单字段,如下表:
字段 | 说明 |
BooleanField | 复选框,如果字段带有required=True,复选框被勾选上 |
CharField | 文本框,参数max_length和min_length分别设置输入长度 |
ChoiceField | 下拉框,参数choices设置数据内容 |
TypedChoiceField | 与ChoiceField相似,但比ChoiceField多出参数coerce和empty_value,分别代表强制转换数据类型和用于表示空值,默认为空字符串 |
DateField | 文本框,具有验证日期格式的功能,参数input_formats设置日期格式 |
EmailField | 文本框,验证输入数据是否为合法的邮箱地址。可选参数为max_length和min_length |
FileField | 文件上传功能,参数max_length和allow_empty_file分别用于设置文件名的最大长度和文件内容是否为空 |
FilePathField | 在特定的目录选择并上传文件,参数path是必需参数,参数recursive、match、allow_files和allow_folders为可选参数 |
FloatField | 验证数据是否为浮点数 |
ImageField | 验证文件是否为Pillow库可识别的图像格式 |
ImtegerField | 验证数据是否为整型 |
GenericIPAddressField | 验证数据是否为有效数值 |
SlugField | 验证数据是否只包括字母、数字、下划线及字符 |
TimeField | 验证数据是否为datetime.time或指定特定时间格式的字符串 |
URLField | 验证数据是否为有效的URL地址 |
从上表可以看出,表单字段除了转换HTML控件之外,还具有一定的数据格式规范,数据格式规范主要由字段类型和字段参数共同实现。每个不同类型的表单字段都有一些自己特殊的参数,但每个表单字段都具有如下表的共同参数:
参数 | 说明 |
Required | 输入数据是否为空,默认值为True |
Widget | 设置HTML控件的样式 |
Label | 用于生成Label标签或显示内容 |
Initial | 设置初始值 |
help_text | 设置帮助提示信息 |
error_messages | 设置错误信息,以字典格式表示:{'required': '不能为空', 'invalid': '格式错误‘} |
show_hidden_initial | 值为True/False,是否在当前差距后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入值是否一致) |
Validators | 自定义数据验证规则。以列表格式表示,列表元素为函数命名 |
Localize | 值为True/False,是否支持本地和,如不同时区显示相应的时间 |
Disabled | 值为True/False,是否可以编辑 |
label_suffix | Label内容后缀,在Label后添加内容 |
根据上面表的参数说明,我们对form.py的表单ProductForm的字段进行优化,代码如下:
from django import forms
from .models import *
from django.core.exceptions import ValidationError #自定义数据验证函数
def weight_validate(value):
if not str(value).isdigit():
raise ValidationError('请输入正确的重量') class ProductForm(forms.Form):
#设置错误信息并设置样式
name = forms.CharField(max_length=20,
label='名字',
widget=forms.widgets.TextInput(attrs={'class': 'c1'}),
error_messages={'required': '名字不能为空'},)
#使用自定义数据验证函数
weight = forms.CharField(max_length=50,
label='重量',
validators=[weight_validate])
size = forms.CharField(max_length=50, label='尺寸')
#获取数据库数据
choices_list = [(i+1,v['type_name']) for i,v in enumerate(Type.objects.values('type_name'))]
#设置CSS样式
type = forms.ChoiceField(widget=forms.widgets.Select(attrs={'class':'type','size':''}),
choices=choices_list, label='产品类型')
优化的代码分别使用了参数widget、label、error_messages和validators,这4个参数是实际开发中常用的参数,参数说明如下:
1、参数widget是一个forms.widgets对象,其作用是设置表单字段的CSS样式。widget的对象类型应与表单字段类型相符合,如果字段类型为CharField和widget的对象类型为forms.widgets.TextInput,这两者的含义与作用是一致的,都代表文本输入框;如果字段类型为CharField和widget的对象类型为forms.widgets.TextInput,前者是下拉选择框,后者是文本输入框,那么在网页上就会优先显示为文本输入框。
2、参数label会转换成HTML的标签<label>,作用是对控件的描述和命名,方便用户理解控件的作用与含义。
3、参数error_messages用于设置数据验证失败后的错误信息,参数值以字典的形式表示,字典的键为表单字段的参数名,字典的值为错误信息。
4、参数validators用于自定义数据验证函数,当用户提交表单数据后,首先执行自定义的验证函数,当数据验证失败后,会抛出自定义的异常信息。所以,字段中设置了参数validators,就无须设置参数error_messages,因为数据验证已由参数validators优先处理。
为了进一步验证优化后的表单是否正确运行,我们对views.py的视图函数index代码优化如下:
#views.py代码,对表单提交的数据进行处理
def index(request):
#GET请求
if request.method == 'GET':
product = ProductForm()
return render(request, 'data_form.html', locals())
#POST请求
else:
product = ProductForm(request.POST)
if product.is_valid():
#获取网页空间name的数据
#方法一
name = product['name']
#方法二
#cleaned_data将控件name的数据进行清洗,转换成Python数据类型
cname = product.cleaned_data['name']
return HttpResponse('提交成功')
else:
#将错误信息输出,error_msg是将错误信息以json格式输出
error_msg = product.errors.as_json()
print(error_msg)
return render(request, 'data_form.html', locals())
以上述代码是views.py的视图函数index进行优化,优化说明如下:
1、首先判断用户的请求方式,不同的请求方式执行不同的程序处理。函数index分别对GET和POST请求做了不同的响应处理。
2、用户在浏览器中访问http://127.0.0.1:8000/index/,等同于向MyDjango发送一个GET请求,函数index将表单ProductForm实例化并传递给模板,由模板引擎生成HTML表单返回给用户。
3、当用户在网页上输入相关信息后单击"提交"按钮,等同于向MyDjango发送一个POST请求,函数index首先获取表单数据对象product,然后由is_valid()对数据对象product进行数据验证。
4、如果验证成功,可以使用product['name']或product.cleaned_data['name']方法来获取用户在某个控件上的输入值。只要将获取到的输入值和模型相互使用,就可以实现表单与模型的信息交互。
5、如果验证失败,使用errors.as_json()方法获取验证失败的信息,然后将验证失败的信息通过模板返回给用户。
从上述例子发现,模板data_form.html的表单是使用HTML的<table>标签展现在网页上,除此之外,表单还可以使用其他HTML标签展现,只需将模板data_form.html的对象product使用以下方法即可生成其他HTML标签:
#将表单生成HTML的ul标签
{{ product.as_ul }}
#将表单生成HTML的p标签
{{ product.as_p }}
#生成单个HTML元素控件
{{ product.type }}
#获取表单字段的参数label属性值
{{ product.type.label }}
7.3 模型与表单
Django的表单分为两种:django.forms.Form和django.forms.ModelForm。前者是一个基础的表单功能,后者是在前者的基础上结合模型所生成的数据表单。数据表单是将模型的字段转换成表单的字段,再从表单的字段生成HTML的元素控件,这是日常开发中常用的表单之一。本节通过讲解表单功能模块ModelForm实现表单数据与模型数据之间的交互开发。
首先在文件form.py中定义表单ProductModelForm,该表单继承自父类forms.ModelForm。代码如下:
#forms.py里面的数据库表单
class ProductModelForm(forms.ModelForm):
#添加模型外的表单字段
productId = forms.CharField(max_length=20, label='产品序号')
#模型与表单设置
class Meta:
#绑定模型
model = Product
#fields属性用于设置转换字段,’__all__'是将全部模型字段转换成表单字段
#fields = '__all__'
fields = ['name','weight','size','type']
#exclude用于禁止模型字段转换表单字段
exclude = []
#labels设置HTML元素控件的label标签
labels = {
'name': '产品名称',
'weight': '重量',
'size': '尺寸',
'type': '产品类型'
}
#定义widgets,设置表单字段的CSS样式
widgets = {
'name': forms.widgets.TextInput(attrs={'class': 'cl'}),
}
#定义字段的类型,一般情况下模型的字段会自动转换成表单字段
field_classes = {
'name': forms.CharField
}
#帮助提示信息
help_texts = {
'name': ''
}
#自定义错误信息
error_messages = {
#__all__设置全部错误信息
'__all__': {'required': '请输入内容',
'invalid': '请检查输入内容'},
#设置某个字段的错误信息
'weight': {'required': '请输入重复数值',
'invalid': '请检查数值是否正确'}
}
#自定义表单字段weight的数据清洗
def clean_weight(self):
#获取字段weight的值
data = self.cleaned_data['weight']
return data+'g'
上述代码中,表单类ProductModelForm可分为三大部分:添加模型外的表单字段、模型与表单设置和自定义表单字段weight的数据清洗函数,说明如下:
1、添加模型外的表单字段是在模型已有的字段下添加额外的表单字段。
2、模型与表单设置是将模型的字段转换成表单字段,由类Meta的属性实现两者的字段转换
3、自定义表单字段weight的数据清洗函数只只是用于字段weight的数据清洗。
模型字段转换成表单字段主要在类Meta中实现。在类Meta中,其属性说明如下:
属性 | 说明 |
Model | 必需属性,用于绑定Model对象 |
Fields | 必须属性,设置模型内那些字段转换成表单字段。属性值为'__all__'代表整个模型的字段,若设置一个或多个,使用列表或元组的数据格式表示,列表或元组里的元素是模型的字段名 |
Exclude | 可选属性,与fields相反,禁止模型内那些字段转换成表单字段。属性值以列表或元组表示,若设置了该属性,则属性fields可以不用设置 |
Labels | 可选属性,设置表单字段里的参数label。属性值以字典表示,字典里的键是模型的字段 |
Widgets | 可选属性,设置表单字段里的参数widget |
field_classes | 可选属性,将模型的字段类型重新定义为表单字段类型,默认情况下,模型字段类型会字段转换为表单字段类型 |
help_texts | 可选属性,设置表单字段里的参数 |
error_messages | 可选属性,设置表单字段里的参数error_messages |
值得注意的是,一些较为特殊的模型字段在转换表单时会有不同的处理方式。例如模型字段的类型为AutoField,该字段在表单中不存在对应的表单字段;模型字段类型为ForeignKey和ManyToManyField,在表单中对应的表单字段为ModelChoiceField和ModelMultipleChoiceField。
自定义表单字段weight的数据清洗函数是在视图函数中使用cleaned_data方法时,首先判断当前清洗的表单字段是否已定义数据清洗函数。例如上述的clean_weight函数,在清洗表单字段weight的数据时会自动执行该自定义函数。在自定义数据清洗函数时,必须以"clean_字段名"的格式作为函数名,而且函数必须有return返回值。如果在函数中设置ValidationError了异常抛出,那么该函数可视为带有数据验证的清洗函数。
7.4 数据表单的使用
上一节通过定义表单类ProductModelForm将模型Product与表单相互结合起来,这节将通过表单类ProductModelForm在网页上生成HTML表单。现在使用前面的data_form.html,在MyDjango的url.py和views.py中分别定义新的URL地址和视图函数,代码如下:
#urls.py的URL地址信息
path('<int:id>.html', views.models_index), #views.py的视图函数model_index
def models_index(request, id):
if request.method == 'GET':
instance = Product.objects.filter(id=id)
# 判断数据是否存在
if instance:
product = ProductModelForm(instance=instance[0])
else:
product = ProductModelForm()
return render(request, 'data_form.html', locals())
else:
product = ProductModelForm(request.POST)
if product.is_valid():
#获取weight的数据,并通过clean_weight进行清洗,转换成Python数据类型
weight = product.cleaned_data['weight']
#数据保存方法一
#直接将数据保存到数据库
#product.save()
#save方法设置commit=False,将生成数据库对象product_db,然后对该对象的属性值修改并保存
product_db = product.save(commit=False)
product_db.name = '我的iPhone'
product_db.save()
#数据保存方法三
#save_m2m()方法用于保存ManyToMany的数据模型
#product.save_m2m()
return HttpResponse('提交成功!weight清洗后的数据为:'+weight)
else:
#将错误信息输出,error_msg是将错误信息以json格式输出
error_msg = product.errors.as_json()
print(error_msg)
return render(request, 'data_form.html', locals())
函数model_index的处理逻辑和7.2节的函数index大致相同,说明如下:
1、首先判断用户的请求方式,不同的请求方式执行不同的处理程序。代码分别对GET和POST请求做了不同的响应处理。
2、若当前请求为GET请求,函数根据URL传递的变量id来查找模型Product的数据,如果数据存在,模型的数据以参数的形式传递给表单ProductModelForm的参数instance,在生成网页时,模型数据会填充到对应的元素控件上。
3、若当前请求为POST请求,函数首先对表单数据进行验证,若验证失败,则返回失败信息;若验证成功,则使用cleaned_data方法对字段weight进行清洗,字段weight清洗由自定义函数clean_weight完成,最后将表单数据保存到数据库,保存数据有三种方式,具体说明可看代码注释,运行结果如下:
我们在views.py中实现了表单ProductModelForm的使用。在实现过程中,有以下疑问:
1、当请求方式为GET的时候,设置表单ProductModelForm的参数instance相当于为表单进行初始化,那么表单的初始化有哪些方法?
2、上图的下拉框数据是一个模型Type对象,如果将模型Type的字段type_name的数据在下拉框中展示呢。
3、将表单数据保存到数据库中,三种保存方式有什么区别?
针对疑问一,表单的初始化有4种方法,每一种方法都有自己的使用方法:
(1) 在视图函数中对表单类进行实例化,可以设置实例化对象的参数initial。例如ProductModelForm(initital={'name':value}),参数值以字典的格式表示,字典的键为表单的字段名,这种方法适用于所有表单类。
(2) 在表单类中进行实例化,如果初始化的数据是一个模型对象的数据,可以设置参数instanse,这种方法只是用于ModelForm,如ProductModelForm(instanse=instanse)。
(3) 定义表单字段时,可以对表单字段设置初始化参数initial,此方法不适用于ModelForm,如name=forms.CharField(initial=value)。
(4) 重写表单类的初始化函数__init__(),适用于所有表单类,如在初始化函数__init__()中设置self.fields['name'].initial=value。
上述四种方法中,我们以方法(3)和方法(4)为例,在定义表单类时设置表单的初始化,代码如下:
#数据库表单
class ProductModelForm(forms.ModelForm):
#方法四:重写ProductModelForm类的初始化函数__init__
def __init__(self, *args, **kwargs):
super(ProductModelForm, self).__init__(*args, **kwargs)
self.fields['name'].initial = '我的手机'
#方法三:定义表单字段时,设置参数initial
productId = forms.CharField(max_length=20, label='产品序号', initial='NO1')
重启MyDjango项目,在浏览器上面输入http://127.0.0.1:8000/index/111.html,运行结果如下图:
解决疑问一的表单初始化问题后,我们接着分析疑问二可以发现,下拉框的数据是一个模型Type对象,而下拉框是由模型Product的外键type所生成的,外键type指向模型Type。因此,要解决下拉框的数据问题,可以从定义模型或者定义表单这两方面解决。
定义模型是在定义模型Type时,设置该模型的返回值。当有外键指向模型Type时,模型Type会将返回值返回给外键。在模型中通过重写__str__函数可以设置模型的返回值,代码如下:
#models.py
class Type(models.Model):
id = models.AutoField(primary_key=True)
type_name = models.CharField(max_length=20)
#设置返回值,若不设置,则默认返回Type对象
def __str__(self):
return self.type_name
如果存在多个下拉框,而且每个下拉框的数据分别取不同一个模型的不同字段,那么重写__str__函数可能不太可行。遇到这种情况,可以在定义表单类的时候重写初始化函数__init__(),代码如下:
class ProductModelForm(forms.ModelForm):
#方法四:重写ProductModelForm类的初始化函数__init__
def __init__(self, *args, **kwargs):
super(ProductModelForm, self).__init__(*args, **kwargs)
#设置下拉框的数据
type_obj = Type.objects.values('type_name')
choices_list = [(i+1,v['type_name']) for i,v in enumerate(Type.objects.values('type_name'))]
self.fields['type'].choices = choices_list
#初始化字段name
self.fields['name'].initial = '我的手机'
最后对于疑问三所提及的数据保存,实质上数据保存只有save()和save_m2m()方法实现,在上述代码中所演示的三种保存方式,前两者是save()的参数commit的不同而导致保存方式有所不同。如果参数commit为True,直接将表单数据保存到数据库;如果参数commit为False,这时将生成一个数据库对象,然后可以对该对象进行增删改查等数据操作,再将修改后的数据保存到数据库中。
值得注意的是save()只适合于将数据保存在非多对多数据关系的数据表,而save_m2m()只适合将数据保存在多对多数据关系的数据表。
7.5 本章小结
用户表单是Web开发的一项基本功能,Django的表单功能有Form类实现,主要分为两种:django.forms.Form和django.forms.ModelForm。前者是一个基础的表单功能,后者是在前者的基础上结合模型所生成的数据表单。
一个完整的表单主要有4个组成部分:提交地址、请求方式、元素控件和提交按钮。其说明如下:
1、提交地址用于设置用户提交的表单数据应由哪个URL接受和处理,由控件<form>的属性action决定。当用户向服务器提交数据时,若属性action为空,提交的数据应由当前的URL来接收和处理,否则网页会跳转到属性action所指向的URL地址。
2、请求方式用于设置表单的提交方式,通常是GET请求或POST请求,由控件<form>的属性method决定。
3、元素控件是供用户输入数据信息的输入框。由HTML的<input>控件实现,其控件属性type用于设置输入框的类型,常用的输入框类型有文本框、下拉框和复选框等。
4、提交按钮供用户提交数据到服务器,该按钮也是由HTML的<input>控件实现的。但该按钮具有一定的特殊性,因此不归纳到元素控件的范围内容。
Django的表单功能主要是通过定义表单类,再由类的实例化生成HTML的表单元素控件,这样可以在模板中减少HTML的硬编码。每个HTML的表单元素控件由表单字段来决定,代码如下:
#表单类ProductForm的表单字段name
name = forms.CharField(max_length=20, label='名字',) #表单字段name所生成的HTML元素控件
<tr>
<th><label for="id_name">名字:</label></th>
<td><input type="text" name="name" id="id_name" required maxlength=""></td>
</tr>
从表单字段转换HTML元素控件可以发现:
1、字段name的参数label转换成HTML的标签<label>的值。
2、字段name的forms.CharField类型转换成HTML的<input type="text>控件,标签<input>是一个输入框控件,type="text"代表当前输入框为文本输入框,参数type用于设置输入框的类型。
3、表单字段name的命名转换成<input>控件的参数name的值,表单字段name的参数max_length转换成<input>控件的参数required maxlength的值。
数据表单是将模型的字段转换成表单的字段,再从表单的字段生成HTML的元素控件,这是日常开发中常用的表单之一。数据表单以类的形式定义,其内部可分为三大部分:添加模型外的表单字段、模型与表单设置和自定义函数,说明如下:
1、添加模型外的表单字段是在模型已有的字段下添加额外的表单字段。
2、模型与表单设置是将模型的字段转换成表单字段,由类Meta的属性实现两者的字段转换。
3、自定义函数是重写模块ModelForm中的函数,使其符合开发需求,如重写初始化函数__init__和自定义数据清洗函数等。
玩转Django2.0---Django笔记建站基础七(表单与模型)的更多相关文章
- <玩转Django2.0>读书笔记:表单
1. 表单字段 参考: 官方文档 Django表单字段汇总 2. 表单代码示例(forms.Form) # form.py代码 # 获取数据库数据 choices_list = [(i+1,v['ty ...
- 玩转Django2.0---Django笔记建站基础十三(第三方功能应用)
第13章 第三方功能应用 在前面的章节中,我们主要讲述Django框架的内置功能以及使用方法,而本章主要讲述Django的第三方功能应用以及使用方法.通过本章的学习,读者能够在网站开发过程中快速开发网 ...
- 玩转Django2.0---Django笔记建站基础十(二)(常用的Web应用程序)
10.3 CSRF防护 CSRF(跨站请求伪造)也成为One Click Attack或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用,窃取网站的用户信息来制作 ...
- 玩转Django2.0---Django笔记建站基础六(模型与数据库)
第六章 模型与数据库 Django对各种数据库提供了很好的支持,包括:PostgreSQL.MySQL.SQLite和Oracle,而且为这些数据库提供了统一的调用API,这些API统称为ORM框架. ...
- 玩转Django2.0---Django笔记建站基础十一(二)((音乐网站开发))
11.5 歌曲排行榜 歌曲排行榜是通过首页的导航链接进入的,按照歌曲的播放次数进行降序显示.从排行榜页面的设计图可以看到,网页实现三个功能:网页顶部搜索.歌曲分类筛选和歌曲信息列表,其说明如下: 1. ...
- 玩转Django2.0---Django笔记建站基础十一(一)(音乐网站开发)
第十一章 音乐网站开发 本章以音乐网站项目为例,介绍Django在实际项目开发中的应用,该网站共分为6个功能模块分别是:网站首页.歌曲排行榜.歌曲播放.歌曲点评.歌曲搜索和用户管理. 11.1 网站需 ...
- 玩转Django2.0---Django笔记建站基础九(二)(Auth认证系统)
9.4 设置用户权限 用户权限主要是对不同的用户设置不同的功能使用权限,而每个功能主要以模型来划分.以9.3节的MyDjango项目为例,在Admin后台管理系统可以查看并设置用户权限,如下图: 用户 ...
- 玩转Django2.0---Django笔记建站基础九(一)(Auth认证系统)
第九章 Auth认证系统 Django除了有强大的Admin管理系统之外,还提供了完善的用户管理系统.整个用户管理系统可分为三大部分:用户信息.用户权限和用户组,在数据库中分别对应数据表auth_us ...
- 玩转Django2.0---Django笔记建站基础八(admin后台系统)
第八章 admin后台系统 admin后台系统也成为网站后台管理系统,主要用于对网站前台的信息进行管理,如文字.图片.影音和其他日常使用文件的发布.更新.删除等操作,也包括功能信息的统计和管理,如用户 ...
随机推荐
- 负margin的原理及应用
在很多布局中我们经常能够见到类似于margin:-10px;的用法,我们对正值的用法早已熟悉的不能再熟悉了,可是这负值到底有何用呢?听我给你吹. 负margin——普通文档流 普通文档流元素(不浮动, ...
- vue移动端图片上传压缩
上传压缩方法 import {api} from '../../api/api.js'; import axios from 'axios'; export function imgPreview ( ...
- codeforces 572(Div2)A、B、C、D1、D2、E
Cdoeforces 572(Div2)A.B.C.D1.D2.E 传送门:https://codeforces.com/contest/1189 A.题意: 给你一串长为n的字符串,要求你将其切割为 ...
- Visual Studio Team Services使用教程【5】:Readers tfs组成员添加
2017.4.23之后建议朋友看下面的帖子 TFS2017 & VSTS 实战(繁体中文视频) Visual Studio Team Services(VSTS)与敏捷开发ALM实战关键报告( ...
- 本地项目推送到coding
当我们本地新建了一个项目,需要放到coding上维护时,按照下面步骤即可做到. 1.先在coding上新建一个项目,并完成初始化. 2.进入到本地项目的目录下 //初始化本地仓库 a:git in ...
- vue学习笔记(三)class和style绑定
前言 通过上一章的学习vue学习笔记(二)vue的生命周期和钩子函数,我们已经更近一步的知道了关于vue的一些知识,本篇博客将进一步探讨vue其它方面的内容,vue中关于class和style绑定,关 ...
- 线程的通信与协作:sleep、wait、notify、yield、join关系与区别
一.sleep.join.yield.wait.notify.notifyAll 1.sleep() 使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁.也 ...
- 【转载】实现a元素href URL链接自动刷新或新窗口打开
又是我偶像的新文,这个小技巧的用户体验真的非常非常棒! 文章转载自 张鑫旭-鑫空间-鑫生活 http://www.zhangxinxu.com/ 原文链接:https://www.zhangxinxu ...
- $Poj1934\ Trip$ 线性$DP+$搜索
Luogu Description 爱丽丝和鲍伯想去度假,他们每个人都制定了一个参观城市的清单,该地区正好有26个城市,因此它们被编码为小写字母“a”到“z”.清单上可能重复出现某个城市.因为他们想一 ...
- 使用宝塔搭建nextcloud的过程(搭建、优化、问题)
宝塔部署教程 参考网址: 使用NextCloud来搭建我们的私有网盘.并结合Redis优化性能(宝塔) https://www.moerats.com/archives/175/ 宝塔面板下nextc ...