如何在Django中通过原生SQL将InMemoryUploadedFile存入SQLite数据库
问题:Django图片上传数据库报错
已在settings.py中配置MEDIA_ROOT与MEDIA_URL,但上传图片时出现报错:
can only concatenate str (not "InMemoryUploadedFile") to str
原因是直接使用原生SQL无法处理InMemoryUploadedFile类型的文件数据。
views.py 相关函数
@login_required def course_add(request): if request.method=='POST': bullyname=request.POST['bullyname'] contact=request.POST['contact'] email=request.POST['email'] facebookLink=request.POST['facebookLink'] instaLink=request.POST['instaLink'] linkedinLink=request.POST['linkedinLink'] snapLink=request.POST['snapLink'] file=request.FILES.get('myfile') # 数据库连接 db_cursor=connections['default'].cursor() # 插入数据的SQL语句 db_cursor.execute("INSERT INTO University_complains (name,contact,email,facebookid,instaid,linkedinid,snapid,prove) VALUES('"+bullyname+"','"+contact+"','"+email+"','"+facebookLink+"','"+instaLink+"','"+linkedinLink+"','"+snapLink+"','"+file+"')") return render(request, 'course_add.html')
models.py 相关类
class Complains(models.Model): name=models.CharField(max_length=50,null=False,verbose_name="Bull Name",primary_key=True) contact=models.CharField(max_length=15,null=False,verbose_name="Contact No") email=models.CharField(max_length=30,verbose_name="E mail") facebookid=models.CharField(max_length=100,verbose_name="Facebook ID") instaid=models.CharField(max_length=100,verbose_name="Instagram ID") linkedinid=models.CharField(max_length=100,verbose_name="Linkedin ID") snapid=models.CharField(max_length=100,verbose_name="Snapchat ID") prove=models.ImageField(upload_to='proves/')
settings.py 媒体配置
STATIC_URL = 'static/' PROJECT_DIR = os.path.dirname(os.path.abspath(__file__)) MEDIA_URL='/media/' MEDIA_ROOT=os.path.join(BASE_DIR,'media')
解决方案
1. 优先使用Django ORM处理(推荐)
Django的ImageField已经封装了文件存储逻辑,用ORM创建对象可自动完成文件保存和数据库路径存储,完全规避类型问题:
修改views.py中的函数:
@login_required def course_add(request): if request.method=='POST': # 直接用ORM实例化模型并保存 complain = Complains( name=request.POST['bullyname'], contact=request.POST['contact'], email=request.POST['email'], facebookid=request.POST['facebookLink'], instaid=request.POST['instaLink'], linkedinid=request.POST['linkedinLink'], snapid=request.POST['snapLink'], prove=request.FILES.get('myfile') ) complain.save() return render(request, 'course_add.html')
ORM会自动将文件保存到MEDIA_ROOT/proves/目录,同时把文件相对路径存入数据库,无需手动处理类型转换。
2. 确保前端表单配置正确
前端表单必须添加enctype="multipart/form-data"属性,否则无法正确接收文件:
<form method="POST" enctype="multipart/form-data"> {% csrf_token %} <!-- 其他表单字段 --> <input type="file" name="myfile"> <button type="submit">提交</button> </form>
3. 若坚持使用原生SQL(不推荐)
如果一定要用原生SQL,需手动将文件保存到本地目录,再把路径字符串插入数据库:
import os from django.conf import settings @login_required def course_add(request): if request.method=='POST': bullyname=request.POST['bullyname'] contact=request.POST['contact'] email=request.POST['email'] facebookLink=request.POST['facebookLink'] instaLink=request.POST['instaLink'] linkedinLink=request.POST['linkedinLink'] snapLink=request.POST['snapLink'] file=request.FILES.get('myfile') if file: # 构建文件保存路径 file_path = os.path.join('proves/', file.name) full_save_path = os.path.join(settings.MEDIA_ROOT, file_path) # 写入文件到本地 with open(full_save_path, 'wb+') as destination: for chunk in file.chunks(): destination.write(chunk) # 用参数化SQL插入路径(避免SQL注入) db_cursor=connections['default'].cursor() db_cursor.execute(""" INSERT INTO University_complains (name,contact,email,facebookid,instaid,linkedinid,snapid,prove) VALUES(%s,%s,%s,%s,%s,%s,%s,%s) """, (bullyname, contact, email, facebookLink, instaLink, linkedinLink, snapLink, file_path)) return render(request, 'course_add.html')
注意:这种方式需要手动处理文件重名、权限、异常等问题,安全性和便捷性远不如ORM。
内容的提问来源于stack exchange,提问作者farhan
相关产品推荐
相关产品推荐

