一、modelForm操作及验证
1.获取数据库数据,界面展示数据并且获取前端提交的数据,并动态显示select框中的数据
views.py
from django.shortcuts import render,HttpResponsefrom app01 import modelsfrom django import formsfrom django.forms import fields as Ffieldsfrom django.forms import widgets as Fwidgetsclass UserInfoModelForm(forms.ModelForm):class Meta:#必须添加model = models.UserInfo#指定去UserInfo表里获取数据fields = '__all__' #在界面显示所有字段# fields = ['username','email']#只在界面显示'username','email'字段# exclude = ['username'] #不在界面显示'username'字段class UserInfoForm(forms.Form):username = Ffields.CharField(max_length=32)email = Ffields.EmailField()user_type = Ffields.ChoiceField(choices=models.UserType.objects.values_list('id','caption')#以'id','caption'为select框中的数据 )def __init__(self, *args, **kwargs):super(UserInfoForm,self).__init__(*args, **kwargs)self.fields['user_type'].choices = models.UserType.objects.values_list('id','caption')#加上这个init函数#后,就能将新添加到数据库中的数据动态显示到select框啦def index(request):if request.method == "GET":#将数据展示在界面obj = UserInfoModelForm()return render(request,'index.html',{'obj': obj})elif request.method == "POST":#获取前端提交的数据obj = UserInfoModelForm(request.POST)if obj.is_valid():#obj.is_valid()只能为true或falseprint(obj.is_valid())print(obj.cleaned_data) #obj.cleaned_data以字典的形式展示前端提交的数据print(obj.errors.as_json())#打印错误信息return render(request,'index.html',{'obj': obj})
index.html
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title></title></head><body><form action="/index/" method="POST">{% csrf_token %}{{ obj.as_p }} #以p标签的形式展示数据<input type="submit" value="提交" /></form></body></html>
View Code
二、完整的在界面展示数据、修改数据、提交数据、跳转到新页面
views.py
from django.shortcuts import render,HttpResponsefrom app01 import modelsfrom django import formsfrom django.forms import fields as Ffields#给导入的fields设置别名为Ffieldsfrom django.forms import widgets as Fwidgets#给导入的widgets设置别名为Fwidgetsclass UserInfoModelForm(forms.ModelForm):is_rmb = Ffields.CharField(widget=Fwidgets.CheckboxInput())#自定义在界面显示的单选框等,而且不用保存在数据库class Meta:#class Meta里一定不要加逗号model = models.UserInfo#指定去UserInfo表里获取数据fields = '__all__' #在界面显示所有字段# fields = ['username','email']#只在界面显示'username','email'字段# exclude = ['username'] #不在界面显示'username'字段labels = {#设定输入框的标签名'username': '用户名','email': '邮箱',}help_texts = {#在输入框后面自定义帮助信息'username': '我是帮助信息'}widgets = {#自定义输入框的属性,即自定义html标签的class'username': Fwidgets.Textarea(attrs={'class': 'c1'})#将输入框设置为text文本框,并添加css:‘c1’ }error_messages = {#自定义错误信息提示'__all__':{#给整体设置错误信息,跟form中的all一样},'email': {#给每个字段设定错误信息'required': '邮箱不能为空','invalid': '邮箱格式错误..',}}field_classes = {#将email输入框的格式验证修改为必须输入URL格式才正确# 'email': Ffields.URLField }localized_fields=('ctime',)#将数据库时间转化为北京时间,括号里写需要转化时间的字段,需要在settings里设置#timezoneclass UserInfoForm(forms.Form):username = Ffields.CharField(max_length=32)email = Ffields.EmailField()user_type = Ffields.ChoiceField(choices=models.UserType.objects.values_list('id','caption')#以'id','caption'为select框中的数据 )def __init__(self, *args, **kwargs):super(UserInfoForm,self).__init__(*args, **kwargs)self.fields['user_type'].choices = models.UserType.objects.values_list('id','caption')#加上这个init函数#后,就能将新添加到数据库中的数据动态显示到select框啦def index(request):#将数据展示在界面if request.method == "GET":obj = UserInfoModelForm()return render(request,'index.html',{'obj': obj})elif request.method == "POST":obj = UserInfoModelForm(request.POST)if obj.is_valid():#obj.is_valid()只能为true或falseobj.save()#自动将前端提交的数据保存在数据库# print(obj.cleaned_data) #obj.cleaned_data以字典的形式获取前端提交的数据# print(obj.errors.as_json())return render(request,'index.html',{'obj': obj})def user_list(request):li = models.UserInfo.objects.all().select_related('user_type')#获取UserInfo表中的所有数据,并且跨表将与UserInfo# 关联的user_type表中的数据也取出来,注意括号中写UserInfo类中的关联字段名,不可以写多对多的字段名,否则报错,#前端html跨表取user_type表数据:{% for row in li %} {{ row.user_type.caption }}return render(request,'user_list.html',{'li': li})def user_edit(request, nid):# 1.获取当前id对应的用户信息# 2.显示用户已经存在数据if request.method == "GET":#数据展示user_obj = models.UserInfo.objects.filter(id=nid).first()#根据nid获取UserInfo表中的相关数据的第一条mf = UserInfoModelForm(instance=user_obj)#将mf传到前端就可以自动生成网页,括号中的instance参数是显示默认值return render(request,'user_edit.html',{'mf': mf, 'nid': nid})#跳转回本页面,也可以跳转到其他页面elif request.method == 'POST':#数据修改user_obj = models.UserInfo.objects.filter(id=nid).first()mf = UserInfoModelForm(request.POST,instance=user_obj)#如果不加这句,就会自动在数据库中新添加数据,而不是修改#已存在的数据if mf.is_valid():mf.save()#将修改的数据写入到数据库中else:#如果出现异常,打印错误信息print(mf.errors.as_json())return render(request,'user_edit.html',{'mf': mf, 'nid': nid})
urls.py
url(r'^admin/', admin.site.urls),url(r'^index/', views.index),url(r'^user_list/', views.user_list),url(r'^edit-(\d+)/', views.user_edit),
index.html
同上
user_list.html
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title></title></head><body><ul>{% for row in li %}<li>{{ row.username }} - {{ row.user_type.caption }} - <a href="/edit-{{ row.id }}/">编辑</a></li>{% endfor %}</ul></body></html>
View Code
user_edit.html
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title></title></head><body><form method="POST" action="/edit-{{ nid }}/"> #以新链接的形式提交数据{% csrf_token %}{{ mf.as_p }}<input type="submit" value="提交" /></form></body></html>
三、ajax操作发送表单,并且获取数据,页面不刷新
1.给后台发送普通数据
views.py
def ajax(request):return render(request, 'ajax.html')def ajax_json(request):import timeprint(request.POST)ret = {'code': True , 'data': request.POST.get('username')}import jsonreturn HttpResponse(json.dumps(ret))
ajax.html
有两种ajax提交方式:推荐用第一种
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title></title></head><body><input type="text"/><input type="button" value="Ajax1" onclick="Ajax1();" />第二种:ifram提交数据<form action="/ajax_json/" method="POST" target="ifm1"><iframe id="ifm1" name="ifm1" ></iframe><input type="text" name="username" /><input type="text" name="email" /><input type="submit" onclick="sumitForm();" value="Form提交"/></form><script type="text/javascript" src="/static/jquery-1.12.4.js"></script><script>第一种:ajax提交表单数据function getXHR(){var xhr = null;if(XMLHttpRequest){xhr = new XMLHttpRequest();}else{xhr = new ActiveXObject("Microsoft.XMLHTTP");}return xhr;}function Ajax1(){var xhr = getXHR();//var xhr = new XMLHttpRequest(); xhr.open('POST', '/ajax_json/',true);#括号内参数依次为:数据提交方式、提交去处、是否异步,true为异步xhr.onreadystatechange = function(){if(xhr.readyState == 4){// 接收完毕var obj = JSON.parse(xhr.responseText);console.log(obj);}};xhr.setRequestHeader('k1','v1');xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8');xhr.send("name=root;pwd=123");}{# 第二种:ifram提交表单数据#}function sumitForm(){$('#ifm1').load(function(){var text = $('#ifm1').contents().find('body').text();var obj = JSON.parse(text);})}</script></body></html>
ifram详解:
<body><form action="/ajax_json/" method="POST" target="ifm1">#表单提交到/ajax_json/ target:在指定的框架中打开<iframe id="ifm1" name="ifm1" ></iframe> #加上display:none就看不到ifram框啦<input type="text" name="username" /><input type="text" name="email" /><input type="submit" onclick="sumitForm();" value="Form提交"/></form> <script> function sumitForm(){#获取ifram框架中的数据$('#ifm1').load(function(){var text = $('#ifm1').contents().find('body').text(); #.contents():由于ifram生成的是完整的html网页,通过contents()属性提取出网页内容,再找到body标签,
#再通过text方法找到后台返回的数据var obj = JSON.parse(text); #将获取到的后台数据json序列化})}</script>
2.给后台上传文件,上传文件有三种方式,优先使用ifram,再次使用jQuery ajax
views.py
def upload(request):return render(request,'upload.html')def upload_file(request):username = request.POST.get('username')fafafa = request.FILES.get('fafafa')import osimg_path = os.path.join('static/imgs/',fafafa.name)#生成图片保存路径with open(img_path,'wb') as f:for item in fafafa.chunks():#保存文件,必须用chunks() f.write(item)ret = {'code': True , 'data': img_path}#将图片路径返回给前端import jsonreturn HttpResponse(json.dumps(ret))
upload.html
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title></title><style>.upload{display: inline-block;padding: 10px;background-color: brown;position: absolute;top: 0;bottom: 0;right: 0;left: 0;z-index: 90;}.file{width: 100px;height: 50px;opacity: 0;position: absolute;top: 0;bottom: 0;right: 0;left: 0;z-index: 100;}</style></head><body><div style="position: relative;width: 100px;height: 50px;"><input class="file" type="file" id="fafafa" name="afafaf" /><a class="upload">上传</a></div>第一种上传方式:原生ajax<input type="button" value="提交XHR" onclick="xhrSubmit();" />第二种上传方式:jQuery ajax<input type="button" value="提交jQuery" onclick="jqSubmit();" /><hr/> 分隔符第三种上传方式:ifram 最好用第三和第二种<form id="form1" action="/upload_file/" method="POST" enctype="multipart/form-data" target="ifm1"><iframe id="ifm1" name="ifm1" style="display: none;"></iframe><input type="file" name="fafafa" onchange="changeUpalod();" /><input type="submit" onclick="iframeSubmit();" value="Form提交"/></form><div id="preview"></div><script src="/static/jquery-1.12.4.js"></script><script>这一步可以不要,选中图片后自动提交,并且生成图片预览function changeUpalod(){$('#ifm1').load(function(){var text = $('#ifm1').contents().find('body').text();var obj = JSON.parse(text); 获取图片路径$('#preview').empty(); #将预览图片标签清空var imgTag = document.createElement('img'); 生成图片标签imgTag.src = "/" + obj.data; 生成图片路径$('#preview').append(imgTag);});$('#form1').submit();}以下有三种文件提交方式,优先使用ifram,再次使用jQuery提交文件以下这一步是:jQuery提交文件function jqSubmit(){// $('#fafafa')[0]var file_obj = document.getElementById('fafafa').files[0];var fd = new FormData();fd.append('username','root');fd.append('fafafa',file_obj);$.ajax({url: '/upload_file/',type: 'POST',data: fd,processData: false, // tell jQuery not to process the datacontentType: false, // tell jQuery not to set contentTypesuccess:function(arg,a1,a2){console.log(arg);console.log(a1);console.log(a2);}})}以下这一步是:原生ajax提交文件function xhrSubmit(){// $('#fafafa')[0]var file_obj = document.getElementById('fafafa').files[0];var fd = new FormData();fd.append('username','root');fd.append('fafafa',file_obj);var xhr = new XMLHttpRequest();xhr.open('POST', '/upload_file/',true);xhr.onreadystatechange = function(){if(xhr.readyState == 4){// 接收完毕var obj = JSON.parse(xhr.responseText);console.log(obj);}};xhr.send(fd);}以下这一步是:ifram提交文件,优先使用ifram提交function iframeSubmit(){$('#ifm1').load(function(){var text = $('#ifm1').contents().find('body').text();var obj = JSON.parse(text); 获取图片路径$('#preview').empty(); #将预览图片标签清空var imgTag = document.createElement('img'); 生成图片标签imgTag.src = "/" + obj.data; 生成图片路径$('#preview').append(imgTag);});}</script></body></html>
View Code
四、生成图片验证码
check_code.py
#!/usr/bin/env python# -*- coding:utf-8 -*-import randomfrom PIL import Image, ImageDraw, ImageFont, ImageFilter_letter_cases = "abcdefghjkmnpqrstuvwxy" # 小写字母,去除可能干扰的i,l,o,z_upper_cases = _letter_cases.upper() # 大写字母_numbers = ''.join(map(str, range(3, 10))) # 数字init_chars = ''.join((_letter_cases, _upper_cases, _numbers))def create_validate_code(size=(120, 30),chars=init_chars,img_type="GIF",mode="RGB",bg_color=(255, 255, 255),fg_color=(0, 0, 255),font_size=18,font_type="Monaco.ttf",length=4,draw_lines=True,n_line=(1, 2),draw_points=True,point_chance=2):"""@todo: 生成验证码图片@param size: 图片的大小,格式(宽,高),默认为(120, 30)@param chars: 允许的字符集合,格式字符串@param img_type: 图片保存的格式,默认为GIF,可选的为GIF,JPEG,TIFF,PNG@param mode: 图片模式,默认为RGB@param bg_color: 背景颜色,默认为白色@param fg_color: 前景色,验证码字符颜色,默认为蓝色#0000FF@param font_size: 验证码字体大小@param font_type: 验证码字体,默认为 ae_AlArabiya.ttf@param length: 验证码字符个数@param draw_lines: 是否划干扰线@param n_lines: 干扰线的条数范围,格式元组,默认为(1, 2),只有draw_lines为True时有效@param draw_points: 是否画干扰点@param point_chance: 干扰点出现的概率,大小范围[0, 100]@return: [0]: PIL Image实例@return: [1]: 验证码图片中的字符串"""width, height = size # 宽高# 创建图形img = Image.new(mode, size, bg_color)draw = ImageDraw.Draw(img) # 创建画笔def get_chars():"""生成给定长度的字符串,返回列表格式"""return random.sample(chars, length)def create_lines():"""绘制干扰线"""line_num = random.randint(*n_line) # 干扰线条数for i in range(line_num):# 起始点begin = (random.randint(0, size[0]), random.randint(0, size[1]))# 结束点end = (random.randint(0, size[0]), random.randint(0, size[1]))draw.line([begin, end], fill=(0, 0, 0))def create_points():"""绘制干扰点"""chance = min(100, max(0, int(point_chance))) # 大小限制在[0, 100]for w in range(width):for h in range(height):tmp = random.randint(0, 100)if tmp > 100 - chance:draw.point((w, h), fill=(0, 0, 0))def create_strs():"""绘制验证码字符"""c_chars = get_chars()strs = ' %s ' % ' '.join(c_chars) # 每个字符前后以空格隔开font = ImageFont.truetype(font_type, font_size)font_width, font_height = font.getsize(strs)draw.text(((width - font_width) / 3, (height - font_height) / 3),strs, font=font, fill=fg_color)return ''.join(c_chars)if draw_lines:create_lines()if draw_points:create_points()strs = create_strs()# 图形扭曲参数params = [1 - float(random.randint(1, 2)) / 100,0,0,0,1 - float(random.randint(1, 10)) / 100,float(random.randint(1, 2)) / 500,0.001,float(random.randint(1, 2)) / 500]img = img.transform(size, Image.PERSPECTIVE, params) # 创建扭曲img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) # 滤镜,边界加强(阈值更大)return img, strs
View Code
views.py
#!/usr/bin/env python# -*- coding:utf-8 -*-from io import BytesIOfrom django.shortcuts import HttpResponsefrom django.shortcuts import renderfrom utils.check_code import create_validate_codedef check_code(request):#该函数对应login.html中的src=/check_code.html"""验证码:param request::return:"""# stream = BytesIO()# img, code = create_validate_code()# img.save(stream, 'PNG')# request.session['CheckCode'] = code# return HttpResponse(stream.getvalue())# data = open('static/imgs/avatar/0809170025.png','rb').read()# return HttpResponse(data)# 1. 创建一张图片 pip3 install Pillow# 2. 在图片中写入随机字符串# obj = object()# 3. 将图片写入到制定文件# 4. 打开制定目录文件,读取内容# 5. HttpResponse(data)stream = BytesIO()#生成一个内存对象img, code = create_validate_code() #生成图片和验证码img.save(stream,'PNG')#将图片保存到内存中,格式为pngrequest.session['CheckCode'] = code #将验证码放到session里return HttpResponse(stream.getvalue())#stream.getvalue()将图片从内存中取出,返回给前端def login(request):"""登陆:param request::return:"""# if request.method == "POST":#if request.session['CheckCode'].upper() == request.POST.get('check_code').upper():# pass#else:# print('验证码错误')if request.method == 'POST':code = request.POST.get('check_code')if code.upper() == request.session['CheckCode'].upper():print('验证码正确')else:print('验证码错误')return render(request, 'login.html')def register(request):"""注册:param request::return:"""return render(request, 'register.html')def logout(request):"""注销:param request::return:"""pass
login.html
<!DOCTYPE html><html><head lang="en"><meta charset="UTF-8"><title></title><link rel="stylesheet" href="/static/plugins/bootstrap/css/bootstrap.css"/><link rel="stylesheet" href="/static/plugins/font-awesome/css/font-awesome.css"/><link rel="stylesheet" href="/static/css/edmure.css"/><link rel="stylesheet" href="/static/css/commons.css"/><link rel="stylesheet" href="/static/css/account.css"/><style></style></head><body><div class="login"><div style="font-size: 25px; font-weight: bold;text-align: center;">用户登陆</div><form role="form" action="/login.html" method="POST">{% csrf_token %}<div class="form-group"><label for="username">用户名</label><input type="text" class="form-control" placeholder="请输入用户名"></div><div class="form-group"><label for="password">密码</label><input type="password" class="form-control" placeholder="请输入密码"></div><div class="form-group"><label for="password">验证码</label><div class="row"><div class="col-xs-7"><input type="text" class="form-control" placeholder="请输入验证码" name="check_code"></div><div class="col-xs-5"><img src="/check_code.html" οnclick="changeCheckCode(this);">#绑定事件,点击图片生成新的验证码</div></div></div><div class="checkbox"><label><input type="checkbox"> 一个月内自动登陆</label><div class="right"><a href="#">忘记密码?</a></div></div><button type="submit" class="btn btn-default">登 陆</button></form></div><script>function changeCheckCode(ths){ths.src = ths.src + '?';{# 通过在url后边加问号的形式,实现点击验证码图片刷新页面获取新的验证码#}}</script></body></html>
五、富文本框使用
/wupeiqi/articles/6307554.html 视频24天-17-KindEditor基本使用和文件操作