5.10关于文件上传
2.1基本操作
(获取文件,Django内部读取文件、操作文件)
1、在url.py中
from app01.views import depart,user,pretty,admin,account,task,order,chart,upload
# 上传文件 path('upload/list/', upload.upload_list),
这样就可以直接访问网页127.0.0.1:8000/upload/list/

新建 .html 表单
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<form method="post" enctype="multipart/form-data">
{% csrf_token % #通过Django进行提交
<input type="text" name="username">
<input type="file" name="avatar"> #名字为头像
<input type="submit" value="提交">
</form>
</div>
{% endblock %}
新建upload,py文件
from django.shortcuts import render,HttpResponse def upload_list(request): if request.method == "GET": #用户看到页面 return render(requests, 'upload_list.html') # # 'username':[big666'] 下面代码呈现的内容 # print(request.POST) # 请求体中数据 # # {‘avatar':[<InMemoryUploadFile:图片1.png(image/png)>]}> 下面代码呈现的内容 # print(request.FILES) # 请求发过来的文件{} #先不进行request.POST的读取,先根据文件名获取文件对象 file_object = request.FILES.get("avatar") print(file_object.name) # 获取到文件名:图片1.png # 进行request.FILES文件对象内容的读取,并且上传。操作如下: f = open('a1.png', mode='wb') #当前文件以二进制方式写入一个新的本地文件中 ,或者f = open('file_object.name', mode='wb') ,那么上传的文件名与新的本地文件名一致 for chunk in file_object.chunks(): f.write(chunk) f.close() return HttpResponse("...")
得到如下效果:
TIP:
刚开始请求体中数据request.POST时请求的图片的名字而不是文件内容,即request.FILES中没有数据:
![]()
如下操作后:

request.FILES中出现了文件对象,即文件内容。如下图:

注册部分全部代码ending:
在views\account.py中:
# 用户账户相关功能:注册、短信、登录、注销 from django.http import JsonResponse from django.shortcuts import render, HttpResponse from web.forms.account import RegisterModelForm, SendSmsForm from app01 import models def register(request): # 注册 if request.method == 'GET': form = RegisterModelForm() return render(request, 'web/register.html', {'form': form}) # print(request.POST) # 后台拿到的数据,传到ModelForm进行校验 form = RegisterModelForm(data=request.POST) if form.is_valid(): # 验证通过后,写入数据库(密码要是密文) # form.instance.password ="iudasndfiajsd;fj" #在保存之前将instance中的password进行重置 form.save() # 自动剔除数据库中没有的字段 return JsonResponse({'status': True, 'data': '/login/'}) # 注册成功后进行前端跳转页面 # 写入数据库的另外一种写法 # data =form.cleaned_data # data.pop('code') # data.pop('confirm_password') # instance = models.UserInfo.objects.create(**data) # print(form.cleaned_data) # 校验成功,输出cleaned_data return JsonResponse({'status': False, 'error': form.errors}) def send_sms(request): # 发送短信 # print(request.GET) # mobile_phone = request.GET.get('mobile phone') # tpl = request.GET.get('tpl') # register/login 根据tpl取短信模版 # sms_template_id = settings.TENCENT_SMS_TEMPLATE9(tpl) form = SendSmsForm(request, data=request.GET) # 只是校验手机号:不能为空,格式是否正确 if form.is_valid(): # 判断在form中是否校验成功 # 验证通过后,发短信 # 写redis return JsonResponse({'status': True}) # 表示短信发送成功 return JsonResponse({'status': False, 'error': form.errors}) # 表示校验失败,所有错误信息都会放在form.errors中 # return HttpResponse('{"k1":123}')
在forms\account.py中:
import random import requests from django import forms from django.conf import settings from django_redis import get_redis_connection from app01 import models from django.core.validators import RegexValidator from django.core.exceptions import ValidationError from utils import encrypt from utils.tencent.sms import send_sms_single class RegisterModelForm(forms.ModelForm): # 重写规则,进行表单展示.增加正则表达式的校验 mobile_phone = forms.CharField(label='手机号', validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'), ]) password = forms.CharField( label='密码', min_length=8, max_length=64, error_messages={ 'min_length': "密码长度不能小于8个字符", 'max_length': "密码长度不能大于64个字符" }, widget=forms.PasswordInput()) confirm_password = forms.CharField( label='重复密码', min_length=8, max_length=64, error_messages={ 'min_length': "重复密码长度不能小于8个字符", 'max_length': "重复密码长度不能大于64个字符" }, widget=forms.PasswordInput()) code = forms.CharField( label='验证码', widget=forms.TextInput()) class Meta: model = models.UserInfo fields = ['username', 'email', 'password', 'confirm_password', 'mobile_phone', 'code'] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for name, field in self.fields.items(): field.widget.attrs['class'] = 'form-control' field.widget.attrs['placeholder'] = '请输入%s' % (field.label,) # 利用钩子函数(用户名),对字段进行校验 def clean_username(self): username = self.cleaned_data['username'] exists = models.UserInfo.objects.filter(username=username).exists() if exists: raise ValidationError('用户名已存在') #抛出异常后不会在返回值,所以cleaned_data中不会有username # self.add_error('username', '用户名已存在') # 把错误信息进行添加但仍然会返回username的值 return username # 利用钩子函数(邮箱),对字段进行校验 def clean_email(self): email = self.cleaned_data['email'] exists = models.UserInfo.objects.filter(email=email).exists() if exists: raise ValidationError('邮箱已存在') return email # 利用钩子函数(密码),对字段进行校验 def clean_password(self): pwd = self.cleaned_data['password'] # 加密&返回 return encrypt.md5(pwd) # 利用钩子函数(确认密码),对字段进行校验 def clean_confirm_password(self): # pwd = self.cleaned_data['password'] pwd = self.cleaned_data.get('password') # password是否校验通过,都可以拿到这个字段的值 confirm_pwd = encrypt.md5(self.cleaned_data['confirm_password']) # 密文与密文进行匹配 if pwd != confirm_pwd: raise ValidationError('两次密码不一致') return confirm_pwd # 利用钩子函数(手机号),对字段进行校验 def clean_mobile_phone(self): mobile_phone = self.cleaned_data['mobile_phone'] exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists() if exists: raise ValidationError('手机号已注册') return mobile_phone # 利用钩子函数(验证码),对字段进行校验 def clean_code(self): code = self.cleaned_data['code'] # mobile_phone = self.cleaned_data['mobile_phone'] mobile_phone = self.cleaned_data.get('mobile_phone') if not mobile_phone: return code conn = get_redis_connection() redis_code = conn.get(mobile_phone) # 根据手机号获取redis 里的code if not redis_code: # redis里没有code raise ValidationError('验证码失效或未发送,请重新发送') redis_str_code = redis_code.decode('utf-8') # 字节变成字符串 if code.strip() != redis_str_code(): raise ValidationError('验证码错误,请重新输入') return code class SendSmsForm(forms.Form): mobile_phone = forms.CharField(label='手机号', validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'), ]) print("mobile_phone", mobile_phone) def __init__(self, request, *args, **kwargs): super().__init__(*args, **kwargs) self.request = request # 验证手机号 def clean_mobile_phone(self): """手机号校验的钩子函数""" # 校验数据前,都需要获取到被校验的数据 mobile_phone = self.cleaned_data['mobile_phone'] # 获取用户提交的手机号 # 判断短信模版是否有问题 tpl = self.request.GET.get('tpl') mobile_phone = self.request.GET.get('mobile_phone') print(tpl) template_id = settings.TENCENT_SMS_TEMPLATE[tpl] if not template_id: # self.add_error('mobile_phone', '短信模版错误') raise ValidationError('短信模版错误') # 验证数据库中是否已有手机号 exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists() if exists: raise ValidationError('手机号已存在') # 发短信 code = random.randrange(1000, 9999) # 生成随机验证码 # 发送短信 sms = send_sms_single(mobile_phone, template_id, [code, ]) if sms['result'] != 0: raise ValidationError("短信发送失败,{}".format(sms['errmsg'])) # 发送成功后,短信验证码写入redis(利用django-redis组件) conn = get_redis_connection() # redis的连接获取到 conn.set(mobile_phone, code, ex=60) # 设置key,value,超时时间为60 return mobile_phone
浙公网安备 33010602011771号