【问题标题】:How to upload a file in Django? [closed]如何在 Django 中上传文件? [关闭]
【发布时间】:2011-08-17 19:43:51
【问题描述】:

作为 Django 的新手,我在 Django 1.3 中制作上传应用程序时遇到了困难。我找不到任何最新的示例/sn-ps。有人可以发布一个最小但完整的(模型、视图、模板)示例代码吗?

【问题讨论】:

    标签: django file upload


    【解决方案1】:

    唷,Django 文档真的没有很好的例子。我花了 2 个多小时来挖掘所有的碎片以了解它是如何工作的。有了这些知识,我实现了一个项目,可以上传文件并将它们显示为列表。要下载该项目的源代码,请访问https://github.com/axelpale/minimal-django-file-upload-example 或克隆它:

    > git clone https://github.com/axelpale/minimal-django-file-upload-example.git
    

    2013-01-30 更新: GitHub 上的源代码除了 1.3 之外还实现了 Django 1.4。尽管更改很少,以下教程对 1.4 也很有用。

    2013-05-10 更新: 在 GitHub 上实现 Django 1.5。 urls.py 中的重定向和 list.html 中 url 模板标签的使用的微小变化。感谢hubert3 的努力。

    2013-12-07 更新: GitHub 支持 Django 1.6。在 myapp/urls.py 中更改了一项导入。感谢Arthedian

    2015-03-17 更新: GitHub 支持 Django 1.7,感谢 aronysidoro

    2015-09-04 更新: GitHub 支持 Django 1.8,感谢 nerogit

    2016-07-03 更新: GitHub 支持 Django 1.9,感谢 daavvenerogit

    项目树

    一个基本的 Django 1.3 项目,具有单个应用程序和用于上传的 media/ 目录。

    minimal-django-file-upload-example/
        src/
            myproject/
                database/
                    sqlite.db
                media/
                myapp/
                    templates/
                        myapp/
                            list.html
                    forms.py
                    models.py
                    urls.py
                    views.py
                __init__.py
                manage.py
                settings.py
                urls.py
    

    1。设置:myproject/settings.py

    ​​>

    要上传和提供文件,您需要指定 Django 存储上传文件的位置以及 Django 从哪个 URL 提供文件。 MEDIA_ROOT 和 MEDIA_URL 默认在 settings.py 中,但它们是空的。有关详细信息,请参阅Django Managing Files 中的第一行。记住还要设置数据库并将 myapp 添加到 INSTALLED_APPS

    ...
    import os
    
    BASE_DIR = os.path.dirname(os.path.dirname(__file__))
    ...
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'database.sqlite3'),
            'USER': '',
            'PASSWORD': '',
            'HOST': '',
            'PORT': '',
        }
    }
    ...
    MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
    MEDIA_URL = '/media/'
    ...
    INSTALLED_APPS = (
        ...
        'myapp',
    )
    

    2。模型:myproject/myapp/models.py

    ​​>

    接下来您需要一个带有 FileField 的模型。此特定字段存储文件,例如根据当前日期和 MEDIA_ROOT 到 media/documents/2011/12/24/。见FileField reference

    # -*- coding: utf-8 -*-
    from django.db import models
    
    class Document(models.Model):
        docfile = models.FileField(upload_to='documents/%Y/%m/%d')
    

    3。表单:myproject/myapp/forms.py

    ​​>

    要很好地处理上传,您需要一个表单。此表单只有一个字段,但已足够。详情请见Form FileField reference

    # -*- coding: utf-8 -*-
    from django import forms
    
    class DocumentForm(forms.Form):
        docfile = forms.FileField(
            label='Select a file',
            help_text='max. 42 megabytes'
        )
    

    4。查看:myproject/myapp/views.py

    ​​>

    所有魔术都发生的视图。注意request.FILES 的处理方式。对我来说,真的很难发现 request.FILES['docfile'] 可以像这样保存到 models.FileField 中。模型的 save() 自动处理文件到文件系统的存储。

    # -*- coding: utf-8 -*-
    from django.shortcuts import render_to_response
    from django.template import RequestContext
    from django.http import HttpResponseRedirect
    from django.core.urlresolvers import reverse
    
    from myproject.myapp.models import Document
    from myproject.myapp.forms import DocumentForm
    
    def list(request):
        # Handle file upload
        if request.method == 'POST':
            form = DocumentForm(request.POST, request.FILES)
            if form.is_valid():
                newdoc = Document(docfile = request.FILES['docfile'])
                newdoc.save()
    
                # Redirect to the document list after POST
                return HttpResponseRedirect(reverse('myapp.views.list'))
        else:
            form = DocumentForm() # A empty, unbound form
    
        # Load documents for the list page
        documents = Document.objects.all()
    
        # Render list page with the documents and the form
        return render_to_response(
            'myapp/list.html',
            {'documents': documents, 'form': form},
            context_instance=RequestContext(request)
        )
    

    5。项目网址:myproject/urls.py

    ​​>

    Django 默认不提供 MEDIA_ROOT 服务。这在生产环境中会很危险。但在开发阶段,我们可以缩短。注意最后一行。该行使 Django 能够从 MEDIA_URL 提供文件。这仅在开发阶段有效。

    详情请见django.conf.urls.static.static reference。另见this discussion about serving media files

    # -*- coding: utf-8 -*-
    from django.conf.urls import patterns, include, url
    from django.conf import settings
    from django.conf.urls.static import static
    
    urlpatterns = patterns('',
        (r'^', include('myapp.urls')),
    ) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
    

    6。应用网址:myproject/myapp/urls.py

    ​​>

    要使视图可访问,您必须为其指定 url。这里没什么特别的。

    # -*- coding: utf-8 -*-
    from django.conf.urls import patterns, url
    
    urlpatterns = patterns('myapp.views',
        url(r'^list/$', 'list', name='list'),
    )
    

    7。模板:myproject/myapp/templates/myapp/list.html

    最后一部分:列表模板及其下方的上传表单。表单必须将 enctype-attribute 设置为“multipart/form-data”,并将方法设置为“post”,以使上传到 Django 成为可能。详情请见File Uploads documentation

    FileField 有许多可以在模板中使用的属性。例如。 {{ document.docfile.url }} 和 {{ document.docfile.name }} 在模板中。在Using files in models articleThe File object documentation 中查看更多信息。

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <title>Minimal Django File Upload Example</title>   
        </head>
        <body>
        <!-- List of uploaded documents -->
        {% if documents %}
            <ul>
            {% for document in documents %}
                <li><a href="{{ document.docfile.url }}">{{ document.docfile.name }}</a></li>
            {% endfor %}
            </ul>
        {% else %}
            <p>No documents.</p>
        {% endif %}
    
            <!-- Upload form. Note enctype attribute! -->
            <form action="{% url 'list' %}" method="post" enctype="multipart/form-data">
                {% csrf_token %}
                <p>{{ form.non_field_errors }}</p>
                <p>{{ form.docfile.label_tag }} {{ form.docfile.help_text }}</p>
                <p>
                    {{ form.docfile.errors }}
                    {{ form.docfile }}
                </p>
                <p><input type="submit" value="Upload" /></p>
            </form>
        </body>
    </html> 
    

    8。初始化

    只需运行 syncdb 和 runserver。

    > cd myproject
    > python manage.py syncdb
    > python manage.py runserver
    

    结果

    终于,一切准备就绪。在默认的 Django 开发环境中,上传文档的列表可以在 localhost:8000/list/ 看到。今天文件上传到/path/to/myproject/media/documents/2011/12/17/,可以从列表中打开。

    我希望这个答案能像它对我一样帮助别人。

    【讨论】:

    • 在 django 文档中找到显示文件上传的位置。此答案中的示例非常好,但 django 文档中的信息将与新版本保持同步。 docs.djangoproject.com/en/dev/topics/http/file-uploads
    • 该示例不适用于 Django "1.5"。在 HTML 中,{% url list %} 变为 {% url "list" %}
    • 非常感谢。它真的对我有用。但是,对于即将到来的观众,您应该检查 gitHub 中的代码,以获得与新版本 Python 和 Django 的最佳兼容性。例如,views.py、render_to_response() 应该替换为 render(request,...,) 以避免 CSRF 错误。干杯。
    • 没有FORMS也可以这样做吗?
    • 文件可以是.zip,还是其他压缩文件?
    【解决方案2】:

    一般来说,当您尝试“获得一个工作示例”时,最好“开始编写代码”。这里没有可以帮助您的代码,因此对我们来说回答这个问题变得更加容易。

    如果你想抓取一个文件,你需要在某个 html 文件中的某处:

    <form method="post" enctype="multipart/form-data">
        <input type="file" name="myfile" />
        <input type="submit" name="submit" value="Upload" />
    </form>
    

    这会给你一个浏览按钮,一个上传按钮来启动操作(提交表单)并记下 enctype 以便 Django 知道给你request.FILES

    在某个视图中,您可以使用以下命令访问文件

    def myview(request):
        request.FILES['myfile'] # this is my file
    

    file upload docs里面信息量很大

    我建议您彻底阅读该页面并开始编写代码 - 然后在它不起作用时返回示例和堆栈跟踪。

    【讨论】:

    • 谢谢亨利。实际上我已经阅读了文档并编写了一些代码,但是由于文档有一些差距(例如“从某处导入 handle_uploaded_file”)并且我的代码有缺陷,我认为如果我可以从一个工作示例开始会更好.
    • 同意qliq。一个简单的工作示例是让新手上手的最有效方法,而不是文档
    • enctype="multipart/form-data" 我需要什么才能完成这项工作,谢谢!
    • 不要错过表单标签中的 {% csrf_token %}。
    • 可以在没有 FORMS.PY 的表格的情况下执行此操作吗?
    【解决方案3】:

    Demo

    查看github repo,与 Django 3 一起使用

    一个最小的 Django 文件上传示例

    1。创建一个django项目

    运行 startproject::

    $ django-admin.py startproject sample
    

    现在创建了一个文件夹(sample)。

    2。创建应用

    创建一个应用::

    $ cd sample
    $ python manage.py startapp uploader
    

    现在创建了一个包含这些文件的文件夹(uploader)::

    uploader/
      __init__.py
      admin.py
      app.py
      models.py
      tests.py
      views.py
      migrations/
        __init__.py
    

    3。更新 settings.py

    ​​>

    sample/settings.py 上添加'uploader'INSTALLED_APPS 并添加MEDIA_ROOTMEDIA_URL,即::

    INSTALLED_APPS = [
        'uploader',
        ...<other apps>...      
    ]
    
    MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
    MEDIA_URL = '/media/'
    

    4。更新 urls.py

    ​​>

    sample/urls.py添加::

    ...<other imports>...
    from django.conf import settings
    from django.conf.urls.static import static
    from uploader import views as uploader_views
    
    urlpatterns = [
        ...<other url patterns>...
        path('', uploader_views.UploadView.as_view(), name='fileupload'),
    ]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
    

    5。更新 models.py

    ​​>

    更新uploader/models.py::

    from django.db import models
    class Upload(models.Model):
        upload_file = models.FileField()    
        upload_date = models.DateTimeField(auto_now_add =True)
    

    6。更新views.py

    ​​>

    更新uploader/views.py::

    from django.views.generic.edit import CreateView
    from django.urls import reverse_lazy
    from .models import Upload
    class UploadView(CreateView):
        model = Upload
        fields = ['upload_file', ]
        success_url = reverse_lazy('fileupload')
        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            context['documents'] = Upload.objects.all()
            return context
    

    7。创建模板

    创建一个文件夹sample/uploader/templates/uploader

    创建一个文件upload_form.htmlsample/uploader/templates/uploader/upload_form.html::

    <div style="padding:40px;margin:40px;border:1px solid #ccc">
        <h1>Django File Upload</h1>
        <form method="post" enctype="multipart/form-data">
          {% csrf_token %}
          {{ form.as_p }}
          <button type="submit">Submit</button>
        </form><hr>
        <ul>
        {% for document in documents %}
            <li>
                <a href="{{ document.upload_file.url }}">{{ document.upload_file.name }}</a>
                <small>({{ document.upload_file.size|filesizeformat }}) - {{document.upload_date}}</small>
            </li>
        {% endfor %}
        </ul>
    </div>
    

    8。同步数据库

    同步数据库和运行服务器::

    $ python manage.py makemigrations
    $ python manage.py migrate
    $ python manage.py runserver
    

    访问http://localhost:8000/

    【讨论】:

    • 完美,除了最后一行 - 应该是 localhost.com:8000/upload> 这适用于 django 1.6 和 Python 3.3。
    • +1 用于可重用的 django 应用程序设计模式
    • Akseli 使用了FileField,而 suhail 使用了ImageField,有人可以解释一下这些选择吗?
    • @dtgq 我更新了答案以使用FileFieldImageField 必须仅用于图片上传。该更新将适用于 Django 1.11。
    • 在 Django 2.0 上测试并完美运行
    【解决方案4】:

    我必须说我发现 django 的文档令人困惑。 同样对于最简单的示例,为什么要提到表格? 我在views.py中工作的例子是:-

    for key, file in request.FILES.items():
        path = file.name
        dest = open(path, 'w')
        if file.multiple_chunks:
            for c in file.chunks():
                dest.write(c)
        else:
            dest.write(file.read())
        dest.close()
    

    html文件看起来像下面的代码,虽然这个例子只上传了一个文件,保存文件的代码处理了很多:-

    <form action="/upload_file/" method="post" enctype="multipart/form-data">{% csrf_token %}
    <label for="file">Filename:</label>
    <input type="file" name="file" id="file" />
    <br />
    <input type="submit" name="submit" value="Submit" />
    </form>
    

    这些示例不是我的代码,它们是从我找到的另外两个示例中选择的。 我是 django 的相对初学者,所以很可能我错过了一些关键点。

    【讨论】:

    • +1 表示不使用FileFieldmodel.Form。对于初学者(和琐碎的任务)来说,手动处理如上所示的上传文件不会那么混乱。
    • dest = open(path, 'wb') 当文件写入字节时
    【解决方案5】:

    我也有类似的要求。网上的大多数示例都要求创建模型并创建我不想使用的表单。这是我的最终代码。

    if request.method == 'POST':
        file1 = request.FILES['file']
        contentOfFile = file1.read()
        if file1:
            return render(request, 'blogapp/Statistics.html', {'file': file1, 'contentOfFile': contentOfFile})
    

    我在要上传的 HTML 中写道:

    {% block content %}
        <h1>File content</h1>
        <form action="{% url 'blogapp:uploadComplete'%}" method="post" enctype="multipart/form-data">
             {% csrf_token %}
            <input id="uploadbutton" type="file" value="Browse" name="file" accept="text/csv" />
            <input type="submit" value="Upload" />
        </form>
        {% endblock %}
    

    以下是显示文件内容的 HTML:

    {% block content %}
        <h3>File uploaded successfully</h3>
        {{file.name}}
        </br>content = {{contentOfFile}}
    {% endblock %}
    

    【讨论】:

    • 很好,因为有时只想使用文件的内容而不是保存上传...
    【解决方案6】:

    扩展至Henry's example:

    import tempfile
    import shutil
    
    FILE_UPLOAD_DIR = '/home/imran/uploads'
    
    def handle_uploaded_file(source):
        fd, filepath = tempfile.mkstemp(prefix=source.name, dir=FILE_UPLOAD_DIR)
        with open(filepath, 'wb') as dest:
            shutil.copyfileobj(source, dest)
        return filepath
    

    您可以使用上传的文件对象从您的视图中调用此handle_uploaded_file 函数。这将在文件系统中以唯一名称(以原始上传文件的文件名为前缀)保存文件,并返回保存文件的完整路径。您可以将路径保存在数据库中,然后对文件进行处理。

    【讨论】:

    • Imran,我在视图上尝试了您的代码,但收到此错误:'WSGIRequest' object has no attribute 'name'。
    • 将上传的文件对象 (request.FILES['myfile']) 传递给 handle_uploaded_file,而不是 request 本身。
    • 我可以直接保存到数据库吗? stackoverflow.com/questions/24705246/…
    • 通过使用prefix=source.name,它在文件末尾添加了额外的字符,弄乱了文件扩展名。例如。 upload.csv 已更改为 upload.csv5334。将其更改为 suffix=source.name 已为我修复。
    【解决方案7】:

    这里可能对您有所帮助: 在你的 models.py 中创建一个文件字段

    用于上传文件(在您的 admin.py 中):

    def save_model(self, request, obj, form, change):
        url = "http://img.youtube.com/vi/%s/hqdefault.jpg" %(obj.video)
        url = str(url)
    
        if url:
            temp_img = NamedTemporaryFile(delete=True)
            temp_img.write(urllib2.urlopen(url).read())
            temp_img.flush()
            filename_img = urlparse(url).path.split('/')[-1]
            obj.image.save(filename_img,File(temp_img)
    

    并在您的模板中使用该字段。

    【讨论】:

    【解决方案8】:

    您可以参考Fine Uploader中的服务器示例,它有django版本。 https://github.com/FineUploader/server-examples/tree/master/python/django-fine-uploader

    它非常优雅,最重要的是,它提供了特色的 js 库。模板不包含在服务器示例中,但您可以在其网站上找到演示。 上传者:http://fineuploader.com/demos.html

    django-fine-uploader

    views.py

    UploadView 将发布和删除请求分派给相应的处理程序。

    class UploadView(View):
    
        @csrf_exempt
        def dispatch(self, *args, **kwargs):
            return super(UploadView, self).dispatch(*args, **kwargs)
    
        def post(self, request, *args, **kwargs):
            """A POST request. Validate the form and then handle the upload
            based ont the POSTed data. Does not handle extra parameters yet.
            """
            form = UploadFileForm(request.POST, request.FILES)
            if form.is_valid():
                handle_upload(request.FILES['qqfile'], form.cleaned_data)
                return make_response(content=json.dumps({ 'success': True }))
            else:
                return make_response(status=400,
                    content=json.dumps({
                        'success': False,
                        'error': '%s' % repr(form.errors)
                    }))
    
        def delete(self, request, *args, **kwargs):
            """A DELETE request. If found, deletes a file with the corresponding
            UUID from the server's filesystem.
            """
            qquuid = kwargs.get('qquuid', '')
            if qquuid:
                try:
                    handle_deleted_file(qquuid)
                    return make_response(content=json.dumps({ 'success': True }))
                except Exception, e:
                    return make_response(status=400,
                        content=json.dumps({
                            'success': False,
                            'error': '%s' % repr(e)
                        }))
            return make_response(status=404,
                content=json.dumps({
                    'success': False,
                    'error': 'File not present'
                }))
    

    forms.py

    class UploadFileForm(forms.Form):
    
        """ This form represents a basic request from Fine Uploader.
        The required fields will **always** be sent, the other fields are optional
        based on your setup.
        Edit this if you want to add custom parameters in the body of the POST
        request.
        """
        qqfile = forms.FileField()
        qquuid = forms.CharField()
        qqfilename = forms.CharField()
        qqpartindex = forms.IntegerField(required=False)
        qqchunksize = forms.IntegerField(required=False)
        qqpartbyteoffset = forms.IntegerField(required=False)
        qqtotalfilesize = forms.IntegerField(required=False)
        qqtotalparts = forms.IntegerField(required=False)
    

    【讨论】:

      【解决方案9】:

      不确定这种方法是否有任何缺点,但在views.py中甚至更小:

      entry = form.save()
      
      # save uploaded file
      if request.FILES['myfile']:
          entry.myfile.save(request.FILES['myfile']._name, request.FILES['myfile'], True)
      

      【讨论】:

        【解决方案10】:

        我遇到了类似的问题,并由 django 管理站点解决。

        # models
        class Document(models.Model):
            docfile = models.FileField(upload_to='documents/Temp/%Y/%m/%d')
        
            def doc_name(self):
                return self.docfile.name.split('/')[-1] # only the name, not full path
        
        # admin
        from myapp.models import Document
        class DocumentAdmin(admin.ModelAdmin):
            list_display = ('doc_name',)
        admin.site.register(Document, DocumentAdmin)
        

        【讨论】:

        猜你喜欢
        • 2019-04-09
        • 1970-01-01
        • 2011-09-30
        • 2013-08-27
        • 2017-08-18
        • 1970-01-01
        • 2017-12-12
        相关资源
        最近更新 更多