Как загрузить файл в Django? [закрыто]

668

Как новичок в Django, я испытываю трудности при создании приложения для загрузки в Django 1.3. Я не смог найти ни одного актуального примера / фрагмента. Может ли кто-нибудь опубликовать для этого минимальный, но полный пример кода (Model, View, Template)?

qliq
источник

Ответы:

1273

Уф, документация 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 также имеет реализацию для Django 1.4 в дополнение к 1.3. Несмотря на небольшое количество изменений, следующий урок также полезен для 1.4.

Обновление 2013-05-10: реализация для Django 1.5 на GitHub. Небольшие изменения в перенаправлении в urls.py и использование тега шаблона URL в list.html. Спасибо hubert3 за усилия.

Обновление 2013-12-07: Django 1.6 поддерживается на GitHub. Один импорт изменен в myapp / urls.py. Спасибо идет в Arthedian .

Обновление 2015-03-17: Django 1.7 поддерживается на GitHub, благодаря aronysidoro .

Обновление 2015-09-04: Django 1.8 поддерживается на GitHub, благодаря nerogit .

Обновление 2016-07-03: Django 1.9 поддерживается на GitHub, благодаря daavve и nerogit

Дерево проекта

Базовый проект Django 1.3 с одним приложением и медиа / каталогом для загрузки.

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 хранит загруженные файлы и с какого URL Django их обслуживает. 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 / documents / 2011/12/24 / на основе текущей даты и MEDIA_ROOT. Смотрите ссылку на FileField .

# -*- 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

Для удобной загрузки вам нужна форма. Эта форма имеет только одно поле, но этого достаточно. См. Ссылку FileField формы для деталей.

# -*- 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']можно сохранить в моделях. 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. URL проекта: myproject / urls.py

Django не обслуживает MEDIA_ROOT по умолчанию. Это было бы опасно в производственной среде. Но на стадии разработки мы могли бы прервать. Обратите внимание на последнюю строчку. Эта строка позволяет Django обслуживать файлы из MEDIA_URL. Это работает только в стадии разработки.

Подробности смотрите в django.conf.urls.static.static . Смотрите также это обсуждение об обслуживании медиа-файлов .

# -*- 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. URL-адреса приложений: 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, установленный в «multipart / form-data», и метод, установленный в «post», чтобы сделать возможной загрузку в Django. Подробнее смотрите в документации по загрузке файлов .

FileField имеет много атрибутов, которые можно использовать в шаблонах. Например, {{document.docfile.url}} и {{document.docfile.name}} как в шаблоне. Подробнее об этом см. В статье « Использование файлов в моделях» и документации по объекту «Файл» .

<!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 / и могут быть открыты из списка.

Я надеюсь, что этот ответ поможет кому-то так же, как и мне.

Аксели Пален
источник
9
Нашел место в django docs, которое показывает загрузку файлов. Пример в этом ответе превосходен, но информация в документации django будет обновляться с новыми выпусками. docs.djangoproject.com/en/dev/topics/http/file-uploads
ТайваньGrapefruitTea
1
Пример не работает для Django "1.5". В HTML {% url list %}делается {% url "list" %}.
Матье Риглер
4
Большое спасибо . Это действительно работает для меня. Однако, для будущих зрителей, вы должны проверить код в gitHub для лучшей совместимости с новыми версиями Python и Django. Например, views.py, render_to_response () следует заменить на render (request, ...,), чтобы избежать ошибки CSRF. Приветствия.
Хай, чем
1
Возможно ли это сделать без форм?
Roel
1
Может быть файл .zip или другие сжатые файлы?
qg_java_17137
74

Вообще говоря, когда вы пытаетесь «просто получить рабочий пример», лучше всего «просто начать писать код». Здесь нет кода, который мог бы вам помочь, поэтому он делает ответ на этот вопрос намного более полезным для нас.

Если вы хотите получить файл, вам нужно что-то вроде этого в html-файле:

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

Это даст вам кнопку обзора, кнопку загрузки, чтобы начать действие (отправить форму) и отметить энктип, чтобы Django знал, чтобы дать вам request.FILES

В представлении где-то вы можете получить доступ к файлу с

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

В документах для загрузки файлов содержится огромное количество информации.

Я рекомендую вам внимательно прочитать страницу и просто начать писать код, а затем возвращаться с примерами и трассировкой стека, когда он не работает.

Генри
источник
10
Спасибо, Генри. На самом деле я прочитал документы и написал некоторый код, но поскольку в документах есть пробелы (например, «откуда-то импортировать handle_uploaded_file»), и мой код был ошибочным, я подумал, что было бы намного лучше, если бы я мог начать с рабочего примера ,
Qliq
26
Согласитесь с qliq. Простой рабочий пример - самый эффективный способ начать работу новичков, а не документов
Philip007
11
enctype="multipart/form-data", Что мне нужно , чтобы сделать эту работу, спасибо!
Джон Чарльз
5
Только не пропустите {% csrf_token%} внутри тегов формы.
Йонинканада
возможно ли это делать БЕЗ ФОРМ ИЗ FORMS.PY?
Рул
71

демонстрация

Смотрите репозиторий github , работает с Django 3

Минимальный пример загрузки файла Django

1. Создайте проект Django

Запустите startproject ::

$ django-admin.py startproject 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_ROOTи MEDIA_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.html т.е. sample/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 /

suhailvs
источник
2
отлично, за исключением последней строки - должно быть localhost.com:8000/upload > Это сработало для django 1.6 и Python 3.3.
Стив
5
+1 за многоразовый шаблон дизайна приложения django
Марсель
1
Аксели использовал какое- FileFieldто время, а Сухаил использовал ImageField, может кто-нибудь объяснить, пожалуйста, выбор?
2006 г.
@dtgq Я обновил ответ, чтобы использовать с FileField. ImageFieldнеобходимо только для загрузки изображения. обновление будет работать с Django 1.11.
suhailvs
протестирован на Django 2.0 и работал отлично
Diek
29

Я должен сказать, что нахожу документацию в 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, поэтому очень вероятно, что я упустил какой-то ключевой момент.

jimscafe
источник
3
+1 за неиспользование а FileFieldи а model.Form. Для начинающих (и для тривиальных задач) ручная обработка загруженных файлов, как показано выше, менее запутанна.
AneesAhmed777
dest = open (путь, 'wb'), когда запись файла с байтами
Бипул Рой
20

У меня тоже было подобное требование. Большинство примеров в сети просят создать модели и формы, которые я не хотел использовать. Вот мой окончательный код.

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 %}
Четан Павар
источник
хорошо, потому что иногда просто хочется использовать содержимое файла, а не сохранять загрузку ...
nemesisfixx
17

Продолжая на примере Генри :

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функцию из своего поля зрения с загруженным файловым объектом. Это сохранит файл с уникальным именем (с префиксом имени исходного загруженного файла) в файловой системе и вернет полный путь сохраненного файла. Вы можете сохранить путь в базе данных и что-то сделать с файлом позже.

Имран
источник
Имран, я попробовал твой код на моем представлении, но получил эту ошибку: объект 'WSGIRequest' не имеет атрибута 'name'.
Qliq
2
Передайте объект загруженного файла ( request.FILES['myfile']) handle_uploaded_file, а не requestсамому себе.
Имран
Могу ли я сохранить его непосредственно в базе данных? stackoverflow.com/questions/24705246/…
AlexandruC
При prefix=source.nameего использовании добавляются дополнительные символы в конце файла, что портит расширение файла. Например, upload.csvизменился на upload.csv5334. Меняя это, чтобы suffix=source.nameисправить это для меня.
Тарим Икбал
13

Здесь это может помочь вам: создайте поле файла в вашем 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)

и используйте это поле в вашем шаблоне.

Виджеш Венугопал
источник
1
Это полезно, когда вам нужно вручную закалить файлы, которые вы хотите сохранить. Если это так, вам также может понадобиться этот раздел: docs.djangoproject.com/en/dev/topics/files/#the-file-object
kecske
11

Вы можете обратиться к примерам сервера в Fine Uploader, который имеет версию django. https://github.com/FineUploader/server-examples/tree/master/python/django-fine-uploader

Это очень элегантный и самый важный из всех, он предоставляет JS lib. Шаблон не включен в примеры серверов, но вы можете найти демо на его сайте. Fine Uploader: http://fineuploader.com/demos.html

Джанго-тонкий загрузчик

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)
Джавэй Дай
источник
7

Не уверен, есть ли какие-либо недостатки в этом подходе, но еще более минимальный, в views.py:

entry = form.save()

# save uploaded file
if request.FILES['myfile']:
    entry.myfile.save(request.FILES['myfile']._name, request.FILES['myfile'], True)
PhoebeB
источник
0

Я столкнулся с подобной проблемой и решил администратор сайта 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)
hlpmee
источник
[введите описание ссылки здесь] [1] [введите описание ссылки здесь] [2] [1]: youtu.be/0tNZB3dyopY [2]: youtu.be/klhMYMc3PlY
uda123