文件上传

关于文件上传

修改myproject/myproject/urls.py 

添加路由

 # 上传文件
    path('upload/list/', upload.upload_list),

新建myproject/app01/views/upload.py

from django.shortcuts import render, HttpResponse

def upload_list(request):
    if request.method == "GET":
        return render(request, 'upload_list.html')
    print(request.POST) #请求中的数据
    print(request.FILES) #请求发过来的文件
    return HttpResponse("...")

新建myproject/app01/templates/upload_list.html

{% extends 'layout.html' %}

{% block content %}
    <div class="container">
        <form method="post" enctype="multipart/form-data">
            {% csrf_token %}
            <input type="text" name="username">
            <input type="file" name="avatar">
            <input type="submit" value="提交">
        </form>
    </div>
{% endblock %}

注意:

不添加 enctype="multipart/form-data"得到的是<QueryDict: {'csrfmiddlewaretoken': ['OeDA7cKmsOLEneNjULy6Isg0hn6GazDOYkLHPrfHrHOLMuLzNNMRuhENQASgz8o9'], 'username': ['123'], 'avatar': ['20200119123801_bjxpj.jpg']}>文件那返回的是文件名的字符串,并不是文件
添加 enctype="multipart/form-data"得到的是<QueryDict: {'csrfmiddlewaretoken': ['TNDydKrOMZ6Vcn6jdhrEhs34WSR1fMEZ3TLFVZW9LS92BD4z6jFp3hrRv5DBElpk'], 'username': ['222']}><MultiValueDict: {'avatar': [<InMemoryUploadedFile: 20200119123801_bjxpj.jpg (image/jpeg)>]}>

   添加后才能得到文件

修改myproject/app01/views/upload.py

from django.shortcuts import render, HttpResponse

def upload_list(request):
    if request.method == "GET":
        return render(request, 'upload_list.html')
    # print(request.POST) #请求中的数据
    # print(request.FILES) #请求发过来的文件

    # 声明图片的对象
    file_object = request.FILES.get("avatar")

    # 分块进行存储
    # file_object.name 表示图片上传时图片本身是什么名字,保存图片时就用什么名字
    f = open(file_object.name, mode='wb')
    for chunk in file_object.chunks():
        f.write(chunk)
    f.close()

    return HttpResponse("上传成功")

  

 

 

 

 案例:批量上传数据

实现:表格上传至服务器并将数据读取保存至数据库中

我们在部门管理代码的基础上进行操作

修改myproject/app01/templates/depart.html

   <div class="panel panel-default">
            <!-- Default panel contents -->
            <div class="panel-heading">
                <span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
                批量上传
            </div>

            <div class="panel-body">
                <form method="post" enctype="multipart/form-data" action="/depart/multi/">
                    {% csrf_token %}
                    <div class="form-group">
                        <input type="file" name="exc">
                    </div>
                    <input type="submit" value="上传" class="btn btn-info btn-sm">
                </form>

            </div>

        </div>

  

 

安装openpyxl

pip install openpyxl

修改myproject/app01/views/depart.py

def depart_multi(request):
    """批量上传Excel文件"""
    from openpyxl import load_workbook

    #1.获取用户上传的文件对象
    file_object = request.FILES.get("exc")
    print(type(file_object))

    #2.把对象传递给openpyxl,由openpyxl读取文件的内容
    wb = load_workbook(file_object)
    sheet = wb.worksheets[0]

    #cell = sheet.cell(1,1) 获取第一行的第一个数据

    #3.循环获取每一行数据
    for row in sheet.iter_rows(min_row=2):
        text = row[0].value
        print(text)
        #部门重复的不添加
        exists = models.Department.objects.filter(title=text).exists()
        if not exists:
            #4.添加到数据库
            models.Department.objects.create(title=text)


    return redirect('/depart/list/')

  

 编辑myproject/myproject/urls.py

path('depart/multi/', depart.depart_multi),

  

浏览器访问测试

手动创建一个表格,填入如下内容

 将表格进行上传

 

 这里会存在一个问题,如果上传的字段就为空,页面就会报错处理起来也简单,针对为空的情况做一下简单的判断即可

 案例:混合数据上传(Form)

提交页面时:用户输入的数据+文件(输入不能为空、报错都要有)

编辑myprojrct/app01/templates/layout.html

<li><a href="/upload/form/">Form上传</a></li>

  

 添加路由

编辑myproject/myproject/urls.py

path('upload/form/', upload.upload_form),

编写视图函数

编辑myprojrct/app01/views.py/upload.py

from django.shortcuts import render, HttpResponse

def upload_list(request):
    if request.method == "GET":
        return render(request, 'upload_list.html')
    # print(request.POST) #请求中的数据
    # print(request.FILES) #请求发过来的文件

    # 声明图片的对象
    file_object = request.FILES.get("avatar")

    # 分块进行存储
    # file_object.name 表示图片上传时图片本身是什么名字,保存图片时就用什么名字
    f = open(file_object.name, mode='wb')
    for chunk in file_object.chunks():
        f.write(chunk)
    f.close()

    return HttpResponse("上传成功")

from django import forms
from app01.utils.bootstrap import BootStrapForm
class UpForm(BootStrapForm):
 
    name = forms.CharField(label="姓名")
    age = forms.IntegerField(label="年龄")
    img = forms.FileField(label="头像")


def upload_form(request):
    title = "Form上传"
    form = UpForm()
    return render(request, 'upload_form.html', {"form":form, "title":title})

  

 新建upload_form.html

编辑myproject/app01/templates/upload_form.html

{% extends 'layout.html' %}

{% block content %}
    <div class="container">
        <div class="panel panel-default">
            <div class="panel-heading">
                <h3 class="panel-title">{{ title }}</h3>
            </div>
            <div class="panel-body">
                {#   novalidate去除浏览器的错误提示  #}
                <form method="post" enctype="multipart/form-data" novalidate>
                    {% csrf_token %}

                    {% for field in form %}
                        <div class="form-group">
                            <label>{{ field.label }}</label>
                            {{ field }}
                            {#  {{ field.errors }}错误信息是一个列表[错误1,错误2,错误3...], {{ field.errors.0 }}只取第一个错误1  #}
                            <span style="color: red;">{{ field.errors.0 }}</span>
                            {#   <input type="text" class="form-control" placeholder="姓名" name="user">  #}
                        </div>
                    {% endfor %}

                    <button type="submit" class="btn btn-primary">提 交</button>
                </form>
            </div>
        </div>
    </div>
{% endblock %}

  浏览器访问,会发现有一个问题,上传图片的输入框也添加了bootstrap样式:

 去除上传图片输入框的bootstrap样式:

修改myproject/app01/utils/bootstrap.py

from django import forms

class BootStrap:
    #如果哪个输入框不想用BootStrap样式
    bootstrap_exclude_fields = []

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 循环找到所有的插件,添加class = "form-control"样式
        for name, field in self.fields.items():
            # 如果哪个输入框不想用BootStrap样式,把name写出来
            if name in self.bootstrap_exclude_fields:
                continue
            #字段中有属性,保留原来的属性,没有属性,才增加
            if field.widget.attrs:
                field.widget.attrs["class"] = "form-control"
                field.widget.attrs["placeholder"] = field.label
            else:
                field.widget.attrs = {
                    "class": "form-control",
                    "placeholder": field.label
                }

class BootStrapModelForm(BootStrap, forms.ModelForm):
    pass
class BootStrapForm(BootStrap, forms.Form):
    pass

  

 修改myproject/app01/vierws/upload.py

 bootstrap_exclude_fields = ['img']

  

 

 接下来实现图片的上传(保存至本地与数据库)

新创建一个表

编辑myproject/app01/models.py

class Boss(models.Model):
    """老板"""
    name = models.CharField(verbose_name="姓名", max_length=32)
    age = models.IntegerField(verbose_name="年龄")
    img = models.CharField(verbose_name="头像", max_length=128)

执行

makemigrations
migrate

修改myproject/app01/views/upload.py

import os
from django.shortcuts import render, HttpResponse
from app01 import models
def upload_list(request):
    if request.method == "GET":
        return render(request, 'upload_list.html')
    # print(request.POST) #请求中的数据
    # print(request.FILES) #请求发过来的文件

    # 声明图片的对象
    file_object = request.FILES.get("avatar")

    # 分块进行存储
    # file_object.name 表示图片上传时图片本身是什么名字,保存图片时就用什么名字
    f = open(file_object.name, mode='wb')
    for chunk in file_object.chunks():
        f.write(chunk)
    f.close()

    return HttpResponse("上传成功")

from django import forms
from app01.utils.bootstrap import BootStrapForm
class UpForm(BootStrapForm):
    bootstrap_exclude_fields = ['img']

    name = forms.CharField(label="姓名")
    age = forms.IntegerField(label="年龄")
    img = forms.FileField(label="头像")


def upload_form(request):
    title = "Form上传"
    if request.method == "GET":
        form = UpForm()
        return render(request, 'upload_form.html', {"form":form, "title":title})
    form = UpForm(data=request.POST, files=request.FILES)
    if form.is_valid():
        #cleaned_data:{'name': '方法', 'age': 11, 'img': <InMemoryUploadedFile: 20200119123801_bjxpj.jpg (image/jpeg)>}
        #print(form.cleaned_data)
        #读取到内容,自己处理每个字段的数据
        #1.读取图片内容,写入文件夹中并获取文件的路径
        image_object = form.cleaned_data.get("img")
        #file_path = "app01/static/img/{}".format(image_object.name)
        #win系统和Linux系统/有差别,建议用os做拼接
        file_path = os.path.join("app01","static", "img", image_object.name)
        f = open(file_path, mode='wb')
        for chunk in image_object.chunks():
            f.write(chunk)
            f.close()

        #2.将图片文件路径写入到数据库
        models.Boss.objects.create(
            name=form.cleaned_data['name'],
            age=form.cleaned_data['age'],
            img=file_path,
        )

        return HttpResponse("...")
    return render(request, 'upload_form.html', {"form":form, "title":title})

  

 

 数据库中查看新增数据

 

 此时查看图片地址:http://127.0.0.1:8000/app01/static/img+图片文件名

怎么把app01去掉,直接http://127.0.0.1:8000/static/img+图片文件名 访问呢

 修改myproject/app01/views/upload.py

def upload_form(request):
    title = "Form上传"
    if request.method == "GET":
        form = UpForm()
        return render(request, 'upload_form.html', {"form":form, "title":title})
    form = UpForm(data=request.POST, files=request.FILES)
    if form.is_valid():
        #cleaned_data:{'name': '方法', 'age': 11, 'img': <InMemoryUploadedFile: 20200119123801_bjxpj.jpg (image/jpeg)>}
        #print(form.cleaned_data)
        #读取到内容,自己处理每个字段的数据
        #1.读取图片内容,写入文件夹中并获取文件的路径
        image_object = form.cleaned_data.get("img")
        #file_path = "app01/static/img/{}".format(image_object.name)
        #win系统和Linux系统/有差别,建议用os做拼接
        db_file_path = os.path.join("static", "img", image_object.name)
        file_path = os.path.join("app01",db_file_path)
        f = open(file_path, mode='wb')
        for chunk in image_object.chunks():
            f.write(chunk)
            f.close()

        #2.将图片文件路径写入到数据库
        models.Boss.objects.create(
            name=form.cleaned_data['name'],
            age=form.cleaned_data['age'],
            img=db_file_path,
        )

        return HttpResponse("...")
    return render(request, 'upload_form.html', {"form":form, "title":title})

  

 浏览器新增加一条数据

 

 

 就目前而言,所有的静态文件都只能放在static目录

后续可以分开

static存放项目的静态文件

media目录存放用户上传的文件

在django开发过程中有两个特殊的文件夹

static:存放静态文件的路径,包括CSS、JS、项目图片

 media:用户上传的数据的目录,但是使用 media 需要做一些配置

启用media

1.在urls.py中进行配置

from django.urls import path, re_path
from django.views.static import serve
from django.conf import settings

urlpatterns = [

    # path('admin/', admin.site.urls),
    re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}, name='media'),
]

  

 2.在settings中进行配置

import os

MEDIA_ROOT = os.path.join(BASE_DIR, "media") MEDIA_URL = "/media/"

 

新建目录myproject/media 

配置后就可以在浏览器上访问地址了:127.0.0.1;8000/media/+图片名字

我们来修改一下上面图片的上传路径试试吧

 修改myproject/app01/views/upload.py

import os
from django.conf import settings
from django.shortcuts import render, HttpResponse
from app01 import models
def upload_list(request):
    if request.method == "GET":
        return render(request, 'upload_list.html')
    # print(request.POST) #请求中的数据
    # print(request.FILES) #请求发过来的文件

    # 声明图片的对象
    file_object = request.FILES.get("avatar")

    # 分块进行存储
    # file_object.name 表示图片上传时图片本身是什么名字,保存图片时就用什么名字
    f = open(file_object.name, mode='wb')
    for chunk in file_object.chunks():
        f.write(chunk)
    f.close()

    return HttpResponse("上传成功")

from django import forms
from app01.utils.bootstrap import BootStrapForm
class UpForm(BootStrapForm):
    bootstrap_exclude_fields = ['img']

    name = forms.CharField(label="姓名")
    age = forms.IntegerField(label="年龄")
    img = forms.FileField(label="头像")


def upload_form(request):
    title = "Form上传"
    if request.method == "GET":
        form = UpForm()
        return render(request, 'upload_form.html', {"form":form, "title":title})
    form = UpForm(data=request.POST, files=request.FILES)
    if form.is_valid():
        #cleaned_data:{'name': '方法', 'age': 11, 'img': <InMemoryUploadedFile: 20200119123801_bjxpj.jpg (image/jpeg)>}
        #print(form.cleaned_data)
        #读取到内容,自己处理每个字段的数据
        #1.读取图片内容,写入文件夹中并获取文件的路径
        image_object = form.cleaned_data.get("img")
        #file_path = "app01/static/img/{}".format(image_object.name)
        #win系统和Linux系统/有差别,建议用os做拼接
        #db_file_path = os.path.join("static", "img", image_object.name)



        media_path = os.path.join(settings.MEDIA_ROOT, image_object.name)

        f = open(media_path, mode='wb')
        for chunk in image_object.chunks():
            f.write(chunk)
            f.close()

        #2.将图片文件路径写入到数据库
        models.Boss.objects.create(
            name=form.cleaned_data['name'],
            age=form.cleaned_data['age'],
            img=media_path,
        )

        return HttpResponse("...")
    return render(request, 'upload_form.html', {"form":form, "title":title})

  

 

 

 

 

返回的是绝对路径 C:\Users\lenovo\Desktop\dj_base\pythoncode\gx\day16\media\84268f771c2c053555fb28a860134baf.jpeg

 若不想用绝对路径,改为相对路径

 修改myproject/app01/views/upload.py

        #settings.MEDIA_ROOT返回的是绝对路径 C:\Users\lenovo\Desktop\dj_base\pythoncode\gx\day16\media\84268f771c2c053555fb28a860134baf.jpeg
        #media_path = os.path.join(settings.MEDIA_ROOT, image_object.name)
        #相对路径
        media_path = os.path.join("media", image_object.name)

  

 

 

 

 

 案例:混合数据上传(ModelForm)

新加一个按钮

编辑myproject/app01/templates/layout.html

            <ul class="nav navbar-nav">
                <li class="dropdown">
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
                       aria-expanded="false">功能管理 <span class="caret"></span></a>
                    <ul class="dropdown-menu">
                        <li><a href="/admin/list/">管理员账户管理</a></li>
                        <li><a href="/depart/list/">部门管理</a></li>
                        <li><a href="/user/list/">用户管理</a></li>
                        <li><a href="/prettynum/list/">靓号管理</a></li>
                        <li><a href="/task/list/">任务管理</a></li>
                    </ul>
                </li>

                <li><a href="/chart/list/">数据统计</a></li>
                <li><a href="/chart/highcharts/">Highcharts</a></li>
                <li><a href="/upload/list/">上传图片</a></li>
                <li><a href="/upload/form/">Form上传</a></li>
                <li><a href="/upload/model/form/">ModelForm上传</a></li>
            </ul>

添加路由

编辑myproject/myproject/urls.py

path('upload/model/form/', upload.upload_model_form),

编辑myproject/myproject/models.py创建一个新的数据库

class City(models.Model):
    """城市"""
    name = models.CharField(verbose_name="名称", max_length=32)
    count = models.IntegerField(verbose_name="人口")
    #本质上数据库中也是CharField,FileField可以自动保存数据
    img = models.FileField(verbose_name="LOGO", max_length=128, upload_to='city/')

执行命令

makemigrations
migrate

编写视图函数myproject/app01/views/upload.py

import os
from django.conf import settings
from django.shortcuts import render, HttpResponse
from app01 import models
def upload_list(request):
    if request.method == "GET":
        return render(request, 'upload_list.html')
    # print(request.POST) #请求中的数据
    # print(request.FILES) #请求发过来的文件

    # 声明图片的对象
    file_object = request.FILES.get("avatar")

    # 分块进行存储
    # file_object.name 表示图片上传时图片本身是什么名字,保存图片时就用什么名字
    f = open(file_object.name, mode='wb')
    for chunk in file_object.chunks():
        f.write(chunk)
    f.close()

    return HttpResponse("上传成功")

from django import forms
from app01.utils.bootstrap import BootStrapForm, BootStrapModelForm

class UpForm(BootStrapForm):
    bootstrap_exclude_fields = ['img']

    name = forms.CharField(label="姓名")
    age = forms.IntegerField(label="年龄")
    img = forms.FileField(label="头像")
def upload_form(request):
    title = "Form上传"
    if request.method == "GET":
        form = UpForm()
        return render(request, 'upload_form.html', {"form":form, "title":title})
    form = UpForm(data=request.POST, files=request.FILES)
    if form.is_valid():
        #cleaned_data:{'name': '方法', 'age': 11, 'img': <InMemoryUploadedFile: 20200119123801_bjxpj.jpg (image/jpeg)>}
        #print(form.cleaned_data)
        #读取到内容,自己处理每个字段的数据
        #1.读取图片内容,写入文件夹中并获取文件的路径
        image_object = form.cleaned_data.get("img")
        #file_path = "app01/static/img/{}".format(image_object.name)
        #win系统和Linux系统/有差别,建议用os做拼接
        #db_file_path = os.path.join("static", "img", image_object.name)
        #settings.MEDIA_ROOT返回的是绝对路径 C:\Users\lenovo\Desktop\dj_base\pythoncode\gx\day16\media\84268f771c2c053555fb28a860134baf.jpeg
        #media_path = os.path.join(settings.MEDIA_ROOT, image_object.name)
        #相对路径
        media_path = os.path.join("media", image_object.name)

        f = open(media_path, mode='wb')
        for chunk in image_object.chunks():
            f.write(chunk)
            f.close()

        #2.将图片文件路径写入到数据库
        models.Boss.objects.create(
            name=form.cleaned_data['name'],
            age=form.cleaned_data['age'],
            img=media_path,
        )

        return HttpResponse("...")
    return render(request, 'upload_form.html', {"form":form, "title":title})

class UpModelForm(BootStrapModelForm):
    bootstrap_exclude_fields = ['img']
    class Meta:
        model = models.City
        fields = "__all__"

def upload_model_form(request):
    """上传文件和数据(modelform)"""
    title = "ModelForm上传文件"
    if request.method == "GET":
        form = UpModelForm()
        return render(request, 'upload_form.html', {"form": form, "title": title})

    form = UpModelForm(data=request.POST, files=request.FILES)
    if form.is_valid():
        #对于文件自动保存
        #字段+上传路径写入到数据库
        form.save()
        return HttpResponse("成功")
    return render(request, 'upload_form.html', {"form": form, "title": title})

  

 

 

 

 小结

1.自己动手写

file_object = request.FILES.get("exc")
...

2.Form组件(表单验证)

request.POST
file_object = request.FILES.get("exc")

具体文件操作还是需要手动做

3.ModelForm(表单验证 + 自动保存数据库 + 自动保存文件)

-配置Media文件夹
-Models.py定义文件要填写路径upload_to='路径'
  img = models.FileField(verbose_name="LOGO", max_length128, upload_to = 'city/')

 

 

posted @ 2023-11-06 15:48  可可eleven  阅读(94)  评论(0)    收藏  举报