DjangoForm之创建工程
Form是什么东西:
用于验证用户请求数据合法性的一个组件
普通的Form提交的弊端:
1.用户提交数据的验证
2.前台需要进行错误信息的提示
3.需要保留上次用户输入的信息
# 此处是正常的Form的判断操作
"""
def Login(request):
if request.method == "GET":
return render(request, 'login.html')
elif request.method == "POST":
# 如果用户输入了10条数据,则Form里需要写10个get来获取值
user = request.POST.get("user")
passwd = request.POST.get('passwd')
email = request.POST.get('email')
# 判断用户的输入[涉及用户的为空判断,输入格式内容校验以及数据库操作等判断]
# 数据库校验: 传入参数校验 + 字典的传入校验 **kwargs
# filter(user=u, email=e,passwd=p) ==> filter(**kwargs)
# create(user=u, email=e,passwd=p) ==> create(**kwargs)
# 如果校验失败,页面需要给用户显示错误信息,不能redirect[form提交页面会刷新,上次数据无法保留,ajax不涉及]
只能return render(request, 'login.html; 'args'arg),需要给前台HTML添加{{msg}}操作
"""
查看Django为我们创建的正则:
DjangoForm的Form验证
Django的Form验证
- 控诉:
a. 用户提交数据的验证
1、创建模版 class LoginForm(forms.Form):...
2、将请求交给模版,创建一个对象 obj = LoginForm(request.POST)
3、进行验证 obj.is_valid()【必须执行,这里开始校验,否则clean获取不到值】
4、获取正确信息 obj.clean()
5、获取错误信息 obj.errors
b. 错误信息提示[传递Form对象给后台]
Form提交,刷新页面的特性,DjangoForm模版对象内部值丰富,再显示时,值和错误信息都有
c. 保留上一次提交的数据
1、自动生成html标签【实际上{{obj.user}} 就是内部生成了一个HTML的字符串】
2、保留上一次提交的数据【input框的value值更改为上次提交的值即可】
注:
obj对象里面有正确信息也有错误信息
Form使用 a,b,c
ajax使用 a,错误信息处理: as_json() as_data()
DjangoForm之前台参数校验实例
settings.py
INSTALLED_APPS = [
...
'app01', # 注册app
]
STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),) # 现添加的配置,这里是元组,注意逗号
TEMPLATES = [
...
'DIRS': [os.path.join(BASE_DIR, 'templates')],
]
urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
url(r'login.html/', views.Login),
]
views.py
from django.shortcuts import render, redirect
# 创建模板
# 本质是从请求中获取数据后来进行校验
from django import forms
class LoginForm(forms.Form):
# 前台Form表单里面的name属性的值必须跟这里的名称完全一致,这样数据提交后才能进行校验
# 如果名称不一致,则默认数据未传递过来,不作处理
# 如果传递多个参数,则模版默认只按照名称来进行匹配,有则匹配,无责不匹配
user = forms.CharField(min_length=6) # 模版元素
passwd = forms.CharField(min_length=12) # 模版元素
email = forms.EmailField(error_messages={"required": "格式错误"})# 模版元素同时自定义格式
"""
code:
required: 如果输入为空的时候显示
invalid: 输入的类型错误
min_length: 最小长度
"""
def Login(request):
if request.method == "GET":
return render(request, 'login.html')
elif request.method == "POST":
# 模版会自动从request里面取值并校验
obj = LoginForm(request.POST)
# 从模版里面开始验证,全部正确则显示结果正确,否则错误
status = obj.is_valid()
print('验证结果:', status)
if status:
# 获取校验过的值和验证的错误信息
value_dict = obj.clean()
print('验证通过的值:', value_dict)
# 类.create(**value_dict) --> 此时可以直接插入数据到数据库了
else:
error_dict = obj.errors # 此时的返回结果是个ErrorDict对象,可以type看类型
# <class 'django.forms.utils.ErrorDict'>该对象基础DICT这个里面有as_json和as_data方法
print('错误的信息[默认UL显示]:', error_dict)
error_dict_json = obj.errors.as_json() # 此时的返回结果是个JSON集
print('错误的信息[json显示]:', error_dict_json)
return render(request, 'login.html',{'obj': obj})
templates/login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<h1>Form提交数据</h1>
<form method="post" action="/login.html/">
<!-- 前台的属组操作只能用点.来获取列表的第一个元素 -->
<p><input type="text" name="user" placeholder="用户名"><span>{{ obj.user.errors.0}}</span></p>
<p><input type="password" name="passwd" placeholder="密码"><span>{{ obj.passwd.errors.0}}</span></p>
<p><input type="text" name="email" placeholder="邮箱"><span>{{ obj.user.email.0}}</span></p>
<input type="submit" value="Form提交">
<input id='ajax_submit' type="button" value="Ajax提交">
</form>
</body>
<script src="/static/jquery-2.1.4.min.js"></script>
<script>
$(function () {
$('#ajax_submit').click(function () {
$.ajax({
url:"/login.html",
data:{user:'omc', email:'omc@hhh.com', passwd:'lem600'},
type:'POST',
success:function (args) {
console.log(args)
}
})
})
})
</script>
</html>
页面显示:
学习扩展:
# 封装Django里面的所有错误信息
error_dict = obj.errors # 此时的返回结果是个ErrorDict对象
print('错误的信息[UL显示]:', error_dict) # 这里返回的是一个对象
print('错误信息类型:', type(error_dict))#因为返回了ErrorDict里面__str__方法:return self.as_ul();
# 因为返回的是DICT对象,所以可以利用key获取
print('错误信息类型:', type(error_dict)) # 错误信息类型: <class 'django.forms.utils.ErrorDict'>
#print('获取错误信息[属性获取]:', error_dict.user) # 错误,'ErrorDict' object has no attribute 'user'
print('获取错误信息[key获取]:', error_dict['user']) # 正确
print('获取错误信息[key获取]类型:', type(error_dict['user'])) # ErrorList类型,默认返回第一个list[0]
print('获取错误信息[此时是字符串]:', error_dict['user'][0]) # 字符串 This field is required.
DjangoForm之提交数据后保留数据
Django会自动生成HTML,并保留我们生成的数据
settings.py
INSTALLED_APPS = [
...
'app01', # 注册app
]
STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),) # 现添加的配置,这里是元组,注意逗号
TEMPLATES = [
...
'DIRS': [os.path.join(BASE_DIR, 'templates')],
]
urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
url(r'login.html/', views.Login),
]
views.py
from django.shortcuts import render, redirect
# 创建模板
# 本质是从请求中获取数据后来进行校验
from django import forms
class LoginForm(forms.Form):
# 前台Form表单里面的name属性的值必须跟这里的名称完全一致,这样数据提交后才能进行校验
# 如果名称不一致,则默认数据未传递过来,不作处理
# 如果传递多个参数,则模版默认只按照名称来进行匹配,有则匹配,无责不匹配
user = forms.CharField(min_length=6) # 模版元素
passwd = forms.CharField(min_length=12) # 模版元素
email = forms.EmailField(error_messages={"required": "格式错误"})# 模版元素同时自定义格式
"""
code:
required: 如果输入为空的时候显示
invalid: 输入的类型错误
min_length: 最小长度
"""
def Login(request):
if request.method == "GET":
obj = LoginForm() # 这里生成的obj对象只有生成HTML的作用,但是名称必须跟后面POST对象一致
return render(request, 'login.html', {'obj': obj})
elif request.method == "POST":
# 模版会自动从request里面取值并校验
obj = LoginForm(request.POST)
# 从模版里面开始验证,全部正确则显示结果正确,否则错误
status = obj.is_valid()
print('验证结果:', status)
if status:
# 获取校验过的值和验证的错误信息
value_dict = obj.clean()
print('验证通过的值:', value_dict)
# 类.create(**value_dict) --> 此时可以直接插入数据到数据库了
else:
error_dict = obj.errors # 此时的返回结果是个ErrorDict对象,可以type看类型
# <class 'django.forms.utils.ErrorDict'>该对象基础DICT这个里面有as_json和as_data方法
print('错误的信息[默认UL显示]:', error_dict)
error_dict_json = obj.errors.as_json() # 此时的返回结果是个JSON集
print('错误的信息[json显示]:', error_dict_json)
return render(request, 'login.html',{'obj': obj})
templates/login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<h1>Form提交数据</h1>
<form method="post" action="/login.html/">
<!-- 前台的属组操作只能用点.来获取,这里的表单是Django帮我们做的 -->
<p>{{ obj.user }}<span>{{ obj.user.errors.0}}</span></p>
<p>{{ obj.passwd }}<span>{{ obj.passwd.errors.0}}</span></p>
<p>{{ obj.email }}<span>{{ obj.user.email.0}}</span></p>
<input type="submit" value="Form提交">
<input id='ajax_submit' type="button" value="Ajax提交">
</form>
</body>
<script src="/static/jquery-2.1.4.min.js"></script>
<script>
$(function () {
$('#ajax_submit').click(function () {
$.ajax({
url:"/login.html",
data:{user:'omc', email:'omc@hhh.com', passwd:'lem600'},
type:'POST',
success:function (args) {
console.log(args)
}
})
})
})
</script>
</html>
页面显示;
问题:为什么get的Form对象必须和Form的一致?
答: get请求过来后我们实例化了一个不带参数的LoginForm的obj对象,此时的只能在前台生成HTML作用[前台obj.user]
post请求提交数据后,我们实例化了一个带POST参数的LoginForm的obj对象,里面有我们前台请求的数据,此时obj对象具有1.生成前台HTML的作用 2.带了post参数可以直接前台显示 3.我们前台用来同一个模板{{ }}来接收数据【正确/错误信息】,所以obj对象的名称不能改
如果我们更改POST对象名称为obj1,前台也更改为obj1,此时数据提交后就不再显示input框了,因为一个是obj,一个是obj1
附:input标签的生成过程[源码分析]
DjangoForm的Ajax验证【代码有问题】
settings.py
INSTALLED_APPS = [
...
'app01', # 注册app
]
STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),) # 现添加的配置,这里是元组,注意逗号
TEMPLATES = [
...
'DIRS': [os.path.join(BASE_DIR, 'templates')],
]
urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
url(r'login.html/', views.Login),
url(r'^login_ajax.html', views.login_ajax),
]
views.py
from django.shortcuts import render
from django.shortcuts import HttpResponse
import json
def login_ajax(request):
if request.method == "GET":
return render(request, 'login_ajax.html')
elif request.method == "POST":
ret = {'status': True, 'error':None, 'data': None}
obj = LoginForm(request.POST)
if obj.is_valid():
print(obj.clean())
else:
# 方式一
# res_str = obj.errors.as_json() # res_str是一个字符串
# ret['status'] = False
# ret['error'] = res_str
# 两次反序列化
# 方式二:将Django的ValidationError类型转换为JSON对象
ret['status'] = False
ret['error'] = obj.errors.as_data() #Djaongo的数据类型 {'user': [ValidationError(['用户名长度不能小6'])], 'email': [ValidationError(['邮箱格式错误'])]}
# 一次反序列化
return HttpResponse(json.dumps(ret, cls=JsonCustomEncoder))
# 方式一不需要此类
from django.core.validators import ValidationError
class JsonCustomEncoder(json.JSONEncoder):
def default(self, field):
if isinstance(field, ValidationError):
return {'code': field.code, 'message': field.message}
else:
return json.JSONEncoder.default(self, field)
templates/login_ajax.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.error-msg{
color: red;
font-size: 12px;
}
</style>
</head>
<body>
<h1>Form提交数据</h1>
<form id="f1">
<p> <input id="u" type="text" name="user" placeholder="用户名" /> </p>
<p> <input id="e" type="text" name="email" placeholder="邮箱" /> </p>
<p> <input id="p" type="text" name="pwd" placeholder="密码" /> </p>
<input id="ajax_submit" type="button" value="Ajax提交" />
</form>
<script src="/static/jquery-2.1.4.min.js"></script>
<script>
$(function () {
$('#ajax_submit').click(function () {
$.ajax({
url:"/login_ajax.html",
//data: {user: $('#u').val(), email: $('#e').val(), pwd: $('#p').val()},
data: $('#f1').serialize(),
type: 'POST',
success:function (arg) {
$('.error-msg').remove();
var v1 = JSON.parse(arg); //解析JSON数据
console.log(v1);
if(!v1.status){
// var error_obj = JSON.parse(v1.error);
var error_obj = v1.error;
$.each(error_obj,function (k,v) {
// k: user 或 email
// v: [{}{}{},]
var tag = document.createElement('span');
tag.className = 'error-msg';
tag.innerHTML = v[0].message;
$("input[name='" + k +"']").after(tag);
})
}else{
location.href = "/inde.html"
}
// { 'stauts': true, 'error':xx, 'data':’‘}
}
})
})
})
</script>
</body>
</html>
页面显示;
DjangoForm更多用法之多选框
settings.py
INSTALLED_APPS = [
...
'app01', # 注册app
]
STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),) # 现添加的配置,这里是元组,注意逗号
TEMPLATES = [
...
'DIRS': [os.path.join(BASE_DIR, 'templates')],
]
urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^index.html', views.index),
url(r'^edit_index.html', views.edit_index),
]
views.py
from django.shortcuts import render
from django.shortcuts import HttpResponse
class IndexForm(forms.Form):
# 模版中的元素
user = forms.CharField(min_length=6,error_messages={"required": '用户名不能为空','min_length': '用户名长度不能小6'})
email = forms.EmailField(error_messages={"required": '邮箱不能为空','invalid': '邮箱格式错误'})
favor = forms.MultipleChoiceField( choices=[(1,'AAA'),(2,'BBB'),(3,'CCC')] )
def index(request):
obj = IndexForm()
return render(request,'index.html',{'obj': obj})
def edit_index(request):
obj = IndexForm({'user': 'root','email': 'hhh@666.com','favor': [2,3]})
return render(request,'index.html',{'obj': obj})
templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>{{ obj.user }}</p>
<p>{{ obj.email }}</p>
<p>{{ obj.favor }}</p>
</body>
</html>
DjangoForm更多用法之widget插件基本使用
settings.py
INSTALLED_APPS = [
...
'app01', # 注册app
]
STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),) # 现添加的配置,这里是元组,注意逗号
TEMPLATES = [
...
'DIRS': [os.path.join(BASE_DIR, 'templates')],
]
urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
from app01 import views
urlpatterns = [
# 带插件的Form
url(r'^detail.html', views.Detail),
]
views.py
from django.shortcuts import render, redirect
from django import forms # forms里面引用了field,widget的内容
from django.forms import fields # 这里再次引用是为了更加明确而已
from django.forms import widgets
# 带插件的Form,这里是定义模板
class DetailForm(forms.Form):
# user = fields.CharField() 默认widget = TextInput;此时就是一个白框,里面输入的文字都是明文【字符串】
# 自定义样式: attrs={'class': 'c1'} 此时就告诉Django,我要给生成的标签添加了样式class=c1
user = fields.CharField(widget=widgets.PasswordInput(attrs={'class': 'c1', 'placeholder': '请输入密码'}))
# choices接收的是列表,列表里面是元组,里面2个值[第一个参数是value值,第二个是]
choice = fields.ChoiceField(choices=[(1, '北京'), (2, '南京'), (3, '天津')])
# Django可以把前台的字符串转换为数字类型
age = fields.IntegerField()
# 总结: 如果是个单值[字符串],直接获取用户输入的字符串, ---> CharField()[获取字符串]
# 如果是个单值[数 字],直接获取用户输入的数字, ---> IntegerField(),Django帮我们字符串换Int类型
# 如果是个多值[下拉框],直接获取用户选择的字符串, ---> ChoiceField()[获取的是字符串]
# 前台返回的只有3类:字符串,数字, 列表
def Detail(request):
obj = DetailForm()
return render(request, 'detail.html', {'obj': obj})
templates/detail.html、
<!DOCTYPE html>
<html lang="en">
<head> <meta charset="UTF-8"> </head>
<body>
{{ obj.user }}
{{ obj.choice }}
</body>
</html>
页面显示;
学习拓展:
choice = fields.ChoiceField(choices=[(1, '北京'), (2, '南京'), (3, '天津')])
new_choice = fields.CharField(widget=widgets.Select(choices=[(1, '北京'), (2, '南京'), (3, '天津')]))
int_choice = fields.IntegerField(widget=widgets.Select(choices=[(1, '北京'), (2, '南京'), (3, '天津')]))
radio_select = fields.CharField(widget=widgets.RadioSelect(choices=[(1, '北京'), (2, '南京'), (3, '天津')]))
CharField也可以利用插件实现select的效果,所以ChoiceField实际上是new_choice一系列的简写
Choice和new_choice的返回结果是字符串
Int_choice的返回结果是整数类型
最强大的还是CharField,虽然生成的text文本框,但是可以通过插件实现转换其他HTML样式
DjangoForm更多用法之字段和插件更多使用
settings.py
INSTALLED_APPS = [
...
'app01', # 注册app
]
STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),) # 现添加的配置,这里是元组,注意逗号
TEMPLATES = [
...
'DIRS': [os.path.join(BASE_DIR, 'templates')],
]
urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
from app01 import views
urlpatterns = [
# 带插件的Form
url(r'^detail.html', views.Detail),
url(r'^fieldForm.html', views.DetailField),
]
views.py
from django.shortcuts import render, redirect
from django import forms # forms里面引用了field,widget的内容
from django.forms import fields # 这里再次引用是为了更加明确而已
from django.forms import widgets
from django.core.validators import RegexValidator
# 字段的详细使用
class FieldForm(forms.Form):
f = fields.CharField(
required=True, # 是否必须填写, 默认是必填的,
max_length=8, # 最大长度限制
min_length=6, # 最小长度限制
label='用户名', # 用于前端显示用的标签 obj.f.label 自带属性; 也可用obj.f.label_tag实现自动写入
initial='用户名', # 文本框内的初始值; views里面注意区别GET和POST请求,initial默认是GET请求显示
show_hidden_initial='初始隐藏的值', # 显示一个隐藏的标签,可以判断输入的值和隐藏的值是否有区别,然后处理
validators=[RegexValidator(r'^[0-9]+$', 'phoneNumber must be digital', code='phoneNumberError'), ], # 自定义验证规则
error_messages={'required': '不能为空', 'invalid': '格式错误', 'max_length': '格式太长了'}, # 不指定则显示默认的
disabled=True, # 默认disabled=False,表示文本框可以编辑
label_suffix='--->', # label的后缀,默认是冒号,这里更改为 --->
)
'''
注意: error_messages里面通过code来进行错误信息的匹配
想覆盖原来英文的错误信息,在error_messages覆盖即可
error_messages的优先级别高于自定义的优先级,且根据code来进行匹配
error_messages可以根据前面有什么参数[eg,min_length],message的code就可以写什么[这里就是min_length]
最常用的2个: required, invalid max_length min_length
'''
# 另一种方式实现自定义正则[第一种是上述的CharField里面的的validator]
f2 = fields.RegexField(r'^[0-9]+$')
'''
文件上传:
1.form表单需要使用enctype="multipart/form-data"
2.后台需要request.Files来接收文件, obj = FieldForm(request.POST, request.FILES)
3.获取文件对象InMemoryUploadedFile[对象内有文件名称,文件大小,文件内容]
'''
f3 = fields.FileField(allow_empty_file=False) # 文件不允许为空
# 设置下拉框,此时默认返回的是字符串类型
f4 = fields.ChoiceField(
initial=2, # 设置默认值,单选的时候只能选择1个默认值哈
choices=((1, 'AAA'), (2, 'BBB'), (3, 'CCC')), # 设置下拉选项[可迭代的就行]此时返回的1,2,3是字符串'1','2','3'
)
# 自带类型转换的Choice
f5 = fields.TypedChoiceField(
coerce=lambda x: int(x), # 传递的参数转换为int类型; lambda的等号[=]2边不需要空格
initial=2, # 设置默认值,单选的时候只能选择1个默认值哈
choices=((1, 'AAA'), (2, 'BBB'), (3, 'CCC')), # 设置下拉选项[可迭代的就行]此时返回的1,2,3是字符串'1','2','3'
)
# 设置下拉框多选
f6 = fields.MultipleChoiceField(
initial=(2, 3), # 设置默认值,必须是可迭代的就行
choices=((1, 'AAA'), (2, 'BBB'), (3, 'CCC')), # 设置下拉选项[可迭代的就行]此时返回的1,2,3是字符串'1','2','3'
)
# 实现多个验证[既满足A又满足B]
f7 = fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(), ]) # 里面是个可迭代对象
# 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用
f8 = fields.MultiValueField(fields=[fields.ChoiceField(), ]) # 里面是可迭代对象
# 生成2个框,因为继承了MultiValueField[这个类中有2个定制的CharField]
f9 = fields.SplitDateTimeField()
# 文件选项:此时会把当前app01路径下的所有文件以下拉框的形式显示[提交也是提交选中选项]
f10 = fields.FilePathField(path='app01',
match=None, # 正则匹配
recursive=False, # 递归下面的文件夹
allow_files=True, # 是否允许文件
allow_folders=False, # 是否允许文件夹等其他属性)
)
# IP的验证
f11 = fields.GenericIPAddressField()
# 只允许数字,字母,下划线
f12 = fields.SlugField() # 数字,字母,下划线,减号(连字符)
# UUID
f13 = fields.UUIDField()
def DetailField(request):
if request.method == "GET":
obj = FieldForm()
return render(request, 'fieldForm.html', {'obj': obj})
else:
obj = FieldForm(request.POST, request.FILES) # 注意别忘了参数,因为is_valid和clean都是POST请求的
obj.is_valid()
data = obj.clean()
error_json = obj.errors.as_json()
print("正确信息:", data)
print("错误信息:", error_json)
return render(request, 'fieldForm.html', {'obj': obj})
templates/fieldForm.html、
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<form action="/fieldForm.html/" method="post" enctype="multipart/form-data">
<h2>{{ obj.f.id_for_label }} 是个字符串,自动生成了一个id,这里自定制label效果</h2>
<label for="{{ obj.f.id_for_label }}">{{ obj.f.label }}:</label>{{ obj.f }} <hr>
<h2> {{ obj.f.label_tag }}可以自动帮我们生成label标签,等价上面的全部 </h2>
{{ obj.f.label_tag }}{{ obj.f }}<hr>
<h2>第二种自定义正则</h2>
{{ obj.f2 }}<hr>
<h2>文件上传</h2>
{{ obj.f3 }}<hr>
<h2>下拉框</h2>
{{ obj.f4 }}<hr>
<h2>多选下拉框</h2>
{{ obj.f6 }}
<input type="submit" value="提交">
</form>
</body>
</html>
页面显示[不全显示];
DjangoForm应用-- select数据从数据库取且实时刷新
settings.py
INSTALLED_APPS = [
...
'app01', # 注册app
]
STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),) # 现添加的配置,这里是元组,注意逗号
TEMPLATES = [
...
'DIRS': [os.path.join(BASE_DIR, 'templates')],
]
urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
from app01 import views
urlpatterns = [
# select的数据从数据库来,且实时更新
url(r'^db.html', views.db),
]
views.py
from django.shortcuts import render, redirect
from django import forms # forms里面引用了field,widget的内容
from django.forms import fields # 这里再次引用是为了更加明确而已
from django.forms import widgets
from django.core.validators import RegexValidator
from app01.models import DBModel
class DBForm(forms.Form):
d1 = fields.CharField()
# 固定的option
type1 = fields.ChoiceField(choices=[(1, 'AAA'), (2, 'BBB'), (3, 'CCC')])
# 从数据库内获取option
type2 = fields.ChoiceField(choices=DBModel.objects.all().values_list()) # 将数据转换为元组类型的list
# 实时刷新数据库内容
type3 = fields.ChoiceField(choices=[]) # 数据从数据库读取一次,每次生成对象都从内存获取,易产生脏数据
def __init__(self, *args, **kwargs): # 调用父级别的构造方式,每次创建对象的时候都会获取数据
super(DBForm, self).__init__(*args, **kwargs)
self.fields['type3'].choices = DBModel.objects.all().values_list() # 数据从此处获取
def db(request):
# 手动在数据库内创建数据库数据 --> 图形界面提交
if request.method == "GET":
obj = DBForm()
return render(request, 'db.html', {'obj': obj})
else:
obj = DBForm(request.POST, request.FILES) # 注意别忘了参数,因为is_valid和clean都是POST请求
obj.is_valid()
data = obj.clean()
error_json = obj.errors.as_json()
print("正确信息:", data)
print("错误信息:", error_json)
return render(request, 'db.html', {'obj': obj})
app01/models.py
from django.db import models
# Create your models here.
class DBModel(models.Model):
type = models.CharField(max_length=22) # 创建type字段且id是Django帮我们创建
templates/db.html、
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
用户名: {{ obj.d1 }}<br>
固定的: {{ obj.type1 }}<br>
数据库: {{ obj.type2 }}<br>
实时刷新数据库内容: {{ obj.type3 }}<br>
</body>
</html>
初始化数据库:
python manage.py makemigrations
python manage.py migrate
页面显示[不全显示]
数据库内容:
DjangoForm应用--新URL方式编辑时,默认内容选中
settings.py
INSTALLED_APPS = [
...
'app01', # 注册app
]
STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),) # 现添加的配置,这里是元组,注意逗号
TEMPLATES = [
...
'DIRS': [os.path.join(BASE_DIR, 'templates')],
]
urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
from app01 import views
urlpatterns = [
# 新URL方式编辑时,且内容默认选中
url(r'^dbEdit.html', views.dbEdit),
]
views.py
from django.shortcuts import render, redirect
from django import forms # forms里面引用了field,widget的内容
from django.forms import fields # 这里再次引用是为了更加明确而已
from django.forms import widgets
from django.core.validators import RegexValidator
from app01 import models
class DBEditForm(forms.Form):
user = fields.CharField()
user_type1 = fields.IntegerField(widget=widgets.Select(choices=[(1, 'AAA'), (2, 'BBB'), (3, 'CCC')]))
user_type2 = fields.IntegerField(widget=widgets.Select(choices=[]))
def __init__(self, *args, **kwargs):
super(DBEditForm, self).__init__(*args, **kwargs)
self.fields['user_type2'].widget.choices = DBModel.objects.all().values_list()
# 新URL方式编辑时,默认选中
def dbEdit(request):
if request.method == "GET":
nid = request.GET.get('nid') # 前台定义的nid
info = models.UserInfo.objects.filter(id=nid).first()
print('用户姓名:', info.usename, '\n用户类型:', info.type_id)
'''
如果这里的字典dic跟DBEditForm里面的字段一致,则Django默认会帮我们填补数据的
方案一: 自定义固定的内容:这里采用自定义,info我们转换为字典同理同效果
dic = {'user': 'root2020', 'user_type1': 3, 'user_type2': 5}
obj = DBEditForm(dic)
方案二: 将info对象转换为字典,根据前台的nid动态的获取内容
dic = {'user': 'root2020', 'user_type1': 3, 'user_type2': 5}
注意: 如果是多选的话,则只需要返回一个列表即可
dic = {'user': 'root2020', 'user_type1': 3, 'user_type2': 5, 'favor':[1,2,3,4]}
'''
dic = {'user': info.usename, 'user_type1': 3, 'user_type2': info.type_id} # 根据前台的反馈来进行数据匹配
obj = DBEditForm(dic)
return render(request, 'dbEdit.html', {'obj': obj})
else:
obj = DBEditForm(request.POST, request.FILES) # 注意别忘了参数,因为is_valid和clean都是POST请求的
obj.is_valid()
data = obj.clean()
error_json = obj.errors.as_json()
print("正确信息:", data)
print("错误信息:", error_json)
return render(request, 'dbEdit.html', {'obj': obj})
app01/models.py
from django.db import models
# Create your models here.
class DBModel(models.Model):
type = models.CharField(max_length=22) # 创建type字段且id是Django帮我们创建
class UserInfo(models.Model):
usename = models.CharField(max_length=22)
# type在数据库内显示的值为: type_id
type = models.ForeignKey("DBModel", on_delete=True) # 设置外键,一对多,这里是多的一方
templates/ dbEdit.html
<!DOCTYPE html>
<html lang="en">
<head> <meta charset="UTF-8"> </head>
<body>
{{ obj.user }}<br>
{{ obj.user_type1 }}<br>
{{ obj.user_type2 }}<br>
</body>
</html>
初始化数据库:
python manage.py makemigrations
python manage.py migrate
页面显示
数据库内容